Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / key-feed-viewer / viewer / FeedPanel.js
1 /**
2  * @class FeedViewer.FeedPanel
3  * @extends Ext.panel.Panel
4  *
5  * Shows a list of available feeds. Also has the ability to add/remove and load feeds.
6  *
7  * @constructor
8  * Create a new Feed Panel
9  * @param {Object} config The config object
10  */
11
12 Ext.define('FeedViewer.FeedPanel', {
13     extend: 'Ext.panel.Panel',
14
15     alias: 'widget.feedpanel',
16
17     initComponent: function(){
18         Ext.apply(this, {
19             layout: 'fit',
20             title: 'Feeds',
21             animCollapse: true,
22             items: this.createView(),
23             dockedItems: [this.createToolbar()]
24         });
25         this.createMenu();
26         this.addEvents(
27             /**
28              * @event feedremove Fired when a feed is removed
29              * @param {FeedPanel} this
30              * @param {String} title The title of the feed
31              * @param {String} url The url of the feed
32              */
33             'feedremove',
34
35             /**
36              * @event feedselect Fired when a feed is selected
37              * @param {FeedPanel} this
38              * @param {String} title The title of the feed
39              * @param {String} url The url of the feed
40              */
41             'feedselect'
42         );
43
44         this.callParent(arguments);
45     },
46
47     // template method
48     afterRender: function(){
49         this.callParent(arguments);
50         var view = this.view;
51         view.getSelectionModel().select(view.store.first());
52     },
53
54     /**
55      * Create the DataView to be used for the feed list.
56      * @private
57      * @return {Ext.view.View}
58      */
59     createView: function(){
60         var view = this.view = Ext.create('widget.dataview', {
61             store: Ext.create('Ext.data.Store', {
62                 model: 'Feed',
63                 data: this.feeds
64             }),
65             selModel: {
66                 mode: 'SINGLE',
67                 listeners: {
68                     scope: this,
69                     selectionchange: this.onSelectionChange
70                 }
71             },
72             listeners: {
73                 scope: this,
74                 contextmenu: this.onContextMenu
75             },
76             trackOver: true,
77             cls: 'feed-list',
78             itemSelector: '.feed-list-item',
79             overItemCls: 'feed-list-item-hover',
80             tpl: '<tpl for="."><div class="feed-list-item">{title}</div></tpl>'
81         });
82
83         view.on('render', function() {
84
85         }, this);
86         return this.view;
87     },
88
89     /**
90      * Creates the toolbar to be used for controlling feeds.
91      * @private
92      * @return {Ext.toolbar.Toolbar}
93      */
94     createToolbar: function(){
95         this.createActions();
96         this.toolbar = Ext.create('widget.toolbar', {
97             items: [this.addAction, this.removeAction]
98         });
99         return this.toolbar;
100     },
101
102     /**
103      * Create actions to share between toolbar and menu
104      * @private
105      */
106     createActions: function(){
107         this.addAction = Ext.create('Ext.Action', {
108             scope: this,
109             handler: this.onAddFeedClick,
110             text: 'Add feed',
111             iconCls: 'feed-add'
112         });
113
114         this.removeAction = Ext.create('Ext.Action', {
115             itemId: 'remove',
116             scope: this,
117             handler: this.onRemoveFeedClick,
118             text: 'Remove feed',
119             iconCls: 'feed-remove'
120         });
121     },
122
123     /**
124      * Create the context menu
125      * @private
126      */
127     createMenu: function(){
128         this.menu = Ext.create('widget.menu', {
129             items: [{
130                 scope: this,
131                 handler: this.onLoadClick,
132                 text: 'Load feed',
133                 iconCls: 'feed-load'
134             }, this.removeAction, '-', this.addAction],
135             listeners: {
136                 hide: function(c){
137                     c.activeFeed = null;
138                 }
139             }
140         });
141     },
142
143     /**
144      * Used when view selection changes so we can disable toolbar buttons.
145      * @private
146      */
147     onSelectionChange: function(){
148         var selected = this.getSelectedItem();
149         this.toolbar.getComponent('remove').setDisabled(!selected);
150         this.loadFeed(selected);
151     },
152
153     /**
154      * React to the load feed menu click.
155      * @private
156      */
157     onLoadClick: function(){
158         this.loadFeed(this.menu.activeFeed);
159     },
160
161     /**
162      * Loads a feed.
163      * @private
164      * @param {Ext.data.Model} rec The feed
165      */
166     loadFeed: function(rec){
167         if (rec) {
168             this.fireEvent('feedselect', this, rec.get('title'), rec.get('url'));
169         }
170     },
171
172     /**
173      * Gets the currently selected record in the view.
174      * @private
175      * @return {Ext.data.Model} Returns the selected model. false if nothing is selected.
176      */
177     getSelectedItem: function(){
178         return this.view.getSelectionModel().getSelection()[0] || false;
179     },
180
181     /**
182      * Listens for the context menu event on the view
183      * @private
184      */
185     onContextMenu: function(view, index, el, event){
186         var menu = this.menu;
187
188         event.stopEvent();
189         menu.activeFeed = view.store.getAt(index);
190         menu.showAt(event.getXY());
191     },
192
193     /**
194      * React to a feed being removed
195      * @private
196      */
197     onRemoveFeedClick: function(){
198         var active = this.menu.activeFeed || this.getSelectedItem();
199
200
201         this.animateNode(this.view.getNode(active), 1, 0, {
202             scope: this,
203             afteranimate: function(){
204                 this.view.store.remove(active);
205             }
206         });
207         this.fireEvent('feedremove', this, active.get('title'), active.get('url'));
208
209     },
210
211     /**
212      * React to a feed attempting to be added
213      * @private
214      */
215     onAddFeedClick: function(){
216         var win = Ext.create('widget.feedwindow', {
217             listeners: {
218                 scope: this,
219                 feedvalid: this.onFeedValid
220             }
221         });
222         win.show();
223     },
224
225     /**
226      * React to a validation on a feed passing
227      * @private
228      * @param {FeedViewer.FeedWindow} win
229      * @param {String} title The title of the feed
230      * @param {String} url The url of the feed
231      */
232     onFeedValid: function(win, title, url){
233         var view = this.view,
234             store = view.store,
235             rec;
236
237         rec = store.add({
238             url: url,
239             title: title
240         })[0];
241         this.animateNode(view.getNode(rec), 0, 1);
242     },
243
244     /**
245      * Animate a node in the view when it is added/removed
246      * @private
247      * @param {Mixed} el The element to animate
248      * @param {Number} start The start opacity
249      * @param {Number} end The end opacity
250      * @param {Object} listeners (optional) Any listeners
251      */
252     animateNode: function(el, start, end, listeners){
253         Ext.create('Ext.fx.Anim', {
254             target: Ext.get(el),
255             duration: 500,
256             from: {
257                 opacity: start
258             },
259             to: {
260                 opacity: end
261             },
262             listeners: listeners
263          });
264     },
265
266     // Inherit docs
267     onDestroy: function(){
268         Ext.destroy(
269             this.viewNav,
270             this.menu
271         );
272         this.callParent(arguments);
273     }
274 });