QtWebkit select text by itself after pressing space - javascript

I tried to google this question, but google don't know about this issue.
I'm using Qt 4.8.1 QtWebkit 2.2.3+Javascript for implement some kind of Html-Editor.
It is hard to explain the problem by text so I maid some screenshots (link in the end of message).
1) So at first I insert just normal text.
2) After I add one more word, and wrap it in tag using this javascript function
function misspelledWord(id)
{
var sel = rangy.getSelection();
var highlightDiv = document.createElement('span');
highlightDiv.className = "misspelled";
highlightDiv.id = "misspelled_" + id;
range.surroundContents( highlightDiv );
var space = document.createTextNode("\xa0");
highlightDiv.parentNode.insertBefore(space, highlightDiv.nextSibling);
range.setStartAfter(space);
range.setEndAfter(space);
sel.removeAllRanges();
sel.setSingleRange(range);
}
3) After I press space one more time. Webkit select all text till "span" by itself and I can not delete this selection, only if select it by hand one more time.
http://i.stack.imgur.com/PprG0.png - screenshots
So maybe somebody know how to fix this behavior?
Best regards
Paul

Related

iFrame WYSIWYG font size won't reset

Here's my jsFiddle: https://jsfiddle.net/wsounka3/
When I change the font size within the WYSIWYG and then delete all of the written text and begin writing again it retains the last font size instead of starting fresh again.
How can I make the iframe "forget" the last font size?
Code:
function iwrap(elem,iwin,idoc){
var element = idoc.createElement(elem);
var sel = iwin.getSelection();
if(sel.rangeCount){
var range = sel.getRangeAt(0).cloneRange();
range.surroundContents(element);
sel.removeAllRanges();
sel.addRange(range);
}
}
$('#smaller').click(function(){
iwrap('small',iwin,idoc);
update_code();
});
$('#larger').click(function(){
iwrap('big',iwin,idoc);
update_code();
});
Side question: I find it strange that by encasing the text in <big> and <small> tags, it decides to translate that into pixels. Can anyone explain why it does this?
Because when you click delete you are deleting the textual content and not the wrapping tag. You can clear the markup when there is no textual content - plus there is a Chrome bug that retains the last element size, so wrapping in a [span] tag prior to removing seams to fix that
Since you call update_code on keyup, simply add a cleanup check there
function update_code(){
var $body = $(idoc).contents().find('body');
if ($.trim($body.text()).length == 0) {
iwrap('span', iwin, idoc); // chrome bug
$body.empty();
}
var icontent = $body.html();
$('div#code').html(icontent);
}
BIG/SMALL to SPAN:size also appears to be an automatic chrome thing

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.

Move selection after a DOM element

I'm currently building a Markdown editor for the web. Markdown tags are previewed in realtime by appending their HTML equivalents via the Range interface. Following code is used, which should be working according to MDN:
var range = document.createRange()
var selection = window.getSelection()
range.setStart(textNode, start)
range.setEnd(textNode, end + 2)
surroundingElement = document.createElement('strong')
range.surroundContents(surroundingElement)
var cursorRange = document.createRange()
cursorRange.setStartAfter(surroundingElement)
selection.removeAllRanges()
selection.addRange(cursorRange)
Firefox works: Some bold text
Chrome not: Some bold text
Any suggestions what could be wrong? Information on this subject are rare.
Answer
Thanks to #Tim Down, I fixed it using the invisible character workaround he describes in one of the links mentioned in his answer. This is the code I'm using now:
var range = document.createRange()
range.setStart(textNode, start)
range.setEnd(textNode, end + 2)
surroundingElement = document.createElement('strong')
range.surroundContents(surroundingElement)
var selection = window.getSelection()
var cursorRange = document.createRange()
var emptyElement = document.createTextNode('\u200B')
element[0].appendChild(emptyElement)
cursorRange.setStartAfter(emptyElement)
selection.removeAllRanges()
selection.addRange(cursorRange)
The problem is that WebKit has fixed ideas about where the caret (or a selection boundary) can go and is selecting an amended version of your range when you call the selection's addRange() method. I've written about this a few times on Stack Overflow; here are a couple of examples:
Set cursor after span element inside contenteditable div
How to set caret/cursor position in a contenteditable div between two divs.

how to get selected text, but can I get surrounding context in javascript?

I am able to grab the text that a user has selected on a web page,
using this code:
function getSelected() {
var userSelection;
if (window.getSelection) {
selection = window.getSelection();
} else if (document.selection) {
selection = document.selection.createRange();
}
}
is it posible for me to get the words around the
selected word.
Take these sentences for example: "If you need to
framglubble the zartbox, then you should buy the red widget.
Otherwise you can buy the blue widget and save some money."
My code will tell me if the person has selected the word "widget".
But I'd like to know if the selection is after "red" or "blue". Is
this possible? I've been scouring the Internet for some advice, and
I'm having trouble finding an answer.
thank you for your help
I have written quick script that can identify the part before selection and after selection inside the same DIV element.
However if the same DIV contains the same word more than one time and you select only that word, the current code I wrote can't identify if it's the first or second selected word so bottom line it will not answer your needs.
Anyway, you can see/copy/test the code here: http://jsfiddle.net/kvHxJ/ just select something and see the alert that appears.
If it's enough for your needs after all then great, accept this answer and move on... otherwise I need to know: can we assume the user will select whole words only, one word only? If the answer is yes I do have idea how to go around this.
The way to do this in non-IE browsers is to obtain a Range object from the selection. The range has a start and end boundary, and each boundary of the range is expressed as an offset within a node; if the boundary is within a text node, this offset will be a character offset.
For example, if the following was a text node and the selection is delimited by pipes:
"red |widget| blue widget"
... then the range you'd get from the selection would have a start offset of 4 within the text node.
The following will get you a Range representing the selection and alert the start boundary:
var sel = window.getSelection();
var selectedRange = sel.rangeCount ? sel.getRangeAt(0) : null;
if (range) {
alert("Offset " + selectedRange.startOffset
+ " in node " + selectedRange.startContainer.nodeName);
}
Ranges may be compared to other Ranges, so if you wanted to know, for example, if the current selection came after the word "blue" in the above text node, you could create a Range encompassing the word "blue" and compare it with the selected Range:
// Assume the text node is stored in a variable called textNode
var blueRange = document.createRange();
blueRange.setStart(textNode, 11);
blueRange.setEnd(textNode, 15);
var selectionIsAfterBlue =
(selectedRange.compareBoundaryPoints(Range.END_TO_START, blueRange) == 1);
In IE, none of this works and everything is done differently, generally with much more difficulty. To normalize this to single consistent interface, you could use my Rangy library.
IE has the move set of methods, which reduces this problem to just a couple of lines to expand the selection forward or backward any number of words (see http://www.webreference.com/js/column12/trmethods.html). From there, it's just a matter of comparing text against any arbitrary list of values. Other browsers don't have this feature AFAIK. Fate of the browser wars: one develops an awesome feature ignored or barred by patent from any other, so the feature is forever lost and avoided as burden of cross-browser support for all these innovations inevitably falls squarely on the website designers.
So, below is a generalized function to only get the ID of the parent element of the selected text. And, to work with this cross-browser solution, you have to wrap each word in it's own element complete with unique ID or other attribute. With this setup, it should then be a relatively painless jump to looking ahead and back at sibling or sequentially ID'd/named elements.
The catch here is that the client has to click/drag from the start of the word or phrase to the end, and absolutely no bordering spaces. Even double-clicking on a word will cause it to reference the next element (or in the case of IE, the parent DIV). Additionally, you should add code to restrict the selection boundary to a single parent DIV, as the below code may also expand the selection to surrounding elements. But hopefully you can take fixing that up from here. Otherwise, it's up to using vectors to pinpoint the coordinates of a text compared to all surrounding text.
<script type="text/javascript">
function get_selected_element_id() {
if (window.getSelection) {
// FF
var range = window.getSelection();
}
else if (document.selection) {
// IE
var range = document.selection.createRange();
}
if (range.focusNode) {
// FF
var test_value = range.focusNode.parentNode.id;
}
else {
// IE
var test_value = range.parentElement().id;
}
return test_value;
}
</script>
</head>
<body>
<div id="test_div">
<span id="test1">test</span> <span id="test2">asdf</span> <span id="test3">test2</span> <span id="test4">bla</span>
</div>
<button onclick="alert(get_selected_element_id());">go</button>

How do I select arbitrary text on the page using javascript?

Let's say I have a contentEditable div, to the user can edit and change the text and elements inside it. How do I arbitrarily change the selection in this div with javascript? By "change" I don't mean "change the contents of whatever the user has selected", I mean actually change what is selected. The user should then be able to type over the selection, replacing it with something else.
This should take into account that I may want to select text across elements. For instance:
<p>Some text <span>goes</span> here.</p>
I may for instance want to select "Some text go", or everything inside the <p>.
This only needs to work in Safari/Webkit.
Thanks in advance. As a native code developer, I find the DOM and Javascript in general quite frustrating.
Just to answer my own question in detail so anyone searching for something similar doesn't have to go looking elsewhere...
The code I ended up using was something like this:
var range = document.createRange();
range.setStart( <get the node the selection starts in>, <char offset in that node> );
range.setEnd( <get the node the selection ends in>, <char offset in that node> );
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
Big thanks to James Black for pointing me in the right direction.
Unless you need to write your own, you may want to look at tinyMCE, http://tinymce.moxiecode.com/, as it is a nice WYSIWYG editor in javascript.
In order to do this you will probably want to look at something like this:
http://codingtricks.blogspot.com/2009/03/javascript-select-partial-text-in-div.html
These may also be helpful:
JavaScript ranging gone wrong
https://developer.mozilla.org/en/DOM/window.getSelection
What you are trying to do will be complex, as you will need to take the selected area, remove all the tags, then put in the tag that you want for the selected area.
You can use document.getElementById('your_text_id').setSelectionRange(start, end); and you can use Math.random() to generate random numbers for start and end
While #Lucas's answer is good, there is a lot missing that would allow you to successfully use this. The node the selection starts in has to be the exact node, not a parent. In our case we were trying to put some text into a TextAngular control, then select text that looked liked ____ so the user could "fill in the blank".
Our input was html of the order <p>Some text goes here: _____</p> or
<p>Some partial goes here
<ul>
<li>Option 1</li>
<li>_____</li>
</ul>
To get this to work, we had to write something to find the underscores in the right element
function find_(node) {
var i, n;
// return the node with the _'s
for(i=0; i < node.childNodes.length; ++i) {
n = node.childNodes[i];
console.debug(n);
if(n.textContent) {
console.debug(n, n.textContent);
if(n.textContent.search(/___+/) > 0) {
return n;
}
}
if(n.childNodes) {
console.debug(n, n.childNodes);
n = find_(n);
if(n) {
return n;
}
}
}
return null;
}
So in the end, finding the node to satisfy <get the node the selection starts in> was a lot more work than that simple sentence led me to believe.
In the <ul> case. the node that contains the ____ is firstChild of the li node.
I've put this here to help others that need to do this not wonder why they are getting the error message
IndexSizeError: Failed to execute 'setStart' on 'Range': There is no child at offset 65.
When the problem is they are just looking at the wrong node.

Categories