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