Some asp.net controls generate , so to customize its appearance (e.g. childview in grid) i need to change the position of < tr> content. I don't know any ways to change position. The only idea is to generate div wrappers by javascript. Does anybody know a better way?
if you want to "move" the tr to another place, you can try:
<table>
<tr id="tr1"><td>test</td><td>test2</td></tr>
<tr id="tr2"><td>test3</td><td>test4</td></tr>
<tr id="tr3"><td>test4</td><td>test5</td></tr>
</body>
<script>
var tr = document.getElementById("tr2");
tr.style.display = 'block';
tr.style.position = 'absolute';
tr.style.top = "100px";
tr.style.left = "100px";
</script>
it definitely works in firefox (dont know about ie6-8). If you want to exchange the content with another tr, thats even easier (you just remove/add the tr nodes).
Related
I want a table sortable by column using Angular UI-Sortable. When there are multiple rows in the table, the spacing gets confused. I think this is because the dragged cell and the placeholder are taking up space, even though the dragged cell is absolutely positioned.
My table looks like this:
<table>
<thead>
<tr ui-sortable="{'ui-floating': true, axis: 'x'}" ng-model="list">
<th ng-repeat="item in list">
{{item.text}}
</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-repeat="item in list">
{{item.text}}
</td>
</tr>
</tbody>
</table>
and my controller looks like this:
var myapp = angular.module('sortableApp', ['ui.sortable']);
myapp.controller('sortableController', function($scope) {
var tmpList = [];
for (var i = 1; i <= 6; i++) {
tmpList.push({
text: 'Item ' + i,
value: i
});
}
$scope.list = tmpList;
});
I also have an example on codepen. Try dragging the first cell to see the rest of the row shift down past the end of the table.
I'm running Angular v1.4.9 and angular-ui-sortable v0.14.0.
I figured out a workaround. By adding an empty cell to each row, and adding ng-show to the first one, I get a cell to remove when the placeholder is added. This works pretty well, but the empty cell does take up a little space, and it makes the html a little less clear.
Updated codepen here: http://codepen.io/anon/pen/mPZBxq
I've followed the outlines in FullCalendar Change Week View to Vertical List instead of Horizontal Table Columns to create a custom vertical week view in fullcalendar.
The implementation is taken from the original post shown in this fiddle: http://jsfiddle.net/nomatteus/dVGN2/3/
This lays out the view like this:
<table>
<thead>
.tr.td.headercontent....
</thead>
<tbody>
.tr.td.eventcontent....
</tbody>
</table>
However the vertWeek view is used on small screens (smartphones etc), so I would like to have the day header and content to be layed out horizontal to take up less space in height like in this screenshot:
http://i.imgur.com/F4AkoSw.png
The MAN 8. is styled manually as I like it, but TIR 9 is how it is rendered by the view.
I would like to achieve this:
<table>
<thead>
</thead>
<tbody>
<tr>
<td> headercontent
<td> eventcontent
</tr>
</tbody>
</table>
I have tried to understand the fullcalendar code to move the header into the same as the eventcontent - but it seems like the view is rendered in different places for thead and tbody for that container.
Could anyone point me in the right direction on how to modify the code to achieve this?
Post of implemented answer for sharing:
Seems like my understandig was a litte bit inaccurate. The header was placed in an overlapping table above the table containing the events. Tried to traverse the DOM and place the header during the dayRender function, but the corresponding tbody for the event was not yet created.
Simplified illustration:
table
thead
**header**
tbody
table
thead
tbody (not created at dayRender, but available at eventRender)
**event*
The solution was quite simple - hide the .fc-day-number:
dayRender: function( date, cell ) {
// Get the current view
var view = $('#meal_calendar').fullCalendar('getView');
// Check if the view is the new vertWeek -
// in case you want to use different views you don't want to mess with all of them
if (view.name == 'vertWeek') {
// Hide the widget header - looks wierd otherwise
$('.fc-widget-header').hide();
// Remove the default day number with an empty space. Keeps the right height according to your font.
//$('.fc-day-number').html('<div class="fc-vertweek-day"> </div>');
$('.fc-day-number').hide();
// Create a new date string to put in place
var this_date = date.format('ddd, MMM Do');
// Place the new date into the cell header.
cell.append('<div class="fc-vertweek-header"><div class="fc-vertweek-day">'+this_date+'</div></div>');
}
},
In addition I styled the td.fc-event-container in my CSS like this:
td.fc-event-container {
padding-left: 68px;
}
Quite possibly a hack - hours to research, two lines to correct. But works for me......
I have a vertical menu and i want to make it localizable, but localized strings in menu elements often goes out off the edge.
So the question is how to make font resizable depending on the string length in CSS. And if possible, without JavaScript.
Thanks!
UPD: JQuery isn't acceptable. Any way in Pure JS?
You should make familiar with using plugins, they save you much time and of course they're very reliable (they are written by experienced scripters/programmers and have been tested by community). However looks like you want some pure JS solution. I've just made this code for you. It works fairly OK (although I'm not sure if it's as good as some plugins). The only requirement is the element (which you want to adjust the font-size accordingly to the text length) should contain plain text, not some HTML code.
The idea to implement it using pure JS is simple, you need some dummy element created using script, this dummy element is used to measure the size of the text. We need to adjust the font-size of the dummy element until the size of the text (as well as of the dummy element) should be confined to the size of the element (whose font-size you want to adjust). I made the code very clearly, hope you understand it better after reading the code:
//we just need 1 dummy element for the whole page.
var dummy = document.createElement('div');
dummy.className = 'dummy';
var inSingleLineMode, inMultilineMode;
//function used to adjust the font-size of the element
//so that the width is fixed (single-line mode) or both the width and height are
//fixed (multi-line mode), of course the text should be contained within
//the fixed width and height.
function adjustFontSize(element, singleLine){
if(!element.innerHTML) return;
var elementStyle = getComputedStyle(element);
dummy.style.font = elementStyle.font;
initMode(singleLine, function(){ dummy.style.width = elementStyle.width });
dummy.style.padding = elementStyle.padding;
dummy.style.boxSizing = elementStyle.boxSizing;
dummy.innerHTML = element.innerHTML;
document.body.appendChild(dummy);
var dummyStyle = getComputedStyle(dummy);
while(singleLine ? parseInt(dummyStyle.width) < parseInt(elementStyle.width) :
parseInt(dummyStyle.height) < parseInt(elementStyle.height)){
dummy.style.fontSize = parseFloat(dummyStyle.fontSize) + 1 + 'px';
dummyStyle = getComputedStyle(dummy);
}
while(singleLine ? parseInt(dummyStyle.width) > parseInt(elementStyle.width) :
parseInt(dummyStyle.height) > parseInt(elementStyle.height)){
dummy.style.fontSize = parseFloat(dummyStyle.fontSize) - 1 + 'px';
dummyStyle = getComputedStyle(dummy);
}
element.style.fontSize = dummyStyle.fontSize;
document.body.removeChild(dummy);
}
function initMode(singleLine, callback){
if(!dummy) return;
if(singleLine&&!inSingleLineMode) {
dummy.style.whiteSpace = 'nowrap';
dummy.style.width = 'auto';
dummy.style.display = "inline-block";
inSingleLineMode = true;
inMultiLineMode = false;
} else if(!singleLine&&!inMultilineMode) {
if(callback) callback();
dummy.style.whiteSpace = 'initial';
dummy.style.display = "block";
dummy.style.wordWrap = 'break-word';
inMultilineMode = true;
inSingleLineMode = false;
}
}
Demo.
In the demo, you can see that the first menu #menu1 is the Vietnamese word meaning Chrysanthemum while the second menu #menu2 is of course the English word Chrysanthemum. They have much different length, however both are supposed to have fixed width of 100px, hence the second menu #menu2 should have smaller font-size to fit the space.
You can use jQuery Text Fill like this.
Load up the plugin: <script src="jquery.textfill.js" ></script>
Put an id <input type="text" id="dyntext" value="e=mc²"></input>
Use the code to do magic. Preferably put this in <script> tags:
The end result will look something like this:
function update() {
var size = parseInt($('#maxsize').val(), 10);
if (!isNaN(size)) {
$('.dyntextval').html($('#dyntext').val());
$('.jtextfill').textfill({debug: true, maxFontPixels: size});
}
}
$(function () {
$('#maxsize').keyup(update);
$('#dyntext').keyup(update);
update()
});
This is not possible without Javascript. Using Javascript, you can use one of the many libraries, like FitText.
So you could use a Javascript library for this, but that would also mean that various labels have different font sizes.
I think the best approach would be to style the menu in such a way that it gracefully handles multi-line captions. That way, the length doesn't really matter much.
Because some language are 'longer' than others (for instance French labels are on avarage 1.5 to 2 times as long as English, it's a good idea to test your interface with one of those languages.
And for the font size, you could add a modifier on server side, for instace if you know the current language is French, you can add a class 'gui-captions-very-long' to the html tag and apply your CSS based on that class. That way, you can have a generic modifier which you can configure per language. I think that's a better solution than making all labels fit on a single line.
Keep in mind though, that smaller sizes are harder to read. You cannot just make the fonts half the size if the text is twice as long. You'll have to tune your design (or its implementation) to make longer texts possible.
I did look for that in the past then found an answer that really did the trick for me, but cannot remember were exactly... :(
But since it does answer the question using pure javascript and no plugins/libraries (did some optimisations since though), here it is! (with a working example):
// First we add a new function to the String prototype,
// this will be used to get the length of current string according
// to its font-family and font-size
String.prototype.textWidth = function(fontFamily, fontSize) {
var container = document.createElement('div');
container.style.visibility = 'hidden';
container.style.fontFamily = fontFamily;
container.style.fontSize = fontSize + 'px';
container.style.display = 'inline';
document.body.appendChild(container);
container.innerHTML = this;
var pxLength = container.offsetWidth;
container.parentNode.removeChild(container);
return pxLength;
};
// this is the function that will resize our text if it's too long
// classNameTarget (String) = the className of the element we need to resize e a
// tag or an id but you'll need to make modification to this function!
// maxWidth (int) = the max width (in px) of your final string
// fontFamily (String) = the family currently used by your string(wrong one might lead
// to wrong result!)
// fontSize (int) = the initial font-size of your string
var testWidth = function(classNameTarget, maxWidth, fontFamily, fontSize) {
maxWidth = maxWidth || 100;
// first we get all targets
var containers = document.getElementsByClassName(classNameTarget);
for (var i = 0; i < containers.length; i++) {
// for each of them we fetch their current length
var length = containers[i].innerHTML.textWidth(fontFamily, fontSize);
if (length > maxWidth){
// if the current length is bigger then we resize it by using a span styling with
// the new font-size
containers[i].innerHTML = "<span style=\"font-size:" + Math.floor(parseInt(fontSize) / (length / maxWidth)) + "px;\">" + containers[i].innerHTML + "</span>";
}
}
};
// we want our cell to have text no longer than 75px while having them starting at 50px
// font-size in arial
testWidth("firstname", 75, "arial", 50);
testWidth("lastname", 75, "arial", 50);
<table>
<thead>
<tr>
<th>firstname</th>
<th>lastname</th>
</tr>
</thead>
<tbody style="font-size: 50px; font-family: arial;">
<tr>
<td class="firstname">Bob</td>
<td class="lastname">Tomysonorubia</td>
</tr>
<tr>
<td class="firstname">John</td>
<td class="lastname">Doe</td>
</tr>
<tr>
<td class="firstname">François-Xavier</td>
<td class="lastname">De la nouvelle Orléan</td>
</tr>
</tbody>
</table>
the testWidth method might need some adjustements regarding your currents needs, perhaps you'ld like to look into querySelector or querySelectorAll to make it quite generic
I suggest an tiny example. On a pure JavaScript.
https://gist.github.com/dejurin/9bef02be6876e068ee276bee31cb3bcb
"use strict";
(function(w, d) {
var fit = d.getElementById("fit");
var wrap = d.getElementById("wrap");
fontFitResize(fit, wrap);
function fontFitResize(fit, wrap, step = 0.5) {
var currentSize;
while(fit.offsetWidth < wrap.offsetWidth) {
currentSize = parseFloat(w.getComputedStyle(wrap, null).getPropertyValue('font-size'));
wrap.style.fontSize = (currentSize - step) + 'px';
console.log(wrap.style.fontSize);
}
}
})(window, document);
.fit {
border: 1px solid #ff0000;
white-space:nowrap;
font-size:24px;
width:200px;
}
<div id="fit" class="fit">
<span id="wrap">Resize font depending on string length</span>
</div>
I have a table with four columns. The first column needs to be the minimum size to fit the content, and the other three columns need to be equal sizes and consume the rest of the space in the table. Neither my table nor my content is of a known size. (It's a pretty standard variable-sized-label-and-fixed-size-data layout.)
In the good old days of HTML4 I could do this by using the specifying the size of each column as a proportion of the whole, using the 'relative size' functionality:
<colgroup>
<col width="0*"/>
<col width="1*"/>
<col width="1*"/>
<col width="1*"/>
</colgroup>
However, the width attribute is now deprecated and we're supposed to use CSS instead.
But I haven't found any way to replicate this with CSS; CSS size specifiers only let me specify the width as either a fixed size or a fraction of the whole, where what I actually need is a fraction of what's left after the first column is taken away.
Is there any way to do this using modern techniques? (Note that I can't use CSS3, though.)
I would use a little javascript in order to solve your problem: http://jsfiddle.net/qR9g2/
var tableSize = 400; // example of size
var firstCol = document.getElementById('firstCol_01');
var sizeOfFirstCol = firstCol.offsetWidth;
var myOtherCols = document.getElementsByTagName('td');
var nbcols = myOtherCols.length;
var sizeOtherCols = (tableSize-sizeOfFirstCol)/(nbcols-1);
for(var i=0;i<nbcols; i++)
{
if(myOtherCols[i].className === 'otherCols')
{
myOtherCols[i].style.width = sizeOtherCols+'px';
}
}
first give the size of the overall table. Then go get the size of the first column, and distribute the rest of the width to the other columns.
EDIT: here is a CSS solution. It is not perfect, but better than nothing: http://jsfiddle.net/qR9g2/2/
In the css, the main idea is the following:
.col1{
display:table;
float:right;
}
Add for the first column the tag display:table. This will work like a fit-content for all browsers.
Adding a float:right will push the first column onto the right and "stick" it to the rest of the table.
The visual result is exactly what you want. On the negative side, the problem is that your table takes more place then it seems (on the left). (basically if you have a 400px table with 4 columns, it will automatically give 4*100px for each column. adding the upper CSS solution will simply shift the col1 on the right side of the 100px that are given to that column).
You could always try to play with negative left-margins (i don't recommend) in order to shift your table on the left.
var table = document.getElementById('table');
var first_col = document.getElementById('first-col');
var total_col = document.getElementsByClassName('col').length
var rem_width = table.offsetWidth - first_col.offsetWidth;
var col = document.getElementsByClassName('col')
for(let i=0;i<col.length;i++){
col[i].style.width=rem_width/total_col+'px'
}
<table id="table" width="100%" border="1">
<tr>
<th id="first-col">NO</th>
<th class="col">ISBN</th>
<th class="col">Title</th>
<th class="col">Price</th>
</tr>
<tr>
<td>12</td>
<td>3476896</td>
<td>My first HTML</td>
<td>$53</td>
</tr>
</table>
Instead of trying to do a table, you can try a grid layout as follows.
Apologies for the inline css - obviously you would use classes instead but I just tested it quickly and it actually appears to work! I had not actually ever used this before, but making the first column "auto" actually does work and the layout is I think what you are looking for.
<div style="display:grid; grid-template-columns: auto repeat(3, 1fr);">
<div style="width: fit-content">This should fit the content that you decide to insert here</div>
<div>This should fit the content too</div>
<div>This should fit the content .. more text</div>
<div>This should fit the content and some more text</div>
</div>
I checked & grid has been around since 2011 so it's not too modern hopefully. I almost always do my tables with either grid or flexbox now..
Is there a way to make a table row breakable at a certain cell?
<table>
<tr>
<td>Some title descriptive text</td>
<td>nnumbers</td><td>Short text</td><td>datetime</td>
<tr>
... more rows
</table>
Now I would like this row to break after the first cell if the width of the viewport is too small (typically when used on mobile phones).
Is that achievable anyhow using html5 css3 and eventually some Javascript?
As of CSS2.1, it is possible by using appropriate display CSS attribute values. See this demo page:
http://dabblet.com/result/gist/1576044
...and the source:
http://dabblet.com/gist/1576044
Tested on a Galaxy Nexus phone, works, and should work for most Webkit-based mobile browsers. Also, it should work on Firefox Mobile and Opera, though I didn't test.
Long story short, use a media query to detect page width and set a max-width breakpoint and apply:
css
table, tbody, thead, tr, td, th { display: block }
No. Table rows cannot be broken onto multiple lines. That'd imply you want TWO rows of cells instead of a single.
I needed something just like this for a project of mine; i needed to support old browsers so it doesn't use HTML5, just javascript to check the overall width/amount of rows able to handle:
http://pastebin.com/raw.php?i=umFWx3mK (Just copy it inside an HTML file and open it with a browser)
$(window).resize(distribute)
$(document).ready(function(){
allboxes = $(".box");
$('#container').delegate(".box","mouseenter",function(){
$(this).addClass('current')
}).delegate(".box","mouseleave",function(){
$(this).removeClass('current')
});
table = $("#table");
distribute();
})
var lastfit, allboxes, table
function distribute(){
var fitAmount = Math.floor($("#container").width()/180);
if(lastfit!=fitAmount){
if(fitAmount<1){fitAmount=1}
lastfit = fitAmount;
var clones = allboxes.clone(),
emptycells = "", emptyrows = "",
trs = table.find("tr");
for(var i=0;i<fitAmount;i++){
emptycells += "<td> </td>";
}
trs.html(emptycells)
var count = trs.length*fitAmount
if(count < allboxes.length){
var newRows = Math.ceil((allboxes.length - count)/fitAmount);
for(var j=0;j<newRows;j++){
emptyrows += "<tr>"+emptycells+"</tr>";
}
}
table.append(emptyrows)
var tds = table.find("td"), trs = table.find("tr");
clones.each(function(index){
tds.eq(index).html("").append($(this))
})
allboxes = $(".box");
trs.filter(function(){ return !/box/gi.test(this.innerHTML) }).remove()
}
}
function boxmouseover(box){
$(box).css("background","red")
}
function boxmouseout(box){
$(box).css("background","#CCC")
}