Appending all page <table>'s to respective <div> with pure Javascript - javascript

I have a website with a lot of posts with <table> and a new responsive layout.
When big table elements (lot of content) are opened on mobile devices, even with max-width: 100% or other CSS tricks, they get bigger than the screen.
The solution is append tables in a overflow: scroll <div>, but I can't edit all the post content, so I want to do that with pure Javascript. jQuery not allowed.
The objetive is:
Get all <table> elements of the page that are inside #post
Get their content
Append that content in a <div class="table_div"> in the same place that the <table> is
Remove old table elements (the ones that are not inside .table_div)
I already can get all content from table elements and remove the tables, but the part of the code that supposedly should append table content in .table_div do not work.
Part of my code so far:
var post = document.getElementById('post'),
tables = post.getElementsByTagName('table');
for(var i=0; i<tables.length; i++) {
var table = tables[i];
var table_content = table.innerHTML,
table_div = document.createElement('div');
tables.remove();
table_div.appendChild(table);
table_div.className = 'table_div';
document.appendChild(table_div);
}
Full code: http://jsfiddle.net/hmaesta/6mambr93/
Please, help with just pure Javascript. Thank you.

NodeList has two mode; static or live (ref When is NodeList live and when is it static?). Live means that changes in the DOM are reflected in the NodeList. And NodeList from getElementsByTagName is live. In your code, the length of tables is decremented everytime you remove #post table.
There is some way to solve the problem.
Use static NodeList. For example, querySelectorAll returns static one.
Map NodeList to Array. You can do this with var ts = []; Array.prototype.push.apply(ts, tables);. And after this, use ts instead of tables.
Keep length and order of NodeList. Use insertChild instead of appendChild to keep order and to keep <table> in #post.
Here is example.
var tables = document.querySelectorAll('#post table');
for(var i = 0; i < tables.length; i++) {
var table = tables[i];
var table_div = document.createElement('div');
table.parentElement.insertBefore(table_div, table);
table_div.className = 'table_div';
table_div.appendChild(table);
}
https://jsfiddle.net/boy48ngs/2/
Note: You do not need to remove <table> manually in this case. Element cannot has multiple parents and appendChild removes the element from current parent.

See this updated fiddle:
var post = document.getElementById('post'),
tables = post.getElementsByTagName('table');
for(var i=0; i<tables.length; i++) {
var table = tables[i];
var elem = document.createElement('div');
elem.className = 'table_div';
post.replaceChild(elem, table);
elem.appendChild(table);
}
I used the replaceChild method to first replace the table element with a newly created div. Then I append the original table element to that div.

Related

Count hidden next-line items in a list

I have a list with inline list-items. I can see about 8 but then there is not enough space to show more and the rest appears on the next line, hidden (behind the container's z-index) because of its overflow:hidden. How can I count these next line items with JavaScript?
I know jQuery has $('li:visible') but I need a vanilla JavaScript way.
I've tried to leverage getComputedStyle(el) but there doesn't seem to be any way to target these hidden items.
There is also a complicated Page Visibility API but I don't think it can be used for elements, only the document visibility.
Here's a JSFiddle of the list items
For your situation, you need to id if the top of the LI is "under the fold" of the UL. For this we can use element.getBoundingClientRect():
function isVis(elm){
var box = elm.getBoundingClientRect(),
par = elm.parentNode.getBoundingClientRect();
return par.bottom-par.top>= box.top;
}
Live demo:
https://jsfiddle.net/ntcsh18g/
note this is NOT a general purpose "is the element hidden" routine, which is complicated and slow, rather its a simple check against the OP's property that's causing "hiddennes"...
Edit: As suggested by #dandavis, my solution was not generic at all (only works for one row of elements), so only use this in extremely specific and simple cases! To generalize this approach you could try and check whether the offsetTop of an element is greater than the height of the container or the offsetLeft is bigger than the width. Anyway, you are probably better off using his solution anyway. ;)
Well, depending on what you need this for, a very ugly, but working solution could be to check for elements that have a different offsetTop than the first element like this:
const children = [...document.querySelectorAll('#container li')]
const normalOffset = children[0].offsetTop
const overflownChildren = children.filter(li => li.offsetTop !== normalOffset)
https://jsfiddle.net/Isti115/nc3tahw3/
You'll need to target the ul element and save that into a variable var lists = document.getElementsByTagName("ul"); Then use for-loop something like below
<ul id="foo">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
var lists = document.getElementsByTagName("ul");
for (var i = 0; i < lists.length; ++i) {
// filter so that only lists with the class "foo" are counted
if (/(^|\\s)foo(\\s|$)/.test(lists[i].className)) {
var items = lists[i].getElementsByTagName("li");
for (var j = 0; j < items.length; ++j) {
// do something with items[j]
}
}
}

JS select child of this with specific class

I am writing a GreaseMonkey script that goes through a page with various elements and each element has text and a button. It uses document.getElementsByClassName to find the parent elements, and it has a for loop to do something to each parent element. In this loop, I need to select a child node with a specific class and find its text value (innerHTML). I can't figure out how to select the child with a specific class of this element.
You'll want to grab the currently iterated element and use querySelector()
For example:
var elements = document.getElementsByClassName('class');
for (var i = 0, len = elements.length; i < len; i++) {
var child = elements[i].querySelector('.class_of_desired_element');
//do stuff with child
}
Note the dot before the class name in querySelector as it works similar to jQuery.
Try querySelectorAll(), which you can use to find elements within the current element.
var parent = document.getElementsByClassName('parentClass'),
parent[0].querySelectorAll('.childClass');
Depending on exactly what you are looking to do, you could also skip selecting the parent, if you don't explicitly need a reference to it.
document.querySelectorAll('.parentClass .childClass');
https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll
You can use
var yourelement = document.getElementsByClass("");
var i = yourelement.nextSibling;
var e = i.nextSibling;
and keep getting the nextSibling of the element till you get it.
However, like #teddy said in the comments, I would suggest you use jQuery. It has a MUCH easier way to do it:
var value = $('.parentClass .childClass').html();

Inserting variable into array item

I have an array of elements from my webpage which I am trying to then insert some html, stored as a variable into a matching array item. For example
<div class="play">
<div>
<p>Item to be inserted after this p tag</p>
</div>
</div>
var elements = $('.play');
//elements length = 4;
var item = '<p>HTML to be inserted</p>'
$(item).appendTo(elements[1]);
In the above code I am trying to insert 'item' into the second value in the array within the child div shown in the html, however I am unsure how to insert it into the child div. At present this inserts 'item' after the parent html tag containing .play.
Any help would be greatly appreciated.
Note that elements isn't an array, it's a jQuery object, which means you can use jQuery methods to traverse through the DOM:
elements.eq(1).find("div").append(item);
Demo: http://jsfiddle.net/rgQ7g/
.eq(1) selects the second item but returns it wrapped in another jQuery object, so then you can use .find("div") to get to the child div and .append() your item to it.
Try after():
$('.play').find('p').after(item);
This inserts content AFTER a selected element in the DOM. It also does it for all the classes named .play
If you need to specify an index, I recommend a function:
function appendPlay(index, content) {
$('.play').eq(index).find('p').after(content);
}
appendPlay(2, '<p>HTML to be inserted</p>');
jsFiddle
please try using
var element = $('.play div p');
var item = '<p>HTML to be inserted</p>'
$(element).parent().append(item);
Edited
from
var element = $('.play div');
var item = '<p>HTML to be inserted</p>'
$(element).append(item);
Well, I guess this would work:
$(item).appendTo($(elements));
But a better solution would be using:
$('.play').find('p').after(item);
You can use link below. (I edited code after comment)
You should write code like;
var selector = ".play",
text = "<p>HTML to be inserted</p>";
$(selector + " div p").eq(1).after(text);
http://jsbin.com/esesul/5/

Javascript createElement and appendchild in one step

i want to create an element and then append this with other elements in one step.
var header = document.createElement("thead").appendChild(document.createElement("tr"));
Why this Code outputs the only TR and not Thead?
When i use this code then its correct (thead + tr are there)
var header = CH.createElement("thead");
header.appendChild(CH.createElement("tr"));
Because Node.appendChild() returns the appended child...
var appendedChild = element.appendChild(child);
.. you can simply reference the child's parentNode like so (sample fiddle):
var header = document.createElement("thead")
.appendChild(document.createElement("tr"))
.parentNode; // the row's parentNode, i.e.: thead
#antisanity has a good solution. Another solution if your variable is pre-declared is to do this...
(header = document.createElement('thead'))
.appendChild(document.createElement('tr'));
This ensures that the assignment to header happens before the .appendChild().

Clone a div and make ID's of it it's children to be unique using javascript

I need to clone a div and after cloning all the elements within the div should have unique ids. I need to do this using javascript only and not jquery.
Can anyone help me please.
The following code clones an element, uses a recursive function to assign random id's to the cloned element and its children and appends it to the document body. Adjust to your needs. See also this jsfiddle
var someClone = someDiv.clone(true), children = someClone.childNodes;
someClone.id = Math.floor(1000+Math.random()*10000).toString(16);
reId(children);
function reId(nodes){
for (var i=0;i<nodes.length;(i+=1)){
var children = nodes[i].childNodes;
nodes[i].id = Math.floor( 1001+Math.random()*10000 ).toString(16);
if (children.length){
reId(children);
}
}
}
document.body.appendChild(someClone);

Categories