cloneNode issue with HTML5 nodes in IE - html

I am trying to clone an HTML node using cloneNode() method of browser's DOM API and even using Jquery clone() function. The API works perfectly fine with HTML tags, However i am facing some issues while using it with HTML5 tags like time e.g.
The issue is that following <time> tag content <time class="storydate">April 7, 2010</time> gets converted to: <:time class=storydate awpUniq="912">April 7, 2010. Although IE renders the original time node correctly then why such issue with the clone API.
And this issue isn't observed in FF/ chrome. Please give some clue how to avoid this

Is this of any help? From the HTML5 Shiv issue list:
http://code.google.com/p/html5shiv/issues/detail?id=28
Links to
http://pastie.org/935834#49
solution seems to be:
// Issue: <HTML5_elements> become <:HTML5_elements> when element is cloneNode'd
// Solution: use an alternate cloneNode function, the default is broken and should not be used in IE anyway (for example: it should not clone events)
// Example of HTML5-safe element cloning
function html5_cloneNode(element) {
var div = html5_createElement('div'); // create a HTML5-safe element
div.innerHTML = element.outerHTML; // set HTML5-safe element's innerHTML as input element's outerHTML
return div.firstChild; // return HTML5-safe element's first child, which is an outerHTML clone of the input element
} // critique: function could be written more cross-browser friendly?

Related

DOM Selector to get text of element ignoring children?

I'm using the Tab Modifier plugin for Chrome to dynamically rename some tabs that I use daily. In the tab Title definition, it says the following:
You can inject any DOM content with {selector}. Examples: {title} for website title, {h1}, {#id}, {.class}, etc.
Here is an example of the element I want to use to name the tab:
<td class="portalTitleInfoVal">
PORTALNAME
<a class="portalLink">Change Portal</a>
</td>
This is what I'm currently using for the title:
{.portalTitleInfoVal:nth-of-type(4)}
But, of course, the tab is named PORTALNAMEChange Portal.
How can I modify the DOM selector so that the tab is just named "PORTALNAME"?
I know I'm really late to the party, but I found this post while searching for an answer.
I'm working with a lot of old systems and all the tabs just says {title}, which is.. not useful when having 15-20 tabs open at once, and it's tedious to hard code every tab.
So.. I brute forced tested until I found a solution:
Every page has a breadcrumb:
<div class="breadcrumb noPrint">
Home "»"
Materials
123123
</div>
So they might have updated the extension since, but your guess was very close. I don't know why you were putting in 4, but I assume you had more elements than posted.
Anyhow, the way I got it to work were by:
{.breadcrumb :nth-last-child(2)} : {.breadcrumb :last-child}
So, there has to be a space between the .class and the child element, which in my case returns Materials : 12312
I haven't tried nearly half, but DoFactorys list of CSS selectors were a big help for me.
The element's first child node is the plain text, before the HTML element (<a>).
$('. portalTitleInfoVal')[0].childNodes[0].nodeValue
It looks like this plugin will only allow for CSS style element selectors compatible with querySelector. It then grabs the text from that element. From their github repo:
/**
* Returns the text related to the given CSS selector
* #param selector
* #returns {string}
*/
getTextBySelector = function (selector) {
var el = document.querySelector(selector), value = '';
if (el !== null) {
value = el.innerText || el.textContent;
}
return value.trim();
};

Any difference between .innerHTML and .set('html','') in mootools?

To set the html of elements on my site, I use mostly
$('elementId').innerHTML = "<p>text</p>";
Looking through the mootools docs, I found this example given:
$('myElement').set('html', '<div></div><p></p>');
Is there any difference between these? Should I go through and change .innerHTML to the mootools method, or doesn't it make a difference?
the reason why the first one works is because - as it stands - a $ selector (document.id) in mootools returns the actual element. this - in normal browsers - is identical to document.getElementById() and the element object exposes any and all of its attributes/properties for you to edit.
the problems with NOT using .set are:
when mootools 2.0 aka MILK gets released, it won't work as it will be wrapped like jQuery and the selector won't return the object (mootools is becoming AMD hence it won't modify native Types - Element, Array, Number, String, Function(maybe!) - prototypes).
you cannot chain this. with set you can: $('someid').set("html", "loading...").highlight();, for example.
set is overloaded - it can set either a single property or multiples by means of passing an object. eg, element.set({html: "hello", href: "#", events: boundObj});
look at https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L936-942 - you can pass an array as an argument and it will join it for you, this makes it easy to work with multi-line strings and ensures performance in IE
edit: the BBT fan has kind of opened a separate topic: should the framework try to block you / prevent you from doing things that break the browser?
if you want to, you can add disallowed elements by changing that setter Element.Properties.html.set = function() { var tag = this.get("tag"); ... check tag }; - isn't mootools great?
mootools - by default - will NOT try to prevent you from doing stupid shit [tm] - that's your responsibility :) try setting height on an element to a negative value in IE, for example. should the Fx class prevent you from doing that? No. Should the setter prevent you? No. The footprint of constant checks to see if you are not breaking means it will slow everything down in performance-critical cases like animations.

using innerHTML at custom tag in IE

I have a problem I just can't solve, and need your advice since I'm out of ideas:
Context: I'm using tinyMCE Editor on my website and developed a custom plugin to include external xml files. So far everything works as expected. The links to the external xml files are represented as span-Tags:
<span id="-[XML Document 1]-" title="erg" class="xml_embed xml_include">-[XML Document 1]-</span>
but only in the tinyMCE editor with a custom class (xml_include) to distinguish them from normal text and upon switching to the html/source code view or saving, those span tags get replaced to xi:include elements:
<xi:include xmlns:xi="http://www.w3.org/TR/XInclude" show="xml_embed" href="erg">-[XML Document 1]-</xi:include>
The text that was set as innerHTML ("-XML Document 1]-") for the span tag(s) serves as placeholder in the editor and gets moved to the xi:include tag(s) in the source view and serves as placeholder there also.
Now to the problem:
The code to transform span.xml_include to xi:include gets called before the source code popup is displayed:
ed.onPreProcess.add(function(ed, o) {
var elm;
var domelm;
//get all span.xml_include elements
tinymce.each(ed.dom.select('span.xml_include', o.node), function(n) {
//IE ignores innerHTML when created with tinymce.dom, therefore use native JS createElement method to tell IE that custom tag is valid HTML
if(tinymce.isIE)
{
domelm = document.createElement('xi:include');
domelm.setAttribute("xmlns:xi", "http://www.w3.org/TR/XInclude");
domelm.href = n.title;
domelm.innerHTML = n.innerHTML;
domelm.show = n.className.split(/\s+/)[0];
document.body.appendChild(domelm);
ed.dom.replace(domelm, n);
}
else
{
//ed = tinyMCE.activeEditor
elm = ed.dom.create('xi:include', {href: n.title, show: n.className.split(/\s+/)[0]}, n.innerHTML);
elm.setAttribute("xmlns:xi", "http://www.w3.org/TR/XInclude");
ed.dom.replace(elm, n);
}
});
});
this code works perfectly fine in FF and Chrome, but not in IE (I tested 7 & 8): in IE the innerHTML of the new element "domelm" can't be set. Either it stays blank or if set explicitly an error is thrown. n.innerHTML can be accessed. I get an "Unknown runtime error" for the line domelm.innerHTML = n.innerHTML;
What else did I try?
the native JS way: domelm.appendChild(document.createTextNode(n.innerHTML)); to create a text node and append it to the "domelm" with no success (getting error: "unexpected call to method or property access", that should be the translation from "Unerwarteter Aufruf oder Zugriff" (german version))
the tinyMCE API way: tinymce.DOM.setHTML(domelm, n.innerHTML); resulted in no error but also the usual blank innerHTML
the jQuery way: $('#domelm').html(n.innerHTML); or first var jQelm = $(domelm); then jQelm.text(...); or jQelm.html(...); doesn't matter, neither works, IE always returns "unexpected call to method" error in the jquery core, which I obviously won't touch..
the tinyMCE way of creating elements as seen in the "else" part of the if condition above..if domelm.innerHTML = n.innerHTML; isn't explicitly set, elm.innerHTML just stays blank, else the same errors as on the approaches above occur, therefore I could as well skip the if(tinymce.isIE) detection..
What else can I do? Suggestions?
I also made sure to properly declare the custom xml namespaces, changed the MIME-type to application/xhtml+xml instead of simply text/html, "announced" the xi:include node for IE with document.createElement('xi:include'); and generally changed the code to please IE..and this seems to be the last major bug I have to overcome..
I'm not sure if it's an error in my code since FF and Chrome work fine local and remote and don't show any errors..?
Any help is appreciated, I hope I provided enough context for you so that it's clear what I meant. and sorry for mistakes, English is not my first language :)
Ok, wrapping the custom element in a p/div/span tag finally did the trick: I used span to leave the formatting unmodified..here is what I did:
In the "if(tinymce.isIE) part of the onPreProcess function, before "xi:include" is created, a wrapper is needed:
var wrapper = document.createElement('span');
Appending the custom tag-element to the wrapper:
wrapper.appendChild(domelm);
and appending a textNode to the wrapper since appending it to the domelm throws errors:
wrapper.appendChild(document.createTextNode(n.innerHTML));
and finally append the wrapper to the dom and replace the "span" tag (n) with the wrapped "xi:include" (wrapper, span tag to be modified):
document.body.appendChild(wrapper);
ed.dom.replace(wrapper, n);`
The result is a custom "xi:include" tag in IE with the correct innerHTML:
<span><xi:include xmlns:xi="http://www.w3.org/TR/XInclude" href="eh" show="xml_embed">-[XML Document]-</xi:include></span>

Are HTML data attributes safe for older browsers e.g. IE 6? [duplicate]

Custom data attributes: http://dev.w3.org/html5/spec/Overview.html#embedding-custom-non-visible-data
When I say “work”, I mean, if I’ve got HTML like this:
<div id="geoff" data-geoff="geoff de geoff">
will the following JavaScript:
var geoff = document.getElementById('geoff');
alert(geoff.dataGeoff);
produce, in IE 6, an alert with “geoff de geoff” in it?
You can retrieve values of custom (or your own) attributes using getAttribute. Following your example with
<div id="geoff" data-geoff="geoff de geoff">
I can get the value of data-geoff using
var geoff = document.getElementById("geoff");
alert(geoff.getAttribute("data-geoff"));
See MSDN. And although it is mentioned there that you need IE7 to get this to work, I tested this a while ago with IE6 and it functioned correctly (even in quirks mode).
But this has nothing to do with HTML5-specific attributes, of course.
Yes, they work.
IE has supported getAttribute() from IE4 which is what jQuery uses internally for data().
data = elem.getAttribute( "data-" + key ); // Line 1606, jQuery.1.5.2.js
So you can either use jQuery's .data() method or plain vanilla JavaScript:
Sample HTML
<div id="some-data" data-name="Tom"></div>
Javascript
var el = document.getElementById("some-data");
var name = el.getAttribute("data-name");
alert(name);
jQuery
var name = $("#some-data").data("name");
Not only does IE6 not support the HTML5 Data Attribute feature, in fact virtually no current browser supports them! The only exception at the moment is Chrome.
You are perfectly at liberty to use data-geoff="geoff de geoff" as an attribute, but only Chrome of the current browser versions will give you the .dataGeoff property.
Fortunately, all current browsers - including IE6 - can reference unknown attributes using the standard DOM .getAttribute() method, so .getAttribute("data-geoff") will work everywhere.
In the very near future, new versions of Firefox and Safari will start to support the data attributes, but given that there's a perfectly good way of accessessing it that works in all browsers, then there's really no reason to be using the HTML5 method that will only work for some of your visitors.
You can see more about the current state of support for this feature at CanIUse.com.
Hope that helps.
I think IE has always supported this (at least starting from IE4) and you can access them from JS. They were called 'expando properties'. See old MSDN article
This behaviour can be disabled by setting the expando property to false on a DOM element (it's true by default, so the expando properties work by default).
Edit: fixed the URL
If you wanted to retrieve all of the custom data attributes at once like the dataset property in newer browsers, you could do the following. This is what I did and works great for me in ie7+.
function getDataSet(node) {
var dataset = {};
var attrs = node.attributes;
for (var i = 0; i < attrs.length; i++) {
var attr = attrs.item(i);
// make sure it is a data attribute
if(attr.nodeName.match(new RegExp(/^data-/))) {
// remove the 'data-' from the string
dataset[attr.nodeName.replace(new RegExp('^data-'), '')] = attr.nodeValue;
}
}
return dataset;
}
In IE6, it may not work. For reference: MSDN
I suggest using jQuery to handle most of the cases:
var geoff = $("#geoff").data("data-geoff");
alert(geoff);
Try this in your coding.

HTML in Mootools' Element constructor?

I'm currently using the Mootools Element constructor method to dynamically add a new row into a table.
function newPermission(somedata) {
var newUserPerm = new Element('tr', {
'html': '<td>foo</td><td>bar</td>'
});
newUserPerm.inject('permissions_table');
}
However, upon checking the resulting code, the following HTML string gets added to the table:
<tr>foobar</tr>
I'm sure there's some way to send the HTML tags as well, but I can't find much on it here, except one other question, in which the user had an outdated ver. of Mootools...
this has been fixed in mootools 1.3 beta and i think only affects tables (otherwise html setters via element constructors are fine) - in the mean while, do not set the html through the element constructor but set the it after you create the TR:
var tr = new Element('tr').inject(document.id("foo").getElement("tbody"), "top");
tr.set("html", '<td>foo</td><td>bar</td>');
here it is working as you had it in 1.3: http://www.jsfiddle.net/dimitar/ALsBK/
and here it is breaking in 1.2.4: http://www.jsfiddle.net/dimitar/ALsBK/1/
and working in 1.2.4: http://www.jsfiddle.net/dimitar/ALsBK/2/