Ext.onReady(function(){

   
Ext.QuickTips.init();
   
// Album toolbar
   
var newIndex = 3;
   
var tb = new Ext.Toolbar({
        items
:[{
            text
: 'New Album',
            iconCls
: 'album-btn',
            handler
: function(){
               
var node = root.appendChild(new Ext.tree.TreeNode({
                    text
:'Album ' + (++newIndex),
                    cls
:'album-node',
                    allowDrag
:false
               
}));
                tree
.getSelectionModel().select(node);
                setTimeout
(function(){
                    ge
.editNode = node;
                    ge
.startEdit(node.ui.textNode);
               
}, 10);
           
}
       
}]
   
});

   
// set up the Album tree
   
var tree = new Ext.tree.TreePanel({
         
// tree
         animate
:true,
         enableDD
:true,
         containerScroll
: true,
         ddGroup
: 'organizerDD',
         rootVisible
:false,
         
// layout
         region
:'west',
         width
:200,
         split
:true,
         
// panel
         title
:'My Albums',
         autoScroll
:true,
         tbar
: tb,
         margins
: '5 0 5 5'
   
});

   
var root = new Ext.tree.TreeNode({
        text
: 'Albums',
        allowDrag
:false,
        allowDrop
:false
   
});
    tree
.setRootNode(root);

    root
.appendChild(
       
new Ext.tree.TreeNode({text:'Album 1', cls:'album-node', allowDrag:false}),
       
new Ext.tree.TreeNode({text:'Album 2', cls:'album-node', allowDrag:false}),
       
new Ext.tree.TreeNode({text:'Album 3', cls:'album-node', allowDrag:false})
   
);

   
// add an inline editor for the nodes
   
var ge = new Ext.tree.TreeEditor(tree, {/* fieldconfig here */ }, {
        allowBlank
:false,
        blankText
:'A name is required',
        selectOnFocus
:true
   
});

   
// Set up images view

   
var view = new Ext.DataView({
        itemSelector
: 'div.thumb-wrap',
        style
:'overflow:auto',
        multiSelect
: true,
        plugins
: new Ext.DataView.DragSelector({dragSafe:true}),
        store
: new Ext.data.JsonStore({
            url
: '../view/get-images.php',
            autoLoad
: true,
            root
: 'images',
            id
:'name',
            fields
:[
               
'name', 'url',
               
{name: 'shortName', mapping: 'name', convert: shortName}
           
]
       
}),
        tpl
: new Ext.XTemplate(
           
'',
           
'
',
           
'
',
           
'{shortName}
',
           
'
'
       
)
   
});

   
var images = new Ext.Panel({
        id
:'images',
        title
:'My Images',
        region
:'center',
        margins
: '5 5 5 0',
        layout
:'fit',
       
        items
: view
   
});

   
var layout = new Ext.Panel({
        layout
: 'border',
        width
:650,
        height
:400,
        items
: [tree, images]
   
});

    layout
.render('layout');

   
var dragZone = new ImageDragZone(view, {containerScroll:true,
        ddGroup
: 'organizerDD'});
});



/**
 * Create a DragZone instance for our JsonView
 */

ImageDragZone = function(view, config){
   
this.view = view;
   
ImageDragZone.superclass.constructor.call(this, view.getEl(), config);
};
Ext.extend(ImageDragZone, Ext.dd.DragZone, {
   
// We don't want to register our image elements, so let's
   
// override the default registry lookup to fetch the image
   
// from the event instead
    getDragData
: function(e){
       
var target = e.getTarget('.thumb-wrap');
       
if(target){
           
var view = this.view;
           
if(!view.isSelected(target)){
                view
.onClick(e);
           
}
           
var selNodes = view.getSelectedNodes();
           
var dragData = {
                nodes
: selNodes
           
};
           
if(selNodes.length == 1){
                dragData
.ddel = target;
                dragData
.single = true;
           
}else{
               
var div = document.createElement('div'); // create the multi element drag "ghost"
                div
.className = 'multi-proxy';
               
for(var i = 0, len = selNodes.length; i < len; i++){
                    div
.appendChild(selNodes[i].firstChild.firstChild.cloneNode(true)); // image nodes only
                   
if((i+1) % 3 == 0){
                        div
.appendChild(document.createElement('br'));
                   
}
               
}
               
var count = document.createElement('div'); // selected image count
                count
.innerHTML = i + ' images selected';
                div
.appendChild(count);
               
                dragData
.ddel = div;
                dragData
.multi = true;
           
}
           
return dragData;
       
}
       
return false;
   
},

   
// this method is called by the TreeDropZone after a node drop
   
// to get the new tree node (there are also other way, but this is easiest)
    getTreeNode
: function(){
       
var treeNodes = [];
       
var nodeData = this.view.getRecords(this.dragData.nodes);
       
for(var i = 0, len = nodeData.length; i < len; i++){
           
var data = nodeData[i].data;
            treeNodes
.push(new Ext.tree.TreeNode({
                text
: data.name,
                icon
: '../view/'+data.url,
                data
: data,
                leaf
:true,
                cls
: 'image-node'
           
}));
       
}
       
return treeNodes;
   
},
   
   
// the default action is to "highlight" after a bad drop
   
// but since an image can't be highlighted, let's frame it
    afterRepair
:function(){
       
for(var i = 0, len = this.dragData.nodes.length; i < len; i++){
           
Ext.fly(this.dragData.nodes[i]).frame('#8db2e3', 1);
       
}
       
this.dragging = false;    
   
},
   
   
// override the default repairXY with one offset for the margins and padding
    getRepairXY
: function(e){
       
if(!this.dragData.multi){
           
var xy = Ext.Element.fly(this.dragData.ddel).getXY();
            xy
[0]+=3;xy[1]+=3;
           
return xy;
       
}
       
return false;
   
}
});

// Utility functions

function shortName(name){
   
if(name.length > 15){
       
return name.substr(0, 12) + '...';
   
}
   
return name;
};