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