execCommand bold fails in Firefox when all text is selected - javascript

I'm setting up to do some simple WYSIWYG editing using JavaScript, and I've run into an issue in Firefox that I don't get in Chrome or IE (recent versions of all). When all the text in my contentEditable span is selected, if I attempt to make it bold using document.execCommand('bold',false,null), I receive a rather nondescript error message: "NS_ERROR_FAILURE: Failure"
Here's some simple example code to easily reproduce the issue:
<html>
<head>
<script>
function start(){
var edit = document.getElementById('edit');
edit.contentEditable = true;
var button = document.getElementById('button');
button.onclick = function(){
// Get the editable span
var edit = document.getElementById('edit');
// Select the contents of the span
var range = document.createRange();
range.selectNodeContents(edit);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
// Make the text bold
document.execCommand('bold',false,null);
}
}
</script>
</head>
<body onload="start();">
<span id='edit'>Click on the button</span>
<button id='button'>Bold It All!</button>
</body>
</html>
So, what am I doing wrong here? Have I just run into a bug? If so, can anyone suggest a work-around solution?

This is a bug. Consider filing it. In short:
The editor will attempt to wrap the <span> with a <b> (or another <span> when useCSS).
This would remove the <span>.
Therefore the code checks that the parent of the <span> is editable, which it isn't.
Boom!
Work-around: contenteditable="true" a real block element like <div>.

Related

Can't get document.execCommand("copy") to work as expected

I'm trying to scrape some data off a page and can't quite get document.execCommand("copy") to work as expected.
As a test, I am injecting some HTML into the page and then try to copy it to the clipboard
$('#topcard h1').append('<a id="getData" type="text">This is some data</a>')
I can then see This is some data on the page appear
Then:
var copyText = document.querySelector("#getData")
copyText
Shows in the console:
<a id=​"getData" type=​"text">​This is some data​</a>​
It seems that copyText is exactly what I want it to be.
However:
copyText.select()
returns
VM2319:1 Uncaught TypeError: copyText.select is not a function
at <anonymous>:1:10
What am I doing wrong?
.select() will let you set the selection range for an <input> or <textarea>:
document.getElementById("foo").select()
<input id="foo" value="12345">
...but will not work for other DOM nodes (including contentEditable nodes). To select anything other than a form field's contents, you need to use the Selection API:
var r = document.createRange();
r.selectNode(document.getElementById("foo"));
var s = window.getSelection();
s.addRange(r);
<div id="foo">12345</div>
In either case, once the selection is made you can then use document.execCommand("copy") to capture the selected text to the clipboard -- but with one very important caveat: this must be done within a user-initiated event handler. (This is to prevent malicious websites from hijacking the user's clipboard without their knowledge.)
var captureSelection = function() {
var r = document.createRange();
r.selectNode(document.getElementById("foo"));
var s = window.getSelection();
s.addRange(r);
document.execCommand("copy");
}
// this will select the DOM node, but will not copy it to
// the clipboard (because it's not user-initiated):
captureSelection();
// this _will_ copy it to the clipboard:
document.getElementById("bar").onclick = captureSelection;
<div id="foo">12345</div>
<button id="bar">Go</button>
<br><br>
<textarea placeholder="paste text here"></textarea>

HTML5 how to get selected text out of a textarea

I was able to get the highlighted text out of a textarea by recording onselect and storing the beginning and end each time. Then, when I click a button, I build the substring myself. Isn't there a simpler way of simply querying the selection?
I was kind of expecting that there would be methods in html5 dom for all these things, something like:
textarea.getSelectedStart()
textarea.getSelectedEnd();
textArea.setSelected(start,end);
Also, is there a way of programmatically deselecting text in a textarea?
I am putting in code based on the first solution below. This sort of works, but has a weird problem:
<script language=javascript>
function replaceCLOZE(code, questionType) {
var v = code.value;
var s = code.selectionStart;
var e = code.selectionEnd;
var t = v.substr(s, e-s);
var rep = "{:" + questionType + ":="+t+"}";
code.value = v.substr(0,s) + rep + v.substr(e,v.length-e+1);
}
function shortAnswer(code) {
replaceCLOZE(code, "SA");
}
function shortAnswerCaseSensitive(code) {
replaceCLOZE(code, "SAC");
}
function multipleChoice(code) {
replaceCLOZE(code, "MC");
}
The text area does in fact have attributes code.selectionStart and code.selectionEnd. But the code above, which now works, sets the highlighted text on the screen to be the first word in the textarea. Mind you, the selectionStart is still correct, but what is actually highlighted in Firefox is wrong.
In Chrome it works fine. Maybe this is just a bug in firefox or is there something else which should be done to properly update the textarea visually?
Following is simple way to get selected text of textarea of html. Still not clear what you want as following method simply will give you selected text in alert.
<html><head>
<script>
function alertme(){
var textarea = document.getElementById("textArea");
var selection = (textarea.value).substring(textarea.selectionStart,textarea.selectionEnd);
alert (selection);
}
</script>
</head>
<body>
<p><textarea class="noscrollbars" id="textArea"></textarea></p>
<button onclick="alertme()">Click me</button>
</body></html>
When you select text, the button will alert you what you have selected. selectionStart gives you starting point and selectionEnd gives you end point, while substring needs three arguments string, starting point and ending point.

How to select everything inside a span tag, including the span tag itself?

I have a contenteditable div, in which I have a span tag, which contains some text. How do I select the span tag and all of its contents, so when the user presses backspace or delete, the span and its contents get removed?
UPDATE: When I say select, I mean highlight. Sorry for the inconvenience.
UPDATE 2: I'm thinking along the lines of 'element.outerHTML.select()'. See if that helps.
In Firefox you have the Selection API which allows you to do that. Combine it with the DOM2 Range API and you have what you want:
var r = document.createRange();
r.selectNode(domElement);
var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);
The Selection API found its way in a future standard, HTML Editing APIs, but it will be a while until it becomes available in a majority of browsers.
yesterday I answered your other question. I revised the jsfiddle accompanying that answer, please recheck it. Use shift+delete from within an editable span to bring up a dialog and to 'select' the current span.
Try this:
var span = document.getElementById("myspan");
span.onclick = function() {
var range = document.createRange();
range.selectNodeContents(span);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
};​

Saving a selection for later use in JS

I've got a rich text editor in an iframe with designMode that does syntax highlighting for small blocks of text. I'd like it to update the highlighting on keyup, but messing with the DOM causes the frame to blur, thus every time you push a key the caret disappears and you can't type anymore. That wouldn't be a problem if the parser could remember where the caret is, and then refocus the iframe and replace the caret. I've read up on getSelection() and its relatives, but apparently onkeyup removes the selection, at least in Chrome - calling getSelection() inside an onkeyup always yields a null selection. Is there a way around this?
This is what I have:
<iframe>
<html>
<head>
<script>
function parse() {
if(window.getSelection().type != 'None') {
var range = window.getSelection().getRangeAt(0);
}
var text = document.body.textContent;
//Parse text, output is stored in newtext
document.body.innerHTML = newtext;
document.body.focus();
if(range) {
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
}
</script>
</head>
<body onload="document.designMode = 'on'; document.onkeyup = parse;">
Text entered appears here
</body>
</html>
</iframe>
I would recommend to use some other code highlighter. Like CodeMirror for example.
not sure if you're open to using a JS framework, but mootools has some pretty nifty selection utilities (e.g., http://mootools.net/docs/more/Element/Element.Forms#Element:getCaretPosition)

Greasemonkey\JavaScript Copy to Clipboard button

I am trying to write a JavaScript script to add to greasemonkey that adds a button after an element. The onClick for this button should copy the parents element text to the keyboard. I have seen plenty of examples that copy already selected text to the clipboard such as this:
<SCRIPT LANGUAGE="JavaScript">
<!-- Begin
function copyit(theField) {
var selectedText = document.selection;
if (selectedText.type == 'Text') {
var newRange = selectedText.createRange();
theField.focus();
theField.value = newRange.text;
} else {
alert('Alert: Select The text in the textarea then click on this button');
}
}
// End -->
</script>
<input onclick="copyit(this.form.text_select)" type="button" value="Click Here to Copy the Highlighted Text" name="copy_button">
Found here.
I have also found that you can select text in input elements. I have tried combining both techniques, as well as many others with no viable solution yet. I am not even sure why the code above copies to the clipboard. Does anyone have a solution to this?
If you took the time to read the full article, the author states this doesn't work for Firefox...
Actually, I think it doesn't even work for IE, as it does nothing related to the clipboard!
There is a technique using Flash, because by default, Firefox inhibits clipboard access for security reasons.
Otherwise, the classical way to do copy is:
var tc = textToCopy.replace(/\n\n/g, '\n');
if (window.clipboardData) // IE
{
window.clipboardData.setData("Text", tc);
}
else
{
unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const clipboardHelper = Components.classes
["#mozilla.org/widget/clipboardhelper;1"].
getService(Components.interfaces.nsIClipboardHelper);
clipboardHelper.copyString(tc);
}
after enabling copy (for a given site).
Are you sure your example works? It does not in my browser. But take a look at the following page: http://www.jeffothy.com/weblog/clipboard-copy/

Categories