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