I managed to add text to what's being copied using the code in this answer(the second option). However, when I change the string concatenation and add a call to replace, I get an error "replace is not a function".
copytext = window.getSelection().replace(/some pattern/, 'replace value'); // Fails
The "selection" object seems to be very complex and I can't even find the text inside it. I could call toString on it but that's not an option because I'm copying HTML from a contenteditable div and I need to preserve the formatting.
I'm trying to do this because I have relative links in the div's content and they're being converted to absolute links in the copied text for some reason. This only happens when accessing my demo from rawgit. Locally, it works normally.
Any ideas on how I could accomplish this?
UPDATE
Here's a jsfiddle with my current setup: https://jsfiddle.net/8kx8v8pb/
You need to cast it to a string (getSelection() returns a Selection object).
So either append a "" or cast it to a string with .toString() before executing the .replace()
so in your case, the code should be like this:
copytext = (window.getSelection() + "").replace(/some pattern/, 'replace value');
or
copytext = (window.getSelection().toString()).replace(/some pattern/, 'replace value');
Source: https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection
selection is a object so if you want to run the replace function on its text then use following.
window.getSelection().anchorNode.data.replace(/some pattern/, 'replace value');
I hope this will help
I have some JavaScript code that works in IE containing the following:
myElement.innerText = "foo";
However, it seems that the 'innerText' property does not work in Firefox. Is there some Firefox equivalent? Or is there a more generic, cross browser property that can be used?
Update: I wrote a blog post detailing all the differences much better.
Firefox uses W3C standard Node::textContent, but its behavior differs "slightly" from that of MSHTML's proprietary innerText (copied by Opera as well, some time ago, among dozens of other MSHTML features).
First of all, textContent whitespace representation is different from innerText one. Second, and more importantly, textContent includes all of SCRIPT tag contents, whereas innerText doesn't.
Just to make things more entertaining, Opera - besides implementing standard textContent - decided to also add MSHTML's innerText but changed it to act as textContent - i.e. including SCRIPT contents (in fact, textContent and innerText in Opera seem to produce identical results, probably being just aliased to each other).
textContent is part of Node interface, whereas innerText is part of HTMLElement. This, for example, means that you can "retrieve" textContent but not innerText from text nodes:
var el = document.createElement('p');
var textNode = document.createTextNode('x');
el.textContent; // ""
el.innerText; // ""
textNode.textContent; // "x"
textNode.innerText; // undefined
Finally, Safari 2.x also has buggy innerText implementation. In Safari, innerText functions properly only if an element is
neither hidden (via style.display == "none") nor orphaned from the document. Otherwise, innerText results in an empty string.
I was playing with textContent abstraction (to work around these deficiencies), but it turned out to be rather complex.
You best bet is to first define your exact requirements and follow from there. It is often possible to simply strip tags off of innerHTML of an element, rather than deal with all of the possible textContent/innerText deviations.
Another possibility, of course, is to walk the DOM tree and collect text nodes recursively.
Firefox uses the W3C-compliant textContent property.
I'd guess Safari and Opera also support this property.
If you only need to set text content and not retrieve, here's a trivial DOM version you can use on any browser; it doesn't require either the IE innerText extension or the DOM Level 3 Core textContent property.
function setTextContent(element, text) {
while (element.firstChild!==null)
element.removeChild(element.firstChild); // remove all existing content
element.appendChild(document.createTextNode(text));
}
jQuery provides a .text() method that can be used in any browser. For example:
$('#myElement').text("Foo");
As per Prakash K's answer Firefox does not support the innerText property. So you can simply test whether the user agent supports this property and proceed accordingly as below:
function changeText(elem, changeVal) {
if (typeof elem.textContent !== "undefined") {
elem.textContent = changeVal;
} else {
elem.innerText = changeVal;
}
}
A really simple line of Javascript can get the "non-taggy" text in all main browsers...
var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Note that the Element::innerText property will not contain the text which has been hidden by CSS style "display:none" in Google Chrome (as well it will drop the content that has been masked by other CSS technics (including font-size:0, color:transparent, and a few other similar effects that cause the text not to be rendered in any visible way).
Other CSS properties are also considered :
First the "display:" style of inner elements is parsed to determine if it delimits a block content (such as "display:block" which is the default of HTML block elements in the browser's builtin stylesheet, and whose behavior as not been overriden by your own CSS style); if so a newline will be inserted in the value of the innerText property. This won't happen with the textContent property.
The CSS properties that generate inline contents will also be considered : for example the inline element <br \> that generates an inline newline will also generate an newline in the value of innerText.
The "display:inline" style causes no newline either in textContent or innerText.
The "display:table" style generates newlines around the table and between table rows, but"display:table-cell" will generate a tabulation character.
The "position:absolute" property (used with display:block or display:inline, it does not matter) will also cause a line break to be inserted.
Some browsers will also include a single space separation between spans
But Element::textContent will still contain ALL contents of inner text elements independantly of the applied CSS even if they are invisible. And no extra newlines or whitespaces will be generated in textContent, which just ignores all styles and the structure and inline/block or positioned types of inner elements.
A copy/paste operation using mouse selection will discard the hidden text in the plain-text format that is put in the clipboard, so it won't contain everything in the textContent, but only what is within innerText (after whitespace/newline generation as above).
Both properties are then supported in Google Chrome, but their content may then be different. Older browsers still included in innetText everything like what textContent now contains (but their behavior in relation with then generation of whitespaces/newlines was inconsistant).
jQuery will solve these inconsistencies between browsers using the ".text()" method added to the parsed elements it returns via a $() query. Internally, it solves the difficulties by looking into the HTML DOM, working only with the "node" level. So it will return something looking more like the standard textContent.
The caveat is that that this jQuery method will not insert any extra spaces or line breaks that may be visible on screen caused by subelements (like <br />) of the content.
If you design some scripts for accessibility and your stylesheet is parsed for non-aural rendering, such as plugins used to communicate with a Braille reader, this tool should use the textContent if it must include the specific punctuation signs that are added in spans styled with "display:none" and that are typically included in pages (for example for superscripts/subscripts), otherwise the innerText will be very confusive on the Braille reader.
Texts hidden by CSS tricks are now typically ignored by major search engines (that will also parse the CSS of your HTML pages, and will also ignore texts that are not in contrasting colors on the background) using an HTML/CSS parser and the DOM property "innerText" exactly like in modern visual browsers (at least this invisible content will not be indexed so hidden text cannot be used as a trick to force the inclusion of some keywords in the page to check its content) ; but this hidden text will be stil displayed in the result page (if the page was still qualified from the index to be included in results), using the "textContent" property instead of the full HTML to strip the extra styles and scripts.
IF you assign some plain-text in any one of these two properties, this will overwrite the inner markup and styles applied to it (only the assigned element will keep its type, attributes and styles), so both properties will then contain the same content. However, some browsers will now no longer honor the write to innerText, and will only let you overwrite the textContent property (you cannot insert HTML markup when writing to these properties, as HTML special characters will be properly encoded using numeric character references to appear literally, if you then read the innerHTML property after the assignment of innerText or textContent.
myElement.innerText = myElement.textContent = "foo";
Edit (thanks to Mark Amery for the comment below): Only do it this way if you know beyond a reasonable doubt that no code will be relying on checking the existence of these properties, like (for example) jQuery does. But if you are using jQuery, you would probably just use the "text" function and do $('#myElement').text('foo') as some other answers show.
innerText has been added to Firefox and should be available in the FF45 release: https://bugzilla.mozilla.org/show_bug.cgi?id=264412
A draft spec has been written and is expected to be incorporated into the HTML living standard in the future: http://rocallahan.github.io/innerText-spec/, https://github.com/whatwg/html/issues/465
Note that currently the Firefox, Chrome and IE implementations are all incompatible. Going forward, we can probably expect Firefox, Chrome and Edge to converge while old IE remains incompatible.
See also: https://github.com/whatwg/compat/issues/5
This has been my experience with innerText, textContent, innerHTML, and value:
// elem.innerText = changeVal; // works on ie but not on ff or ch
// elem.setAttribute("innerText", changeVal); // works on ie but not ff or ch
// elem.textContent = changeVal; // works on ie but not ff or ch
// elem.setAttribute("textContent", changeVal); // does not work on ie ff or ch
// elem.innerHTML = changeVal; // ie causes error - doesn't work in ff or ch
// elem.setAttribute("innerHTML", changeVal); //ie causes error doesn't work in ff or ch
elem.value = changeVal; // works in ie and ff -- see note 2 on ch
// elem.setAttribute("value", changeVal); // ie works; see note 1 on ff and note 2 on ch
ie = internet explorer, ff = firefox, ch = google chrome.
note 1: ff works until after value is deleted with backspace - see note by Ray Vega above.
note 2: works somewhat in chrome - after update it is unchanged then you click away and click back into the field and the value appears.
The best of the lot is elem.value = changeVal; which I did not comment out above.
As in 2016 from Firefox v45, innerText works on firefox, take a look at its support: http://caniuse.com/#search=innerText
If you want it to work on previous versions of Firefox, you can use textContent, which has better support on Firefox but worse on older IE versions: http://caniuse.com/#search=textContent
What about something like this?
//$elem is the jQuery object passed along.
var $currentText = $elem.context.firstChild.data.toUpperCase();
** I needed to make mine uppercase.
Just reposting from comments under the original post. innerHTML works in all browsers. Thanks stefita.
myElement.innerHTML = "foo";
found this here:
<!--[if lte IE 8]>
<script type="text/javascript">
if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
!Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get)
(function() {
var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
Object.defineProperty(Element.prototype, "textContent",
{ // It won't work if you just drop in innerText.get
// and innerText.set or the whole descriptor.
get : function() {
return innerText.get.call(this)
},
set : function(x) {
return innerText.set.call(this, x)
}
}
);
})();
</script>
<![endif]-->
It's also possible to emulate innerText behavior in other browsers:
if (((typeof window.HTMLElement) !== "undefined") && ((typeof HTMLElement.prototype.__defineGetter__) !== "undefined")) {
HTMLElement.prototype.__defineGetter__("innerText", function () {
if (this.textContent) {
return this.textContent;
} else {
var r = this.ownerDocument.createRange();
r.selectNodeContents(this);
return r.toString();
}
});
HTMLElement.prototype.__defineSetter__("innerText", function (str) {
if (this.textContent) {
this.textContent = str;
} else {
this.innerHTML = str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/\n/g, "<br />\n");
}
});
}
When I am using jQuery to grab CSS values for objects, each of the browsers (IE, Mozilla, Chrome, etc) returns different values.
For example, in Chrome, a background image (.css("background-image")) returns:
url(http://i41.tinypic.com/f01zsy.jpg)
Where in Mozilla, it returns:
url("http://i41.tinypic.com/f01zsy.jpg")
I am having the same problem on other aspects, such as background-size.
In chrome it returns:
50% 50%
But Mozilla returns:
50%+50%
My problem with this is, I have functions that split the CSS (background-size), for example based on a space .split(" "), but this could not work on Mozilla because it uses a + instead.
Is there any way that I can fix this problem and make the browsers to use one standard?
Is there any function that I could write which grabs and splits values, based on the type of browser the user is using?
My problem with this is, I have functions that split the CSS
(background-size), for example based on a space .split(" "), but this
could not work on Mozilla because it uses a + instead.
Try adding \+ to RegExp passed to .split
.split(/\s|\+/)
var res = ["50%+50%", "50% 50%"];
var re = /\s+|\+/;
console.log(res[0].split(re), res[1].split(re));
Different browsers use different CSS standards and you may have to write a full-blown parser to make them one standard.
Workaround is that you should split or use CSS values taking into account the different browsers standards. Like the CSS(background-size) problem can be solved using this:
space.split("\\s|\\+"); //split my string where it either has a space 'or' a plus sign
For CSS(background-image), the solution may be to replace the inverted commas before using it:
space.replace("\"", "");
Try to make the splits generallized for all browsers. Hope that helps.
This probably isn't the cleanest method, but you could run a string parser for the background image source and delete any quotation marks. This would be the most efficient method for parsing the background image URL. It should work without harming the data because URL's typically can't contain quotation marks, as they are encoded as %22
As for the background-size, you could parse the results for + signs and change those to spaces, as + signs typically aren't present as the values for any CSS properties, so you should be relatively safe in taking those out.
In addition, you could check the browser type to see if you'd even have to run these parsings in the first place. As a precaution, you should also see how Opera and Safari return results, and if those are any different, you could create branch statements for the parsers that handle the different types of CSS values returned by the different browsers.
Note: The parsing methods I have described attempt the goal of converting the Firefox results to the Chrome-style results.
Thanks for all the help.
I'll share the code I have ended up using!
cssCommas: function(text)
{
return text.replace(new RegExp("\"", "g"),"");
},
cssPlus: function(text)
{
return text.replace(new RegExp("\\+", "g"),"");
},
cssSplit: function(text,removePercent)
{
var removeParent = removeParent || false;
if(removePercent == true)
{
text = text.replace(new RegExp("%", "g"),"");
}
return text.split(new RegExp("\\s|\\+","g"));
},
css: function(text)
{
return this.cssCommas(this.cssPlus(text));
}
Works perfectly on all browsers now. Thanks a lot.
I have a jsfiddle that demonstrates the question:
http://jsfiddle.net/H6gML/8/
$(document).ready(function() {
// this seems fine in IE9 and 10
var $div = $("<div>");
console.log("In IE, this <div> is just fine: " + $div[0].outerHTML);
// this is weird in IE
var $test = $("<test>");
console.log("However, this <test> has an xml tag prepended: \n"
+ $test[0].outerHTML);
$test.find("test");
console.log("Now, it does not: \n" + $test[0].outerHTML);
console.log("Why does this behave this way?");
});
Why does this happen? It doesn't happen in Chrome or Firefox. Is there a better way to fix this than to call .find("test") on the object?
Edit
To clarify, I'm not asking why the xml tag is added, rather, I'm wondering why the .find() call get's rid of it. It doesn't make sense to me.
Why does this happen? It doesn't happen in Chrome or Firefox. Is there a better way to fix this than to call .find("test") on the object
It is the IE causing the issue while doing document.createElement on an unknown html element type. It thinks it is an XML node and adds the xml namespace prefixed <?XML:NAMESPACE PREFIX = PUBLIC NS = "URN:COMPONENT" />. Instead if you try to make it explicit to mention that it is an html element, this issue doesn't happen.
Try:
var $test = $("<html><test/></html>");
The issue no longer occurs.
To clarify, I'm not asking why the xml tag is added, rather, I'm wondering why the .find() call get's rid of it. It doesn't make sense to me.
Now, when you do a find, jquery internally uses context.getElementsByTagName or (similar based on the type whether it is a class or a tag or id etc..) which means it does this operation on the element test. So in IE when you do that it probably internally resolves the fact that you are trying to perform the operation on an html element and not an xml element and it changes the document type for the underlying context(But i don't know why it changes the parent context though rather than just returning a match). You can check this out by this simple example as well.
var $test = document.createElement("test");
console.log("However, this <test> has an xml tag prepended: \n"
+ $test.outerHTML);
$test.getElementsByTagName("test");
console.log("Now, it does not: \n" + $test.outerHTML);
Demo
Update
Here is a documented way of defining the custom elements
The custom element type identifies a custom element interface and is a sequence of characters that must match the NCName production and contain a U+002D HYPHEN-MINUS character. The custom element type must not be one of the following values:
annotation-xml,
color-profile,
font-face,
font-face-src,
font-face-uri,
font-face-format,
font-face-name,
missing-glyph
So according to this had your tag name been somename-test ex:- custom-test IE recognizes it and it works as expected.
Demo
While debugging some jQuery that is not working in IE, I found this error message:
var item = $("#item_"+ itemArray[itemIndex]).find('a').text().trim();
Object doesn't support this property or method (script.js, line 100, character 2)
The character 2 doesn't make sense to me. Based on the text displayed character 2 would be the letter a in var but of course that doesn't make any sense.
(Should I not use var?)
I know that jQuery is working to some extent or the script would not have been able to get this far on my page.
IE doesn't have String.trim(), you'll need $.trim() (which uses native trim if available, emulates it in IE), like this:
var item = $.trim($("#item_"+ itemArray[itemIndex]).find('a').text());
IE doesn't have a trim method.
Instead, you can call jQuery.trim(...).