]>
Commit | Line | Data |
---|---|---|
1 | define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct) { | |
2 | ||
3 | return declare("fox.FeedTree", dijit.Tree, { | |
4 | _onKeyPress: function(/* Event */ e) { | |
5 | return; // Stop dijit.Tree from interpreting keystrokes | |
6 | }, | |
7 | _createTreeNode: function(args) { | |
8 | var tnode = new dijit._TreeNode(args); | |
9 | ||
10 | var icon = dojo.doc.createElement('img'); | |
11 | if (args.item.icon && args.item.icon[0]) { | |
12 | icon.src = args.item.icon[0]; | |
13 | } else { | |
14 | icon.src = 'images/blank_icon.gif'; | |
15 | } | |
16 | icon.className = 'tinyFeedIcon'; | |
17 | domConstruct.place(icon, tnode.iconNode, 'only'); | |
18 | ||
19 | var id = args.item.id[0]; | |
20 | var bare_id = parseInt(id.substr(id.indexOf(':')+1)); | |
21 | ||
22 | if (bare_id < _label_base_index) { | |
23 | var span = dojo.doc.createElement('span'); | |
24 | var fg_color = args.item.fg_color[0]; | |
25 | var bg_color = args.item.bg_color[0]; | |
26 | ||
27 | span.innerHTML = "α"; | |
28 | span.className = 'labelColorIndicator'; | |
29 | span.setStyle({ | |
30 | color: fg_color, | |
31 | backgroundColor: bg_color}); | |
32 | ||
33 | domConstruct.place(span, tnode.iconNode, 'only'); | |
34 | } | |
35 | ||
36 | if (id.match("FEED:")) { | |
37 | var menu = new dijit.Menu(); | |
38 | menu.row_id = bare_id; | |
39 | ||
40 | menu.addChild(new dijit.MenuItem({ | |
41 | label: __("Mark as read"), | |
42 | onClick: function() { | |
43 | catchupFeed(this.getParent().row_id); | |
44 | }})); | |
45 | ||
46 | if (bare_id > 0) { | |
47 | menu.addChild(new dijit.MenuItem({ | |
48 | label: __("Edit feed"), | |
49 | onClick: function() { | |
50 | editFeed(this.getParent().row_id, false); | |
51 | }})); | |
52 | ||
53 | /* menu.addChild(new dijit.MenuItem({ | |
54 | label: __("Update feed"), | |
55 | onClick: function() { | |
56 | heduleFeedUpdate(this.getParent().row_id, false); | |
57 | }})); */ | |
58 | } | |
59 | ||
60 | menu.bindDomNode(tnode.domNode); | |
61 | tnode._menu = menu; | |
62 | } | |
63 | ||
64 | if (id.match("CAT:") && bare_id >= 0) { | |
65 | var menu = new dijit.Menu(); | |
66 | menu.row_id = bare_id; | |
67 | ||
68 | menu.addChild(new dijit.MenuItem({ | |
69 | label: __("Mark as read"), | |
70 | onClick: function() { | |
71 | catchupFeed(this.getParent().row_id, true); | |
72 | }})); | |
73 | ||
74 | menu.addChild(new dijit.MenuItem({ | |
75 | label: __("(Un)collapse"), | |
76 | onClick: function() { | |
77 | dijit.byId("feedTree").collapseCat(this.getParent().row_id); | |
78 | }})); | |
79 | ||
80 | menu.bindDomNode(tnode.domNode); | |
81 | tnode._menu = menu; | |
82 | } | |
83 | ||
84 | if (id.match("CAT:")) { | |
85 | loading = dojo.doc.createElement('img'); | |
86 | loading.className = 'loadingNode'; | |
87 | loading.src = 'images/blank_icon.gif'; | |
88 | domConstruct.place(loading, tnode.labelNode, 'after'); | |
89 | tnode.loadingNode = loading; | |
90 | } | |
91 | ||
92 | if (id.match("CAT:") && bare_id == -1) { | |
93 | var menu = new dijit.Menu(); | |
94 | menu.row_id = bare_id; | |
95 | ||
96 | menu.addChild(new dijit.MenuItem({ | |
97 | label: __("Mark all feeds as read"), | |
98 | onClick: function() { | |
99 | catchupAllFeeds(); | |
100 | }})); | |
101 | ||
102 | menu.bindDomNode(tnode.domNode); | |
103 | tnode._menu = menu; | |
104 | } | |
105 | ||
106 | ctr = dojo.doc.createElement('span'); | |
107 | ctr.className = 'counterNode'; | |
108 | ctr.innerHTML = args.item.unread > 0 ? args.item.unread : args.item.auxcounter; | |
109 | ||
110 | //args.item.unread > 0 ? ctr.addClassName("unread") : ctr.removeClassName("unread"); | |
111 | ||
112 | args.item.unread > 0 || args.item.auxcounter > 0 ? Element.show(ctr) : Element.hide(ctr); | |
113 | ||
114 | args.item.unread == 0 && args.item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); | |
115 | ||
116 | domConstruct.place(ctr, tnode.rowNode, 'first'); | |
117 | tnode.counterNode = ctr; | |
118 | ||
119 | //tnode.labelNode.innerHTML = args.label; | |
120 | return tnode; | |
121 | }, | |
122 | postCreate: function() { | |
123 | this.connect(this.model, "onChange", "updateCounter"); | |
124 | this.connect(this, "_expandNode", function() { | |
125 | this.hideRead(getInitParam("hide_read_feeds"), getInitParam("hide_read_shows_special")); | |
126 | }); | |
127 | ||
128 | this.inherited(arguments); | |
129 | }, | |
130 | updateCounter: function (item) { | |
131 | var tree = this; | |
132 | ||
133 | //console.log("updateCounter: " + item.id[0] + " " + item.unread + " " + tree); | |
134 | ||
135 | var node = tree._itemNodesMap[item.id]; | |
136 | ||
137 | if (node) { | |
138 | node = node[0]; | |
139 | ||
140 | if (node.counterNode) { | |
141 | ctr = node.counterNode; | |
142 | ctr.innerHTML = item.unread > 0 ? item.unread : item.auxcounter; | |
143 | item.unread > 0 || item.auxcounter > 0 ? | |
144 | item.unread > 0 ? | |
145 | Effect.Appear(ctr, {duration : 0.3, | |
146 | queue: { position: 'end', scope: 'CAPPEAR-' + item.id, limit: 1 }}) : | |
147 | Element.show(ctr) : | |
148 | Element.hide(ctr); | |
149 | ||
150 | item.unread == 0 && item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); | |
151 | ||
152 | } | |
153 | } | |
154 | ||
155 | }, | |
156 | getTooltip: function (item) { | |
157 | if (item.updated) | |
158 | return item.updated; | |
159 | else | |
160 | return ""; | |
161 | }, | |
162 | getIconClass: function (item, opened) { | |
163 | return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon"; | |
164 | }, | |
165 | getLabelClass: function (item, opened) { | |
166 | return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread"; | |
167 | }, | |
168 | getRowClass: function (item, opened) { | |
169 | var rc = (!item.error || item.error == '') ? "dijitTreeRow" : | |
170 | "dijitTreeRow Error"; | |
171 | ||
172 | if (item.unread > 0) rc += " Unread"; | |
173 | if (item.updates_disabled > 0) rc += " UpdatesDisabled"; | |
174 | ||
175 | return rc; | |
176 | }, | |
177 | getLabel: function(item) { | |
178 | var name = String(item.name); | |
179 | ||
180 | /* Horrible */ | |
181 | name = name.replace(/"/g, "\""); | |
182 | name = name.replace(/&/g, "&"); | |
183 | name = name.replace(/—/g, "-"); | |
184 | name = name.replace(/</g, "<"); | |
185 | name = name.replace(/>/g, ">"); | |
186 | ||
187 | /* var label; | |
188 | ||
189 | if (item.unread > 0) { | |
190 | label = name + " (" + item.unread + ")"; | |
191 | } else { | |
192 | label = name; | |
193 | } */ | |
194 | ||
195 | return name; | |
196 | }, | |
197 | expandParentNodes: function(feed, is_cat, list) { | |
198 | try { | |
199 | for (var i = 0; i < list.length; i++) { | |
200 | var id = String(list[i].id); | |
201 | var item = this._itemNodesMap[id]; | |
202 | ||
203 | if (item) { | |
204 | item = item[0]; | |
205 | this._expandNode(item); | |
206 | } | |
207 | } | |
208 | } catch (e) { | |
209 | exception_error(e); | |
210 | } | |
211 | }, | |
212 | findNodeParentsAndExpandThem: function(feed, is_cat, root, parents) { | |
213 | // expands all parents of specified feed to properly mark it as active | |
214 | // my fav thing about frameworks is doing everything myself | |
215 | try { | |
216 | var test_id = is_cat ? 'CAT:' + feed : 'FEED:' + feed; | |
217 | ||
218 | if (!root) { | |
219 | if (!this.model || !this.model.store) return false; | |
220 | ||
221 | var items = this.model.store._arrayOfTopLevelItems; | |
222 | ||
223 | for (var i = 0; i < items.length; i++) { | |
224 | if (String(items[i].id) == test_id) { | |
225 | this.expandParentNodes(feed, is_cat, parents); | |
226 | } else { | |
227 | this.findNodeParentsAndExpandThem(feed, is_cat, items[i], []); | |
228 | } | |
229 | } | |
230 | } else { | |
231 | if (root.items) { | |
232 | parents.push(root); | |
233 | ||
234 | for (var i = 0; i < root.items.length; i++) { | |
235 | if (String(root.items[i].id) == test_id) { | |
236 | this.expandParentNodes(feed, is_cat, parents); | |
237 | } else { | |
238 | this.findNodeParentsAndExpandThem(feed, is_cat, root.items[i], parents.slice(0)); | |
239 | } | |
240 | } | |
241 | } else { | |
242 | if (String(root.id) == test_id) { | |
243 | this.expandParentNodes(feed, is_cat, parents.slice(0)); | |
244 | } | |
245 | } | |
246 | } | |
247 | } catch (e) { | |
248 | exception_error(e); | |
249 | } | |
250 | }, | |
251 | selectFeed: function(feed, is_cat) { | |
252 | this.findNodeParentsAndExpandThem(feed, is_cat, false, false); | |
253 | ||
254 | if (is_cat) | |
255 | treeNode = this._itemNodesMap['CAT:' + feed]; | |
256 | else | |
257 | treeNode = this._itemNodesMap['FEED:' + feed]; | |
258 | ||
259 | if (treeNode) { | |
260 | treeNode = treeNode[0]; | |
261 | if (!is_cat) this._expandNode(treeNode); | |
262 | this.set("selectedNodes", [treeNode]); | |
263 | this.focusNode(treeNode); | |
264 | ||
265 | // focus headlines to route key events there | |
266 | setTimeout(function() { | |
267 | $("headlines-frame").focus(); | |
268 | }, 0); | |
269 | } | |
270 | }, | |
271 | setFeedIcon: function(feed, is_cat, src) { | |
272 | if (is_cat) | |
273 | treeNode = this._itemNodesMap['CAT:' + feed]; | |
274 | else | |
275 | treeNode = this._itemNodesMap['FEED:' + feed]; | |
276 | ||
277 | if (treeNode) { | |
278 | treeNode = treeNode[0]; | |
279 | var icon = dojo.doc.createElement('img'); | |
280 | icon.src = src; | |
281 | icon.className = 'tinyFeedIcon'; | |
282 | domConstruct.place(icon, treeNode.iconNode, 'only'); | |
283 | return true; | |
284 | } | |
285 | return false; | |
286 | }, | |
287 | setFeedExpandoIcon: function(feed, is_cat, src) { | |
288 | if (is_cat) | |
289 | treeNode = this._itemNodesMap['CAT:' + feed]; | |
290 | else | |
291 | treeNode = this._itemNodesMap['FEED:' + feed]; | |
292 | ||
293 | if (treeNode) { | |
294 | treeNode = treeNode[0]; | |
295 | if (treeNode.loadingNode) { | |
296 | treeNode.loadingNode.src = src; | |
297 | return true; | |
298 | } else { | |
299 | var icon = dojo.doc.createElement('img'); | |
300 | icon.src = src; | |
301 | icon.className = 'loadingExpando'; | |
302 | domConstruct.place(icon, treeNode.expandoNode, 'only'); | |
303 | return true; | |
304 | } | |
305 | } | |
306 | ||
307 | return false; | |
308 | }, | |
309 | hasCats: function() { | |
310 | return this.model.hasCats(); | |
311 | }, | |
312 | hideReadCat: function (cat, hide, show_special) { | |
313 | if (this.hasCats()) { | |
314 | var tree = this; | |
315 | ||
316 | if (cat && cat.items) { | |
317 | var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special); | |
318 | ||
319 | var id = String(cat.id); | |
320 | var node = tree._itemNodesMap[id]; | |
321 | var bare_id = parseInt(id.substr(id.indexOf(":")+1)); | |
322 | ||
323 | if (node) { | |
324 | var check_unread = tree.model.getFeedUnread(bare_id, true); | |
325 | ||
326 | if (hide && cat_unread == 0 && check_unread == 0 && (id != "CAT:-1" || !show_special)) { | |
327 | Effect.Fade(node[0].rowNode, {duration : 0.3, | |
328 | queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }}); | |
329 | } else { | |
330 | Element.show(node[0].rowNode); | |
331 | ++cat_unread; | |
332 | } | |
333 | } | |
334 | } | |
335 | } | |
336 | }, | |
337 | hideRead: function (hide, show_special) { | |
338 | if (this.hasCats()) { | |
339 | ||
340 | var tree = this; | |
341 | var cats = this.model.store._arrayOfTopLevelItems; | |
342 | ||
343 | cats.each(function(cat) { | |
344 | tree.hideReadCat(cat, hide, show_special); | |
345 | }); | |
346 | ||
347 | } else { | |
348 | this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide, | |
349 | show_special); | |
350 | } | |
351 | }, | |
352 | hideReadFeeds: function (items, hide, show_special) { | |
353 | var tree = this; | |
354 | var cat_unread = 0; | |
355 | ||
356 | items.each(function(feed) { | |
357 | var id = String(feed.id); | |
358 | ||
359 | // it's a subcategory | |
360 | if (feed.items) { | |
361 | tree.hideReadCat(feed, hide, show_special); | |
362 | } else { // it's a feed | |
363 | var bare_id = parseInt(feed.bare_id);; | |
364 | ||
365 | var unread = feed.unread[0]; | |
366 | var has_error = feed.error[0] != ''; | |
367 | var node = tree._itemNodesMap[id]; | |
368 | ||
369 | if (node) { | |
370 | if (hide && unread == 0 && !has_error && (bare_id > 0 || bare_id < _label_base_index || !show_special)) { | |
371 | Effect.Fade(node[0].rowNode, {duration : 0.3, | |
372 | queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }}); | |
373 | } else { | |
374 | Element.show(node[0].rowNode); | |
375 | ++cat_unread; | |
376 | } | |
377 | } | |
378 | } | |
379 | }); | |
380 | ||
381 | return cat_unread; | |
382 | }, | |
383 | collapseCat: function(id) { | |
384 | if (!this.model.hasCats()) return; | |
385 | ||
386 | var tree = this; | |
387 | ||
388 | var node = tree._itemNodesMap['CAT:' + id][0]; | |
389 | var item = tree.model.store._itemsByIdentity['CAT:' + id]; | |
390 | ||
391 | if (node && item) { | |
392 | if (!node.isExpanded) | |
393 | tree._expandNode(node); | |
394 | else | |
395 | tree._collapseNode(node); | |
396 | ||
397 | } | |
398 | }, | |
399 | getVisibleUnreadFeeds: function() { | |
400 | var items = this.model.store._arrayOfAllItems; | |
401 | var rv = []; | |
402 | ||
403 | for (var i = 0; i < items.length; i++) { | |
404 | var id = String(items[i].id); | |
405 | var box = this._itemNodesMap[id]; | |
406 | ||
407 | if (box) { | |
408 | var row = box[0].rowNode; | |
409 | var cat = false; | |
410 | ||
411 | try { | |
412 | cat = box[0].rowNode.parentNode.parentNode; | |
413 | } catch (e) { } | |
414 | ||
415 | if (row) { | |
416 | if (Element.visible(row) && (!cat || Element.visible(cat))) { | |
417 | var feed_id = String(items[i].bare_id); | |
418 | var is_cat = !id.match('FEED:'); | |
419 | var unread = this.model.getFeedUnread(feed_id, is_cat); | |
420 | ||
421 | if (unread > 0) | |
422 | rv.push([feed_id, is_cat]); | |
423 | ||
424 | } | |
425 | } | |
426 | } | |
427 | } | |
428 | ||
429 | return rv; | |
430 | }, | |
431 | getNextFeed: function (feed, is_cat) { | |
432 | if (is_cat) { | |
433 | treeItem = this.model.store._itemsByIdentity['CAT:' + feed]; | |
434 | } else { | |
435 | treeItem = this.model.store._itemsByIdentity['FEED:' + feed]; | |
436 | } | |
437 | ||
438 | items = this.model.store._arrayOfAllItems; | |
439 | var item = items[0]; | |
440 | ||
441 | for (var i = 0; i < items.length; i++) { | |
442 | if (items[i] == treeItem) { | |
443 | ||
444 | for (var j = i+1; j < items.length; j++) { | |
445 | var id = String(items[j].id); | |
446 | var box = this._itemNodesMap[id]; | |
447 | ||
448 | if (box) { | |
449 | var row = box[0].rowNode; | |
450 | var cat = box[0].rowNode.parentNode.parentNode; | |
451 | ||
452 | if (Element.visible(cat) && Element.visible(row)) { | |
453 | item = items[j]; | |
454 | break; | |
455 | } | |
456 | } | |
457 | } | |
458 | break; | |
459 | } | |
460 | } | |
461 | ||
462 | if (item) { | |
463 | return [this.model.store.getValue(item, 'bare_id'), | |
464 | !this.model.store.getValue(item, 'id').match('FEED:')]; | |
465 | } else { | |
466 | return false; | |
467 | } | |
468 | }, | |
469 | getPreviousFeed: function (feed, is_cat) { | |
470 | if (is_cat) { | |
471 | treeItem = this.model.store._itemsByIdentity['CAT:' + feed]; | |
472 | } else { | |
473 | treeItem = this.model.store._itemsByIdentity['FEED:' + feed]; | |
474 | } | |
475 | ||
476 | items = this.model.store._arrayOfAllItems; | |
477 | var item = items[0] == treeItem ? items[items.length-1] : items[0]; | |
478 | ||
479 | for (var i = 0; i < items.length; i++) { | |
480 | if (items[i] == treeItem) { | |
481 | ||
482 | for (var j = i-1; j > 0; j--) { | |
483 | var id = String(items[j].id); | |
484 | var box = this._itemNodesMap[id]; | |
485 | ||
486 | if (box) { | |
487 | var row = box[0].rowNode; | |
488 | var cat = box[0].rowNode.parentNode.parentNode; | |
489 | ||
490 | if (Element.visible(cat) && Element.visible(row)) { | |
491 | item = items[j]; | |
492 | break; | |
493 | } | |
494 | } | |
495 | ||
496 | } | |
497 | break; | |
498 | } | |
499 | } | |
500 | ||
501 | if (item) { | |
502 | return [this.model.store.getValue(item, 'bare_id'), | |
503 | !this.model.store.getValue(item, 'id').match('FEED:')]; | |
504 | } else { | |
505 | return false; | |
506 | } | |
507 | ||
508 | }, | |
509 | getFeedCategory: function(feed) { | |
510 | try { | |
511 | return this.getNodesByItem(this.model.store. | |
512 | _itemsByIdentity["FEED:" + feed])[0]. | |
513 | getParent().item.bare_id[0]; | |
514 | ||
515 | } catch (e) { | |
516 | return false; | |
517 | } | |
518 | }, | |
519 | }); | |
520 | }); | |
521 |