Modifying the style attributes of selected table cells with jQuery? - javascript

I'm building a pretty basic HTML table creator/editor (based on a designMode iframe) at work, using direct DOM manipulation. It's a pain, obviously due to Internet Explorer.
When in designMode, a table inserted into the editing area iframe is resizable and the contents of the cells can be freely edited. In Firefox, rows and columns can also be added and removed. I'm currently focused on editing border widths, foreground and background colors and other things that require DOM work.
The trouble is the lack of proper DOM Selection/Range functionality in IE6/7. I'm unable to find the containing nodes for several simultaneously selected cells. For a single cell it's doable with parentElement, but for several selected cells, parentElement is the TR node that houses the TD cells. I can't figure out how to extract node references to only those TD cells inside that TR that have been selected, due to lack of anchorNode, focusNode and the various offsets that W3C DOM provides.
I've already got the table creation and the style modification for individual cells as well as groups of selected cells implemented for W3C compliant browsers, but I'm completely stuck with the IE implementation. Could jQuery help me? I've never used it, but it seems intuitive enough that it will take less time to master than it will to figure out how to do this with the IE DOM alone.
There are three basic style modification scenarios that need to work:
A table cell that has not been explicitly selected with Ctrl/Cmd-clicking, but has the text cursor inside it, must have its background color changed. The cell may have formatted text or other parentNode/childNode-relationship complicators in it.
Several explicitly selected table cells (Ctrl/Cmd-clicked, Shift-selected or just "painted over" with the mouse) must have their background colors changed. This has to work for contiguous rectangular selections as well as for scattered, individual selected cells.
Table-level modifications (border width, color etc.) for the "selected table" need to be possible. That is, in the case of several tables in the editing area, the modification will take place for one or more tables that either have cursor focus (scenario 1) or have selected cells in them (scenario 2).
In Firefox, I already have the code for all three scenarios working. Now I need a cross-browser solution. Can anybody help me?
(IE's problems with selections and ranges have been discussed here before, but not in the context of jQuery. I found these at a glance: 164147, 218043, 235411)

If I understand you properly, you want the general code for selecting table cells, and changing properties (CSS attributes) for the selection.
You can do this easily in jQuery.
var curTableCell = null; // "Softclicked" - not part of the selection (1)
// We call this in the click event below. You'd probably want this for keyboard events as well (for arrow key nav, etc.)
function softclick(element) {
$(curTableCell).removeClass('softclicked');
curTableCell = element;
$(element).addClass('softclicked');
}
$('td, th').click(function() {
if(keyHeld) { // Dunno how you do this (I'm not good at Javascript)
$(this).toggleClass('selected'); // Explicitly added/removed to/from selection (2)
} else {
softclick(this);
}
});
/* When you want to do something on selection: */
$('td.selected, th.selected').css({borderColor: 'red', borderWidth: '1px'});
/* When you want to do something on selected tables (3): */
$('td.selected, th.selected').parents('table')
.css({borderColor: 'red', borderWidth: '1px'});
$('td.selected, th.selected').parents('table').children('td') // Change things on all of table's cells
.css({borderColor: 'red', borderWidth: '1px'});
$('td.selected, th.selected, td.softclicked, th.softclicked').parents('table').children('td') // Change things on all of table's cells, including tables of "softclicked" cells
.css({borderColor: 'red', borderWidth: '1px'});
(I am not too good at Javascript or jQuery (am learning at the moment), but I hope this is enough to get you started.)

Related

Make jqGrid's cb column wider

I'm using free-jqGrid and jqGrid has the option to place selection checkboxes for you onto the grid. On my grid I have two columns in the beginning which is placed by jqGrid and not backed up by my own data: a record number column 'rn' and the checkbox for record selection 'cb' (multi select in my case).
I feature the jqGrid on a bootstrap website, so when the loadComplete event hits, I add 'from-control' class to a lot of edits, like the per column search boxes and basically every edit I can find on the page. (I also replace every ugly little icon to glyphicons. I manipulate the DOM of the toolbar buttons so they become real buttons, so they look nicer and chardin.js work well for example. And so on and on and on. The end result is much better than the original. BTW, I'm not sure if that's the best practice, I couldn't find a better way to make jqGrid more bootstrappy, but this can be another question).
When you apply form-control class to a checkbox, it bloats up. That's beneficial, because it's much easier to click on it, you don't need to have a magnifier glass (like for the original tiny checkbox). I can nicely resize the columns for all those data columns what I supply data for, but I cannot figure out how to widen the cb column so it can accommodate the bloated up checkbox.
I tried adding a configuration for that column in my colModel:
Both
{
name: 'cb',
width: 38,
align: 'center',
sortable: false,
}
and
{
width: 38,
align: 'center',
sortable: false,
}
failed, I got an error from jqGrid stating that the number of colModels doesn't match the number of supplied data. That's true, because the data behind the cb column is not backed up by me.
I tried in the loadComplete
var $ajaxGrid = $("#ajaxGrid");
$ajaxGrid.jqGrid('setColProp', 'cb', { width: 38 });
That didn't give me an error, but also didn't change anything. Maybe I should put it into another event handler? Which?
Then I tried to go down the rocky road of manipulation:
$("#ajaxGrid_cb").css("width", "38px");
$(".td_cbox").css("width", "38px");
As you see I separately widen the header and the td elements. But this causes the table horizontal scrollbar to appear. Yuck! I tried to tumble deeper into the hacking hole, and make a wider column on the grid narrower to make the scrollbar disappear, but this didn't help:
$("#ajaxGrid_Name").css("width", "435px");
$('td[aria-describedby="ajaxGrid_Name"]').css("width", "435px");
There must be a way. Now it's ugly. Screenshot:
(Another style problem you can also see is for the Combined column I specify align: 'center' in the colModel but it has no effect.)
You can use multiselectWidth to specify the width of the multiselect column:
multiselectWidth: 38
One more alternative: you can change the columns width later using setColWidth which is the part of free jqGrid. I introduced the method originally in the answer as plugin to old jqGrid versions. Thus the following, for example, will work too:
onInitGrid: function () {
$(this).jqGrid("setColWidth", "cb", 38);
}
The onInitGrid callback or jQuery event "jqGridInitGrid" are good place, where you can modify the grid before the data will be loaded.
P.S. I'm working now on including better support of Bootstrap in free jqGrid. Probably you will just need to use guiStyle: "bootstrap" in the next version of jqGrid to make jqGrid be "in Bootstrap style".

jQuery multiple sortable tables

This question is best read with the fiddle open ;). I've got a tables inside a table. The inside grey tables need to be sorted in there own container. So the grey rows can only be moved in the grey table. But the white rows need to move there grey table with them. So you cannot move a white row or a grey table on there own, they are connected.
Here is my fiddle for what I got right now:
fiddle
options = {
helper: (event, ui) ->
children = ui.children()
view = ui.clone()
view.children().each (index) ->
$(#).width(children.eq(index).width())
return view
}
$('#ccc').find('tbody').sortable(options)
I've been cracking my head on this all day but I cannot figure out how to like a grey table to a white row.
With your current html structure this is quite difficult to achieve.
First of all you need two sortables (one to sort big chunks with white headers and second to sort inside grey tables).
You want to be able to move big tables with small ones inside but as these were all inside sibling elements (tr) it was not really possible (so I've added multiple <tbody>s in there).
Anyway here's the working fiddle: https://jsfiddle.net/9vmvjqm4/5/
You still need to exclude thead from being sortable. I don't like CoffeeScript so I left that (add items : ':not(thead)') to options (or sth like that, there are topics how to do that on stackOverflow).
Also, have a look at this: http://johnny.github.io/jquery-sortable/

How to set HTML Table column widths explicitly in JavaScript

I have hit a scaling problem with an HTML table, whilst manipulating it in JavaScript.
I have a JavaScript code blob that dynamically creates a table from a JSON array.
It fixes the header and allows the table body to scroll, and it works well.
The header is a separate table, and I strongly control cell widths to ensure that the header table's cells match up with the body table cells.
The body table cells all have their width explicitly set.
I iterate the rows in the table, and then interate the cells within that loop, and set each cells width.
This iteration is not scaling, as the rows grow to 100 and the columns get to 40 odd, I get complaints from Firefox that the script is hanging or unresponsive. It is unresponsive, because it is busy setting all the cell widths.
nz.dynatable.setTableColumnWidths = function (table, arrayColumnWidths) {
// Iterate the table and set width settings for each cell
for (var i = 0; i < table.rows.length; ++i) {
for (var j = 0; j < table.rows[i].cells.length; ++j) {
var width = arrayColumnWidths[j] || 0;
table.rows[i].cells[j].style.width = width.toString() + "px";
}
}
}
Q: Is it possible to to set cell widths for a table in one row and have all the other cells in the table fall into line with this? Is Firefox getting whacked because changing the cell widths is causing it to recalc the table size on each loop?
The full code chunk is in a public GitHub repo: https://github.com/Hiblet/DynaTable
Try this: I had have same problem and this is help me:
let tables = document.getElementsByClassName("table");
if(tables.length == 2){
let firstTableCol = tables[0].querySelectorAll('colgroup col');
let secondTableCol = tables[1].querySelectorAll('tr')[0].querySelectorAll('td');
if(firstTableCol.length == secondTableCol.length){
for(let index = 0; index < firstTableCol.length; index++){
firstTableCol[index].style.width = secondTableCol[index].offsetWidth + "px";
}
}else
console.log('cols count mismatch');
}else
console.log('count of tables are bigger than 2');
I tried a few ways to skin this cat and here were my findings. The final solution ended up being very clean and performant, with the caveats that I tested on Chrome, and not other browsers, and with moderately large, but not huge, tables. To summarize, use css such as to following to set the 5th column to width 70, and use javascript to modify that css:
table#my_table th:nth-child(5), table#my_table td:nth-child(5){ max-width:70px; min-width:70px;}
More details:
you need to set both min-width and max-width to avoid columns that you are NOT trying to resize from doing funky stuff in order to keep the table size constant
you can do this using element.style.xxxWidth, but a simple approach such as in the OP doesn't scale well, as the OP notes.
One way to deal with this is to only update the elements that are in a viewable area (let's call this the "viewable area approach"). You can do this by comparing the parent.getBoundingClientRect() results from the parent object and the object you are checking (see e.g. How to tell if a DOM element is visible in the current viewport?)
I was able to get this to work pretty well as long as calls to getBoundingClientRect() (which are expensive) were kept to a minimum (i.e. do it once per column, not per cell). Because I didn't want to maintain a cache of what cells were updated and what were not, after updating viewable cells, I would then update the non-viewable cells using an async function call. This way the UI appeared much more responsive even though it was still doing stuff in the background
However, anything involving direct changes to element.style.xxxWidth felt messy, especially after having to add the code to only update viewable elements. Furthermore, though performance was much better with that change, it still seemed possibly sub-optimal. So the final solution I ended up using was to do the following (let's call this the "dynamic stylesheet approach"):
assume each table will have a unique element ID
initialize the table by creating a new style (document.createElement('style')) for each column. The style that contain one rule that will only select that column for the table with that ID, e.g. for table with id "my_table", column 5 (cellIndex 4), to set width to 70:
table#my_table th:nth-child(5), table#my_table td:nth-child(5){ max-width:70px; min-width:70px;}
add the newly created styleElements to the table element (not the document), so that if the table is removed from the DOM, these extra styles go away also
to change a column width, the only thing that needs to change is the maxWidth / minWidth pieces of rule 0 of the related styleElement (note, you could also do this with a single stylesheet that has multiple rules, but I found it easier to use a separate stylesheet per column with one rule each).
Overall, using the dynamic stylesheet approach was the winner in my view for the following reasons:
it performs well with tables that are large enough to have performance issues under the "naive" approach described in the OP (though I haven't compared the performance of other approaches on very large tables)
it is clean: no element.style changes are required, and it doesn't clutter your basic document DOM as the relevant style elements are attached to the related table (need to test cross-browser)
if its performance isn't already optimized automatically by browsers, its design should make optimization straightforward by leaving the performance challenge up to the browser to handle

Dynamically shorten/hide/overlap tekst in table cells when too long

My table has static width values but sometimes table cells of a certain column can contain text which is too long and which messes up the table's width. I'm looking for a way to dynamically shorten text (kind of like a table grid functionality but then without grids) because it can be of a variable length, and when one hovers over the table cell the entire text is shown without stretching the table.
Currently, I have this hard coded in my script in the following way:
string.substring(0, 65) + '...'; and passing the full text to the 'title' attribute of the table cell.
Note that I don't want to keep using the 'title' attribute. I tried surrounding the text with <span style='position: absolute; background: #EEE'></span> when triggered by the hovering event, but unfortunately that wasn't an appealing solution as the text moved a bit to the bottom while the padding nor the margin style were changed.
The solution can also be a jQuery plugin or JavaScript script.
1. Shortening the original data
I suggest that you consider something more elegant than chopping the string at the 65th character. -- Instead, look for whitespace to break the string at. Only chop mid-word if no whitespace is found.
To save more room in the table cell, use the ellipses character… instead of three periods... Just copy/paste it from this answer. The ellipses character could also be styled with a different or smaller font.
2. Showing the original data on hover
I prefer YUI. Their tooltip widget works well for this. An example.
You should try this CSS instruction:
td { break-word: word-wrap; }
that works in many browsers (yes, including IE 6, even IE 5.5 but not Fx 3.0. It's only recognized by Fx3.5+. Also good for Saf, Chr and Op but I don't know the exact version for these ones) and don't do any harm in the other ones.
If table's width is still messed up, there is also:
table { table-layout: fixed; }
th, td { width: some_value; }
that will force the browser to use the other table algorithm, the one where it doesn't try to adapt many situations including awkward ones but stick to what the stylesheet says.

how to show gridview row in zoom

work on asp.net vs05.i want to set mouse event on gridview
Then based on the event type if event is mouseover it zoom the row else if the event is mouseout it changes the row’s zoom back to its original before the event occurred.
if (e.Row.RowType == DataControlRowType.DataRow )
{
e.Row.Attributes.Add("onmouseover","MouseEvents(this, event)");
e.Row.Attributes.Add("onmouseout", "MouseEvents(this, event)");
}
<script type = "text/javascript">
function MouseEvents(objRef, evt)
{
if (evt.type == "mouseover")
{
objRef.style.height = "100%";
objRef.style.width = "100%";
}
</script>
the above code does not act in this way,Whatever i want .I want zoom in and zoom out?
Although you'd be better off using a JavaScript library to handle this in the long term, I'll just explain how to achieve the zoom effect you're looking for to keep things simple.
Your markup and .NET code is correct the way it is. You'll need to adjust your JavaScript and add some CSS do what you're looking for.
At it's most basic level, what you want to do is this:
function MouseEvents(objRef, evt) {
if (evt.type == "mouseover") {
objRef.style.fontSize= "120%";
} else {
objRef.style.fontSize= "100%";
}
}
Changing the height and width like you did in your question will only change the dimensions of the cells, not the contents. The easiest way to achieve a zoom effect is to increase the font size.
Once you've done this, you need to consider how the flow of your table will be affected by making the font bigge. As the font gets bigger, the height & width of each cell will increase. This can make the layout jump around and become annoying to deal with.
To address height shifts, change the line-height in your table cells. This will ensure that rows don't shift up or down as you hover over them.
To deal with the width shifts, the width of your cells (or better, the table itself) should be set to be large enough that the table itself won't grow as the row needs more space to fit the larger text.
This is how you would address those issues:
tr {line-height: 25px}
/* change the "200px" to be whatever your table needs */
table { 200px }
To take this even further, we can improve the JavaScript to be more flexible...
It is a bad practice to include presentation details in JavaScript. Think about what happens if you need to change the look of a hovered row in the future. If this happens, you'll have to modify code logic, which can be annoying to deal with as your app grows. Presentational rules should be in one place, a central style sheet.
It is better to have JavaScript swap out CSS classes instead. Then you can put your "hover" styling rules in a CSS file. To do this you would change your JavaScript to the following:
function MouseEvents(objRef, evt) {
if (evt.type == "mouseover") {
objRef.className = "hover";
} else {
objRef.className = "";
}
}
Once you've done this, now you can move your "zoom" styles into CSS as the following:
.hover{font-size: 120%}
The JavaScript just adds or removes this CSS class. Anything without this class will have the default 100% font size, and then when that class is added, it will get bigger. Keeping things in CSS also allows you to add other things like changing the background color of the row, the font-weight, the text color, etc. so it is a good idea to do it like this.
A live demo of the code in this answer can be found here: http://jsbin.com/ideve
As I mentioned in the beginning of my post though, you'll be better off using a JavaScript framework like jQuery, Dojo, YUI, MooTools or Prototype. This will allow you to completely separate your JavaScript code from your markup (and also your ASP.NET code logic), making it much easier to work with. It also allows you to avoid the perils of cross-browser quirks in JavaScript events, which I'm assuming is why you're using HTML attributes for triggering JavaScript events in the first place, since it's much easier than doing it from scratch entirely in JavaScript with no frameworks.

Categories

Resources