source: Dev/trunk/src/client/dojox/widget/FeedPortlet.js @ 485

Last change on this file since 485 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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