Is it possible to prevent the browser from parsing certain elements? - javascript

Consider the following markup:
<div hidden id="table-template">
<table>
<tbody>
<slot></slot>
</tbody>
</table>
</div>
<div hidden id="table-row-template">
<tr>
<td>
Some Content
</td>
</tr>
</div>
I would like to use 'table-template' and 'table-row-template' as re-usable components in my script.
(clone them and append them on demand)
but as the page loads the browser parses the markup and mutates it (taking 'slot' element and insert it before the 'table' element, and stripping 'td' and 'tr' tags).
This is reasonable (not valid HTML of course), but is there any way I can prevent the browser from parsing those elements?
So far I have tried:
using hidden elements,
wrapping with 'pre'/'code' tags,
but none seem to work.

You can try using <script type="text/template"></script>
<script id="mytemplate" type="text/template">
...your table's html...
</script>
Then:
<script>
alert($('#mytemplate').html());
</script>
Many libraries use this method, handlebar.js for example.
The <template> element may gain compatibility with more browser versions: http://caniuse.com/#feat=template

Use a fictional tag that the browser wouldn't recognise. You can still target it with Javascript and read it's text content but the browser won't parse it.
Say <template id="the-template">Foo bar</template>.
But really the best way to re-use html snippets it to create them in Javascript without polluting the DOM.
e.g
var elToReuse = document.createElement('div').innerHTML('<h1>Lets have title here</h1>');
// Let's do some things to the elToReuse
var anotherVersion = elToReuse.querySelector('h1').innerText('My another title');
// Now it's the time to append to the DOM
document.body.appendChild(anotherVersion);

So I have researched a bit about my problem, and this is what i figured out -
the 'tbody' element accpets only 'tr' elements as children.
so browsers will 'fix' the markup while parsing it one way or the other.
using template tags as vassiliskrikonis suggested will not work for the 'table-template' but will fix the 'table-row-template' issue,
using script tag as #Mihaly_KR suggested will work for both, but when accessing the template you will get a plain string to work with (injecting this string into the DOM will make the browser parse it and 'fix' it once again...)
The workaround I have found is to use other tag as a placeholder for my content.
one way is using a comment e.g.
but accessing this comment element requires a use of treeWalker or nodeIterator (which are much less performant then querySelector or getElementsByTagName)
other way is using a script tag as a placeholder.
browsers will not change the markup, and it can be accessed later using querySelector or getElementsByTagName.
so my refactored code looks like this:
<template id="table-template">
<table>
<tbody>
<script type="slot"></script>
</tbody>
</table>
</template>
<template id="table-row-template">
<tr>
<td>
Some Content
</td>
</tr>
</template>

Related

JQuery accessing text deep below unique id

I'm trying to make an app that pulls our data from our existing website. As we have no known API, I have decided to use ajax with whateverorigin.org to pull the full HTML from our site, and parse it with jQuery from there.
Unfortunately, much of the data I need lies far below any unique ID's. With $(data.contents).find("#unique").text() I am able to retrieve data of the type:
<div id="unique">
<div>
Text I want
</div>
</div>
However, as the nesting gets deeper, like:
<span id="unique2">
<table>
<tbody>
<tr>
<td>
Text I want
that snippet always returns "".
I have tried chaining the levels together with .join, but that doesn't work either.
Code in context here, around line 40-50. The site I'm trying to access is wmbr.org. The id that works is #now_on_the_air, one of the id's that doesn't is #recent_plays. The log is empty.

Using CSS or Java to Show or Hide Empty Content Area

I am trying to create a page template that uses section headers and subsequent content that is being dynamically pulled in based on a separate database. Currently I have the page set up to look something like this:
<tr>
<td>
<h3>Product Applications</h3>
{tag_applications}<br />
</td>
</tr>
Where the Product Applications is a formatted header on the page and the {tag_applications} is link through the CMS that is pulling in content from a field defined elsewhere. I am trying to figure out how to hide the entire cell (or div if I need to) with either CSS or a script when the {tag_applications} is empty or blank. I tried to use the 'empty' tag in CSS on the cell and setting the display to hidden, but of course, the cell is not actually empty because of the header.
What is the best way that I can accomplish this without creating separate pages for each item?
Thanks!
Try wrapping your content area in a div, like this:
<tr>
<td>
<h3>Product Applications</h3>
<div class="contentSection">{tag_applications}</div>
</td>
</tr>
Then your script can check if the div is empty or not. (uses jQuery)
$(function()
{
$(".contentSection").each(function(idx, ele)
{
if($(ele).html() == "")
$(ele).parent().hide();
});
});
My apologies if I made any syntax errors...

JQuery: elegant way to replace set of elements with another set?

I have a bunch of DOM like
<div>
<div class="stuff"/>
<div class="stuff"/>
<div class="stuff"/>
</div>
and I want to replace it with a new set of stuff
<div>
<div class="stuff"/>
<p class="stuff"/>
<ul class="stuff"/>
<a class="stuff"/>
</div>
Which will be fetched via Ajax. My question is: what is the best way to do this?
$.replaceWith doesn't quite do what I want, because I then end up with multiple copies of the new stuff.
I can guarantee that all the stuff will be in one contiguous block, and so presumably I could put in some placeholder after the last element (or before the first element) of the old stuff, remove the old stuff, and replace the placeholder with the new stuff.
However, this seems rather roundabout and inelegant. Is there any clever way of, removing all the old stuff and putting in a single copy of the new stuff, all at one go?
EDIT: I would also like to do this without using any container divs. Using container divs would work in the above case, but would fail in some cases, like when the stuff is inside a <table>:
<table>
<head/>
<body>
<tr/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr class="stuff"/>
<tr/>
</body>
</table>
If i want to replace the rows labelled stuff with another set of rows, possibly more, possibly fewer, there is no way I can nicely put them in a container thingy without breaking the HTML, since the <body> can only contain <tr>s (IIRC).
$('#outerdiv').empty().append(newContent);
Unlike .html(), this will work regardless of whether newContent is an HTML string, or an existing DOM structure.
If there are multiple elements to be replaced but where you need to retain their siblings, you can do this:
$('.stuff').first().before(newContent).end().remove();
i.e. take the first .stuff element, add the new content before it, and then remove all the .stuff elements.
Yes: $('#tagetDiv').html(newContent)
One way to do it would be with wrapAll:
$('.stuff').wrapAll('<div/>').parent().replaceWith('<div class="stuff"/>');
I'm not sure if that passes the "elegant" test, but it does work regardless of whether there is any other content in the containing element.
With that said, though, this seems to be a very complicated solution to a simple problem. The simple solution would be to wrap your elements in a containing element; this shouldn't be a problem if, as you say, you can guarantee that they will always be together.

How can I use literal HTML in a CoffeeKup template?

I'm becoming a huge fan of CoffeeKup, but I'm wondering how I can use literal HTML in such a template? For example when I just want to copy-paste some existing, non-CoffeeKup markup.
You can add arbitrary text with the text function:
text '<p>foo</p>'
For multiline strings, CoffeeScript's heredocs are a pleasure:
text '''
<table>
<tr>
<td>Foo</td>
</tr>
</table>
'''
Just make sure you have autoescape set to false (the default value).
Have you tried using this tool too for converting your markup instead of just inlining in?
https://github.com/brandonbloom/html2coffeekup
It's linked from the main github page of coffeekup. If it handles your old markup it would be a more elegant solution.

AJAX response with TD tags replacing table row is placed nasty in Chrome

I am trying to use editInPlace JavaScript code with Python & Django on Google App Engine.
After editing the row of the table:
<table>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
<tr id="editme" class="editme">
<td>Date</td>
<td>Description</td>
<td>Details</td>
</tr>
</table>
Which looks like this:
___ ___ ___
|___|___|___|
|___|___|___|
|___|___|___|
I maid that editInPlace JavaScript would save original string like "<td>Date</td><td>Description</td><td>Details</td>" by replacing it with striped string without <td> (ex. "Date Description Details") placing the string in to the <td colspan="3"><form>...</form></td> for editor to edit.
So here I prepared that the Http Response after submitting a new value would also be imitating 3 cols, I mean would have <td></td> tags (ex. "<td>ResponseDate</td><td>ResponseDescription</td><td>ResponseDetails</td>") to be placed in between <tr></tr> tags.
But the problem is such that after AJAX replacing values without refreshing hole page, gives me nasty table.
All the row in Chrome v12 is like moved a side and starts filling from the second col:
___ ___ ___
|___|___|___|___
___|___|___|___|
|___|___|___|
Please use Chrome Developer Tools to inspect the affected row after it has been edited (and displayed in the wrong way) - right-click on any cell and select "Inspect Element" in the popup menu. The DevTools window will show up, and you will be able to examine (in the Elements panel) whether the final DOM is correct. If it is, then it's a Chrome/WebKit bug.
Summary of my problem
After sometime debugging my issue i found my problem was caused by the following situation.
A class with a style content: "" being applied to a target TR prior to an ajax call which would replace the TDs with a fresh set of TDs, then, after removing that class I had the same problem as the OP; The end result was the shifting of the TDs to the right. The HTML on inspection was sound.
In detail this is what I had.
I had a TR which was my targetId container.
I had a TD with an ajax link that then returned a set of TDs to replace the old set within the targetId TR.
I am using jquery ajax and prior to the call I applied a class to the targetId TR, the class of which can be found in this answer and contains the content: "" style.
After the ajax call completes, removing that class.
This is what I ended up doing.
The ajax masking class I was using for the targetId, I replaced with a new class that just did some opacity. I kept the ajax masking class for the sender control.
Relating to the OP's problem
I downloaded and searched the "jquery-editinplace" the OP uses but could not find a content style being applied. Maybe someone with good search tools may find it. As stated in the comments above, the problem disappeared when chrome upgraded. This is my case of it remaining because of something possibly related.
I have not made a fiddle of this situation as I had trouble creating an ajax scenario. I would have liked to to prove it is a chrome bug and to submit it to Google.
Feel free to comment if something is unclear and I will update my answer accordingly.
To me, use same Id on multiple <tr> seems awkward.
It might cause some weird behavior.
Keep your unique Id per DOM.
Also I would use
<div>
Instead of tables
because with <div>, you can get more control with CSS.
HTML:
<div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
<div class="editme">
<div>Date</div>
<div>Description</div>
<div>Details</div>
</div>
</div>
CSS:
.editme { clear:both; }
.editme div { float:left; }
So after changing your HTML and CSS like this
you can simply replace those three divs
with a single DIV with FORM
Here is an example of DIV version

Categories