terça-feira, 15 de outubro de 2013
quarta-feira, 24 de julho de 2013
Recursividade
Recursividade é, basicamente, quando um método chama a ele mesmo.
A recursividade está ao nosso redor. Quando fazemos contas, nas árvores, nos cristais, quando jogamos damas ou xadrez e mesmo quando um ribossomo e DNA montam uma proteína.
Por exemplo:
Um exemplo visual:
Bonito não é? Seu código:
A recursividade está ao nosso redor. Quando fazemos contas, nas árvores, nos cristais, quando jogamos damas ou xadrez e mesmo quando um ribossomo e DNA montam uma proteína.
Por exemplo:
<html> <head> <script> metodo = function(lugarImpressao, poda) { lugarImpressao.appendChild( document.createTextNode(" - ") ) if(poda>1) { // metodo chama a sí mesmo metodo(lugarImpressao, poda-1); } } load = function() { metodo( document.body, 4 ); } </script> </head> <body onload="load();"> </body> </html>Note que é importante a existência de uma variável poda. É isso mesmo! Podar a árvore. Sem essa variável para limitar o número de chamadas a sí mesmo, ela iria continuar sem parar.
Um exemplo visual:
Bonito não é? Seu código:
<html> <head> <script> manterLimites = function(angulo) { while(angulo>=360) { angulo=angulo-360; } while(angulo<0) { angulo=angulo+360; } return angulo; } getSenCos = function(angulo) { angulo = manterLimites(angulo); seno = Math.sin(angulo * Math.PI / 180); cose = Math.cos(angulo * Math.PI / 180); return [cose, seno]; } galho = function(ctx, x1, y1, tamanho, angulo, poda) { var senCos= getSenCos(angulo) var tx = x1+tamanho*senCos[0] var ty = y1+tamanho*senCos[1] ctx.lineWidth = poda*poda; ctx.beginPath(); ctx.strokeStyle="#FF0000"; ctx.moveTo(x1,y1); ctx.lineTo(tx,ty); ctx.stroke(); if( poda>1 ) { galho(ctx, tx, ty, tamanho*0.5, angulo+90,poda-1 ) galho(ctx, tx, ty, tamanho*0.5, angulo, poda-1 ) galho(ctx, tx, ty, tamanho*0.5, angulo-90,poda-1 ) } } load = function() { var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); galho(ctx, 250, 250, 45, 0+45, 4); galho(ctx, 250, 250, 45, 90+45, 4); galho(ctx, 250, 250, 45, 180+45, 4); galho(ctx, 250, 250, 45, 270+45, 4); } </script> </head> <body onload="load();"> <canvas id="myCanvas" width="500" height="500" style="border:1px solid #000000;"> </canvas> </body> </html>
segunda-feira, 22 de julho de 2013
Checkbox com 3 estados em javaScript
Como fazer um checkbox de 3 estados. (Three states in a checkbox)
As imagems b0.png, b1.png e b2.png medem 13x13 px² e representam os checkboxes:
desmarcado
semi-marcado
marcado
Uma de minhas estratégias para desenvolvimentos de componentes para formulários é manter um padrão para todos. Motivo: Facilitar o desenvolvimento de códigos recursivos como por exemplo os necessários à pegar ou setar os valores dos componentes. Exemplo de métodos e variaveis padrões que poderemos encontrar futuramente:
setOptions(): insere as opções basicas do componente
trigger(): função que é executada quando ocorre mudança de valor
getValue: retorna valor
setValue():atualiza valor
reset(): coloca valor em estado default
setEnabledTo(): seta o componente para um dos modos: seleção, edição ou inserção.
validate(): se diferente de nulo, toda vez que ocorrer tentativa de alteração de valor, esse validade acusa se o novo valor é aceitavel ou não. retorna um valor booleano.
mascara: String de formatação do campo. Exemplo com telefone: (##) ####-####
Futuramente deixaremos este componente um pouco mais complexo.
As imagems b0.png, b1.png e b2.png medem 13x13 px² e representam os checkboxes:
desmarcado
semi-marcado
marcado
Uma de minhas estratégias para desenvolvimentos de componentes para formulários é manter um padrão para todos. Motivo: Facilitar o desenvolvimento de códigos recursivos como por exemplo os necessários à pegar ou setar os valores dos componentes. Exemplo de métodos e variaveis padrões que poderemos encontrar futuramente:
setOptions(): insere as opções basicas do componente
trigger(): função que é executada quando ocorre mudança de valor
getValue: retorna valor
setValue():atualiza valor
reset(): coloca valor em estado default
setEnabledTo(): seta o componente para um dos modos: seleção, edição ou inserção.
validate(): se diferente de nulo, toda vez que ocorrer tentativa de alteração de valor, esse validade acusa se o novo valor é aceitavel ou não. retorna um valor booleano.
mascara: String de formatação do campo. Exemplo com telefone: (##) ####-####
Futuramente deixaremos este componente um pouco mais complexo.
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <script type="text/javascript"> stateBox = function () { var div = document.createElement("div"); div.style.background="#00ffff" div.style.position="absolute"; div.style.top="0px"; div.style.left="0px"; div.style.width="13px"; div.style.height="13px"; div.disabled=false div.isTristate=false div.value = false div.style.backgroundImage = "url('b0.png')"; div.setValue = function (valuev) { if( valuev == false ) { this.value = false this.style.backgroundImage = "url('b0.png')"; } else if( valuev == true ) { this.value = true this.style.backgroundImage = "url('b2.png')"; } else { this.value = null this.style.backgroundImage = "url('b1.png')"; } } div.getValue = function () { return this.value; } div.onclick = function() { if(!this.disabled) { if(this.isTristate) { if( this.value == true ) { this.value = false this.style.backgroundImage = "url('b0.png')"; } else if( this.value == false ) { this.value = null this.style.backgroundImage = "url('b1.png')"; } else { this.value = true this.style.backgroundImage = "url('b2.png')"; } } else { if( this.value == false ) { this.value = true this.style.backgroundImage = "url('b2.png')"; } else { this.value = false this.style.backgroundImage = "url('b0.png')"; } } } } return div; } function load() { var div = document.getElementById("div"); chb = stateBox(); chb.isTristate=true chb.setValue(null) div.appendChild( chb ) ; } </script> </head> <body onload="load()"> <div id="div"></div> </body> </html>
domingo, 21 de julho de 2013
HTMLEDitor em JavaScript
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>