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