Safari calculates wrong width in table - javascript

I'm working on developing a simple column resize functionality for HTML tables.
The table works OK so far - except in Safari (ver 5.1.4). For some reason Safari gives the cell widths a negative(!) value.
a JSFiddle is available here: simple-resize
The negative column width values can be seen if the style="width" attributes are removed from the <th> elements (or disabled in the code inspector)
HTML:
<div class="tblcont" id="cont">
<table id="table1" class="pivot-table pivot-fixed-layout">
<thead>
<tr id="tr1">
<th style="width: 52px;">city</th>
<th style="width: 26px;"># c</th>
<th style="width: 37px;"># id</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tel Aviv</td>
<td>814</td>
<td>1,047</td>
</tr>
<tr>
<td>Natanya</td>
<td>805</td>
<td>1,016</td>
</tr>
</tbody>
</table>
</div>
CSS:
.pivot-table.pivot-fixed-layout {
border-collapse: collapse;
table-layout: fixed;
width: 0;
}
.pivot-table td, .pivot-table th {
overflow: hidden;
padding: 0 6px;
border-right: 1px solid;
border-bottom: 1px solid;
text-overflow: ellipsis;
}
.pivot-table th {
cursor: col-resize;
}
Javascript:
var pressed = false,
$column,
$table = $("table"),
startX, startWidth,
tableInitialWidth = $('#cont').width() - 100,
currentTableWidth, newTableWidth;
$("table th").mousedown(function(e) {
$column = $(this);
pressed = true;
startX = e.pageX;
startWidth = $column.width();
$column.addClass("resizing");
});
$(document).mousemove(function(e) {
if(pressed) {
var delta = e.pageX - startX,
currentColumnWidth,
newColumnWidth;
currentColumnWidth = $column.width();
newColumnWidth = startWidth + delta;
currentTableWidth = $table.width();
newTableWidth = currentTableWidth + delta;
// no not make columns smaller than min width
if (newColumnWidth > 2) {
$column.width(newColumnWidth);
}
}
});
$(document).mouseup(function() {
if(pressed) {
$column.removeClass("resizing");
pressed = false;
}
});

Related

Hover keyframe values green and red

I'm kind of stuck in a keyframe. I have a table with values from a fetch (json) and i should add a hover when the values is less than 5 in red and starting from 5 in green. This is my code in javascript ->
how do i have to implement the keyframe with it in css or is it different that i think?
// Html
<div id="group3">
<table class="table">
<thead>
<tr class="info">
<th></th>
<th>February</th>
<th>March</th>
<th>April</th>
<th>May</th>
<th>June</th>
<th>July</th>
<th>August</th>
</tr>
</thead>
<tbody id='mytable'>
</tbody>
</table>
</div>
//CSS
Keyframe?
//hover
let cells = document.querySelectorAll("tbody");
cells.forEach( el => el.addEventListener('mouseenter', function () {
if(el.textContent < 5){
el.classList.add('underfive');
} else if (el.textContent >=5){
el.classList.add('abovefive');
}
}));
// reset animationx
cells.forEach(el => el.addEventListener('mouseleave', function () {
if(el.textContent < 5){
el.classList.remove('underfive');
} else if (el.textContent >=5){
el.classList.remove('abovefive');
}
}));
it should be like this ->
this is the startpage, background is white
this is the end result how it should be, uploaded from a json file in a table, red value
this is the green value when it's 5 of higher
Based on what you say you want to show a different background color or styling in general than the default if the mouse is over the td.
So use :hover for that. You want to have a transition between those states so use transition.
You want to have a different color if it is above or below 5. So define what you want to have as default and add a class for the other case.
let data = [1,4,2,8,12,2,5,7];
const tr = document.querySelector('tr');
data.forEach(elem => {
let td = document.createElement('td');
td.textContent = elem;
td.classList.toggle('belowfive', elem < 5);
tr.appendChild(td);
});
td {
transition: background-color 1s;
background-color: white;
padding: 1rem;
border: 1px solid hsl(0 0% 50%);
}
td:hover {
background-color: green;
}
td.belowfive:hover {
background-color: red;
}
<table>
<tbody>
<tr>
</tr>
</tbody>
</table>

Support resizing two side by side iframes in JavaScript

I have a web page where I need to show two iFrames side by side, and allow a user to resize them horizontally (so they can easily see the complete contents of either side).
My code looks like this:
<div style="padding:30px">
<table style="width:100%;border:0px;border-collapse:collapse;">
<tr>
<td class="cLeft cSide">
<iframe class="cFrame" src="{MyLeftPage}">
</iframe>
</td>
<td class="cRight cSide">
<iframe class="cFrame" src="{MyRightPage}">
</iframe>
</td>
</tr>
</table>
</div>
Finally managed it: jsFiddle
The problem with using the standard approaches as mentioned here (Thanks user!) is that when you have iFrames and you move the mouse over them, the $(document).mousemove() stops firing.
The trick is to have a column in the middle, and have a div that shows up when you click the column. Since the div is in the parent page, the mousemove event keeps firing, allowing you to easily resize it.
Here's what the final HTML looks like:
<div style="user-select:none;padding:30px">
<table style="width:100%;border:0px;border-collapse:collapse;">
<tr>
<td class="cLeft cSide">
<iframe class="cFrame" src="{MyLeftPage}">
</iframe>
</td>
<td class="resize-bar">
<div class="resize-panel"></div>
</td>
<td class="cRight cSide">
<iframe class="cFrame" src="{MyRightPage}">
</iframe>
</td>
</tr>
</table>
</div>
This is the CSS
.resize-bar {
width: 5px;
cursor: col-resize;
position:relative;
background-color: #AAA;
margin:20px;
}
.resize-panel {
height: 100%;
background-color: #DDDDDD00;
display: inline-block;
position: absolute;
top:0px;
left:-2px;
right:-2px;
cursor: col-resize;
}
.resize-panel.rx {
left:-400px;
right:-400px;
}
.cSide {
min-width:200px;
}
.cFrame {
width: 100%;
border: 1px solid #DDD;
height: calc(100vh - 170px);
overflow-x:scroll;
}
And this is the JavaScript:
$(function() {
var pressed = false;
$("table td").mousedown(function(e) {
pressed = true;
$(".resize-panel").addClass("rx");
e.stopPropagation();
});
$(".resize-panel").mousedown(function(e) {
pressed = false;
});
$(document).mousemove(function(e) {
if (e.which == 1 && pressed) {
var ww = $(window).width();
var cPos = e.pageX;
if (cPos < 0.20 * ww) cPos = 0.2 * ww;
if (cPos > 0.80 * ww) cPos = 0.8 * ww; {
$(".cLeft").width(cPos);
}
}
});
$(document).mouseup(function() {
if (pressed) {
$(".resize-panel").removeClass("rx");
pressed = false;
}
});
});

table scroll css change from Jquery

Actually I've a table where I need to set a max-height and make it scrollable.
My Table design
<table class="table table-striped table-notactiveusers table-custom-scroll" style="border: 1px solid #e7eaec;" id="tblNonUandMeUsersList" runat="server">
<thead>
<tr>
<th style="width: 5%">#</th>
<th style="width: 33%">First Name</th>
<th style="width: 30%">Country Code</th>
<th style="width: 32%">Mobile Number</th>
</tr>
</thead>
</table>
My Table css :
.table-custom-scroll > thead, .table-custom-scroll > tbody {
display: block;
}
.table-custom-scroll > tbody {
max-height: 450px;
overflow-y: auto;
overflow-x: hidden;
}
But, if the table has less rows than the max height, there is a space for the body on the right side like shown in the image
So,I thought of changing the css to display : compact, if the table rows are less than 12.
My JS to change css
<script>
$(document).ready(function () {
var notactiverowCount = $('.table-notactiveusers tr').length;
if (notactiverowCount < 12) {
$('.table-notactiveusers > thead').css('display', 'compact');
$('.table-notactiveusers > body').css('display', 'compact');
}
if (notactiverowCount < 12) {
$('.table-notactiveusers').children('head').css('display', 'compact');
$('.table-notactiveusers').children('body').css('display', 'compact');
}
});
</script>
But the css is not changing. Can anyone tell me the mistake I was doing?
what about using only css
.table-custom-scroll{
display: block;
}
see demo HERE

HTML column layout - automatically wrap div element to next column

I want an HTML layout with max 5 rows
If I have 6 items (i.e. divs) I want to wrap the 6th element in the 2nd column of 1st row
I tried the following, But can't get the 6th element in the next column.
p {
display: inline-block;
background-color:gray;
}
.wrap {
display: inline;
background-color:red;
}
<div>
<div><p>I am bla</p></div>
<div><p>Your mom</p></div>
<div><p>Test</p></div>
<div><p>Teddy</p></div>
<div><p>James</p></div>
<div><p class="wrap">John Appleseed</p></div>
</div>
Update: the Problem is that the items needs to have a flexible width, see here: https://dl.dropboxusercontent.com/u/1771956/float_html2.png
Going back some years, the Html layout was often completely built with the table element, today most layouts are not.
However, you seem to want your layout built table-like (rows, columns...) so I would not hesitate to use a table.
<table>
<tr>
<td>row 1 column 1</td>
<td>row 1 column 2</td>
</tr>
<tr>
<td>row 2 column 1</td>
</tr>
<tr>
<td>row 3 column 1</td>
</tr>
<tr>
<td>row 4 column 1</td>
</tr>
<tr>
<td>row 5 column 1</td>
</tr>
</table>
If ancient browser support is not an issue, you can make use of css3 flexible box.
#container{
display:-webkit-flex;
display:flex;
-webkit-flex-direction:column;
flex-direction:column;
-webkit-align-content:flex-start;
align-content:flex-start;
-webkit-flex-wrap:wrap;
flex-wrap:wrap;
height:500px;
background:hotpink;
}
#container div{
display:inline-block;
width:90px;
height:90px;
margin:5px;
background-color:gray;
}
.wrap {
display: inline;
background-color:red;
}
<div id='container'>
<div><p>I am blah</p></div>
<div><p>Your mom</p></div>
<div><p>Test</p></div>
<div><p>Teddy</p></div>
<div><p>James</p></div>
<div><p class="wrap">John Appleseed</p></div>
</div>
this is not a complete solution, hopefully you can tweak it according to your needs
More about css flex # css tricks
Fixed it
I used some javascript and position absolute to calculate the layout
$(function () {
// Handler for .ready() called.
var rows = 5
var items = $("#container").children()
var firstDiv = $("#container").children().eq(0)
var height = firstDiv.height()
var margin_bottom = firstDiv.outerHeight(true) - firstDiv.innerHeight()
var margin_right = firstDiv.outerWidth(true) - firstDiv.innerWidth()
var row = 0
var index = 0
items.each(function () {
var leftPos = 0
if (index >= rows) {
var siblingDiv = $("#container").children().eq(index-rows)
if (index == 10) {
}
leftPos = siblingDiv.width() + siblingDiv.position().left + margin_right
}
var topPos = ((height + margin_bottom) * row)
$(this).css('top', topPos + 'px')
$(this).css('left', leftPos + 'px')
row += 1
index += 1
if (row >= rows) {
row = 0
}
})
});
#container {
background-color:gray;
position:relative;
top: 10px;
left:0px;
height:500px;
}
.item {
background-color:green;
position:absolute;
height:50px;
top: 0px;
left:0px;
margin-right:10px;
margin-bottom:10px;
}
JSFiddle Demo
Here is my solution:
p {
display: inline-block;
background-color:gray;
}
.wrap {
display: inline-block;
background-color:red;
}
div {
float:left;
}
.clr {
clear:both;
}
<div>
<div><p>I am bla</p></div>
<div class="clr"></div>
<div><p>Your mom</p></div>
<div class="clr"></div>
<div><p>Test</p></div>
<div class="clr"></div>
<div><p>Teddy</p></div>
<div class="clr"></div>
<div><p>James</p></div>
</div>
<div><p class="wrap">John Appleseed</p></div>

Sticky headers not maintaining width when scrolling

I have some table headers which I planned on making sticky (fixed) as the user scrolls down the page, but they currently shrink when the sticky is activated, I would like them to inherit the widths of the headers, but they shrink to the size of the text at the moment.
My JS:
$(document).ready(function() {
var stickyNavTop = $('.th').offset().top;
SOLUTION:
$(".th th").each(function(){$(this).width($(this).width());});
$('.th').width($('.th').width());
var stickyNav = function(){
var scrollTop = $(window).scrollTop();
if (scrollTop > stickyNavTop) {
$('.th').addClass('sticky');
} else {
$('.th').removeClass('sticky');
}
};
stickyNav();
$(window).scroll(function() {
stickyNav();
});
});
My HTML:
<table class="mGrid" cellspacing="0" rules="all" border="1" id="1"
style="width:98%;border-collapse:collapse;">
<tr class="th">
<th scope="col">Membership No.</th>
<th scope="col">Surname</th>
<th scope="col">Other Name(s)</th>
</tr>
<tr>
<td>
<div id="2" class="formInput">
<label for="2">Membership No.</label>
<input name="2" type="text" value="AH6973" id="2"
class="required" style="width:60px;" />
</div>
</td>
<td>
<div id="3" class="formInput">
<label for="3">Surname</label>
<input name="3" type="text" value="CARTER" id="3"
style="width:100px;" />
</div>
</td>
<td>
<div id="4" class="formInput">
<label for="4">Other Name(s)</label>
<input name="4" type="text" value="RAYMOND" id="4"
style="width:150px;" />
</div>
</td>
</tr>
</table>
my CSS:
.sticky {
position: fixed;
width: 100%;
top: 0;
z-index: 100;
border-top: 0;
color: #fff !important;
background: #666;
border-left: solid 1px #525252;
font-size: 1.0em;
}
(This is modelled to be the same as the header style, it's just the width shrinks to fit the width of the text at the moment. I tried to edit the header style but it's apparently read-only "'HeaderStyle' property is read-only and cannot be set."
Just add this line before your function definition:
$('th').width($('th').width());
Full JavaScript code:
$(document).ready(function() {
var stickyNavTop = $('.th').offset().top;
$('th').width($('th').width());
var stickyNav = function(){
var scrollTop = $(window).scrollTop();
if (scrollTop > stickyNavTop) {
$('.th').addClass('sticky');
} else {
$('.th').removeClass('sticky');
}
};
stickyNav();
$(window).scroll(function() {
stickyNav();
});
});
here is a common solution, it auto detects each sub-element's width and height and reflect when scrolling, it is something like following:
var $this = $(this),
top = $this.offset().top,
left = $this.offset().left,
width = $this.width(),
height = $this.height(),
widthArr = [],
heightArr = [];
$this.find("*").each(function(i, e) {
widthArr.push($(this).width());
heightArr.push($(this).height());
});
$(window).scroll(function() {
if($(window).scrollTop() >= top) {
$this.css({
position: "fixed",
top: 0,
left: left,
"z-index": 100,
width: width,
height: height
});
$this.find("*").each(function(i, e) {
$(this).width(widthArr[i]);
$(this).height(heightArr[i]);
});
} else {
// to be implemented
}
});
My solution to avoid column width changes : cloning the header. (Thanks to #Matt for the line: $('th').width($('th').width()); and his solution.)
JS
var stickyNavTop = jQuery('thead tr:first-child').offset().top;
// init state
var stickState = (jQuery(window).scrollTop() > stickyNavTop);
var stickyNav = function() {
var scrollTop = jQuery(window).scrollTop();
// state has changed?
if (stickState != (scrollTop > stickyNavTop)) {
// remember/catch new state
stickState = (scrollTop > stickyNavTop);
if (stickState) {
jQuery('thead tr:first-child th').each(
function() { jQuery(this).width( jQuery(this).width() ); }
);
// cloning the header : the original columns won't move
jQuery('thead tr:first-child')
.clone()
.prependTo(jQuery('thead'))
.addClass('sticky');
} else {
jQuery('tr.sticky').remove();
}
}
};
jQuery(window).scroll(function() {
stickyNav();
});
stickyNav();
CSS
.sticky {
position: fixed;
top: 0;
z-index: 100;
}

Categories