Обозреватель изображений (tree panel и data views)


Как видно на скриншоте выше, слева у нас tree panel, а справа data views.

Структура проекта:

Следующая вьюха рендерит самую просматриваемую часть приложения. Она использует tree panel и data views.

Ext.define('PE.view.pics.Pics', {
    extend: 'Ext.panel.Panel',

    /* Marks these are required classes to be to loaded before
loading this view */
    requires: ['PE.view.pics.PicsController'],

    xtype: 'app-pics',
    controller: 'pics',

    items: [{
        xtype: 'container',
        layout: 'hbox',

        cls: 'pics-list',
        items: [{
            xtype: 'treepanel',
            width: 200,

            height: '100%',
            store: 'albums',
            border: true,
            useArrows: true,
            cls: 'tree',
            rootVisible: false,
            listeners: {
                itemclick: 'onNodeSelect'
            },
            dockedItems: [{
                xtype: 'toolbar',
                dock: 'top',
                ui: 'footer',
                items: [{
                    xtype: 'component',
                    flex: 1
                }, {
                    xtype: 'button',
                    text: 'Upload',
                    cls: 'btn-blue'
                }]
            }]

        }, {
            xtype: 'dataview',
            reference: 'picsList',
            cls: 'pics-list-content',
            store: 'pics',
            tpl: ['<tpl for=".">', '<div class="thumb"><img src="{url}" title=""></div>', '</tpl>'],
            multiSelect: true,
            minHeight: 400,
            flex: 1,
            trackOver: true,
            overItemCls: 'x-item-over',
            itemSelector: 'div.thumb',
            emptyText: 'No images to display'
        }]
    }]
});

ViewController обрабатывает событие itemdblclick у tree panel для отображения картинок выбранного альбома.

Ext.define('PE.view.pics.PicsController', {
    extend: 'Ext.app.ViewController',

    alias: 'controller.pics',
    views: ['PE.view.pics.Pics'],
    requires: ['PE.store.Pics', 'PE.store.Albums'],

    onNodeSelect: function(node, rec, item, index, e) {
        var albums = [];
        albums.push(rec.id);
        rec.childNodes.forEach(function(item) {
            albums.push(item.id);
        });

        Ext.getStore('pics').filter({
            property: 'albumId',
            operator: 'in',
            value: albums
        });
    }
});

Код модели и хранилища:

Ext.define('Pic', {
    extend: 'Ext.data.Model',
    fields: ['id', 'url', 'albumId']
});
Ext.define('PE.store.Pics', {
    extend: 'Ext.data.Store',

    storeId: 'pics',
    model: 'Pic',

    proxy: {
        type: 'rest',
        url: 'pics', // URL that will load data with respect to startand limit params
        reader: {
            type: 'json'
        }
    }
});
Ext.create('PE.store.Pics').load();
Ext.define('PE.store.Albums', {
    extend: 'Ext.data.TreeStore',
    storeId: 'albums',
    root: {
        expanded: true,
        children: [{
            id: 100,
            text: ' California',
            expanded: true,
            children: [{
                id: 600,
                text: ' Big Sur',
                leaf: true
            }, {
                id: 500,
                text: ' Yosemite',
                leaf: true
            }]
        }, {
            id: 400,
            text: ' Arizona',
            expanded: true,
            children: [{
                id: 300,
                text: ' Horseshoe bend',
                leaf: true
            }]
        }, {
            id: 200,
            text: ' Home',
            leaf: true
        }, {
            id: 700,
            text: ' India',
            expanded: true,
            children: [{
                id: 800,
                text: ' Ooty',
                leaf: true
            }, {
                id: 900,
                text: ' Chennai',
                leaf: true
            }, {
                id: 1000,
                text: ' Munnar',
                leaf: true
            }]
        }]
    }
});
Ext.create('PE.store.Albums');

Для того чтобы настроить drag and drop нужно сделать три вещи:

  1. Настроить элементы как перетаскиваемые.
  2. Создать drop target.
  3. Завершить drop target.
Для того чтобы сделать элемент перетаскиваемым нужно создать для него объект Ext.dd.DD.

// Configure the pics as draggable
var pics = Ext.get('pics').select('div');
Ext.each(pics.elements, function(el) {
    var dd = Ext.create('Ext.dd.DD', el, ' picsDDGroup', {
        isTarget: false
    });
});

Используйте Ext.dd.DDTarget для создания drop target контейнера. Следующий код создает drop target для всех div элементов с классом album:
var albums = Ext.get('album').select('div');
Ext.each(albums.elements, function(el) {
    var albumDDTarget = Ext.create('Ext.dd.DDTarget', el, 'picsDDGroup');
});

Когда перетаскиваемый элемент бросается на drop target, нам нужно переместить элемент из источника в drop target контейнера. Этого можно достичь перезаписью метода onDragDrop у DD.

var overrides = {

    onDragDrop: function(evtObj, targetElId) {
        var dropEl = Ext.get(targetElId);

        if (this.el.dom.parentNode.id != targetElId) {
            dropEl.appendChild(this.el);
            this.onDragOut(evtObj, targetElId);
            this.el.dom.style.position = '';
            this.el.dom.style.top = '';
            this.el.dom.style.left = '';
        } else {
            this.onInvalidDrop();
        }
    },
    onInvalidDrop: function() {
        this.invalidDrop = true;
    },
};

Применения override-а:
var albums = Ext.get('album').select('div');
var pics = Ext.get('pics').select('div');
Ext.each(pics.elements, function(el) {
    var dd = Ext.create('Ext.dd.DD', el, ' picsDDGroup', {
        isTarget: false
    });
    Ext.apply(dd, overrides);
});