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)
Related
I'm facing an issue with the combination of using appendChild() and Range.selectNode() in JavaScript.
When attempting to use a range to select the newly-appended <textarea> node, it selects too much of the DOM. Copying and pasting the selection seems to just contain a space.
However, if I put the <textarea> node into the DOM from the start (i.e. don't add it with appendChild()) then it works perfectly well and I can copy and paste the selected text as expected.
Note that the CSS isn't really necessary here, but it highlights the fact that the selection contains more than just the <textarea> (or at least it does in Chrome).
HTML:
<div>
<a class="hoverTrigger">Click to trigger textarea element with selected text</a>
</div>
CSS:
.floating {
position: absolute;
}
JavaScript/jQuery (run on DOM ready):
$(".hoverTrigger").click(createAndSelectStuff);
function createAndSelectStuff() {
var textArea = document.createElement("textarea");
textArea.className = "floating";
textArea.value = "Some dynamic text to select";
this.parentNode.appendChild(textArea);
selectObjectText(textArea);
return false;
}
function selectObjectText(container) {
var range = document.createRange();
range.selectNode(container);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
Here's a jsFiddle.
This is what the resulting selection looks like in Chrome:
How can I stop this happening, and just select the desired text?
Replace your call to selectObjectText with:
container.setSelectionRange(0, container.value.length);
The problem with textarea elements is that they do not hold their contents in DOM nodes. The text value is a property of the element. When you call range.selectNode, what happens is that the range is set so as to encompass the node you pass to the function and the children node of this node, but since a textarea does not store its text in children nodes, then you select only the textarea.
setSelectionRange works with the value of an input element so it does not suffer from this problem. You might want to check the compatibility matrix here to check which browsers support it.
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.
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>.
I have an editable DIV in my site to send a forum message. People can edit their messages (Bold, Italic, underline, add links and more)
But I want when some one paste or drop (- drop is not necessary, but paste it is) their text I want it to go in the DIV without HTML tags - clean, just text. (like if some one is going to word and make the text 200 points size, then copy & paste it in my DIV, they will have a very different message... and I don't want it to happen).
How can I scan the text coming from the clipboard to remove any HTML tags and then paste it in the DIV?
<html>
<head>
<script type="text/javascript" language="javascript">
function PasteFilter()
{
//windows.clipboardData filter on paste to go here
}
function CopyFilter()
{
//windows.clipboardData filter on copy to go here
}
</script>
</head>
<body>
<Div class="body" onpaste="PasteFilter()" oncopy="CopyFilter">
<!-- div content goes here.-->
</Div>
</body>
</html>
I would like to also apply the same filter with COPY too.
Thanks
I believe there are 2 ways to do this:
1) The easy way - insert the following code in PasteFilter():
var foo = window.clipboardData.getData('Text');
window.clipboardData.setData('Text', foo);
the first line gets the Text value of clipboardData (already stripped of HTML tags)
and the second line sets the clipboardData to the plain text...
(Tested on IE8)
2) The other way - if for some reason that isn't suitable for you..
In PasteFilter(), you trigger another function with a small delay timeout.
In that function, you get the innerHTML contents of the DIV and run a regular expression to remove all tags.
Example:
function PasteFilter()
{
setTimeout('foo()', 200);
}
function foo()
{
var contents = document.getElementById("test").innerHTML;
var new_contents = contents.replace(/(<([^>]+)>)/g, ""); // taken from http://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
document.getElementById("test").innerHTML = new_contents;
}
The problem with this method is that you lose the caret position...
Hope this helps...
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/