source: Dev/branches/rest-dojo-ui/client/dojox/widget/FeedPortlet.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 12.6 KB
Line 
1dojo.provide("dojox.widget.FeedPortlet");
2dojo.require("dojox.widget.Portlet");
3dojo.require("dijit.Tooltip");
4dojo.require("dijit.form.TextBox");
5dojo.require("dijit.form.Button");
6dojo.require("dojox.data.GoogleFeedStore");
7
8dojo.declare("dojox.widget.FeedPortlet", dojox.widget.Portlet, {
9        // summary:
10        //              A Portlet that loads a XML feed.
11        // description: The feed is displayed as
12        //              an unordered list of links.     When a link is hovered over
13        //              by the mouse, it displays a summary in a tooltip.
14
15        // local: Boolean
16        //              Specifies whether the feed is to be loaded from the same domain as the
17        //              page, or a remote domain.       If local is true, then the feed must be an
18        //              Atom feed.      If it is false, it can be an Atom or RSS feed.
19        local: false,
20
21        // maxResults: Number
22        //              The number of results to display from the feed.
23        maxResults: 5,
24
25        // url: String
26        //              The URL of the feed to load.    If this is different to the domain
27        //              of the HTML page, local should be set to false.
28        url: "",
29
30        // openNew: Boolean
31        //              If true, when a link is clicked it will open in a new window.
32        //              If false, it will not.
33        openNew: true,
34
35        // useFeedTitle: Boolean
36        //              If true, the title of the loaded feed is displayed in the title bar of the portlet.
37        //              If false, the title remains unchanged.
38        showFeedTitle: true,
39
40        postCreate: function(){
41                this.inherited(arguments);
42                if(this.local && !dojox.data.AtomReadStore){
43                        throw Error(this.declaredClass + ": To use local feeds, you must include dojox.data.AtomReadStore on the page.");
44                }
45        },
46
47        onFeedError: function(){
48                // summary:
49                //              Called when a feed fails to load successfully.
50                this.containerNode.innerHTML = "Error accessing the feed."
51        },
52
53        addChild: function(child){
54                this.inherited(arguments);
55                var url = child.attr("feedPortletUrl");
56                if(url){
57                        this.set("url", url);
58                }
59        },
60
61        _getTitle: function(item){
62                // summary:
63                //              Gets the title of a feed item.
64                var t = this.store.getValue(item, "title");
65                return this.local ? t.text : t;
66        },
67
68        _getLink: function(item){
69                // summary:
70                //              Gets the href link of a feed item.
71                var l = this.store.getValue(item, "link");
72                return this.local ? l.href : l;
73        },
74
75        _getContent: function(item){
76                // summary:
77                //              Gets the summary of a feed item.
78                var c = this.store.getValue(item, "summary");
79                if(!c){
80                        return null;
81                }
82                if(this.local){
83                        c = c.text;
84                }
85                // Filter out any sneaky scripts in the code
86                c = c.split("<script").join("<!--").split("</script>").join("-->");
87                c = c.split("<iframe").join("<!--").split("</iframe>").join("-->");
88                return c;
89
90        },
91
92        _setUrlAttr: function(url){
93                // summary:
94                //              Sets the URL to load.
95                this.url = url;
96                if(this._started){
97                        this.load();
98                }
99        },
100
101        startup: function(){
102                // summary:
103                //              Loads the widget.
104                if(this.started || this._started){return;}
105
106                this.inherited(arguments);
107
108                if(!this.url || this.url == ""){
109                        throw new Error(this.id + ": A URL must be specified for the feed portlet");
110                }
111                if(this.url && this.url != ""){
112                        this.load();
113                }
114        },
115
116        load: function(){
117                // summary:
118                //              Loads the feed.
119                if(this._resultList){
120                        dojo.destroy(this._resultList);
121                }
122                var store, query;
123
124                // If the feed is on the same domain, use the AtomReadStore,
125                // as we cannot be guaranteed that it will be available to
126                // Google services.
127                if(this.local){
128                        store = new dojox.data.AtomReadStore({
129                                url: this.url
130                        });
131                        query = {};
132
133                }else{
134                        store = new dojox.data.GoogleFeedStore();
135                        query = {url: this.url};
136                }
137                var request = {
138                        query: query,
139                        count: this.maxResults,
140                        onComplete: dojo.hitch(this, function(items){
141                                if (this.showFeedTitle && store.getFeedValue) {
142                                        var title = this.store.getFeedValue("title");
143                                        if(title){
144                                                this.set("title", title.text ? title.text : title);
145                                        }
146                                }
147                                this.generateResults(items);
148                        }),
149                        onError: dojo.hitch(this, "onFeedError")
150                };
151
152                this.store = store;
153                store.fetch(request);
154        },
155
156        generateResults: function (items){
157                // summary:
158                //              Generates a list of hyperlinks and displays a tooltip
159                //              containing a summary when the mouse hovers over them.
160                var store = this.store;
161                var timer;
162                var ul = (this._resultList =
163                        dojo.create("ul", {"class" : "dojoxFeedPortletList"}, this.containerNode));
164
165                dojo.forEach(items, dojo.hitch(this, function(item){
166                        var li = dojo.create("li", {
167                                innerHTML: '<a href="'
168                                        + this._getLink(item)
169                                        + '"'
170                                        + (this.openNew ? ' target="_blank"' : '')
171                                        +'>'
172                                        + this._getTitle(item) + '</a>'
173                        },ul);
174
175                        dojo.connect(li, "onmouseover", dojo.hitch(this, function(evt){
176                                if(timer){
177                                        clearTimeout(timer);
178                                }
179
180                                // Show the tooltip after the mouse has been hovering
181                                // for a short time.
182                                timer = setTimeout(dojo.hitch(this, function(){
183                                        timer = null;
184                                        var summary = this._getContent(item);
185                                        if(!summary){return;}
186                                        var content = '<div class="dojoxFeedPortletPreview">'
187                                                + summary + '</div>'
188
189                                        dojo.query("li", ul).forEach(function(item){
190                                                if(item != evt.target){
191                                                        dijit.hideTooltip(item);
192                                                }
193                                        });
194
195                                        // Hover the tooltip over the anchor tag
196                                        dijit.showTooltip(content, li.firstChild, !this.isLeftToRight());
197                                }), 500);
198
199
200                        }));
201
202                        // Hide the tooltip when the mouse leaves a list item.
203                        dojo.connect(li, "onmouseout", function(){
204                                if(timer){
205                                        clearTimeout(timer);
206                                        timer = null;
207                                }
208                                dijit.hideTooltip(li.firstChild);
209                        });
210                }));
211
212                this.resize();
213        }
214});
215
216dojo.declare("dojox.widget.ExpandableFeedPortlet", dojox.widget.FeedPortlet, {
217        // summary:
218        //              A FeedPortlet that uses an list of expandable links to display
219        //              a feed. An icon is placed to the left of each item
220        //              which, when clicked, toggles the visible state
221        //              of the item summary.
222
223        // onlyOpenOne: Boolean
224        //              If true, only a single item can be expanded at any given time.
225        onlyOpenOne: false,
226
227        generateResults: function(items){
228                // summary:
229                //              Generates a list of items, and places an icon beside them that
230                //              can be used to show or hide a summary of that item.
231
232                var store = this.store;
233                var iconCls = "dojoxPortletToggleIcon";
234                var collapsedCls = "dojoxPortletItemCollapsed";
235                var expandedCls = "dojoxPortletItemOpen";
236
237                var timer;
238                var ul = (this._resultList = dojo.create("ul", {
239                        "class": "dojoxFeedPortletExpandableList"
240                }, this.containerNode));
241
242                // Create the LI elements.      Each LI has two DIV elements, the
243                // top DIV contains the toggle icon and title, and the bottom
244                // div contains the extended summary.
245                dojo.forEach(items, dojo.hitch(this, dojo.hitch(this, function(item){
246                        var li = dojo.create("li", {"class": collapsedCls}, ul);
247                        var upper = dojo.create("div", {style: "width: 100%;"}, li);
248                        var lower = dojo.create("div", {"class": "dojoxPortletItemSummary", innerHTML: this._getContent(item)}, li);
249                        dojo.create("span", {
250                                "class": iconCls,
251                                innerHTML: "<img src='" + dojo.config.baseUrl + "/resources/blank.gif'>"}, upper);
252                        var a = dojo.create("a", {href: this._getLink(item), innerHTML: this._getTitle(item) }, upper);
253
254                        if(this.openNew){
255                                dojo.attr(a, "target", "_blank");
256                        }
257                })));
258
259                // Catch all clicks on the list. If a toggle icon is clicked,
260                // toggle the visible state of the summary DIV.
261                dojo.connect(ul, "onclick", dojo.hitch(this, function(evt){
262                        if(dojo.hasClass(evt.target, iconCls) || dojo.hasClass(evt.target.parentNode, iconCls)){
263                                dojo.stopEvent(evt);
264                                var li = evt.target.parentNode;
265                                while(li.tagName != "LI"){
266                                        li = li.parentNode;
267                                }
268                                if(this.onlyOpenOne){
269                                        dojo.query("li", ul).filter(function(item){
270                                                return item != li;
271                                        }).removeClass(expandedCls).addClass(collapsedCls);
272                                }
273                                var isExpanded = dojo.hasClass(li, expandedCls);
274                                dojo.toggleClass(li, expandedCls, !isExpanded);
275                                dojo.toggleClass(li, collapsedCls, isExpanded);
276                        }
277                }));
278        }
279});
280
281
282dojo.declare("dojox.widget.PortletFeedSettings",
283        dojox.widget.PortletSettings, {
284
285        // summary:
286        //              A Settings widget designed to be used with a dojox.widget.FeedPortlet
287        // description:
288        //              It provides form items that the user can use to change the URL
289        //              for a feed to load into the FeedPortlet.
290        //              There are two forms that it can take.   <br>
291        //              The first is to display a text field, with Load and Cancel buttons,
292        //              which is prepopulated with the enclosing FeedPortlet's URL.
293        //              If a <select> DOM node is used as the source node for this widget,
294        //              it displays a list of predefined URLs that the user can select from
295        //              to load into the enclosing FeedPortlet.
296        //
297        // example:
298        //              <div dojoType="dojox.widget.PortletFeedSettings"></div>
299        //
300        // example:
301        //              <select dojoType="dojox.widget.PortletFeedSettings">
302        //                      <option>http://www.dojotoolkit.org/aggregator/rss</option>
303        //                      <option>http://dojocampus.org/content/category/podcast/feed/</option>
304        //              </select>
305
306        "class" : "dojoxPortletFeedSettings",
307
308        // urls: Array
309        //              An array of JSON object specifying URLs to display in the
310        //              PortletFeedSettings object. Each object contains a 'url' and 'label'
311        //              attribute, e.g.
312        //              [{url:'http:google.com', label:'Google'}, {url:'http://dojotoolkit.org', label: 'Dojo'}]
313        urls: null,
314
315        // selectedIndex: Number
316        //              The selected URL. Defaults to zero.
317        selectedIndex: 0,
318
319        buildRendering: function(){
320                // If JSON URLs have been specified, create a SELECT DOM node,
321                // and insert the required OPTION elements.
322                var s;
323                if(this.urls && this.urls.length > 0){
324                        console.log(this.id + " -> creating select with urls ", this.urls)
325                        s = dojo.create("select");
326                        if(this.srcNodeRef){
327                                dojo.place(s, this.srcNodeRef, "before");
328                                dojo.destroy(this.srcNodeRef);
329                        }
330                        this.srcNodeRef = s;
331                        dojo.forEach(this.urls, function(url){
332                                dojo.create("option", {value: url.url || url, innerHTML: url.label || url}, s);
333                        });
334                }
335
336                // If the srcNodeRef is a SELECT node, then replace it with a DIV, and insert
337                // the SELECT node into that div.
338                if(this.srcNodeRef.tagName == "SELECT"){
339                        this.text = this.srcNodeRef;
340                        var div = dojo.create("div", {}, this.srcNodeRef, "before");
341                        div.appendChild(this.text);
342                        this.srcNodeRef = div;
343                        dojo.query("option", this.text).filter("return !item.value;").forEach("item.value = item.innerHTML");
344                        if(!this.text.value){
345                                if(this.content && this.text.options.length == 0){
346                                        this.text.appendChild(this.content);
347                                }
348                                dojo.attr(s || this.text, "value", this.text.options[this.selectedIndex].value);
349                        }
350                }
351                this.inherited(arguments);
352        },
353
354        _setContentAttr: function(){
355
356        },
357
358        postCreate: function(){
359                console.log(this.id + " -> postCreate");
360                if(!this.text){
361                        // If a select node is not being used, create a new TextBox to
362                        // edit the URL.
363                        var text = this.text = new dijit.form.TextBox({});
364                        dojo.create("span", {
365                                innerHTML: "Choose Url: "
366                        }, this.domNode);
367                        this.addChild(text);
368                }
369
370                // Add a LOAD button
371                this.addChild(new dijit.form.Button({
372                        label: "Load",
373                        onClick: dojo.hitch(this, function(){
374                                // Set the URL of the containing Portlet with the selected URL.
375                                this.portlet.attr("url",
376                                        (this.text.tagName == "SELECT") ? this.text.value : this.text.attr('value'));
377                                if(this.text.tagName == "SELECT"){
378                                        // Set the selected index on the Select node.
379                                        dojo.some(this.text.options, dojo.hitch(this, function(opt, idx){
380                                                if(opt.selected){
381                                                        this.set("selectedIndex", idx);
382                                                        return true;
383                                                }
384                                                return false;
385                                        }));
386                                }
387                                // Hide the widget.
388                                this.toggle();
389                        })
390                }));
391
392                // Add a CANCEL button, which hides this widget
393                this.addChild(new dijit.form.Button({
394                        label: "Cancel",
395                        onClick: dojo.hitch(this, "toggle")
396                }));
397                this.inherited(arguments);
398        },
399
400        startup: function(){
401                // summary:
402                //              Sets the portlet associated with this PortletSettings object.
403                if(this._started){return;}
404                console.log(this.id + " -> startup");
405                this.inherited(arguments);
406
407                if(!this.portlet){
408                        throw Error(this.declaredClass + ": A PortletFeedSettings widget cannot exist without a Portlet.");
409                }
410                if(this.text.tagName == "SELECT"){
411                        // Set the initial selected option.
412                        dojo.forEach(this.text.options, dojo.hitch(this, function(opt, index){
413                                dojo.attr(opt, "selected", index == this.selectedIndex);
414                        }));
415                }
416                var url = this.portlet.attr("url");
417                if(url){
418                        // If a SELECT node is used to choose a URL, ensure that the Portlet's URL
419                        // is one of the options.
420                        if(this.text.tagName == "SELECT"){
421                                if(!this.urls && dojo.query("option[value='" + url + "']", this.text).length < 1){
422                                        dojo.place(dojo.create("option", {
423                                                value: url,
424                                                innerHTML: url,
425                                                selected: "true"
426                                        }), this.text, "first");
427                                }
428                        }else{
429                                this.text.attr("value", url);
430                        }
431                }else{
432                        this.portlet.attr("url", this.get("feedPortletUrl"));
433                }
434        },
435
436        _getFeedPortletUrlAttr: function(){
437                return this.text.value;
438        }
439});
Note: See TracBrowser for help on using the repository browser.