Раширение классов в ExtJS

Цель.

Давайте добавим функциональности к Ext.form.Combobox, сделаем так, чтобы перед каждым элементом списка отображалась иконка.
ExtJS Combobox

Давайте назовем наш плагин Ext.ux.IconCombo, а также зарегистрируем для него xtype iconcombo.

Создаем файлы.

Наш первый шаг заключается в том, чтобы подготовить файлы для нашего плагина.

  • iconcombo.html: HTML код приложения, которое будет содержать наш плагин. Чтобы сделать этот пример более простым, этот файл также будет содержать Javascript код и CSS. В реальном приложении нужно хранить отдельно код и стили.
  • Ext.ux.IconCombo.js: Javascript код нашего плагина.

iconcombo.html

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs-2.0/resources/css/ext-all.css">
    <script type="text/javascript" src="../extjs-2.0/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs-2.0/ext-all-debug.js"></script>
    <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>

    <style type="text/css">
    .ux-flag-us {
        background-image:url(../img/flags/us.png) ! important;
    }
    .ux-flag-de {
        background-image:url(../img/flags/de.png) ! important;
    }
    .ux-flag-fr {
        background-image:url(../img/flags/fr.png) ! important;
    }
    .ux-icon-combo-icon {
        background-repeat: no-repeat;
        background-position: 0 50%;
        width: 18px;
        height: 14px;
    }

    /* X-BROWSER-WARNING: this is not being honored by Safari */
    .ux-icon-combo-input {
        padding-left: 25px;
    }

    .x-form-field-wrap .ux-icon-combo-icon {
        top: 3px;
        left: 5px;
    }
    .ux-icon-combo-item {
        background-repeat: no-repeat ! important;
        background-position: 3px 50% ! important;
        padding-left: 24px ! important;
    }
    </style>

    <script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../extjs-2.0/resources/images/default/s.gif';
Ext.onReady(function() {
    var win = new Ext.Window({
        title:'Icon Combo Ext 2.0 Extension Class Example',
        width:400,
        height:300,
        layout:'form',
        bodyStyle:'padding:10px',
        labelWidth:70,
        defaults:{anchor:'100%'},
        items:[{
            xtype:'iconcombo',
            fieldLabel:'IconCombo',
            store: new Ext.data.SimpleStore({
                    fields: ['countryCode', 'countryName', 'countryFlag'],
                    data: [
                        ['US', 'United States', 'ux-flag-us'],
                        ['DE', 'Germany', 'ux-flag-de'],
                        ['FR', 'France', 'ux-flag-fr']
                    ]
            }),
            valueField: 'countryCode',
            displayField: 'countryName',
            iconClsField: 'countryFlag',
            triggerAction: 'all',
            mode: 'local'
        }]
    });
    win.show();
});
    </script>
    <title>Icon Combo Ext 2.0 Extension Class Example</title>
</head>
<body>
</body>
</html>

Этот файл помимо html разметки содержит функцию фасад — onReady, которая создает окно с формой, а на ней единственный элемент наш iconcombo. Будьте внимательны, в этом примере реальной формы не создается (тега <form> нет). Хранилище (store) iconcombo содержит уже заполненые данные для тестирования.

Вам необходимо изменить пути к файлам ExtJS, если он установлен в другом месте.

Вам, возможно, также понадобится поменять пути к изображениям флагов.

Ext.ux.IconCombo.js

// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.IconCombo Extension Class for Ext 2.x Library
  *
  * @author  Ing. Jozef Sakalos
  * @version $Id: Ext.ux.IconCombo.js 617 2007-12-20 11:29:56Z jozo $
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  */
Ext.ux.IconCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent:function() {

        // call parent initComponent
        Ext.ux.IconCombo.superclass.initComponent.call(this);

    } // end of function initComponent
});

// register xtype
Ext.reg('iconcombo', Ext.ux.IconCombo);

// end of file

Первый шаг в расширении класса, это создание дополнения, которое не изменяет функциональности родительского класса. Таким образом мы можем быть уверены, что родительский класс отлично работает, и добавленный нами функционал не затронет его работу.

Javascript файл выше делает именно это.

Теория.

Чтобы расширить класс в ExtJS мы не должны создавать функцию-конструктор. Нам просто нужно присвоить значение возвращаемое функцией Ext.extend при ее вызове в нашем пространстве имен. Ext.extend получает в качестве аргументов родительский класс и конфиг (функционал расширения) в качестве второго аргумента, и возвращает наш класс-раширение.

Все что мы раньше делали в конструкторе в старых версиях Ext 1.x, теперь делается в методе initComponent, который мы перезаписываем в родительском классе. initComponent это метод-конструктор родительского класса.

Тем не менее метод initComponent родительского класса содержит полезный код, который должен быть выполнен. Вы можете посмотреть как мы вызываем метод initComponent родительского класса в приведенном выше коде. Модель вызова метода родителя, одинакова для все функции, которые мы переопределяем в классе.

Регистрации xtype для нашего расширения не является обязательной, но это очень удобно, вы можете вызывать расширение просто набрав несколько символов имени его xtype. То есть точно также, как показано в этом примере.

Приступим.

Пока все хорошо. Теперь если открыть iconcombo.html, вы должны увидеть стандартный combobox с тремя значениями и выбранной Германией. Пока конечно же никаких иконок.

Теперь пришло время поработать. Добавьте следующие строки в Ext.ux.IconCombo.js перед вызовом родительского метода initComponent:

Ext.apply(this, {
            tpl:  '&lt;tpl for=&quot;.&quot;&gt;'
                + '&lt;divst0&quot;&gt;'{' + this.iconClsField + '}&quot;&gt;'
                + '{' + this.displayField + '}'
                + '&lt;/div&gt;&lt;/tpl&gt;'
        });

В этом коде мы переопределяем стандартные элементы combobox нашими, которые будут использовать css класс iconClsField.

Отлично, готовы протестировать ? Обновите страницу, круто да ?

Замечательно у нас красивые значки при открытии списка, но мы также хотим видеть флаг, когда combobox закрыт, не так ли ?

Добавьте следующий код после окончания кода метода initComponent:

onRender:function(ct, position) {
        // call parent onRender
        Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);

        // adjust styles
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('ux-icon-combo-input');

        // add div for icon
        this.icon = Ext.DomHelper.append(this.el.up('div.x-form-field-wrap'), {
            tag: 'div', style:'position:absolute'
        });
    }, // end of function onRender

    setIconCls:function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.icon.className = 'ux-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    }, // end of function setIconCls

    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    } // end of function setValue

Вызов события onRender сначала вызывает родительский метод onRender, а потом добавляет стили и div’ы с иконками.

Мы также добавляем метод setIconCls и перезаписываем родительский метод setValue. Конечно мы хотим, чтобы родительский метод setValue тоже выполнился, поэтому мы сначала вызываем его, а потом выполняем наш метод setIconCls.

Окончание.

Теперь последние испытание: перезагрузите страницы. Если вы при копировании примера не сделали ошибок вы получили новое расширение Ext.ux.IconCombo. Конечно можно еще усовершенствовать наше расширение, но это только лишь пример, как раcширять классы в ExtJS.

Окончательный код.

Вот полный код того, что у нас получилось:

// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.IconCombo Extension Class for Ext 2.x Library
  *
  * @author  Ing. Jozef Sakalos
  * @version $Id: Ext.ux.IconCombo.js 617 2007-12-20 11:29:56Z jozo $
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  */
Ext.ux.IconCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent:function() {

        Ext.apply(this, {
            tpl:  '&lt;tpl for=&quot;.&quot;&gt;'
                + '&lt;divst0&quot;&gt;'{' + this.iconClsField + '}&quot;&gt;'
                + '{' + this.displayField + '}'
                + '&lt;/div&gt;&lt;/tpl&gt;'
        });

        // call parent initComponent
        Ext.ux.IconCombo.superclass.initComponent.call(this);

    }, // end of function initComponent

    onRender:function(ct, position) {
        // call parent onRender
        Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);

        // adjust styles
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('ux-icon-combo-input');

        // add div for icon
        this.icon = Ext.DomHelper.append(this.el.up('div.x-form-field-wrap'), {
            tag: 'div', style:'position:absolute'
        });
    }, // end of function onRender

    setIconCls:function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.icon.className = 'ux-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    }, // end of function setIconCls

    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    } // end of function setValue
});

// register xtype
Ext.reg('iconcombo', Ext.ux.IconCombo);

// end of file

Источник: http://www.extjs.com/learn/Tutorial:Extending_Ext2_Class.

One thought on “Раширение классов в ExtJS

  1. Спасибо! Очень сайт понравился, очень интересные статьи. Автору — респект

Comments are closed.