FeedViewer.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.atom.widget.FeedViewer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.atom.widget.FeedViewer"] = true;
  8. dojo.provide("dojox.atom.widget.FeedViewer");
  9. dojo.require("dijit._Widget");
  10. dojo.require("dijit._Templated");
  11. dojo.require("dijit._Container");
  12. dojo.require("dojox.atom.io.Connection");
  13. dojo.requireLocalization("dojox.atom.widget", "FeedViewerEntry", null, "ROOT,ar,az,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
  14. dojo.experimental("dojox.atom.widget.FeedViewer");
  15. dojo.declare("dojox.atom.widget.FeedViewer",[dijit._Widget, dijit._Templated, dijit._Container],{
  16. // summary:
  17. // An ATOM feed viewer that allows for viewing a feed, deleting entries, and editing entries.
  18. // description:
  19. // An ATOM feed viewer that allows for viewing a feed, deleting entries, and editing entries.
  20. feedViewerTableBody: null, //The body of the feed viewer table so we can access it and populate it. Will be assigned via template.
  21. feedViewerTable: null, //The overal table container which contains the feed viewer table. Will be assigned via template.
  22. entrySelectionTopic: "", //The topic to broadcast when any entry is clicked so that a listener can pick up it and display it.
  23. url: "", //The URL to which to connect to initially on creation.
  24. xmethod: false,
  25. localSaveOnly: false,
  26. //Templates for the HTML rendering. Need to figure these out better, admittedly.
  27. templateString: dojo.cache("dojox.atom", "widget/templates/FeedViewer.html", "<div class=\"feedViewerContainer\" dojoAttachPoint=\"feedViewerContainerNode\">\n\t<table cellspacing=\"0\" cellpadding=\"0\" class=\"feedViewerTable\">\n\t\t<tbody dojoAttachPoint=\"feedViewerTableBody\" class=\"feedViewerTableBody\">\n\t\t</tbody>\n\t</table>\n</div>\n"),
  28. _feed: null,
  29. _currentSelection: null, // Currently selected entry
  30. _includeFilters: null,
  31. alertsEnabled: false,
  32. postCreate: function(){
  33. // summary:
  34. // The postCreate function.
  35. // description:
  36. // The postCreate function. Creates our AtomIO object for future interactions and subscribes to the
  37. // event given in markup/creation.
  38. this._includeFilters = [];
  39. if(this.entrySelectionTopic !== ""){
  40. this._subscriptions = [dojo.subscribe(this.entrySelectionTopic, this, "_handleEvent")];
  41. }
  42. this.atomIO = new dojox.atom.io.Connection();
  43. this.childWidgets = [];
  44. },
  45. startup: function(){
  46. // summary:
  47. // The startup function.
  48. // description:
  49. // The startup function. Parses the filters and sets the feed based on the given url.
  50. this.containerNode = this.feedViewerTableBody;
  51. var children = this.getDescendants();
  52. for(var i in children){
  53. var child = children[i];
  54. if(child && child.isFilter){
  55. this._includeFilters.push(new dojox.atom.widget.FeedViewer.CategoryIncludeFilter(child.scheme, child.term, child.label));
  56. child.destroy();
  57. }
  58. }
  59. if(this.url !== ""){
  60. this.setFeedFromUrl(this.url);
  61. }
  62. },
  63. clear: function(){
  64. // summary:
  65. // Function clearing all current entries in the feed view.
  66. // description:
  67. // Function clearing all current entries in the feed view.
  68. //
  69. // returns:
  70. // Nothing.
  71. this.destroyDescendants();
  72. },
  73. setFeedFromUrl: function(/*string*/url){
  74. // summary:
  75. // Function setting the feed from a URL which to get the feed.
  76. // description:
  77. // Function setting the dojox.atom.io.model.Feed data into the view.
  78. //
  79. // url:
  80. // The URL to the feed to load.
  81. //
  82. // returns:
  83. // Nothing.
  84. if(url !== ""){
  85. if(this._isRelativeURL(url)){
  86. var baseUrl = "";
  87. if(url.charAt(0) !== '/'){
  88. baseUrl = this._calculateBaseURL(window.location.href, true);
  89. }else{
  90. baseUrl = this._calculateBaseURL(window.location.href, false);
  91. }
  92. this.url = baseUrl + url;
  93. }
  94. this.atomIO.getFeed(url,dojo.hitch(this,this.setFeed));
  95. }
  96. },
  97. setFeed: function(/*object*/feed){
  98. // summary:
  99. // Function setting the dojox.atom.io.model.Feed data into the view.
  100. // description:
  101. // Function setting the dojox.atom.io.model.Feed data into the view.
  102. //
  103. // entry:
  104. // The dojox.atom.io.model.Feed object to process
  105. //
  106. // returns:
  107. // Nothing.
  108. this._feed = feed;
  109. this.clear();
  110. var entrySorter=function(a,b){
  111. var dispA = this._displayDateForEntry(a);
  112. var dispB = this._displayDateForEntry(b);
  113. if(dispA > dispB){return -1;}
  114. if(dispA < dispB){return 1;}
  115. return 0;
  116. };
  117. // This function may not be safe in different locales.
  118. var groupingStr = function(dateStr){
  119. var dpts = dateStr.split(',');
  120. dpts.pop(); // remove year and time
  121. return dpts.join(",");
  122. };
  123. var sortedEntries = feed.entries.sort(dojo.hitch(this,entrySorter));
  124. if(feed){
  125. var lastSectionTitle = null;
  126. for(var i=0;i<sortedEntries.length;i++){
  127. var entry = sortedEntries[i];
  128. if(this._isFilterAccepted(entry)){
  129. var time = this._displayDateForEntry(entry);
  130. var sectionTitle = "";
  131. if(time !== null){
  132. sectionTitle = groupingStr(time.toLocaleString());
  133. if(sectionTitle === "" ){
  134. //Generally an issue on Opera with how its toLocaleString() works, so do a quick and dirty date construction M/D/Y
  135. sectionTitle = "" + (time.getMonth() + 1) + "/" + time.getDate() + "/" + time.getFullYear();
  136. }
  137. }
  138. if((lastSectionTitle === null) || (lastSectionTitle != sectionTitle)){
  139. this.appendGrouping(sectionTitle);
  140. lastSectionTitle = sectionTitle;
  141. }
  142. this.appendEntry(entry);
  143. }
  144. }
  145. }
  146. },
  147. _displayDateForEntry: function(/*object*/entry){
  148. // summary:
  149. // Internal function for determining the appropriate date to display.
  150. // description: Internal function for determining of a particular entry is editable.
  151. //
  152. // entry:
  153. // The dojox.atom.io.model.Entry object to examine.
  154. //
  155. // returns:
  156. // An appropriate date for the feed viewer display.
  157. if(entry.updated){return entry.updated;}
  158. if(entry.modified){return entry.modified;}
  159. if(entry.issued){return entry.issued;}
  160. return new Date();
  161. },
  162. appendGrouping: function(/*string*/titleText){
  163. // summary:
  164. // Function for appending a new grouping of entries to the feed view.
  165. // description:
  166. // Function for appending a grouping of entries to the feed view.
  167. //
  168. // entry:
  169. // The title of the new grouping to create on the view.
  170. //
  171. // returns:
  172. // Nothing.
  173. var entryWidget = new dojox.atom.widget.FeedViewerGrouping({});
  174. entryWidget.setText(titleText);
  175. this.addChild(entryWidget);
  176. this.childWidgets.push(entryWidget);
  177. },
  178. appendEntry: function(/*object*/entry){
  179. // summary:
  180. // Function for appending an entry to the feed view.
  181. // description:
  182. // Function for appending an entry to the feed view.
  183. //
  184. // entry:
  185. // The dojox.atom.io.model.Entry object to append
  186. //
  187. // returns:
  188. // Nothing.
  189. var entryWidget = new dojox.atom.widget.FeedViewerEntry({"xmethod": this.xmethod});
  190. entryWidget.setTitle(entry.title.value);
  191. entryWidget.setTime(this._displayDateForEntry(entry).toLocaleTimeString());
  192. entryWidget.entrySelectionTopic = this.entrySelectionTopic;
  193. entryWidget.feed = this;
  194. this.addChild(entryWidget);
  195. this.childWidgets.push(entryWidget);
  196. this.connect(entryWidget, "onClick", "_rowSelected");
  197. entry.domNode = entryWidget.entryNode;
  198. //Need to set up a bi-directional reference here to control events between the two.
  199. entry._entryWidget = entryWidget;
  200. entryWidget.entry = entry;
  201. },
  202. deleteEntry: function(/*object*/entryRow){
  203. // summary:
  204. // Function for deleting a row from the view
  205. // description:
  206. // Function for deleting a row from the view
  207. if(!this.localSaveOnly){
  208. this.atomIO.deleteEntry(entryRow.entry, dojo.hitch(this, this._removeEntry, entryRow), null, this.xmethod);
  209. }else{
  210. this._removeEntry(entryRow, true);
  211. }
  212. dojo.publish(this.entrySelectionTopic, [{ action: "delete", source: this, entry: entryRow.entry }]);
  213. },
  214. _removeEntry: function(/*FeedViewerEntry*/ entry, /* boolean */success){
  215. // summary:
  216. // callback for when an entry is deleted from a feed.
  217. // description:
  218. // callback for when an entry is deleted from a feed.
  219. if(success){
  220. /* Check if this is the last Entry beneath the given date */
  221. var idx = dojo.indexOf(this.childWidgets, entry);
  222. var before = this.childWidgets[idx-1];
  223. var after = this.childWidgets[idx+1];
  224. if( before.declaredClass === 'dojox.atom.widget.FeedViewerGrouping' &&
  225. (after === undefined || after.declaredClass === 'dojox.atom.widget.FeedViewerGrouping')){
  226. before.destroy();
  227. }
  228. /* Destroy the FeedViewerEntry to remove it from the view */
  229. entry.destroy();
  230. }else{}
  231. },
  232. _rowSelected: function(/*object*/evt){
  233. // summary:
  234. // Internal function for handling the selection of feed entries.
  235. // description:
  236. // Internal function for handling the selection of feed entries.
  237. //
  238. // evt:
  239. // The click event that triggered a selection.
  240. //
  241. // returns:
  242. // Nothing.
  243. var selectedNode = evt.target;
  244. while(selectedNode){
  245. if(selectedNode.attributes){
  246. var widgetid = selectedNode.attributes.getNamedItem("widgetid");
  247. if(widgetid && widgetid.value.indexOf("FeedViewerEntry") != -1){
  248. break;
  249. }
  250. }
  251. selectedNode = selectedNode.parentNode;
  252. }
  253. for(var i=0;i<this._feed.entries.length;i++){
  254. var entry = this._feed.entries[i];
  255. if( (selectedNode === entry.domNode) && (this._currentSelection !== entry) ){
  256. //Found it and it isn't already selected.
  257. dojo.addClass(entry.domNode, "feedViewerEntrySelected");
  258. dojo.removeClass(entry._entryWidget.timeNode, "feedViewerEntryUpdated");
  259. dojo.addClass(entry._entryWidget.timeNode, "feedViewerEntryUpdatedSelected");
  260. this.onEntrySelected(entry);
  261. if(this.entrySelectionTopic !== ""){
  262. dojo.publish(this.entrySelectionTopic, [{ action: "set", source: this, feed: this._feed, entry: entry }]);
  263. }
  264. if(this._isEditable(entry)){
  265. entry._entryWidget.enableDelete();
  266. }
  267. this._deselectCurrentSelection();
  268. this._currentSelection = entry;
  269. break;
  270. }else if( (selectedNode === entry.domNode) && (this._currentSelection === entry) ){
  271. //Found it and it is the current selection, we just want to de-select it so users can 'unselect rows' if they want.
  272. dojo.publish(this.entrySelectionTopic, [{ action: "delete", source: this, entry: entry }]);
  273. this._deselectCurrentSelection();
  274. break;
  275. }
  276. }
  277. },
  278. _deselectCurrentSelection: function(){
  279. // summary:
  280. // Internal function for unselecting the current selection.
  281. // description:
  282. // Internal function for unselecting the current selection.
  283. //
  284. // returns:
  285. // Nothing.
  286. if(this._currentSelection){
  287. dojo.addClass(this._currentSelection._entryWidget.timeNode, "feedViewerEntryUpdated");
  288. dojo.removeClass(this._currentSelection.domNode, "feedViewerEntrySelected");
  289. dojo.removeClass(this._currentSelection._entryWidget.timeNode, "feedViewerEntryUpdatedSelected");
  290. this._currentSelection._entryWidget.disableDelete();
  291. this._currentSelection = null;
  292. }
  293. },
  294. _isEditable: function(/*object*/entry){
  295. // summary:
  296. // Internal function for determining of a particular entry is editable.
  297. // description:
  298. // Internal function for determining of a particular entry is editable.
  299. // This is used for determining if the delete action should be displayed or not.
  300. //
  301. // entry:
  302. // The dojox.atom.io.model.Entry object to examine
  303. //
  304. // returns:
  305. // Boolean denoting if the entry seems editable or not..
  306. var retVal = false;
  307. if(entry && entry !== null && entry.links && entry.links !== null){
  308. for(var x in entry.links){
  309. if(entry.links[x].rel && entry.links[x].rel == "edit"){
  310. retVal = true;
  311. break;
  312. }
  313. }
  314. }
  315. return retVal;
  316. },
  317. onEntrySelected: function(/*object*/entry){
  318. // summary:
  319. // Function intended for over-riding/replacement as an attachpoint to for other items to recieve
  320. // selection notification.
  321. // description: Function intended for over0-riding/replacement as an attachpoint to for other items to recieve
  322. // selection notification.
  323. //
  324. // entry:
  325. // The dojox.atom.io.model.Entry object selected.
  326. //
  327. // returns:
  328. // Nothing.
  329. },
  330. _isRelativeURL: function(/*string*/url){
  331. // summary:
  332. // Method to determine if the URL is relative or absolute.
  333. // description:
  334. // Method to determine if the URL is relative or absolute. Basic assumption is if it doesn't start
  335. // with http:// or file://, it's relative to the current document.
  336. //
  337. // url:
  338. // The URL to inspect.
  339. //
  340. // returns:
  341. // boolean indicating whether it's a relative url or not.
  342. var isFileURL = function(url){
  343. var retVal = false;
  344. if(url.indexOf("file://") === 0){
  345. retVal = true;
  346. }
  347. return retVal;
  348. }
  349. var isHttpURL = function(url){
  350. var retVal = false;
  351. if(url.indexOf("http://") === 0){
  352. retVal = true;
  353. }
  354. return retVal;
  355. }
  356. var retVal = false;
  357. if(url !== null){
  358. if(!isFileURL(url) && !isHttpURL(url)){
  359. retVal = true;
  360. }
  361. }
  362. return retVal;
  363. },
  364. _calculateBaseURL: function(/*string*/fullURL, /*boolean*/currentPageRelative){
  365. // summary:
  366. // Internal function to calculate a baseline URL from the provided full URL.
  367. // description:
  368. // Internal function to calculate a baseline URL from the provided full URL.
  369. //
  370. // fullURL:
  371. // The full URL as a string.
  372. // currentPageRelative:
  373. // Flag to denote of the base URL should be calculated as just the server base, or relative to the current page/location in the URL.
  374. //
  375. // returns:
  376. // String of the baseline URL
  377. var baseURL = null;
  378. if(fullURL !== null){
  379. //Check to see if we need to strip off any query parameters from the URL.
  380. var index = fullURL.indexOf("?");
  381. if(index != -1){
  382. fullURL = fullURL.substring(0,index);
  383. //console.debug("Removed query parameters. URL now: " + fullURL);
  384. }
  385. if(currentPageRelative){
  386. //Relative to the 'current page' in the URL, so we need to trim that off.
  387. //Now we need to trim if necessary. If it ends in /, then we don't have a filename to trim off
  388. //so we can return.
  389. index = fullURL.lastIndexOf("/");
  390. if((index > 0) && (index < fullURL.length) && (index !== (fullURL.length -1))){
  391. //We want to include the terminating /
  392. baseURL = fullURL.substring(0,(index + 1));
  393. }else{
  394. baseURL = fullURL;
  395. }
  396. }else{
  397. //We want to find the first occurance of / after the <protocol>://
  398. index = fullURL.indexOf("://");
  399. if(index > 0){
  400. index = index + 3;
  401. var protocol = fullURL.substring(0,index);
  402. var fragmentURL = fullURL.substring(index, fullURL.length);
  403. index = fragmentURL.indexOf("/");
  404. if((index < fragmentURL.length) && (index > 0) ){
  405. baseURL = protocol + fragmentURL.substring(0,index);
  406. }else{
  407. baseURL = protocol + fragmentURL;
  408. }
  409. }
  410. }
  411. }
  412. return baseURL;
  413. },
  414. _isFilterAccepted: function(/*object*/entry) {
  415. // summary:
  416. // Internal function to do matching of category filters to widgets.
  417. // description:
  418. // Internal function to do matching of category filters to widgets.
  419. //
  420. // returns:
  421. // boolean denoting if this entry matched one of the accept filters.
  422. var accepted = false;
  423. if (this._includeFilters && (this._includeFilters.length > 0)) {
  424. for (var i = 0; i < this._includeFilters.length; i++) {
  425. var filter = this._includeFilters[i];
  426. if (filter.match(entry)) {
  427. accepted = true;
  428. break;
  429. }
  430. }
  431. }
  432. else {
  433. accepted = true;
  434. }
  435. return accepted;
  436. },
  437. addCategoryIncludeFilter: function(/*object*/filter) {
  438. // summary:
  439. // Function to add a filter for entry inclusion in the feed view.
  440. // description:
  441. // Function to add a filter for entry inclusion in the feed view.
  442. //
  443. // filter:
  444. // The basic items to filter on and the values.
  445. // Should be of format: {scheme: <some text or null>, term: <some text or null>, label: <some text or null>}
  446. //
  447. // returns:
  448. // Nothing.
  449. if (filter) {
  450. var scheme = filter.scheme;
  451. var term = filter.term;
  452. var label = filter.label;
  453. var addIt = true;
  454. if (!scheme) {
  455. scheme = null;
  456. }
  457. if (!term) {
  458. scheme = null;
  459. }
  460. if (!label) {
  461. scheme = null;
  462. }
  463. if (this._includeFilters && this._includeFilters.length > 0) {
  464. for (var i = 0; i < this._includeFilters.length; i++) {
  465. var eFilter = this._includeFilters[i];
  466. if ((eFilter.term === term) && (eFilter.scheme === scheme) && (eFilter.label === label)) {
  467. //Verify we don't have this filter already.
  468. addIt = false;
  469. break;
  470. }
  471. }
  472. }
  473. if (addIt) {
  474. this._includeFilters.push(dojox.atom.widget.FeedViewer.CategoryIncludeFilter(scheme, term, label));
  475. }
  476. }
  477. },
  478. removeCategoryIncludeFilter: function(/*object*/filter) {
  479. // summary:
  480. // Function to remove a filter for entry inclusion in the feed view.
  481. // description:
  482. // Function to remove a filter for entry inclusion in the feed view.
  483. //
  484. // filter:
  485. // The basic items to identify the filter that is present.
  486. // Should be of format: {scheme: <some text or null>, term: <some text or null>, label: <some text or null>}
  487. //
  488. // returns:
  489. // Nothing.
  490. if (filter) {
  491. var scheme = filter.scheme;
  492. var term = filter.term;
  493. var label = filter.label;
  494. if (!scheme) {
  495. scheme = null;
  496. }
  497. if (!term) {
  498. scheme = null;
  499. }
  500. if (!label) {
  501. scheme = null;
  502. }
  503. var newFilters = [];
  504. if (this._includeFilters && this._includeFilters.length > 0) {
  505. for (var i = 0; i < this._includeFilters.length; i++) {
  506. var eFilter = this._includeFilters[i];
  507. if (!((eFilter.term === term) && (eFilter.scheme === scheme) && (eFilter.label === label))) {
  508. //Keep only filters that do not match
  509. newFilters.push(eFilter);
  510. }
  511. }
  512. this._includeFilters = newFilters;
  513. }
  514. }
  515. },
  516. _handleEvent: function(/*object*/entrySelectionEvent) {
  517. // summary:
  518. // Internal function for listening to a topic that will handle entry notification.
  519. // description:
  520. // Internal function for listening to a topic that will handle entry notification.
  521. //
  522. // entrySelectionEvent:
  523. // The topic message containing the entry that was selected for view.
  524. //
  525. // returns:
  526. // Nothing.
  527. if(entrySelectionEvent.source != this) {
  528. if(entrySelectionEvent.action == "update" && entrySelectionEvent.entry) {
  529. var evt = entrySelectionEvent;
  530. if(!this.localSaveOnly){
  531. this.atomIO.updateEntry(evt.entry, dojo.hitch(evt.source,evt.callback), null, true);
  532. }
  533. this._currentSelection._entryWidget.setTime(this._displayDateForEntry(evt.entry).toLocaleTimeString());
  534. this._currentSelection._entryWidget.setTitle(evt.entry.title.value);
  535. } else if(entrySelectionEvent.action == "post" && entrySelectionEvent.entry) {
  536. if(!this.localSaveOnly){
  537. this.atomIO.addEntry(entrySelectionEvent.entry, this.url, dojo.hitch(this,this._addEntry));
  538. }else{
  539. this._addEntry(entrySelectionEvent.entry);
  540. }
  541. }
  542. }
  543. },
  544. _addEntry: function(/*object*/entry) {
  545. // summary:
  546. // callback function used when adding an entry to the feed.
  547. // description:
  548. // callback function used when adding an entry to the feed. After the entry has been posted to the feed,
  549. // we add it to our feed representation (to show it on the page) and publish an event to update any entry viewers.
  550. this._feed.addEntry(entry);
  551. this.setFeed(this._feed);
  552. dojo.publish(this.entrySelectionTopic, [{ action: "set", source: this, feed: this._feed, entry: entry }]);
  553. },
  554. destroy: function(){
  555. // summary:
  556. // Destroys this widget, including all descendants and subscriptions.
  557. // description:
  558. // Destroys this widget, including all descendants and subscriptions.
  559. this.clear();
  560. dojo.forEach(this._subscriptions, dojo.unsubscribe);
  561. }
  562. });
  563. dojo.declare("dojox.atom.widget.FeedViewerEntry",[dijit._Widget, dijit._Templated],{
  564. // summary:
  565. // Widget for handling the display of an entry and specific events associated with it.
  566. // description: Widget for handling the display of an entry and specific events associated with it.
  567. templateString: dojo.cache("dojox.atom", "widget/templates/FeedViewerEntry.html", "<tr class=\"feedViewerEntry\" dojoAttachPoint=\"entryNode\" dojoAttachEvent=\"onclick:onClick\">\n <td class=\"feedViewerEntryUpdated\" dojoAttachPoint=\"timeNode\">\n </td>\n <td>\n <table border=\"0\" width=\"100%\" dojoAttachPoint=\"titleRow\">\n <tr padding=\"0\" border=\"0\">\n <td class=\"feedViewerEntryTitle\" dojoAttachPoint=\"titleNode\">\n </td>\n <td class=\"feedViewerEntryDelete\" align=\"right\">\n <span dojoAttachPoint=\"deleteButton\" dojoAttachEvent=\"onclick:deleteEntry\" class=\"feedViewerDeleteButton\" style=\"display:none;\">[delete]</span>\n </td>\n <tr>\n </table>\n </td>\n</tr>\n"),
  568. entryNode: null,
  569. timeNode: null,
  570. deleteButton: null,
  571. entry: null,
  572. feed: null,
  573. postCreate: function(){
  574. var _nlsResources = dojo.i18n.getLocalization("dojox.atom.widget", "FeedViewerEntry");
  575. this.deleteButton.innerHTML = _nlsResources.deleteButton;
  576. },
  577. setTitle: function(/*string*/text){
  578. // summary:
  579. // Function to set the title of the entry.
  580. // description:
  581. // Function to set the title of the entry.
  582. //
  583. // text:
  584. // The title.
  585. //
  586. // returns:
  587. // Nothing.
  588. if (this.titleNode.lastChild){this.titleNode.removeChild(this.titleNode.lastChild);}
  589. var titleTextNode = document.createElement("div");
  590. titleTextNode.innerHTML = text;
  591. this.titleNode.appendChild(titleTextNode);
  592. },
  593. setTime: function(/*string*/timeText){
  594. // summary:
  595. // Function to set the time of the entry.
  596. // description:
  597. // Function to set the time of the entry.
  598. //
  599. // timeText:
  600. // The string form of the date.
  601. //
  602. // returns:
  603. // Nothing.
  604. if (this.timeNode.lastChild){this.timeNode.removeChild(this.timeNode.lastChild);}
  605. var timeTextNode = document.createTextNode(timeText);
  606. this.timeNode.appendChild(timeTextNode);
  607. },
  608. enableDelete: function(){
  609. // summary:
  610. // Function to enable the delete action on this entry.
  611. // description:
  612. // Function to enable the delete action on this entry.
  613. //
  614. // returns:
  615. // Nothing.
  616. if (this.deleteButton !== null) {
  617. //TODO Fix this
  618. this.deleteButton.style.display = 'inline';
  619. }
  620. },
  621. disableDelete: function(){
  622. // summary:
  623. // Function to disable the delete action on this entry.
  624. // description:
  625. // Function to disable the delete action on this entry.
  626. //
  627. // returns:
  628. // Nothing.
  629. if (this.deleteButton !== null) {
  630. this.deleteButton.style.display = 'none';
  631. }
  632. },
  633. deleteEntry: function(/*object*/event) {
  634. // summary:
  635. // Function to handle the delete event and delete the entry.
  636. // description:
  637. // Function to handle the delete event and delete the entry.
  638. //
  639. // returns:
  640. // Nothing.
  641. event.preventDefault();
  642. event.stopPropagation();
  643. this.feed.deleteEntry(this);
  644. },
  645. onClick: function(/*object*/e){
  646. // summary:
  647. // Attach point for when a row is clicked on.
  648. // description:
  649. // Attach point for when a row is clicked on.
  650. //
  651. // e:
  652. // The event generated by the click.
  653. }
  654. });
  655. dojo.declare("dojox.atom.widget.FeedViewerGrouping",[dijit._Widget, dijit._Templated],{
  656. // summary:
  657. // Grouping of feed entries.
  658. // description:
  659. // Grouping of feed entries.
  660. templateString: dojo.cache("dojox.atom", "widget/templates/FeedViewerGrouping.html", "<tr dojoAttachPoint=\"groupingNode\" class=\"feedViewerGrouping\">\n\t<td colspan=\"2\" dojoAttachPoint=\"titleNode\" class=\"feedViewerGroupingTitle\">\n\t</td>\n</tr>\n"),
  661. groupingNode: null,
  662. titleNode: null,
  663. setText: function(text){
  664. // summary:
  665. // Sets the text to be shown above this grouping.
  666. // description:
  667. // Sets the text to be shown above this grouping.
  668. //
  669. // text:
  670. // The text to show.
  671. if (this.titleNode.lastChild){this.titleNode.removeChild(this.titleNode.lastChild);}
  672. var textNode = document.createTextNode(text);
  673. this.titleNode.appendChild(textNode);
  674. }
  675. });
  676. dojo.declare("dojox.atom.widget.AtomEntryCategoryFilter",[dijit._Widget, dijit._Templated],{
  677. // summary:
  678. // A filter to be applied to the list of entries.
  679. // description:
  680. // A filter to be applied to the list of entries.
  681. scheme: "",
  682. term: "",
  683. label: "",
  684. isFilter: true
  685. });
  686. dojo.declare("dojox.atom.widget.FeedViewer.CategoryIncludeFilter",null,{
  687. constructor: function(scheme, term, label){
  688. // summary:
  689. // The initializer function.
  690. // description:
  691. // The initializer function.
  692. this.scheme = scheme;
  693. this.term = term;
  694. this.label = label;
  695. },
  696. match: function(entry) {
  697. // summary:
  698. // Function to determine if this category filter matches against a category on an atom entry
  699. // description:
  700. // Function to determine if this category filter matches against a category on an atom entry
  701. //
  702. // returns:
  703. // boolean denoting if this category filter matched to this entry.
  704. var matched = false;
  705. if (entry !== null) {
  706. var categories = entry.categories;
  707. if (categories !== null) {
  708. for (var i = 0; i < categories.length; i++) {
  709. var category = categories[i];
  710. if (this.scheme !== "") {
  711. if (this.scheme !== category.scheme) {
  712. break;
  713. }
  714. }
  715. if (this.term !== "") {
  716. if (this.term !== category.term) {
  717. break;
  718. }
  719. }
  720. if (this.label !== "") {
  721. if (this.label !== category.label) {
  722. break;
  723. }
  724. }
  725. //Made it this far, everything matched.
  726. matched = true;
  727. }
  728. }
  729. }
  730. return matched;
  731. }
  732. });
  733. }