Tenho feito meus estudos em javaScript e hoje gostaria de apresentar o resultado de um código estruturado (não OO) em javaScript: Um HTMLEDitor.
Eu ví um exemplo de como se navegar entre os DOMs e reimplementei os metodos getTextNodesIn e setSelectionRange. Fonte original:http://stackoverflow.com/questions/6240139/highlight-text-range-using-javascript
Dicas:
1) Pra pegar a seleção do range, é necessário 4 coisas:
o nó onde começa a seleção: startContainer
a posição dentro do nó ende começa a seleção: startOffset
o nó onde termina a seleção: endContainer
e a posição dentro do no onde termina a seleção.: endOffset
2) Prorpiedades da Div
contentEditable = true
Isso determina que a DIV pode ser edivavel.
style.whiteSpace = "pre";
Isso determina que a DIV trabalhe com espaços e enteres no formato "\n" ao invez de "<BR>"
3) o metodo mais complicado é setProperty.
Notem que ele é um método recursivo e seu pseudo código é esse:
setProperty = function (div, node, atributo, valor)
{
verificar se é a primeira chamada do metodo
se for, cria um marcador para sabermos
se foi encontrado os nos iniciais e finais
e pega o range que armazena os dados da
seleção
se não existir seleção, apesar do cursor estar na div
retorna a mesma coisa. OU seja, não vai ser feito
nenhuma alteração.
Verifica se o nó é um textNode.
{
se for, é necessario saber que:
os nós possiveis serão de 5 tipos:
no sem nenhuma seleção (parte inicial e sem seleção de todo o texto)
no com seleção parcial, onde o final é o selecionado
no com seleção total (todo o nó)
no com seleção parcial, onde o inicio é o selecionado
no sem nenhuma seleção (parte final e sem seleção de todo o texto)
A primeira condição é a mais fácil
se o no é igual ao inicial e ao final do range
{
marca que encontrou o no inicial e final
existe a possibilidade desse texto ser dividida em 3 partes:
texto inicial, que não tem seleção
texto da seleção
texto final, sem seleção nenhuma.
}
se não, se o nó é igual ao inicial do range
{
marca que encontrou o no inicial
existe a possibilidade desse texto ser dividida em 2 partes:
texto inicial, que não tem seleção
texto da seleção
}
se não, se o nó é igual ao final do range
{
marca que encontrou o no final
existe a possibilidade desse texto ser dividida em 2 partes:
texto da seleção
texto final, que não tem seleção
}
aqui, é o tratamento para os nos que não fazem parte do range.
nossos marcadores serão analizados aqui.
os que vem antes e depois da seleção não precisam ser alterados
já o que está no meio da seleção, irá receber as novas propriedades
antes da seleção : não achou inicio da seleção
no meio da seleção : achou inicio mas não achou o fim da seleção.
recebetratamento.
ou depois da seleção: achou inicio e fim da seleção
}
se não for
{
realiza a recursividade nos nós filhos
}
}
Esboço:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <script type="text/javascript"> Selector = function() { if (window.getSelection) { return window.getSelection(); } else if (document.getSelection) { return document.getSelection(); } } createRange = function (cell) { var rng=null; if(cell.createRange) { rng=cell.createRange(); } else if(cell.getRangeAt) { rng=cell.getRangeAt(0); if(rng.toString()=="") rng=null; } return rng; } getTextNodesIn = function (node) { var textNodes = []; if (node!=undefined && node.nodeType !=undefined && node.nodeType == Node.TEXT_NODE ) { textNodes.push(node); } else { var children = node.childNodes; for (var i = 0, len = children.length; i < len; ++i) { textNodes = textNodes.concat( getTextNodesIn(children[i]) ); } } return textNodes; } getCursorPosition = function (div) { var se = Selector (); var range = se.getRangeAt(0); textNodes = getTextNodesIn(div); countChar=0; for (var i = 0; i<textNodes.length; i++ ) { if ( range.startContainer==textNodes[i] ) { return countChar+range.startOffset } countChar += textNodes[i].textContent.length } return null; } getStartContainer = function (div) { var se = Selector (); var range = se.getRangeAt(0); textNodes = getTextNodesIn(div); return range.startContainer; } getSelectionPosition = function (div) { var se = Selector (); var range = se.getRangeAt(0); textNodes = getTextNodesIn(div); endCharCount = 0; Int=null end=null for (var i = 0; i<textNodes.length; i++ ) { if ( range.startContainer==textNodes[i] ) { Int = endCharCount+range.startOffset } if ( range.endContainer==textNodes[i] ) { end = endCharCount+range.endOffset break; } endCharCount += textNodes[i].textContent.length } return [Int, end]; } setSelectionPosition = function (div, start, end) { range = createRange(document); range.selectNodeContents(div); var foundStart = false; var charCount=0; textNodes = getTextNodesIn(div); var aa=0 var bb=0 for (var i = 0; i<textNodes.length; i++ ) { velhoCount = charCount; charCount += textNodes[i].textContent.length if (!foundStart && velhoCount <= start && start <= charCount ) { aa = textNodes[i].textContent.length - (charCount - start ); range.setStart(textNodes[i], aa ); foundStart = true; } if (foundStart && end <= charCount) { bb = textNodes[i].textContent.length - (charCount - end) ; range.setEnd(textNodes[i], bb ); break; } } var sel = Selector(); sel.removeAllRanges(); sel.addRange(range); div.focus(); } setCursorPosition = function (div, position) { range = createRange(document); range.selectNodeContents(div); var charCount = 0 var endCharCount; textNodes = getTextNodesIn(div); for (var i = 0; i<textNodes.length; i++ ) { textNode = textNodes[i]; endCharCount = charCount + textNode.length; if (position >= charCount && position <= endCharCount ) { range.setStart(textNode, position - charCount); range.setEnd(textNode, position - charCount); range.collapse(false); break; } charCount = endCharCount; } var sel = Selector(); sel.removeAllRanges(); sel.addRange(range); div.focus(); } enterEvent = function (event) { if (event.keyCode == 13) { event.preventDefault(); var position = getCursorPosition (this) var se = Selector (); var range = se.getRangeAt(0); var posA = 0 ; var posB = range.endOffset ; var posC = range.endContainer.textContent.length ; var a = range.endContainer.textContent.substring( posA, posB ) ; var b = range.endContainer.textContent.substring( posB, posC ) ; range.endContainer.parentNode.innerHTML = (a + '\n' + b) ; setCursorPosition (this, position+1) } } setStyle = function (tag, atributo, valor) { tag.style[atributo] = valor; } setProperty = function (div, node, atributo, valor) { if(node==undefined || node==null ) { div.achouEndContainer = false; div.achouStartContainer = false; var se = Selector (); div.range = se.getRangeAt(0); node = div } if( div.range.startContainer == div.range.endContainer && div.range.startOffset==div.range.endOffset ) { return; } if( node.nodeType == Node.TEXT_NODE ) { var conteudo = node.textContent ; var posA = 0 ; var posB = div.range.startOffset ; var posC = div.range.endOffset ; var posD = conteudo.length ; if(node == div.range.startContainer && node == div.range.endContainer ) { div.achouEndContainer = true; div.achouStartContainer = true; var span = document.createElement("span"); var s1 = document.createElement("span"); s1.textContent = conteudo.substring( posA, posB ) span.appendChild(s1) var s2 = document.createElement("span"); setStyle(s2, atributo, valor) s2.textContent = conteudo.substring( posB, posC ) span.appendChild(s2) var s3 = document.createElement("span"); s3.textContent = conteudo.substring( posC, posD) span.appendChild(s3) var rec = node.parentNode; rec.removeChild(node); rec.appendChild( span ) ; } else if( node == div.range.startContainer) { div.achouStartContainer = true; var span = document.createElement("span"); var s1 = document.createElement("span"); s1.textContent = conteudo.substring( posA, posB ) span.appendChild(s1) var s2 = document.createElement("span"); setStyle(s2, atributo, valor) s2.textContent = conteudo.substring( posB, posD ) span.appendChild(s2) var rec = node.parentNode; rec.removeChild(node); rec.appendChild( span ) ; } else if( node == div.range.endContainer) { div.achouEndContainer = true; var span = document.createElement("span"); var s1 = document.createElement("span"); setStyle(s1, atributo, valor); s1.textContent = conteudo.substring( posA, posC ) span.appendChild(s1) var s2 = document.createElement("span"); s2.textContent = conteudo.substring( posC, posD ) span.appendChild(s2) var rec = node.parentNode; rec.removeChild(node); rec.appendChild( span ) ; } else if( !div.achouStartContainer ) { } else if( div.achouStartContainer && !div.achouEndContainer ) { var span = document.createElement("span"); setStyle(span, atributo, valor); var s1 = document.createTextNode(conteudo); span.appendChild(s1); var rec = node.parentNode; rec.removeChild(node); rec.appendChild( span ) ; } else if( div.achouEndContainer ) { } } else { var children = node.childNodes; for (var i = 0; i<children.length; i++) { setProperty( div, children[i], atributo, valor); } } } load = function() { var divA = document.getElementById("div"); divA.style.whiteSpace = "pre"; divA.contentEditable = true; divA.style.position = "absolute"; divA.style.border = "1px solid #000000"; divA.style.position = "absolute"; divA.style.left = "30px"; divA.style.top = "30px"; divA.style.width = "450"; divA.style.height = "150"; divA.style.border = "1px solid #000000"; divA.innerHTML = "<span>abcdefghij 1234567890a\n1234567890</span>" ; divA.onkeydown = enterEvent; } teste1 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'color', 'red'); setSelectionPosition(rec, obj[0], obj[1] ) } teste2 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'color', 'blue'); setSelectionPosition(rec, obj[0], obj[1] ) } teste3 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'fontWeight', 'bold'); setSelectionPosition(rec, obj[0], obj[1] ) } teste4 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'fontWeight', 'normal'); setSelectionPosition(rec, obj[0], obj[1] ) } teste5 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'fontStyle', 'italic'); setSelectionPosition(rec, obj[0], obj[1] ) } teste6 = function() { var rec = document.getElementById("div") obj = getSelectionPosition(rec) setProperty (rec, null, 'fontStyle', 'normal'); setSelectionPosition(rec, obj[0], obj[1] ) } </script> </head> <body onload="load()"> <div id="div">sdf</div> <button type="button" onclick="teste1()">vermelho</button> <button type="button" onclick="teste2()">azul</button> <button type="button" onclick="teste3()">bold</button> <button type="button" onclick="teste4()">unbold</button> <button type="button" onclick="teste5()">italic</button> <button type="button" onclick="teste6()">normal text</button> </body> </html>
Nenhum comentário:
Postar um comentário