FeedPanel.js 7.1 KB

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