cloneNode in internet explorer - javascript

While executing the following code IE throws the error -- Object doesn't support this property or method -- referring to the cloneNode() method. 'i' is the loop counter, source and dest are both HTML select elements.
dest.options[dest.options.length] = source.options[i].cloneNode( true );
FF and Chrome behave as expected. Any ideas on how to get IE to execute cloneNode()? The IE 8 debugger shows source.options[i] does have a cloneNode() method.
Thanks.

IE requires the
new Option()
construct.
document.createElement( 'option' );
or
cloneNode()
will fail. Of course, all options work as expected in a proper web browser.

Actually, cloneNode isn't throwing any error. Break your code down into smaller chunks to properly identify the source of the error:
var origOpt = source.options[i];
var clonedOpt = origOpt.cloneNode( true ); // no error here
var destOptLength = dest.options.length;
dest.options[destOptLength] = clonedOpt; // error!
dest.options.add(clonedOpt); // this errors too!
dest.appendChild(clonedOpt); // but this works!
Or, putting it back the way you had it, all on one line:
dest.appendChild(source.options[i].cloneNode( true ));

I've found this post useful: IE’s cloneNode doesn’t actually clone!

<!doctype html>
<html lang="en">
<head>
<meta charset= "utf-8">
<title>Untitled Document</title>
<style>
p, select,option{font-size:20px;max-width:640px}
</style>
<script>
function testSelect(n, where){
var pa= document.getElementsByName('testselect')[0];
if(!pa){
pa= document.createElement('select');
where.appendChild(pa);
pa.name= 'testselect';
pa.size= '1';
}
while(pa.options.length<n){
var i= pa.options.length;
var oi= document.createElement('option');
pa.appendChild(oi);
oi.value= 100*(i+1)+'';
oi.text= oi.value;
}
pa.selectedIndex= 0;
pa.onchange= function(e){
e= window.event? event.srcElement: e.target;
var val= e.options[e.selectedIndex];
alert(val.text);
}
return pa;
}
window.onload= function(){
var pa= testSelect(10, document.getElementsByTagName('h2')[0]);
var ox= pa.options[0];
pa.appendChild(ox.cloneNode(true))
}
</script>
</head>
<body>
<h2>Dynamic Select:</h2>
<p>You need to insert the select into the document,
and the option into the select,
before IE grants the options any attributes.
This bit creates a select element and 10 options,
and then clones and appends the first option to the end.
<br>It works in most browsers.
</p>
</body>
</html>

Related

why dont work insertAfter function in javascript

but insertbefore work
var a=document.querySelector("#div");
var y=document.createElement('p');
y.innerText='yazilarucun';
var c=document.querySelector(".p");
a.insertAfter(y,c);
<body>
<div id='div'>yazi
<p class='p'>p etiketi</p>
</div>
</body>
Your Problem Can be fixed pretty easily. You can fix this by adding the node before the node that is after the the node
function insertAfter(newNode, existingNode) {
existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
}
//Create Element
var new_para = document.createElement('p');
new_para.innerText = 'yazilarucun';
//Add the element
var old_para = document.querySelector(".p");
insertAfter(new_para, old_para)
<body>
<div id='div'>yazi
<p class='p'>p etiketi</p>
</div>
</body>
The node.insertAfter() is not an inbuilt javascript method, instead we created a user-defined function.
<!DOCTYPE html>
<html>
<body>
<p id="point">Start</p>
<script>
var parentNode = document.getElementsByTagName("body")[0];
var refNode = document.getElementById("point");
function insertAfter(newNode, refNode){
refNode.parentNode.insertBefore(newNode, refNode.nextSibling);
}
var newNode = document.createElement("p");
var textnode = document.createTextNode("End");
newNode.appendChild(textnode);
insertAfter(newNode, refNode);
</script>
</body>
</html>
check : https://www.wikimass.com/js/node-insertafter
There is at least 3 ways to do it.
let targetNode = document.querySelector('#wrapper'),
placeNode = document.querySelector('#footer');
targetNode.after(placeNode);
targetNode.insertAdjacentElement('afterend', placeNode);
targetNode.parentNode.insertBefore(placeNode, targetNode.nextSibling);
The first of these 3, is the newest and simplest. Has been supported since Chrome 54+, Firefox 49+, Edge 17+. No IE support...
Last one is best support, oldest and most complicated one...
Middle one is somewhere in the middle... Is still too hard... Not intuitive enough...

How to access an iframe from chrome extension?

How can I get my extension to work on all frames like adblock does?
I tried adding "all_frames" : true to my manifest file but it didn't work.
I tried to use this code to get the text with specific ids:
var theId = "starts with something";
var myArray = [];
$('[id^="theId"]').each(function(i, obj) {
myArray.push($(this).text());
});
$.unique(myArray);
console.log(myArray);
but it says my array is empty. When I inspect element on the page, I see a "top" layer, and a "target content" layer. The code only works when I execute it in the console on the "target content" layer. Can I use this code in a content script, or do I need to use background.js somehow?
Continued from SO44122853
I see you figured out that the content was loaded in an iframe. So I have a working demo here PLUNKER, the snippet is here just in case the plunker goes down.
Details are commented in PLUNKER
Demo
Not functional due to the need to run 2 separate pages
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<style></style>
</head>
<body>
<!--iframe is same as the one on the site, with the exception
of the src-->
<iframe id="ptifrmtgtframe" name="TargetContent" title="Main Content" frameborder="0" scrolling="auto" width='90%' src="tables.html"></iframe>
<!--The data is displayed as a one string-->
<output id='display'></output>
<script>
// Reference the iframe
var iFID = document.getElementById("ptifrmtgtframe");
// Register the load event on iframe
iFID.onload = function(e) {
// Callback is extractText function
return extractText('#ptifrmtgtframe', '#display', '.PSLONGEDITBOX');
}
/* Pass iframe and display as a single selector
|| Pass targets as a multiple selector
*/
function extractText(iframe, display, targets) {
var iArray = [];
var iFrame = document.querySelector(iframe);
var iView = document.querySelector(display);
var iNode = "";
/* .contentWindow is property that refers to content
|| that is in an iframe. This is the heart of the
|| demo.
*/
var iContent = iFrame.contentDocument || iFrame.contentWindow.document;
var iTarget = iContent.querySelectorAll(targets);
/* .map() will call a function on each element
|| and return a new array as well.
*/
Array.from(iTarget).map(function(node, idx) {
iNode = node.textContent;
iView.textContent += iNode;
iArray.push(iNode);
return iArray;
});
console.log(iArray);
}
</script>
</body>
I think your script may be executing before the DOM loads, try putting your function inside:
document.addEventListener('DOMContentLoaded', function() {
});
EDIT
That event seems to do nothing in content scripts, I think that is because they are already loading after DOM is loaded, and never fires.
However this seems to fire but not sure why:
$(function(){
//something
});
This needs jQuery injected aswell

Fire an event before `cut` event in ace editor

I want to fire an event before cut, so that I can get what text is being cut i.e. what has been already selected. I am currently using the following code, which doesn't seem to work as desired.
$("#editor").bind({
cut:function(){
console.log('Cut Detected');
alert(editor.selection.getRange());
}
});
editor is the id of the "div" tag which is editable. editor.selection.getRange() returns the start and end of selection.
edit I am woring with content editable div and want to apply the functionality on it.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Editor</title>
</head>
<body>
<div id='myTa' contenteditable>hello world where are you</div>
<script type='text/javascript' src='jquery-2.1.4.min.js'></script>
<script type='text/javascript'>
$("#myTa").on("cut", function(){
alert(this.selectionStart+ " to " + this.selectionEnd);
})
</script>
</body>
</html>
You are correct that you need to use the cut event. The ClipboardEvent API is apparently unstable but yes, I would have thought it would include the text being moved onto the clipboard.
The following works for me:
$("textarea").on("cut", function(){
alert(this.value.substring(this.selectionStart, this.selectionEnd));
})
It's worth noting that bind is deprecated in jQuery, you should use on instead. Try out the snippet:
$("textarea").on("cut", function() {
alert(this.value.substring(this.selectionStart, this.selectionEnd));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
I think at first that clipboardEvent will have the clipped text, but it seems not, so I try to find the selection related properties of input and found it.
And the reference is HTMLInputElement.
This codes work in presumption that your $("#editor") is either an input or textarea.
$("#editor").bind({
cut:function(e){
console.log('Cut Detected');
var $this = $(this);
var selectStart = this.selectionStart;
var selectionEnd = this.selectionEnd;
var clippedValue = $this.val().slice(selectStart, selectionEnd);
// Now you have the clipped value, do whatever you want with the
// value.
alert(clippedValue);
}
});
For works on contentediable, you can do this, which I just found info from Return HTML from a user-selected text and MDN
$("#myTa").on("cut", function(e){
// Seems diff bro
var selections = window.getSelection();
var currentSelection = selections.getRangeAt(0);
var start = currentSelection.startOffset;
var end = currentSelection.endOffset;
var selectedContents = currentSelection.toString();
// Do whatever you want.
console.log(start, end);
console.log(selectedContents);
alert(selectedContents);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id='myTa' contenteditable>ask;ndjkasn asdbasj aujs d sdib askjbnsaab asbh mjn a</div>
I have got the solution to my answer. apperently there is an editor.on('cut',function(e)) in ace editor I use
editor.on("cut", function(e){
console.log('Cut Detected');
console.log(editor.selection.getRange());
});

Javascript createElement() not working in Chrome

Javascript createElement() is not working in Chrome but it works in IE and Firefox fine. Why?
It's working perfectly, use this code:
var catDiv = document.createElement("div");
catDiv.innerHTML = "Test";
document.body.appendChild(catDiv);
Another working example (if you have an element with Id = myTableBody in your HTML)
var appendingTo = document.getElementById("myTableBody");
var tr = document.createElement("tr");
tr.setAttribute("name", "i");
appendingTo.appendChild(tr);
var name = document.createElement("Div" );
will work. And later you can add the attributes like
name.colSpan="2";
document.body.appendChild(name);
Note: don't try to use angular brackets like createElement("<div />").
It will not work in Chrome.
Edit: syntax issue in above code fixed. there should be a dot instead of comma.
Beacause your code is messed up, there's nothing wrong with "createElement":
<html>
<head>
<meta charset = "utf-8">
<title></title>
<script>
window.onload = function () {
for (var i = 0; i < 100; i ++) {
var div = document.createElement ("div");
div.style.border = "1px solid black";
div.style.margin = "20px";
div.style.padding = "10px";
document.body.appendChild (div);
}
}
</script>
<style></style>
</head>
<body></body>
</html>
So I also couldn't get createElement() to work in chrome. After reading Caio's post and testing the code provided I figured out what I was doing wrong.
On w3schools.com the examples they provide always use the tag name in all caps ex. createElement("DIV"), which is the way I was using it and with poor results.
After changing from "DIV" to "div" in my own code it instantly worked.
Thanks Caio.

Range Selection and Mozilla

I would like to specify that firefox select a range. I can do this easily with IE, using range.select();. It appears that FFX expects a dom element instead. Am I mistaken, or is there a better way to go about this?
I start by getting the text selection, converting it to a range (I think?) and saving the text selection. This is where I'm getting the range from initially:
// Before modifying selection, save it
var userSelection,selectedText = '';
if(window.getSelection){
userSelection=window.getSelection();
}
else if(document.selection){
userSelection=document.selection.createRange();
}
selectedText=userSelection;
if(userSelection.text){
selectedText=userSelection.text;
}
if(/msie|MSIE/.test(navigator.userAgent) == false){
selectedText=selectedText.toString();
}
origRange = userSelection;
I later change the selection (successfully). I do so by range in IE and by a dom ID in ffx. But after I do that, I want to set back the selection to the original selection.
This works like a charm in IE:
setTimeout(function(){
origRange.select();
},1000);
I would like to do something like this in FFX:
var s = w.getSelection();
setTimeout(function(){
s.removeAllRanges();
s.addRange(origRange);
},1000);
Unfortunately, FFX has not been cooperative and this doesn't work. Any ideas?
The short answer is: IE and other browsers differ in their implementations of selecting text using JavaScript (IE has its proprietary methods). Have a look at Selecting text with JavaScript.
Also, see setSelectionRange at MDC.
EDIT: After making a little test case, the problem becomes clear.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>addRange test</title>
<style>
#trigger { background: lightgreen }
</style>
</head>
<body>
<p id="test">This is some (rather short) text.</p>
<span id="trigger">Trigger testCase().</span>
<script>
var origRange;
var reselectFunc = function () {
var savedRange = origRange;
savedRange.removeAllRanges();
savedRange.addRange(origRange);
};
var testCase = function () {
// Before modifying selection, save it
var userSelection,selectedText = '';
if(window.getSelection){
userSelection=window.getSelection();
}
else if(document.selection){
userSelection=document.selection.createRange();
}
selectedText=userSelection;
if(userSelection.text){
selectedText=userSelection.text;
}
if(/msie|MSIE/.test(navigator.userAgent) === false){
/* you shouldn't do this kind of browser sniffing,
users of Opera and WebKit based browsers
can easily spoof the UA string */
selectedText=selectedText.toString();
}
origRange = userSelection;
window.setTimeout(reselectFunc, 1000);
};
window.onload = function () {
var el = document.getElementById("trigger");
el.onmouseover = testCase;
};
</script>
</body>
</html>
When testing this in Firefox, Chromium and Opera, the debugging tools show that after invoking removeAllRanges in reselectFunc, both savedRange and origRange are reset. Invoking addRange with such an object causes an exception to be thrown in Firefox:
uncaught exception: [Exception...
"Could not convert JavaScript argument
arg 0 [nsISelection.addRange]"
nsresult: "0x80570009
(NS_ERROR_XPC_BAD_CONVERT_JS)"
location: "JS frame ::
file:///home/mk/tests/addrange.html ::
anonymous :: line 19" data: no]
No need to say that in all three browsers no text is selected.
Apparently this in intended behaviour. All variables assigned a (DOM)Selection object are reset after calling removeAllRanges.
Thank you Marcel. You're right, the trick is to clone the range, then remove the specific original range. This way we can revert to the cloned range. Your help led me to the below code, which switches the selection to elsewhere, and then back according to a timeout.
I couldn't have done it without you, and grant you the correct answer for it :D
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>addRange test</title>
<style>
#trigger { background: lightgreen }
</style>
</head>
<body>
<p id="switch">Switch to this text</p>
<p id="test">This is some (rather short) text.</p>
<span id="trigger">Trigger testCase().</span>
<script>
var origRange;
var s = window.getSelection();
var reselectFunc = function () {
s.removeAllRanges();
s.addRange(origRange);
};
var testCase = function () {
// Before modifying selection, save it
var userSelection,selectedText = '';
if(window.getSelection){
userSelection=window.getSelection();
}
else if(document.selection){
userSelection=document.selection.createRange();
}
selectedText=userSelection;
if(userSelection.text){
selectedText=userSelection.text;
}
if(/msie|MSIE/.test(navigator.userAgent) === false){
/* you shouldn't do this kind of browser sniffing,
users of Opera and WebKit based browsers
can easily spoof the UA string */
selectedText=selectedText.toString();
}
origRange = userSelection;
var range = s.getRangeAt(0);
origRange = range.cloneRange();
var sasDom = document.getElementById("switch");
s.removeRange(range);
range.selectNode(sasDom);
s.addRange(range);
window.setTimeout(reselectFunc, 1000);
};
window.onload = function () {
var el = document.getElementById("trigger");
el.onmouseover = testCase;
};
</script>
</body>
</html>

Categories

Resources