Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / 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         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         return this.view;
83     },
84
85     /**
86      * Creates the toolbar to be used for controlling feeds.
87      * @private
88      * @return {Ext.toolbar.Toolbar}
89      */
90     createToolbar: function(){
91         this.createActions();
92         this.toolbar = Ext.create('widget.toolbar', {
93             items: [this.addAction, this.removeAction]
94         });
95         return this.toolbar;
96     },
97
98     /**
99      * Create actions to share between toolbar and menu
100      * @private
101      */
102     createActions: function(){
103         this.addAction = Ext.create('Ext.Action', {
104             scope: this,
105             handler: this.onAddFeedClick,
106             text: 'Add feed',
107             iconCls: 'feed-add'
108         });
109
110         this.removeAction = Ext.create('Ext.Action', {
111             itemId: 'remove',
112             scope: this,
113             handler: this.onRemoveFeedClick,
114             text: 'Remove feed',
115             iconCls: 'feed-remove'
116         });
117     },
118
119     /**
120      * Create the context menu
121      * @private
122      */
123     createMenu: function(){
124         this.menu = Ext.create('widget.menu', {
125             items: [{
126                 scope: this,
127                 handler: this.onLoadClick,
128                 text: 'Load feed',
129                 iconCls: 'feed-load'
130             }, this.removeAction, '-', this.addAction],
131             listeners: {
132                 hide: function(c){
133                     c.activeFeed = null;
134                 }
135             }
136         });
137     },
138
139     /**
140      * Used when view selection changes so we can disable toolbar buttons.
141      * @private
142      */
143     onSelectionChange: function(){
144         var selected = this.getSelectedItem();
145         this.toolbar.getComponent('remove').setDisabled(!selected);
146         this.loadFeed(selected);
147     },
148
149     /**
150      * React to the load feed menu click.
151      * @private
152      */
153     onLoadClick: function(){
154         this.loadFeed(this.menu.activeFeed);
155     },
156
157     /**
158      * Loads a feed.
159      * @private
160      * @param {Ext.data.Model} rec The feed
161      */
162     loadFeed: function(rec){
163         if (rec) {
164             this.fireEvent('feedselect', this, rec.get('title'), rec.get('url'));
165         }
166     },
167
168     /**
169      * Gets the currently selected record in the view.
170      * @private
171      * @return {Ext.data.Model} Returns the selected model. false if nothing is selected.
172      */
173     getSelectedItem: function(){
174         return this.view.getSelectionModel().getSelection()[0] || false;
175     },
176
177     /**
178      * Listens for the context menu event on the view
179      * @private
180      */
181     onContextMenu: function(view, index, el, event){
182         var menu = this.menu;
183
184         event.stopEvent();
185         menu.activeFeed = view.store.getAt(index);
186         menu.showAt(event.getXY());
187     },
188
189     /**
190      * React to a feed being removed
191      * @private
192      */
193     onRemoveFeedClick: function(){
194         var active = this.menu.activeFeed || this.getSelectedItem();
195
196
197         this.animateNode(this.view.getNode(active), 1, 0, {
198             scope: this,
199             afteranimate: function(){
200                 this.view.store.remove(active);
201             }
202         });
203         this.fireEvent('feedremove', this, active.get('title'), active.get('url'));
204
205     },
206
207     /**
208      * React to a feed attempting to be added
209      * @private
210      */
211     onAddFeedClick: function(){
212         var win = Ext.create('widget.feedwindow', {
213             listeners: {
214                 scope: this,
215                 feedvalid: this.onFeedValid
216             }
217         });
218         win.show();
219     },
220
221     /**
222      * React to a validation on a feed passing
223      * @private
224      * @param {FeedViewer.FeedWindow} win
225      * @param {String} title The title of the feed
226      * @param {String} url The url of the feed
227      */
228     onFeedValid: function(win, title, url){
229         var view = this.view,
230             store = view.store,
231             rec;
232
233         rec = store.add({
234             url: url,
235             title: title
236         })[0];
237         this.animateNode(view.getNode(rec), 0, 1);
238     },
239
240     /**
241      * Animate a node in the view when it is added/removed
242      * @private
243      * @param {Mixed} el The element to animate
244      * @param {Number} start The start opacity
245      * @param {Number} end The end opacity
246      * @param {Object} listeners (optional) Any listeners
247      */
248     animateNode: function(el, start, end, listeners){
249         Ext.create('Ext.fx.Anim', {
250             target: Ext.get(el),
251             duration: 500,
252             from: {
253                 opacity: start
254             },
255             to: {
256                 opacity: end
257             },
258             listeners: listeners
259          });
260     },
261
262     // Inherit docs
263     onDestroy: function(){
264         this.callParent(arguments);
265         this.menu.destroy();
266     }
267 });