I'm making a text-searching mechanism (like ⌘ + F) for an iOS app and It's working but I have two issues.
Whenever someone searches something in Arabic, the word becomes disconnected.
Users can't search if there are diacritics in the text but their search does not (so basically I'm trying to make it diacritic-insensitive)
Here's the code for my highlighting (which I found from this):
var uiWebview_SearchResultCount = 0;
/*!
#method uiWebview_HighlightAllOccurencesOfStringForElement
#abstract // helper function, recursively searches in elements and their child nodes
#discussion // helper function, recursively searches in elements and their child nodes
element - HTML elements
keyword - string to search
*/
function uiWebview_HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
var count = 0;
var elementTmp = element;
while (true) {
var value = elementTmp.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx < 0) break;
count++;
elementTmp = document.createTextNode(value.substr(idx+keyword.length));
}
uiWebview_SearchResultCount += count;
var index = uiWebview_SearchResultCount;
while (true) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx < 0) break; // not found, abort
//we create a SPAN element for every parts of matched keywords
var span = document.createElement("span");
var text = document.createTextNode(value.substr(idx,keyword.length));
var spacetxt = document.createTextNode("\u200D");//\u200D
span.appendChild(text);
span.appendChild(spacetxt);
span.setAttribute("class","uiWebviewHighlight");
span.style.backgroundColor="#007DC8a3";
span.style.borderRadius="3px";
index--;
span.setAttribute("id", "SEARCH WORD"+(index));
//span.setAttribute("id", "SEARCH WORD"+uiWebview_SearchResultCount);
//element.parentNode.setAttribute("id", "SEARCH WORD"+uiWebview_SearchResultCount);
//uiWebview_SearchResultCount++; // update the counter
text = document.createTextNode(value.substr(idx+keyword.length));
element.deleteData(idx, value.length - idx);
var next = element.nextSibling;
//alert(element.parentNode);
element.parentNode.insertBefore(span, next);
element.parentNode.insertBefore(text, next);
element = text;
}
} else if (element.nodeType == 1) { // Element node
if (element.style.display != "none" && element.nodeName.toLowerCase() != 'select') {
for (var i=element.childNodes.length-1; i>=0; i--) {
uiWebview_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function uiWebview_HighlightAllOccurencesOfString(keyword) {
uiWebview_RemoveAllHighlights();
uiWebview_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
// helper function, recursively removes the highlights in elements and their childs
function uiWebview_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute("class") == "uiWebviewHighlight") {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i--) {
if (uiWebview_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function uiWebview_RemoveAllHighlights() {
uiWebview_SearchResultCount = 0;
uiWebview_RemoveAllHighlightsForElement(document.body);
}
function uiWebview_ScrollTo(idx) {
var idkNum = uiWebview_SearchResultCount - idx
var scrollTo = document.getElementById("SEARCH WORD" + idkNum);
if (scrollTo) scrollTo.scrollIntoView();
}
and I also found this that actually does exactly what I want (does not disconnect words and is diacritic-insensitive) but it's in JQuery and I couldn't figure out how to implement it in my code.
Instead of using indexOf, you can convert the string to an NSString and then use range(of:options:):
var range = value.range(of: keyword, options: [.caseInsensitive, .diacriticInsensitive])
Related
My goal:
Let users highlight different substring in a single long string.
However, once I've highlighted one substring with range.surroundContents(newNode) (newNode is a span with yellow background), the innerHTML of the whole long string changed-- it started to contain the span element; consequently, if the user wants to highlight a substring after the previous highlighted substring in the same long string, the anchorOffset will return the index starting after the previous span.
For example, in this long string:
"Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much."
this long sentence is wrapped by a p whose class name is noting. If the range.surroundContents() method the substring "Privet Drive", then, when I want to get the window.getSelection().anchorOffset of the substring "thank", the answer wrongly is 53 while the correct answer should be 102.
How should I do? Thank you!!
P.S. I don't want to use substring method to find the position, thank you!
$(".noting").mouseup(function(e){
$("#noteContent").val("");/*flushing*/
curSentNum = $(this).attr("id").split("-")[1];
$('#curSentNum').val(curSentNum);
highlightLangName = $(this).attr("id").split("-")[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
}
else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
And then I'll save the anchorAt information to db; after the db operation, I'll immediately call this function using the previous variables remained:
function highlightNoteJustSaved(){
var curI = noteCounter;
var anchorAt = parseInt($("#anchorAt").val());
var highlightLen = parseInt($("#highlightLen").val());
/*p to find, for example: p-2-French*/
var curP = document.getElementById('p-'+curSentNum.toString()+"-"+$("#highlightLangName").val());
var range = document.createRange();
root_node = curP;
range.setStart(root_node.childNodes[0], anchorAt);
range.setEnd(root_node.childNodes[0], anchorAt+highlightLen);
var newNode = document.createElement("span");
newNode.style.cssText="background-color:#ceff99";//yellow
newNode.className = alreadyNoteStr;
newNode.setAttribute('id','already-note-'+curI.toString());
range.surroundContents(newNode);
}
for HTML tree node structure, please take a look at the comment below( I didn't figure out how to copy-paste the code at this asking area).
I replaced your method to highlight text with 2 methods. highlightTextNodes finds the word in the content of the node. Searching each child. Also I implemented a highlight remover to show how it works. I replaced the span with a mark tag.
let alreadyNoteStr = 'already';
let noteCounter = 0;
let elementId;
$('p.noting').mouseup(function(e) {
elementId = $(this).attr('id');
$('#noteContent').val(''); /*flushing*/
curSentNum = elementId.split('-')[1];
$('#curSentNum').val(curSentNum);
highlightLangName = elementId.split('-')[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$("#noteContent").val(highlightedText);
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
highlight(elementId, highlightedText);
} else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
function highlightNoteJustSaved() {
let curI = noteCounter;
let anchorAt = parseInt($("#anchorAt").val());
let highlightLen = parseInt($("#highlightLen").val());
/*p to find, for example: p-2-French*/
let curP = document.getElementById('p-' + curSentNum.toString() + "-" + $("#highlightLangName").val());
let range = document.createRange();
rootNode = curP;
let childNode = rootNode.childNodes[0];
range.setStart(rootNode.childNodes[0], anchorAt);
range.setEnd(rootNode.childNodes[0], anchorAt + highlightLen);
var newNode = document.createElement("span");
newNode.style.cssText = "background-color:#ceff99"; //yellow
newNode.className = alreadyNoteStr;
newNode.setAttribute('id', 'already-note-' + curI.toString());
range.surroundContents(newNode);
}
/*
* Takes in an array of consecutive TextNodes and returns a document fragment with `word` highlighted
*/
function highlightTextNodes(nodes, word) {
if (!nodes.length) {
return;
}
let text = '';
// Concatenate the consecutive nodes to get the actual text
for (var i = 0; i < nodes.length; i++) {
text += nodes[i].textContent;
}
let fragment = document.createDocumentFragment();
while (true) {
// Tweak this if you want to change the highlighting behavior
var index = text.toLowerCase().indexOf(word.toLowerCase());
if (index === -1) {
break;
}
// Split the text into [before, match, after]
var before = text.slice(0, index);
var match = text.slice(index, index + word.length);
text = text.slice(index + word.length);
// Create the <mark>
let mark = document.createElement('mark');
mark.className = 'found';
mark.appendChild(document.createTextNode(match));
// Append it to the fragment
fragment.appendChild(document.createTextNode(before));
fragment.appendChild(mark);
}
// If we have leftover text, just append it to the end
if (text.length) {
fragment.appendChild(document.createTextNode(text));
}
// Replace the nodes with the fragment
nodes[0].parentNode.insertBefore(fragment, nodes[0]);
for (var i = 0; i < nodes.length; i++) {
let node = nodes[nodes.length - i - 1];
node.parentNode.removeChild(node);
}
}
/*
* Highlights all instances of `word` in `$node` and its children
*/
function highlight(id, word) {
let node = document.getElementById(id);
let children = node.childNodes;
let currentRun = [];
for (var i = 0; i < children.length; i++) {
let child = children[i];
if (child.nodeType === Node.TEXT_NODE) {
// Keep track of consecutive text nodes
currentRun.push(child);
} else {
// If we hit a regular element, highlight what we have and start over
highlightTextNodes(currentRun, word);
currentRun = [];
// Ignore text inside of our <mark>s
if (child.nodeType === Node.ELEMENT_NODE && child.className !== 'found') {
highlight(child, word);
}
}
}
// Just in case we have only text nodes as children
if (currentRun.length) {
highlightTextNodes(currentRun, word);
}
}
/*
* Removes all highlighted <mark>s from the given node
*/
function unhighlight(id) {
let node = document.getElementById(id);
let marks = [].slice.call(node.querySelectorAll('mark.found'));
for (var i = 0; i < marks.length; i++) {
let mark = marks[i];
// Replace each <mark> with just a text node of its contents
mark.parentNode.replaceChild(document.createTextNode(mark.childNodes[0].textContent), mark);
}
}
label {
display: block;
position: relative;
padding-left: 100px;
}
button {
margin-top: 20px;
margin-bottom: 20px;
padding: 10px;
}
label>span {
position: absolute;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" onclick="unhighlight(elementId);">Unhighlight</button>
<div id="div-0" class="only-left-border">
<p class="lan-English noting" id="p-1-English">Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much.</p>
</div>
<label><span>Content:</span><input type="text" id="noteContent"></input></label>
<label><span>Numer:</span><input type="text" id="curSentNum"></input></label>
<label><span>Language:</span><input type="text" id="highlightLangName"></input></label>
<label><span>Anchor:</span><input type="text" id="anchorAt"></input></label>
<label><span>Length:</span><input type="text" id="highlightLen"></input></label>
I am working on a xamarin.ios application to show the content in a text file into webview. I could able to display the content.
Now I need to add search feature, so that the selected string needs to highlighted and SCROLL need to position in to the search text. I am using below Javascript to highlight the searched text and highlighting is working as expected.
string startSearch = "MyApp_HighlightAllOccurencesOfString('" + searchStr + "')";
this.webView.EvaluateJavascript (startSearch);
How can I move the scroll position to the searched string using this webview?
Thanks in advance
Roshil K
You can use the code snippet to reset the scroll position of the WebView, like this:
webView.ScrollView.ContentOffset = new CGPoint(0,50);
But you have to know the (x,y) point of the related string. I am not familiar with Javascript, maybe it can be returned by your JS code.
Also, I found a solution via JS which maybe help you here:https://stackoverflow.com/a/38317775/5474400.
I got is solved by adding the below javascript to my existing "MyApp_HighlightAllOccurencesOfString" javascript.
var desiredHeight = span.offsetTop - 140;
window.scrollTo(0,desiredHeight);
My Complete Javascript is below.
this.webView.EvaluateJavascript ("// We're using a global variable to store the
number of occurrences
var MyApp_SearchResultCount = 0;
// helper function, recursively searches in elements and their child nodes
function MyApp_HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
while (true) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx < 0) break; // not found, abort
var span = document.createElement(\"span\");
var text = document.createTextNode(value.substr(idx,keyword.length));
span.appendChild(text);
span.setAttribute(\"class\",\"MyAppHighlight\");
span.style.backgroundColor=\"yellow\";
span.style.color=\"black\";
text = document.createTextNode(value.substr(idx+keyword.length));
element.deleteData(idx, value.length - idx);
var next = element.nextSibling;
element.parentNode.insertBefore(span, next);
element.parentNode.insertBefore(text, next);
element = text;
var desiredHeight = span.offsetTop - 140;
window.scrollTo(0,desiredHeight); MyApp_SearchResultCount++;\t// update the counter
}
} else if (element.nodeType == 1) { // Element node
if (element.style.display != \"none\" && element.nodeName.toLowerCase() != 'select') {
for (var i=element.childNodes.length-1; i>=0; i--) {
MyApp_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function MyApp_HighlightAllOccurencesOfString(keyword) {
MyApp_RemoveAllHighlights();
MyApp_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
// helper function, recursively removes the highlights in elements and their childs
function MyApp_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute(\"class\") == \"MyAppHighlight\") {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i--) {
if (MyApp_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function MyApp_RemoveAllHighlights() {
MyApp_SearchResultCount = 0;
MyApp_RemoveAllHighlightsForElement(document.body);
}");
I have a JS function which searches for a string in the HTML source, and outputs the parent node:
function searchHTML(searchTerm) {
queue = [document.body],
curr
;
while (curr = queue.pop()) {
if (!curr.textContent.match(searchTerm)) continue;
for (var i = 0; i < curr.childNodes.length; ++i) {
switch (curr.childNodes[i].nodeType) {
case Node.TEXT_NODE : // 3
if (curr.childNodes[i].textContent.match(searchTerm)) {
console.log(curr);
// End of search
}
break;
case Node.ELEMENT_NODE : // 1
queue.push(curr.childNodes[i]);
break;
}
}
}
}
Currently, its output (in Javascript console) is not a string.
I need to perform regex on the output (curr), so I need it to be a string.
What I have tried:
curr = curr.toString()
curr = curr.replace(/[0-9]/g, "")
You can use .text() jQuery function to get the string from an HTML.
Here is an example of how you get string :
text= curr.text();
curr = text.replace(/[0-9]/g, "");
It seems to me you need to find the commonAncestorContainer for the term searched. That means if the term starts in a node and ends in another, you don't really have a clear definition of the common parent, until you get the a range.
I put together the function below where you can call search('My Term') and it should get a commonAncestorContainer. Some tweek should still be needed to search the same term more than once and to make sure that words ending inside an element still consider that element as the parent instead of the next one after the parent.
var search = function (searchTerm) {
// Stop if there is nothing to look for
if (!searchTerm || typeof searchTerm !== 'string')
return null;
searchTerm = searchTerm.toLowerCase();
var bodyText = document.body.textContent.toLowerCase(),
range = document.createRange(),
startOffset = bodyText.indexOf(searchTerm),
endOffset = startOffset + searchTerm.length,
iterationObject = {
index: 0,
length: bodyText.length,
startOffset: startOffset,
endOffset: endOffset,
startInNodeOffset: -1,
endInNodeOffset: -1,
startNode: null,
endNode: null
};
var textContent = function (textNode) {
return textNode.nodeValue || textNode.textContent || textNode.wholeText;
};
(function iterate (node, iterationObject) {
if (node.nodeType === 1) {
var childNodes = node.childNodes;
// Keep iterating but we should try to stop it when nodes are found
for (var i = 0, iLen = childNodes.length; i < iLen; i++)
iterate(childNodes[i], iterationObject);
} else if (node.nodeType === 3) {
var text = textContent(node),
startInNodeOffset,
endInNodeOffset;
// Change index and move on
if (iterationObject.index + text.length < iterationObject.startOffset)
iterationObject.index += text.length;
else if (iterationObject.startNode === null) {
startInNodeOffset = iterationObject.startOffset - iterationObject.index;
// Start range in the current node
// This condition should really only be needed to decide if the selection should start
// before or after this node. But that is another story.
if (startInNodeOffset <= text.length) {
iterationObject.startNode = node;
iterationObject.startInNodeOffset = startInNodeOffset;
}
iterationObject.index += text.length;
} else {
// Now try to find the endNode
if (iterationObject.index + text.length < iterationObject.endOffset)
iterationObject.index += text.length;
else if (iterationObject.endNode === null) {
endInNodeOffset = iterationObject.endOffset - iterationObject.index;
if (endInNodeOffset <= text.length) {
iterationObject.endNode = node;
iterationObject.endInNodeOffset = endInNodeOffset;
}
}
}
}
if (iterationObject.startNode !== null && iterationObject.endNode !== null)
return;
})(document.body, iterationObject);
if (iterationObject.startInNodeOffset > -1 && iterationObject.endInNodeOffset > -1) {
range.setStart(iterationObject.startNode, iterationObject.startInNodeOffset);
range.setEnd(iterationObject.endNode, iterationObject.endInNodeOffset);
return range.commonAncestorContainer;
}
return null;
};
If you are using jQuery, you can try outerHTML to get the string from the commonAncestorContainer.
var parentElement = search('Whatever'),
result = '';
if (parentElement !== null)
result = $(parentElement).outerHTML();
You can create a temporary DOM node, and then append curr to it. Then get the innerHTML and the result will be a string:
var tempNode = document.createElement("div");
tempNode.appendChild(curr);
console.log(temp.innerHTML);
Working example here:
http://codepen.io/anon/pen/QypxwM
I'm building an interface that consists of 9 cells in table. When a person mouses over a cell, I want other cells to become visible, and change the text content of some of the cells. I can do that just fine if I create individual functions to change the content of each cell, but that's crazy.
I want a single function to change the text depending on the cells involved. I created a function that can take n arguments, and loops through making changes based on the arguments passed in to the function. It doesn't work.
Code for the function is below. If I call it, onMouseOver="changebox('div3')", the argument makes it to the function when I mouse over the cell. If I uncomment the document.write(cell) statement, in this instance, it prints div3 to the screen. So... why isn't it making any changes to the content of the div3 cell?
function changebox() {
for (var i = 0; i < arguments.length; i++) {
var cell = document.getElementById(arguments[i]).id;
var text = "";
if (cell == 'div3') {
text = "Reduced Travel";
} else if (cell == 'div4') {
text = "Reduced Cost";
}
//document.write(cell)
cell.innerHTML = text;
}
}
In your code cell is a string which holds the id of the object. Update the code as follows
function changebox() {
for (var i = 0; i < arguments.length; i++) {
var cell = document.getElementById(arguments[i]),
text = "";
if (cell.id == 'div3') {
text = "Reduced Travel";
} else if (cell.id == 'div4') {
text = "Reduced Cost";
}
//document.write(cell)
cell.innerHTML = text;
}
}
UPDATE :
You can reduce the code as #Tushar suggested.
No need of iterating over arguments(assuming there are only two elements, but can be modified for more elements).
function changebox() {
// As arguments is not real array, need to use call
// Check if div is present in the arguments array
var div3Index = [].indexOf.call(arguments, 'div3') > -1,
div4Index = [].indexOf.call(arguments, 'div4') > -1;
// If present then update the innerHTML of it accordingly
if (div3Index) {
document.getElementById('div3').innerHTML = 'Reduced Travel';
} else if (div4Index) {
document.getElementById('div4').innerHTML = 'Reduced Cost';
}
}
function changebox() {
var args = [].slice.call(arguments);
args.map(document.getElementById.bind(document)).forEach(setElement);
}
function setElement(ele) {
if (ele.id === 'div3') {
ele.innerHTML = "Reduced Travel";
} else if (ele.id === 'div4') {
ele.innerHTML = "Reduced Cost";
}
}
this make your function easy to be tested
As your assigning the cell variable the id of the element and changing the innerHTML of cell which is not valid .
var changeText = function() {
console.log("in change text");
for(var i= 0; i<arguments.length; i++) {
var elem = document.getElementById(arguments[i]);
var cell = document.getElementById(arguments[i]).id;
var text = "";
console.log(cell)
if (cell === "div-1") {
text = cell+" was selected!!";
} else if(cell === "div-3") {
text = cell+" was selected!!";
} else {
text = cell+" was selected";
}
elem.innerHTML = text;
}
}
This would properly change the text of div mouseovered!!
I am just wondering if there is a simple solution already to the problem of turning selected content in tinymce to upperCase letters.
Anyone got a solution?
PS: The upperCase-function is known, but won't solve the tinymce setting of selected content alone.
This is what i came up with after some fiddling
// check if a node intersects the given range
rangeIntersectsNode: function (range, node) {
var nodeRange;
if (range.intersectsNode) {
return range.intersectsNode(node);
}
else {
nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
} catch (e) {
nodeRange.selectNodeContents(node);
}
return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
}
},
// Tinymce-Shortcut: (cmd/ctrl + shift +a)
if ( ( (mac && evt.metaKey)|| (!mac && evt.ctrlKey)) && evt.shiftKey && evt.keyCode == 65 ){
if (!ed.selection.isCollapsed()) {
var selection = ed.getWin().getSelection(); // user selection
var range = selection.getRangeAt(0); // erste range
var start = range.startContainer;
var start_offset = range.startOffset;
var end = range.endContainer;
var end_offset = range.endOffset;
// Get all textnodes of the common ancestor
// Check foreach of those textnodes if they are inside the selection
// StartContainer and EndContainer may be partially inside the selection (if textnodes)
// concatenate those textnode parts and make toUppercase the selected part only
// all textnodes inbetween need to become upperCased (the nodeContents)
// Selection needs to be reset afterwards.
var textnodes = t.getTextNodes(range.commonAncestorContainer);
for (var i=0; i<textnodes.length; i++) {
if (t.rangeIntersectsNode(range, textnodes[i])){
if (textnodes[i] == start && textnodes[i] == end) {
var text_content = start.textContent;
text_content = start.textContent.substring(0, start_offset) + text_content.substring(start_offset, end_offset).toUpperCase() + end.textContent.substring(end_offset);
textnodes[i].nodeValue = text_content;
}
else if (textnodes[i] == start){
var text_content = start.textContent.substring(0, start_offset) + start.textContent.substring(start_offset).toUpperCase();
textnodes[i].nodeValue = text_content;
}
else if (textnodes[i] == end){
var text_content = end.textContent.substring(0, end_offset).toUpperCase() + end.textContent.substring(end_offset);
textnodes[i].nodeValue = text_content;
}
else {
// Textnodes between Start- and Endcontainer
textnodes[i].nodeValue = textnodes[i].nodeValue.toUpperCase();
}
}
}
// reset selection
var r = ed.selection.dom.createRng();
r.setStart(start, start_offset);
r.setEnd(end, end_offset);
ed.selection.setRng(r);
evt.preventDefault();
return false;
}
}