Ext JS - Learning Center

Tutorial:Extending Ext Class (Portuguese)

From Learn About the Ext JavaScript Library

Revision as of 17:18, 4 February 2009 by Everton3x (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Summary: Este tutorial mostra os passos necessários para criar extensão às classes Ext.
Author: Jozef Sakalos
Published: Fevereiro 5, 2009
Ext Version: 1.1+ / 2.0+
Languages: en.png English cn.png Chinese kr.png Korean

br.png Portuguese

Contents

Objetivo

Intended resulting IconCombo

Vamos criar uma extensão da classe Ext.form.Combobox que irá exibir ícones na frente dos textos. Essa combinação pode ser útil, por exemplo, para a seleção de países onde normalmente não teríamos a bandeira do país seguido do nome do país.

Vamos chamar a extensão de Ext.ux.IconCombo.


Criando os arquivos

O primeiro passo é preparar arquivos que usaremos no processo de desenvolvimento. Vamos precisar destes arquivos:

  • Iconcombo.html: marcação html para a aplicação que irá usar a nossa nova extensão
  • Iconcombo.js: a aplicação javascript
  • Ext.ux.IconCombo.js: arquivo javascript da nossa extensão
  • Ext.ux.IconCombo.css: folhas de estilo para a nossa extensão

iconcombo.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">
    <link rel="stylesheet" type="text/css" href="Ext.ux.IconCombo.css">
    <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
    <script type="text/javascript" src="iconcombo.js"></script>
    <!-- A Localization Script File comes here -->
    <script type="text/javascript">Ext.onReady(iconcombo.init, iconcombo);</script>
    <title>Ext.ux.IconCombo Tutorial</title>
</head>
<body>
<div style="position:relative;width:300px;top:24px;left:64px;font-size:11px">
    <div>Icon combo:</div>
    <div id="combo-ct"></div>
</div>
</body>
</html>

Este é uma cópia modificada do arquivo encontrado no tutorial Application Layout for Beginners.

iconcombo.js

/**
  * Ext.ux.IconCombo Tutorial
  * by Jozef Sakalos, aka Saki
  * http://extjs.com/learn/Tutorial:Extending_Ext_Class
  */
 
// referência ao local da imagem em branco
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
// cria a aplicação
iconcombo = function() {
 
    // espaço público
    return {
        // propriedades públicas, e.g. strings para traduzir
 
        // métodos públicos
        init: function() {
            var icnCombo = new Ext.ux.IconCombo({
                store: new Ext.data.SimpleStore({
                    fields: ['countryCode', 'countryName', 'countryFlag'],
                    data: [
                        ['US', 'United States', 'x-flag-us'],
                        ['DE', 'Germany', 'x-flag-de'],
                        ['FR', 'France', 'x-flag-fr']
                    ]
                }),
                valueField: 'countryCode',
                displayField: 'countryName',
                iconClsField: 'countryFlag',
                triggerAction: 'all',
                mode: 'local',
                width: 160
            });
            icnCombo.render('combo-ct');
            icnCombo.setValue('DE');
        }
    };
}(); // fim do aplicativo
 
// fim do arquivo

Neste arquivo nós criamos um IconCombo, assim temos algo para brincar e testar a nossa extensão.

Ext.ux.IconCombo.js

// Cria um namespace para nossa extensão (Ext.ux)
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo Extension Class
  *
  * @author Jozef Sakalos, aka Saki
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config Configuration options
  */
Ext.ux.IconCombo = function(config) {
 
    // chama a construção do parent
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
}; // fim do construtor Ext.ux.IconCombo 
 
// extend
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
}); // fim do extend
 
// fim do arquivo

O que fizemos realmente neste processo é criar uma extensão vazia que não faz nada mais do que a Ext.form.ComboBox faz. Isto é tudo por enquanto, pois só precisamos de um ponto inicial que funcione nesta fase.

Ext.ux.IconCombo.css

.x-flag-us {
    background-image: url(../img/flags/us.png) !important;
}
.x-flag-de {
    background-image: url(../img/flags/de.png) !important;
}
.x-flag-fr {
    background-image: url(../img/flags/fr.png) !important;
}

Seus caminhos podem variar dependendo de onde você colocar os ícones das bandeiras os quais você pode fazer o download em famfamfam.com.

Vamos lá!

Até aqui, tudo bem. Se você visualizar iconcombo.html você deve ver um combo com três itens e a Alemanha deve ser selecionada, certo? Sem ícones ainda, claro ...


Agora é hora de trabalhar. Adicione as seguintes linhas em Ext.ux.IconCombo.js, logo após a chamada para o construtor pai (parent) ( nota que a marca correta é TPL (em minúsculas), para "model", não TP1):

this.tpl = config.tpl ||
      '<tpl for="."><div class="x-combo-list-item">'
    + '<table><tbody><tr>'
    + '<td>'
    + '<div class="{' + this.iconClsField + '} x-icon-combo-icon"></div></td>'
    + '<td>{' + this.displayField + '}</td>'
    + '</tr></tbody></table>'
    + '</div></tpl>'
;

O que fazemos aqui é que sobrepomos o item padrão do combobox com o nosso próprio modelo que faz uso do iconClsField.


Agora acrescente as seguintes linhas ao Ext.ux.IconCombo.css:

.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}

Bom! Pronto para o próximo teste, para recarregar a página. Tudo bem?

Bem, nós temos ícones agradáveis quando a lista está aberta, mas gostaríamos de ter também ícones quando ele está fechado, não queremos?


Adicionar seguintes linhas após a criação, em nosso modelo em construção:

this.on({
    render:{scope:this, fn:function() {
        var wrap = this.el.up('div.x-form-field-wrap');
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('x-icon-combo-input');
        this.flag = Ext.DomHelper.append(wrap, {
            tag: 'div', style:'position:absolute'
        });
    }}
});

Este código adiciona um listener render event que ajusta os estilos dos elementos e acrescenta a div recipiente da bandeira.

Em seguida, adicione o seguinte código na extensão na parte em que se lê:

// extensão
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // fim da extensão

Estamos adicionando uma função setIconCls e sobrepondo-a à função setValue. Evidentemente, queremos que a original setValue faça o seu trabalho, para chamar em primeiro lugar nosso campo e, depois, nós chamamos a nossa função setIconCls.


Por último mas não menos importante, acrescente as seguintes linhas ao seu arquivo Ext.ux.IconCombo.css:

.x-icon-combo-input {
    padding-left: 26px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 6px;
}

O grande final

Agora, o teste final: recarregar a página. Se você (ou eu no copiar/colar) não tenham cometido um erro, você terá a sua nova extensão Ext.ux.IconCombo. Claro, você pode ainda melhorá-la, mas estas são as bases de uma extensão de classe Ext.


Obrigado ao Brian Moeskau. Eu simplifiquei Ext.ux.IconCombo para que possa ser agora considerada a versão final podendo ser utilizada em suas aplicações.

O último código e css seguir:

Ext.ux.IconCombo.js

// Cria o namespace da extensão (Ext.ux)
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo Extension Class
  *
  * @author  Jozef Sakalos
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config Configuration options
  */
Ext.ux.IconCombo = function(config) {
 
    // chama o contrutor do parent
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
    this.tpl = config.tpl ||
          '<tpl for="."><div class="x-combo-list-item x-icon-combo-item {' 
        + this.iconClsField 
        + '}">{' 
        + this.displayField 
        + '}</div></tpl>'
    ;
 
    this.on({
        render:{scope:this, fn:function() {
            var wrap = this.el.up('div.x-form-field-wrap');
            this.wrap.applyStyles({position:'relative'});
            this.el.addClass('x-icon-combo-input');
            this.flag = Ext.DomHelper.append(wrap, {
                tag: 'div', style:'position:absolute'
            });
        }}
    });
} // fim do construtor Ext.ux.IconCombo
 
// extensão
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // fim da extensão
 
// fim do arquivo

Ext.ux.IconCombo.css

/* estilos específicos da aplicação */
.x-flag-us {
    background-image:url(../img/flags/us.png) !important;
}
.x-flag-de {
    background-image:url(../img/flags/de.png) !important;
}
.x-flag-fr {
    background-image:url(../img/flags/fr.png) !important;
}
 
/* estilos principais da Ext.ux.IconCombo */
.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}
.x-icon-combo-input {
    padding-left: 25px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 5px;
}
.x-icon-combo-item {
    background-repeat: no-repeat !important;
    background-position: 3px 50% !important;
    padding-left: 24px;
}