goncin@wordpress.com:~$ _

Linux, programação e toda sorte de nerdices

Arquivos da Categoria: web

Meu ambiente de trabalho em 7 itens

Não sei direito onde a coisa começou. Recebi do Alexandre Gaigalas (@alganet) e, num segundo momento, também do Bruno Roberto Gomes (@brgomes) a incumbência de compartilhar 7 itens do meu ambiente de trabalho. Tanto um quanto o outro já escreveu sobre o mesmo tema, tendo recebido a tarefa de outras pessoas. Pesquisei um pouco a respeito, e descobri no blog do Duodraco que a ideia é fazer disso um meme. Então vamos lá. 🙂

Meu ambiente de trabalho. Não reparem a bagunça :P

Meu ambiente de trabalho. Não reparem a bagunça 😛

1) Um Ubuntu altamente personalizado

Há cerca de um ano, encarei o desafio de abandonar o Windows como plataforma de desenvolvimento e usar Linux para esse propósito. Escolhi a distribuição Ubuntu, que já usava nos meus computadores pessoais e com a qual já estava familiarizado.

Como gosto de deixar as coisas bem do meu jeito, meu Ubuntu, ao menos visualmente, em nada se parece com uma instalação recém-feita desse sistema operacional. Entre as personalizações que costumo fazer na interface, estão:

  • a troca do tema padrão (atualmente, uso o tema Orta com os ícones Faenza);
  • a redução para apenas um painel, o inferior, e o utilização do Docky na parte superior da tela para lançamento de aplicativos;
  • o applet Cardápio no lugar do tradicional menu do GNOME; e
  • o applet Dockbarx em substituição à lista de janelas/tarefas.

Minha instalação corrente começou na versão Karmic Koala (9.10), foi atualizada para a Lucid Lynx (10.04 LTS) e, no momento, corresponde à versão mais atual do SO, Maverick Meerkat (10.10). Tudo isso sem precisar formatar, comprovando a estabilidade do ambiente. Um ano, três versões e tudo rodando redondo. Exceto, é claro, quando eu tento fazer alguma atualização bleeding edge e ferro alguma coisa – a maior vítima é o driver da placa de vídeo. Mas #SouDev e não desisto nunca, daqui a pouco ponho o sistema de volta pra funcionar.

2) Netbeans para desenvolvimento PHP

Sempre estive em busca do IDE perfeito e open source (ou, pelo menos, freeware) para desenvolver em PHP (havia até um post meu sobre isso numa rede do Ning, mas todo mundo sabe o que aconteceu…). A meu ver, o estado da arte em termos de ambiente integrada para essa linguagem ainda não foi atingido. Contudo, o Netbeans evoluiu rapidamente e é, nos dias atuais, o que mais se aproxima do Olimpo. Tem, como vantagens, o fato de ser open source, multiplataforma (ainda que “multiplataforma”, aqui, seja sinônimo de Java) e relativamente leve, consideradas as circunstâncias. Por outro lado, ser baseado em Java, após a aquisição da Sun pela Oracle, é algo no mínimo temerário. Não por acaso, aguardo ansiosamente que o KDevelop com suporte a PHP amadureça e se torne logo utilizável. Pelo que já vi deste último, vem coisa boa por aí.

Netbeans IDE 7.0 Beta

Netbeans IDE 7.0 Beta

Quem estiver interessado no meu esquema (escuro) de cores para o Netbeans, pode baixá-lo aqui e importá-lo em Ferramentas > Opções > Importar (no canto inferior esquerdo do diálogo).

3) Wine, PlayOnLinux e Winetricks

Esta tríade de utilitários permite executar no Linux muitos programas da plataforma Windows. Se o Wine é uma camada de tradução das bibliotecas de runtime do Windows, o PlayOnLinux é um front-end que, por intermédio de scripts, automatiza a instalação de vários aplicativos comuns (algumas versões do Microsoft Office e do Photoshop, por exemplo), embora seu foco seja a instalação de jogos. Por seu turno, o Winetricks é um script que localiza, baixa e instala muitas das dependências mais recorrentes de programas Windows, como as fontes TrueType da Microsoft, os MDAC, os runtimes do Visual Basic e do Visual C++, etc.

PSPad editor rodando via Wine

PSPad editor rodando via Wine

Dessa forma, consigo trabalhar, no Ubuntu, com alguns bons programas feitos para a plataforma do Tio Bill, tais como o PSPad, o EMS SQL Manager 2010 for MySQL e o EMS SQL Manager 2008 for SQL Server.

4) Firefox com WebDeveloper Toolbar e outras extensões

Como desenvolvedor web, tenho um bom número de navegadores instalados (o Infernet Explorer roda na VM, veja mais abaixo). Meu navegador principal continua sendo o Firefox, porque muitas de suas extensões ainda não encontram paralelos para o Google Chrome – apesar de todos os predicados deste. Dentre as extensões que mais utilizo, estão a WebDeveloper Toolbar e a DownThemAll!. Um recurso nativo particularmente interessante do navegador, para mim, é o Console de Erros Javascript – pego muitos erros por ele, sem sequer precisar acionar o Firebug.

Firefox com WebDeveloper Toolbar em ação

Firefox com WebDeveloper Toolbar em ação

5) VMWare Player

OK, esse não é open source, é só freeware. Trabalho uma Instituição de Ensino Superior com foco em Ciências Sociais Aplicadas, ou, traduzindo, o povo daqui adora uma planilha. E, para manter a compatibilidade, eu, o único linuxista dessas bandas, não posso viver só de OpenOffice.org. Necessito utilizar o Microsoft Office, versão 2010, adquirida pela Instituição e que (ainda) não consegui instalar via Wine. Há outras cositas também que me forçam a ter um ambiente Windows à disposição, como Photoshop, Delphi (para alguns sistemas legados) e Crystal Reports.

Durante muito tempo, deixei o VirtualBox , da Sun Oracle, encarregado das minhas máquinas virtuais. Sem embargo, dois fatores fizeram com que eu passasse a utilizar o VMWare Player: (1) este divide o disco virtual em vários arquivos, facilitando o processo de backup e (2) com ele, os efeitos visuais funcionam, ao contrário do que ocorria com o VirtualBox. Pode parecer frescura, mas, para mim, os efeitos visuais são fundamentais, principalmente quanto a testá-los em outras distros Linux e versões futuras do Ubuntu, coisa que faço com frequência. Além do mais, suspender e recuperar uma VM mostrou-se sensivelmente mais rápido no VMWare Player, relativamente ao VirtualBox.

VMWare Player rodando Windows 7

VMWare Player rodando Windows 7

6) Gnome-RDP Remmina

UPDATE: seguindo o conselho do visitante BlueHood, expresso em seu comentário mais abaixo, acabei por trocar o Gnome-RDP pelo Remmina, até então desconhecido para mim. Vale a pena conhecê-lo! =D

Há muitos servidores rodando Windows Server aqui. E a rede toda é baseada no Active Directory. Felizmente, o Ubuntu conta com ferramentas para acesso remoto a máquinas Windows utilizando o protocolo RDP (mais conhecido por “Terminal Services”). O Gnome-RDP Remmina é simples, objetivo, e cumpre muito bem o seu papel, e ademais suporta também os protocolos VNC, SFTP e SSH. Para quem utiliza KDE, o utilitário equivalente é o KRDC.

O Remmina acessando um servidor Windows via Terminal Services

O Remmina acessando um servidor Windows via Terminal Services

7) The Gimp

OK, OK, passo longe de ser um designer. Mas nem por isso estou livre de usar softwares de edição gráfica. Tenho o Photoshop instalado na VM, e <vergonha-propria mode="on"> desse programa sei utilizar menos de 1% do seu potencial </vergonha-propria>.

Quando a tarefa com imagens não é complexa o bastante para justificar a subida da VM à memória, faço uso do Gimp, sempre em Single-Window mode. Com ele, consigo fazer as coisas mais triviais, como redimensionamento e conversão de formatos, recortes e strokes. Enfim, no quesito “software gráfico” sou um mero principiante, em início de aprendizado, esperando absorver novas habilidades à medida que as necessidades surjam.

The Gimp e o meu papel de parede atual

The Gimp e o meu papel de parede atual

Bonus track: Terminal + Guake

Nenhum desenvolvedor que se preze deve temer a linha de comando. Algumas tarefas (como, por exemplo, atualizar o Ubuntu) são muito mais simples via terminal. E o Guake, uma quase-unanimidade, torna a praticidade do terminal ainda mais prática, se é que me entendem. Após instalado e carregado, basta um F12 para que uma janela de terminal se descortine com elegância à frente de seus olhos.

O Guake trabalhando

O Guake trabalhando

Passando a bola adiante

Para manter o espírito do meme, passo a bola para o Francisco Prado (@fr_prado), o Henrique Lobo Weissmann (@loboweissmann), o Bruno Bemfica (@CodeAddicted) e o Fábio Vedovelli (@vedovelli). Compartilhem sua forma de trabalho, pessoal! 🙂

Anúncios

Aproveitando “layouts” implementados em ASP em aplicações PHP

Hoje, quase sem querer, descobri uma solução inusitada que me poupou muito tempo e esforço. Senta que lá vem história…

O caso

Estava eu trabalhando num hotsite para um congresso internacional. Uma outra pessoa fez todo o layout e as páginas informativas, tendo ficado por minha conta desenvolver o processo de inscrição dos participantes.

O problema

O layout e as páginas informativas foram feitas em ASP (clássico), e eu vou desenvolver o procedimento de inscrição em PHP. As páginas da inscrição devem seguir o look and feel das demais páginas, aproveitando cabeçalho, rodapé e menus.

A solução

No código-fonte ASP, havia três includes:

<!--#include file="cabecalho.asp"-->
(...)
<!--#include file="menu.asp"-->
(...)
<!--#include file="rodape.asp"-->

Para não ter de refazer em PHP esses três arquivos, que, aliás, estavam alocados em outro servidor, achei por bem pegar o conteúdo deles, já devidamente processados, e injetá-los no layout para ser usado com PHP. Assim, esses três includes transformaram-se em:

<?php echo file_get_contents('http://servidor/caminho/cabecalho.asp'); ?>
(...)
<?php echo file_get_contents('http://servidor/caminho/menu.asp'); ?>
(...)
<?php echo file_get_contents('http://servidor/caminho/rodape.asp'); ?>

Funcionou, foi uma boa sacada, mas isso resolvia apenas parte do problema. Como os arquivos incluídos estavam em outro servidor em relação ao meu script PHP, os hiperlinks e os caminhos para as imagens ficaram quebrados. Foi necessário incluir o caminho para o servidor nas tags a e image. Nada que um str_replace não dê jeito.

<?php
  $include = file_get_contents('http://servidor/caminho/cabecalho.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>
(...)
<?php
  $include = file_get_contents('http://servidor/caminho/menu.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>
(...)
<?php
  $include = file_get_contents('http://servidor/caminho/rodape.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>

E voilà! Tudo funcionando, sem precisar reimplementar do zero o layout em PHP. 🙂 Agora posso me concentrar apenas em gerar o conteúdo.

jQuery: evitando conflitos com outros “frameworks” Javascript

Post publicado originalmente em http://devfranca.ning.com/group/jquery/forum/topics/jquery-evitando-conflitos-com-1 em 7 de outubro de 2009

Que o jQuery é ótimo, todo mundo já sabe (ou pelo menos deveria saber). Um dos seus mais poderosos recursos é o atalho $, que, entre tantos outros usos, substitui com vantagem o famigerado document.getElementById().

Nada obstante, os problemas com o $ começam quando se usa o jQuery com outros frameworks, que também usam o cifrão para alguma coisa. Experimentei esse problema ao combinar jQuery com Scriptaculous.

Mas nem tudo está perdido. Há algumas saídas:

  1. Utilizar o método noConflict() do jQuery, atribuindo o resultado a uma variável, que então substituirá o cifrão. Isso deixa o cifrão livre para uso por outros frameworks. Esse método, pelo menos para mim, não deu certo (o jQuery continuou funcionando, mas o Scriptaculous não):
    jq = jQuery.noConflict();
    jq("#elemento").hide(); // Ao invés de $("#elemento").hide();
    
  2. Utilizar o próprio objeto jQuery no lugar do cifrão. Esse método “eu agarântio”, mas precisei fazer um “Encontrar/Substituir” todos os "$" por "jQuery" também no código fonte dos plugins (que, invariavelmente, usam o cifrão):
    jQuery("#elemento").hide(); // Ao invés de $("#elemento").hide();
    

Fica a dica! 🙂

Gerador de formulários HTML em PHP orientado a objetos (parte 2)

Se você chegou aqui diretamente, recomendo que você dê uma olhada na parte 1, sob pena de não entender nada 😛 …

Aqui estou eu novamente, continuando meu brainstorm a respeito de um gerador de formulários HTML implementado em PHP orientado a objetos. Como eu havia dito, ainda havia controles a implementar, e então aqui vai mais um, o <select> (drop down):

class GSelect extends GFormControl {

    private $_items = array();
    private $_selectedValue = null;

    public function  __construct($id, $label = '', $attributes = array(), $items = array(), $selectedValue = null) {
      $this->setId($id);
      $this->setLabel($label);
      $this->setAttributes($attributes);
      $this->setItems($items);
      $this->setSelectedValue($selectedValue);
    }

    protected function getOpenTag() {
      return '<select';
    }

    protected function getCloseTag() {
      return "\t</select>";
    }

    public function setItems($items) {
      if (is_array($items)) $this->_items = $items;
      return $this;
    }

    public function getItems() {
      return $this->_items;
    }

    public function setSelectedValue($value) {
      $this->_selectedValue = $value;
      return $this;
    }

    public function getSelectedValue() {
      return $this->_selectedValue;
    }

    protected function renderField() {
      $html = $this->getOpenTag() . " id='{$this->getId()}' ";
      $html .= $this->renderFieldAttributes() . ">\n";

      $items = $this->getItems();

      foreach($items as $value => $text) {
        $html .= "\t\t<option value='{$value}'";
        if ($value === $this->getSelectedValue())
           $html .= " selected='selected'";
        $html .= ">{$text}</option>\n";
      }

      $html .= $this->getCloseTag();

      return $html;
    }

  }

Este controle deu um pouco mais de trabalho para codificar porque, ao contrário dos anteriores, ele não é baseado na tag <input>. Basicamente, foi necessário fazer isso:

  • implementar métodos para configurar e retornar os itens da lista de seleção (setItems() e getItems());
  • implementar para configurar e retornar o valor que já virá selecionado na lista (setSelectedValue() e getSelectedValue());
  • sobrescrever método renderField(), a fim de refletir as particularidades desse controle; e
  • sobrescrever o construtor para que este aceitasse dois novos parâmetros, $items e $selectedValue, de forma que o controle pudesse ser totalmente configurado no momento de sua criação.

Por fim, ficou faltando escrever o controle que represente o próprio formulário (<form>). Isso foi feito facilmente, estendendo também o GForm a partir de GFormControl.

  class GForm extends GFormControl {

    private $_controls = array();

    protected function getOpenTag() {
      return '<form';
    }

    protected function getCloseTag() {
      return '</form>';
    }

    public function addControl($control) {
      if ($control instanceof GFormControl) $this->_controls[] = $control;
      return $this;
    }

    protected function getControls() {
      return $this->_controls;
    }

    protected function renderField() {
      $html = $this->getOpenTag() . " id='{$this->getId()}' action='{$this->getLabel()}' ";
      $html .= $this->renderFieldAttributes() . ">\n";

      $controls = $this->getControls();

      foreach($controls as $ctl)
        $html .= "{$ctl->render()}\n";

      $html .= $this->getCloseTag();

      return $html;

    }

    public function render() {
      return $this->renderField();
    }

  }

O grande diferencial do GForm em relação aos controles anteriormente desenvolvidos é sua capacidade de ter controles filhos, cujo gerenciamento básico é feito pelos métodos addControl() e getControls(). Assim, quando for chamado o método render() do formulário, este fará a chamada ao método render() de cada um de seus filhos, poupando-nos linhas de código. E, por tocar no assunto de economia de codificação, reparem que o método addControl() retorna a instância do objeto ($this), permitindo-nos montar o formulário mediante chamadas de métodos encadeados. Vejam só:

  $opcoes = array (
    0 => '(Selecione)',
    1 => 'Aluno',
    2 => 'Professor',
    3 => 'Administrativo'
  );

  $form = new GForm('form1', 'proc_login.php');

  echo $form
    ->addControl(new GTextBox('usuario', 'Usuário:', array('maxlength'=>50, 'size'=>15)))
    ->addControl(new GPassword('senha', 'Senha:', array('maxlength'=>50, 'size'=>15)))
    ->addControl(new GSelect('tipo_acesso', 'Tipo de Acesso:', null, $opcoes, 2))
    ->addControl(new GCheckBox('guardar_info', 'Guardar informações?'))
    ->addControl(new GSubmit('enviar', 'Enviar'))
    ->render();

O segundo parâmetro do construtor, que nos outros controles é o texto descritivo (label), no caso do GForm serve para especificar o valor do atributo action. As linhas 10 a 16 constituem uma única instrução, encadeando métodos. O <select> gerado vem com a opção de valor 2 pré-selecionada (último parâmetro do construtor do GSelect).

Eis o código fonte HTML gerado:

<form id='form1' action='proc_login.php' >
<div>
	<label for='usuario'>Usuário:</label><br />
	<input type='text' id='usuario' maxlength='50' size='15' />
</div>

<div>
	<label for='senha'>Senha:</label><br />
	<input type='password' id='senha' maxlength='50' size='15' />
</div>

<div>
	<label for='tipo_acesso'>Tipo de Acesso:</label><br />
	<select id='tipo_acesso' >
		<option value='0'>(Selecione)</option>
		<option value='1'>Aluno</option>
		<option value='2' selected='selected'>Professor</option>
		<option value='3'>Administrativo</option>
	</select>
</div>

<div>
	<label for='guardar_info'>Guardar informações?</label><br />
	<input type='checkbox' id='guardar_info' />
</div>

<div>
	<input type='submit' id='enviar' value='Enviar' />
</div>

</form>
Aparência do formulário HTML gerado pelo código PHP

Aparência do formulário HTML gerado pelo código PHP

Mais uma vez, devo agradecê-lo por me acompanhar na leitura deste loooooongo e super-hiper-mega-técnico post. Espero que tenha valido a pena, que você tenha compreendido o que eu quis demonstrar (conceitos de programação orientada a objetos), e que tenhamos, eu e você, aprendido coisas novas. 😀

Gerador de formulários HTML em PHP orientado a objetos (parte 1)

Os frameworks para desenvolvimento Web nunca estiveram tão em voga quanto atualmente. De fato, utilizá-los é bem melhor do que reinventar a roda, apesar do esforço despendido no apendizado no aprendizado da ferramenta.

O código fonte de seu framework favorito é uma fonte abundante de técnicas de programação. Não hesite em vasculhá-lo. Foi olhando um desses códigos (no caso, o do Yii Framework), que cogitei em escrever um gerador de formulários HTML, como prova de conceito.

Mas, para quê reimplementar, se já está no framework? No meu caso, pelo próprio aprendizado, para dominar técnicas novas. E, diga-se de passagem, não sou o único a fazer esse tipo de coisa. Obviamente, essas experimentações jamais entrarão em produção. A não ser que, é claro, fiquem tão boas e estáveis que se tornem um novo framework. 😛

A ideia por detrás do gerador de formulários é bastante simples: a partir de uma conjunto de objetos, cada qual representando um controle de formulário e com propriedades corretamente configuradas, obter código o HTML válido correspondente. Não sei quando a vocês, mas acho digitar HTML um porre (abre tag, põe id, configura atributos, etc., etc. e, no fim, acaba esquecendo de fechar a tag). Por que não, então, escrever esses formulários em puro PHP, e deixá-lo gerar o chato do HTML?

De acordo? Vamos lá.

Comecei codificando uma classe genérica e abstrata, para servir de base a todos os controles, chamada GFormControl. Segue o código abaixo:

<?php
  abstract class GFormControl {

    private $_id;                         // ID do campo de formulário
    private $_label;                      // Texto descritivo do campo
    private $_attributes;                 // Outros atributos do campo
    private $_labelSeparator = '
';  // Separador entre o "label" e o campo

    public function  __construct($id, $label = '', $attributes = array()) {
      $this->setId($id);
      $this->setLabel($label);
      $this->setAttributes($attributes);
    }

    /********** SETTERS **********/

    protected function setId($value) {
      $this->_id = $value;
      return $this;
    }

    public function setLabel($value) {
      $this->_label = $value;
      return $this;
    }

    public function setLabelSeparator($value) {
      $this->_labelSeparator = $value;
      return $this;
    }

    public function setAttributes($value) {
      $this->_attributes = $value;
      return $this;
    }

    /********** GETTERS **********/

    public function getId() {
      return $this->_id;
    }

    public function getLabel() {
      return $this->_label;
    }

    abstract protected function getOpenTag();

    abstract protected function getCloseTag();

    public function getLabelSeparator() {
      return $this->_labelSeparator;
    }

    public function getAttributes() {
      return $this->_attributes;
    }

    /***** MÉTODOS PROTEGIDOS *****/

    // Rendereiza a abertura da DIV
    protected function renderOpenDiv() {
      return "<div>\n\t";
    }

    // Renderiza o LABEL que contém a descrição do campo
    protected function renderLabel($labelSeparator = null) {

      if (! is_null($labelSeparator))
        $this->setLabelSeparator($labelSeparator);

      return "<label for="{$this->getId()}">{$this->getLabel()}</label>{$this->getLabelSeparator()}\n\t";

    }

    // Renderiza o campo de formulário propriamente dito
    protected function renderField() {

      $html = $this->getOpenTag() . " id='{$this->getId()}' ";
      $html .= $this->renderFieldAttributes();
      $html .= $this->getCloseTag();

      return $html;

    }

    // Renderiza os atributos do campo de formulário
    protected function renderFieldAttributes() {
      $html = '';

      if ($attrs = $this->getAttributes())
        foreach($attrs as $attr => $value)
          $html .= "{$attr}='{$value}' ";

      return $html;
    }

    // Renderiza o fechamento da DIV
    protected function renderCloseDiv() {
      return "\n</div>\n";
    }

    /***** MÉTODOS PÚBLICOS */

    /*
     * Renderiza o campo de formulário, de acordo com os parâmetros configurados.
     * Para tanto, efetua chamadas aos métodos protegidos responsáveis pela
     * renderização das diferentes partes.
     * Cada campo será renderizado da seguinte forma:
     *
     *
<div>
     *   <label for="nome_campo">Descrição do campo</label>
     *
     *</div>
     */

    public function render($labelSeparator = null) {

      $html = $this->renderOpenDiv();
      $html .= $this->renderLabel($labelSeparator);
      $html .= $this->renderField();
      $html .= $this->renderCloseDiv();

      return $html;

    }

  }

Por que uma classa abstrata? Simples: não desejo criar instâncias dessa classe. Sua razão de ser é servir como ancestral para as classes de cada controle de formulário. Além da própria classe, os métodos protegidos getOpenTag() e getCloseTag() estão também marcados como abstract. Isso significa que qualquer classe que estenda GFormControl fica obrigada a implementar esses dois métodos.

O único método público da classe (desconsiderando-se os getters) é o render(), responsável por gerar o código HTML correspondente ao campo de formulário. Esse método faz chamadas a outros métodos, cada qual responsável por renderizar uma parte diferente do campo. Os métodos renderXXX() foram definidos como protegidos – isso significa que são visíveis somente pelas classes descendentes, pois não foram projetadas para serem chamados pelo usuário final.

Em suma, esta classe define muita coisa, mas não faz nada. E agora? Veja como ficou o código de quatro controles:

<?php
  // Campo de texto
  class GTextBox extends GFormControl {

    protected function getOpenTag() {
      return "<input type="text" />';
    }

  }

  /***********************************************************/

  // Campo de senha
  class GPassword extends GFormControl {

    protected function getOpenTag() {
      return "<input type="password" />';
    }

  }

  /***********************************************************/

  // Caixa de verificação
  class GCheckBox extends GFormControl {

    protected function getOpenTag() {
      return "<input type="checkbox" />';
    }

  }

  /***********************************************************/

  // Botão de enviar
  class GSubmit extends GFormControl {

    protected function getOpenTag() {
      return "<input type="submit" />';
    }

    /* No caso do botão de enviar, foi necessária uma sobrecarga (override)
     * dos métodos renderField() e render(), porque o controle não tem um
     * LABEL associado a ele, e o texto que iria no LABEL vai no atributo
     * VALUE do próprio controle.
     */

    protected function renderField() {
      $html = $this->getOpenTag() . " id='{$this->getId()}' value='{$this->getLabel()}' ";
      $html .= $this->renderFieldAttributes();
      $html .= $this->getCloseTag();

      return $html;
    }

    public function render() {
      $html = $this->renderOpenDiv();
      $html .= $this->renderField();
      $html .= $this->renderCloseDiv();

      return $html;

    }
  }

?>

Nos casos dos controles de caixa de texto, caixa de senha e caixa de verificação, basta implementar os métodos getOpenTag() e getCloseTag(), para que tudo o que foi definido no ancestral funcione apropriadamente. No caso do botão de enviar, foram necessárias algumas modificações nos métodos definidos na classe base, pois seu comportamento foge um pouco ao padrão (vide comentários no código).

Isso feito, podemos escrever um formulário simples de login da seguinte forma:

<?php   $usuario = new GTextBox('usuario', 'Usuário:', array('maxlength'=-->50, 'size'=>15));
  $senha = new GPassword('senha', 'Senha:', array('maxlength'=>50, 'size'=>15));
  $guardarInfo = new GCheckBox('guardar_info', 'Guardar informações?');
  $enviar = new GSubmit('enviar', 'Enviar');

  echo $usuario->render();
  echo $senha->render();
  echo $guardarInfo->render(' ');
  echo $enviar->render();

?>

O código HTML gerado, por seu turno, é o seguinte:

<div>
	<label for="usuario">Usuário:</label>

	<input id="usuario" maxlength="50" size="15" type="text" /></div>
<div>
	<label for="senha">Senha:</label>

	<input id="senha" maxlength="50" size="15" type="password" /></div>
<div>
	<label for="guardar_info">Guardar informações?</label>

	<input id="guardar_info" type="checkbox" /></div>
<div>
	<input id="enviar" type="submit" value="Enviar" /></div>
Aparência do formulário gerado

Aparência do formulário gerado

Acho que devo parabenizá-lo por ter chegado até aqui na leitura deste post. E, se entendeu o que eu quis fazer, parabéns duplos!!

Todavia, o trabalho está bem longe de terminar. Falta escrever os demais controles de formulário e, se você notou bem, o código sequer gera a tag <form>. Isso é tarefa para as próximas partes. 😉

jQuery e Javascript não-obtrusivo

A ideia deste post surgiu de uma conversa com o colega Francisco Prado, ontem, no Twitter. Naquela ocasião, ele sugeria uma dica rápida de Javascript: para que o valor de um campo de formulário fosse limpo ao ser clicado, basta acrescer o atributo onclick="this.value='';" ao elemento. Por meu turno, aleguei que onfocus="this.value='';" seria melhor, pois funciona mesmo se o campo tiver sido acessado pelo teclado.

Horas mais tarde, refletindo sobre isso, cheguei à conclusão de que talvez estivéssemos fazendo apenas a coisa fácil, e não a coisa certa. Nos dias de hoje, quando imperam os padrões de desenvolvimento, misturar código Javascript diretamente ao HTML chega a ser quase um crime. Ademais, isso fere uma das premissas básicas da técnica denominada Javascript não-obtrusivo: manter funcionalidade (Javascript) e aparência (HTML) separadas uma da outra. Implementar isso é um tanto quanto chato, mas, acredite em mim, facilita muito a manutenção posterior.

Mas, como se faz? Senão vejamos:

Considere este formulário HTML como exemplo:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Novo Usuário</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>

  <h1>Novo Usuário</h1>
  <form>

    <label for="nome">Nome:</label>&nbsp;
    <input type="text" id="nome"/><br />

    <label for="sobrenome">Sobrenome:</label>&nbsp;
    <input type="text" id="sobrenome" /><br />

    <label for="id">ID de usuário:</label>&nbsp;
    <input type="text" id="id"/><br />

    <label for="senha">Senha:</label>&nbsp;
    <input type="password" id="senha" /><br />

    <label for="confsenha">Redigite a senha:</label>&nbsp;
    <input type="password" id="confsenha" /><br />

    <input type="submit" value="Enviar" />

 </form>

 </body>
</html>

Temos um formulário com cinco campos (nome, sobrenome, ID de usuário, senha e confirmação da senha). Destes, desejamos que os três últimos fiquem em branco assim que ganharem foco.

O segundo passo é criar um arquivo Javascript vazio (denominei-o newuser.js) e fazer a referência a ele na seção <head> do arquivo HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Novo Usuário</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="newuser.js"></script>
  </head>
  (...)

O conteúdo do arquivo newuser.js pode ser implementado de vários modos. A grande dificuldade é que, separando o Javascript do HTML, caberá ao desenvolvedor conectar manualmente os manipuladores de eventos às funções Javascript, e fazer isso “na unha” envolve, quase sempre, ter que lidar com o modo com que os diferentes navegadores identificam o elemento que disparou o evento.

A biblioteca jQuery é uma ótima saída para este tipo de problema, já que ela lida internamente com essas diferenças de forma transparente. Utilizando-a, o conteúdo do newuser.js poderia ser semelhante ao que segue:

jQuery(document).ready(function() {

  jQuery('.clearonfocus').bind(
    'focus',
    function (e) {
      jQuery(this).val('');
    }
  );

});

Em poucas palavras, o código acima, tão logo o documento HTML esteja carregado (jQuery(document).ready), adiciona um manipulador para o evento onfocus para todos os elementos que utilizem a classe CSS clearonfocus, o qual, por seu turno, apaga o valor do elemento quando este for focado.

Por fim, precisamos fazer algumas pequenas adaptações ao código HTML original:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Novo Usuário</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="jquery-1.4.2.min.js"></script>
    <script type="text/javascript" src="newuser.js"></script>
  </head>
  <body>

  <h1>Novo Usuário</h1>
  <form>

    <label for="nome">Nome:</label>&nbsp;
    <input type="text" id="nome"/><br />

    <label for="sobrenome">Sobrenome:</label>&nbsp;
    <input type="text" id="sobrenome" /><br />

    <label for="id">ID de usuário:</label>&nbsp;
    <input type="text" id="id" class="clearonfocus" /><br />

    <label for="senha">Senha:</label>&nbsp;
    <input type="password" id="senha" class="clearonfocus" /><br />

    <label for="confsenha">Redigite a senha:</label>&nbsp;
    <input type="password" id="confsenha" class="clearonfocus" /><br />

    <input type="submit" value="Enviar" />

 </form>

 </body>
</html>

As alterações feitas: acréscimo da biblioteca jQuery (linha 6) e adição do atributo de classe aos elementos sobre os quais desejamos ligar (bind) o manipulador de eventos (linhas 21, 24 e 27).

Este é um exemplo bastante banal, mas mostra como é possível manter Javascript e HTML separados sem perda de funcionalidade. E quanto à manutenção do código? Veja bem: se quisermos que mais algum campo tenha seu valor limpo ao ganhar foco, basta acrescentar class="clearonfocus" aos seus atributos. De forma semelhante, se desejarmos retirar esse comportamento do elemento, basta retirar o citado atributo. Em ambos os casos, mexemos só no arquivo HTML. 🙂

%d blogueiros gostam disto: