Usando a Prototype – passo 1 – escondendo selects debaixo de uma popup

Vamos lá, falar de usos práticos da biblioteca Prototype. Okey, aqui no And After há alguns posts a respeito já, mas estou pensando em criar uma série deles.
Nesse primeiro, amos ver como criar uma função que esconde determinados elementos do html se outro estiver por cima.

Não entendeu? Vamos lá, vou explicar de onde veio a idéia – acho que fica mais fácil.
Uma coisa que aparece em qualquer projeto de web ultimamente é a necessidade de se fazer caixas (normalmente divs) que abrem por cima de outras. Normalmente para mostrar conteúdos oriundos de requisições ajax (ok, sei que o termo não está correto, mas não consegui pensar em outro).
Aí, o que normalmente se faz? Tem-se uma div com display:none e no retorno da requisição (callback), dá-se um display:block nela mostrando o conteúdo da forma adequada.
O grande problema é quando essa div abre por cima de um select ou um flash, por exemplo. O IE6 mostra o select ou o swf por cima da div (não ocorre no Firefox nem IE7), acabando com o layout e dificultando tudo. Para isso fiz essa função aqui, genérica, que recebe dois parâmetros: o id do seu elemento html que estará por cima, e o id de um elemento html que contém elementos do tipo select.

Usando o objeto Position (veja a documentação aqui) da Prototype, é possível acessar o método cumulativeOffset(element) que retorna um array com as posições das coordenadas x e y do elemento, independente do local no código em que esteja (posição relativa dos pais, absoluta, floats, etc…)
Com isso, o que é feito: pega-se a posição da div de popup e suas dimensões, e se varre a lista de selects presentes no outro elemento. A cada select que é encontrado, pega-se também as coordenadas desse select e suas dimensões, e através de uma lógica simples faz a comparação nos eixos x e y se a popup está por cima do select. Se sim, deixa o select como invisível.
Segue o código:

function escondeNoOver(id_popup, id_area) {
        //define qual a popup
        var popup = $(id_popup);
        //pega todas os selects de um determinado elemento
        var selects = $(id_area).getElementsByTagName("select");
        //pega coordenadas X/Y da popup (topo do lado esquerdo) e dimensões da mesma
        var posX = Position.cumulativeOffset(popup)[0];
        var posY = Position.cumulativeOffset(popup)[1];
        var width = popup.clientWidth;
        var height = popup.clientHeight;
       
        //percorre a lista de selects
        for(i=0; i<selects.length; i++) {
           
            //pega coordenadas X/Y do select (topo do lado esquerdo) e dimensões do mesmo
            var selX = Position.cumulativeOffset(selects[i])[0];
            var selY = Position.cumulativeOffset(selects[i])[1];
            var widthS = selects[i].clientWidth;
            var heightS = selects[i].clientHeight;
           
            var onX = false;
            //verifica se no eixo X (horizontal), a popup está entre o início e o final do select
            if(posX<selX+widthS) {
                if(posX+width>selX)
                    onX = true;
            } else {
                if(selX+widthS>posX+width)
                    onX = true;
            }
           
           
            //verifica se no eixo Y (vertical), a popup está entre o início e o final do select
            var onY = false;
            if(posY<selY+heightS) {
           
                if(posY+height>selY)
                    onY = true;
            } else {
                if(selY+heightS>posY+height)
                    onY = true;
            }
           
            //tem que estar dentro de X e Y para esconder a popup
            if(onX && onY){
                selects[i].style.visibility = "hidden";
            }
        }
    }

Abaixo segue o código funcional de um html com essa função, onde ao clicar no link do final da página sera chamada a função e ela verificará se há campos do tipo select por baixo daquela div de popup que possui um fundo acinzentado.
Vale notar que essa função pode ser alterada para verificar outros tipos de objetos e não precisa ser usada apenas para essa questão de retorno de requisições ajax – muitas vezes precisamos esconder algumas coisas, independente do motivo, não? 🙂
 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<style type="text/css">
* {margin:0; padding:0; border:0;}
body {font-family:Verdana, Arial, Helvetica, sans-serif;}
input, select, textarea {border:1px solid #000000;}
form {margin:50px;}
p {margin:10px;}
div#popup{padding:20px; border:3px solid #000000; position:absolute; left:80px; top:350px; background-color:#F0F0F0; width:200px;}
</style>
<script type="text/javascript" src="http://www.prototypejs.org/assets/2008/1/25/prototype-1.6.0.2.js"></script>
<script type="text/javascript">
    function escondeNoOver(id_popup, id_area) {
        //define qual a popup
        var popup = $(id_popup);
        //pega todas os selects de um determinado elemento
        var selects = $(id_area).getElementsByTagName("select");
        //pega coordenadas X/Y da popup (topo do lado esquerdo) e dimensões da mesma
        var posX = Position.cumulativeOffset(popup)[0];
        var posY = Position.cumulativeOffset(popup)[1];
        var width = popup.clientWidth;
        var height = popup.clientHeight;
        //percorre a lista de selects
        for(i=0; i<selects.length; i++) {
            //pega coordenadas X/Y do select (topo do lado esquerdo) e dimensões do mesmo
            var selX = Position.cumulativeOffset(selects[i])[0];
            var selY = Position.cumulativeOffset(selects[i])[1];
            var widthS = selects[i].clientWidth;
            var heightS = selects[i].clientHeight;
            var onX = false;
            //verifica se no eixo X (horizontal), a popup está entre o início e o final do select
            if(posX<selX+widthS) {
                if(posX+width>selX)
                    onX = true;
            } else {
                if(selX+widthS>posX+width)
                    onX = true;
            }
            //verifica se no eixo Y (vertical), a popup está entre o início e o final do select
            var onY = false;
            if(posY<selY+heightS) {
           
                if(posY+height>selY)
                    onY = true;
            } else {
                if(selY+heightS>posY+height)
                    onY = true;
            }
            //tem que estar dentro de X e Y para esconder a popup
            if(onX && onY){
                selects[i].style.visibility = "hidden";
            }
        }
    }
</script>
</head>
<body>
<div id="popup">sua div de popup</div>
<form action="entreemcontato.php" method="post" id="form">
<div>
    <p>Nome:</p>
    <p><input type="text" name="nome" value="Seu Nome"/></p>
    <p>Comentários:</p>
    <p><textarea name="comentários" rows="5" cols="20">
    Seus comentários
    </textarea></p>
    <p>Você é:</p>
    <p><input type="radio" name="vocee" value="homem" checked="checked"/>
    Homem
    </p>
    <p><input type="radio" name="vocee" value="mulher"/>
    Mulher
    </p>
    <p><input type="checkbox" name="cefet" checked="checked"/>Estudo no Cefet</p>
    <p>O que você achou desse minicurso?</p>
    <select>
    <option value="bom">Bom</option>
    <option value="regular" selected="selected">Regular</option>
    <option value="ruim">Ruim</option>
    </select>
    <p>Você repetiria esse curso?</p>
    <select>
    <option value="bom">Sim</option>
    <option value="regular" selected="selected">Sempre</option>
    </select>
    <p><input type="submit" value="Enviar"/></p>
    <p><input type="reset" value="Limpar"/></p>
</div>
</form>
<a href="#" onclick="escondeNoOver(´popup´, ´form´);" title="checar popup">checar popup</a>
</body>
</html>
 

Em breve, outros exemplos usando a Prototype 🙂

SWFObject – inserindo flash na sua página sem complicações

Há aproximadamente 2 anos, os desenvolvedores web tiveram uma grande (ou não) dor de cabeça quando a Microsoft perdeu uma disputa judicial contra uma empresa americana, chamada Eolas, a qual patenteou – simplificando o assunto – o carregamento de um plugin em um documento hipertexto. Com isso, as versões atualizadas do IE7 de lá pra cá pedem para que o usuário clique no flash para que ele comece a ser reproduzido, causando umd esconforto na experiência do usuário.

De lá pra cá, muito já se discutiu sobre como contornar essa questão, e muitas soluções já foram expostas. As mais conhecidas se baseiam em inserir o flash via javascript (e não mais escrevendo diretamente no html as tags object e embed), e com isso a tal questão do "Clique aqui para ativar" é contornada.

No começo, usava-se muito uma biblioteca javascript chamada dynActiveX.js. Depois, uma outra chamada SWFObject ficou conhecida e foi adotada pela maior parte da comunidade de desenvolvedores (vejo por aí alguns projetos que usam um plugin da jQuery para isso. Me parece uma boa também).

Uma outra vantagem de utilizar essa forma de inserir flash no seu html é que você não precisa se preocupar com todas as formalidades que a tag object necessita, nem ter que ficara duplicando todo o código dentro da tag embed (para que os browsers gecko entendem). Ou seja, write once, work always 🙂

A versão 2.0 da SWFObject foi lançada alguns meses atrás; se você usava a 1.x, terá que mudar a forma de escrever seu código. Você pode fazer o download direto do Google Code aqui.
*aproveito e deixo a dica de ler um pouco a respeito do Google Code e da Ajax Libraries aqui

Como utilizar?

Depois de fazer download do arquivo, você pode usar esse código mínimo como exemplo:

<html>
<head>
<script type="text/javascript" src="swfobject.js"></script>
</head>
<body>
<div id="flashcontent">
  Esse btexto é substituído pelo Flash
</div>
<script type="text/javascript">
   var so = new SWFObject("movie.swf", "meuflashvideo", "400", "200", "8", "#336699");
   so.write("flashcontent");
</script>
</body>
</html>

O que é feito, basicamente, é que o javascript insere dentro da div com id="flashcontent" o código necessário para inserir o flash troca a div com o id="flashcontent" pelo código necessário para inserir o flash (obrigado @rulico pela correção, na 1.x é que funcionava dessa outra forma!).
Segundo a documentação do SWFObject, você pode parametrizar o flash da seguinte forma:

var so = new SWFObject(swf, id, width, height, version, background-color
[, quality, xiRedirectUrl, redirectUrl]);

 

Onde:

  • swf: é o caminho do arquivo .swf
  • id: id do objeto, para tratamento javascript
  • width: largura do swf
  • height: altura do swf
  • version: versão necessária do Flash Player necessária (ver a documentação oficial para mais detalhes)
  • background-color: cor de fundo do Flash, em hexadecimal

 

Existem ainda os parâmetros opcionais:

  • quality: a qualidade que deve ser usada. Por padrão, é usado o valor high
  • xiRedirectUrl: url para onde o usuário que fez o download do flash player pelo Expressinstall
  • redirectUrl: use se você quise redirecionar o usuário que não tem a versão correta do flash player para alguma página

 

Definindo outros atributos e passando variáveis

Caso seja necessário, você pode definir outros atributos usando o método setAttribute. A sintaze é a seguinte:

so.setAttribute("parametro", "valor");

Você pode passar quantos atributos quiser, é só replicar esse código.
Pode ser necessário também passar variáveis para o seu flash. Siga o seguinte código como base:

so.addVariable("nome da variável", "valor");

Qualquer coisa, vejam na documentação oficial um how-to com todos os detalhes e um FAQ bem completo a respeito 🙂

[update]Gerador de código para inserir o SWFObject (by @rulico): http://www.swffix.org/swfobject/generator/[/update]