1 # -*- Mode
: C
++; tab
-width
: 8; indent
-tabs
-mode
: nil
; c
-basic
-offset
: 2 -*- */
2 # ***** BEGIN LICENSE BLOCK
*****
3 # Version
: MPL
1.1/GPL 2.0/LGPL
2.1
5 # The contents
of this file are subject to the Mozilla Public License Version
6 # 1.1 (the
"License"); you may not
use this file except
in compliance
with
7 # the License
. You may obtain a copy
of the License at
8 # http
://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an
"AS IS" basis
,
11 # WITHOUT WARRANTY OF ANY KIND
, either express or implied
. See the License
12 # for the specific language governing rights and limitations under the
15 # The Original Code is the Feed Writer
.
17 # The Initial Developer
of the Original Code is Google Inc
.
18 # Portions created by the Initial Developer are
Copyright (C
) 2006
19 # the Initial Developer
. All Rights Reserved
.
22 # Ben Goodger
<beng
@google
.com
>
23 # Jeff Walden
<jwalden
+code
@mit
.edu
>
24 # Asaf Romano
<mano
@mozilla
.com
>
25 # Robert Sayre
<sayrer
@gmail
.com
>
26 # Michael Ventnor
<m
.ventnor
@gmail
.com
>
27 # Will Guaraldi
<will
.guaraldi
@pculture
.org
>
29 # Alternatively
, the contents
of this file may be used under the terms
of
30 # either the GNU General Public License Version
2 or
later (the
"GPL"), or
31 # the GNU Lesser General Public License Version
2.1 or
later (the
"LGPL"),
32 # in which
case the provisions
of the GPL or the LGPL are applicable instead
33 # of those above
. If you wish to allow
use of your version
of this file only
34 # under the terms
of either the GPL or the LGPL
, and not to allow others to
35 # use your version
of this file under the terms
of the MPL
, indicate your
36 # decision by deleting the provisions above and replace them
with the notice
37 # and other provisions required by the GPL or the LGPL
. If you
do not
delete
38 # the provisions above
, a recipient may
use your version
of this file under
39 # the terms
of any one
of the MPL
, the GPL or the LGPL
.
41 # ***** END LICENSE BLOCK
***** */
43 const Cc
= Components
.classes
;
44 const Ci
= Components
.interfaces
;
45 const Cr
= Components
.results
;
46 const Cu
= Components
.utils
;
48 Cu
.import("resource://gre/modules/XPCOMUtils.jsm");
51 var prefB
= Cc
["@mozilla.org/preferences-service;1"].
52 getService(Ci
.nsIPrefBranch
);
54 var shouldLog
= false;
56 shouldLog
= prefB
.getBoolPref("feeds.log");
62 dump("*** Feeds: " + str
+ "\n");
66 * Wrapper function for nsIIOService::newURI.
68 * The URL string from which to create an nsIURI.
69 * @returns an nsIURI object, or null if the creation of the URI failed.
71 function makeURI(aURLSpec
, aCharset
) {
72 var ios
= Cc
["@mozilla.org/network/io-service;1"].
73 getService(Ci
.nsIIOService
);
75 return ios
.newURI(aURLSpec
, aCharset
, null);
81 const XML_NS
= "http://www.w3.org/XML/1998/namespace"
82 const HTML_NS
= "http://www.w3.org/1999/xhtml";
83 const XUL_NS
= "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
84 const TYPE_MAYBE_FEED
= "application/vnd.mozilla.maybe.feed";
85 const TYPE_MAYBE_AUDIO_FEED
= "application/vnd.mozilla.maybe.audio.feed";
86 const TYPE_MAYBE_VIDEO_FEED
= "application/vnd.mozilla.maybe.video.feed";
87 const URI_BUNDLE
= "chrome://browser/locale/feeds/subscribe.properties";
88 const SUBSCRIBE_PAGE_URI
= "chrome://browser/content/feeds/subscribe.xhtml";
90 const PREF_SELECTED_APP
= "browser.feeds.handlers.application";
91 const PREF_SELECTED_WEB
= "browser.feeds.handlers.webservice";
92 const PREF_SELECTED_ACTION
= "browser.feeds.handler";
93 const PREF_SELECTED_READER
= "browser.feeds.handler.default";
95 const PREF_VIDEO_SELECTED_APP
= "browser.videoFeeds.handlers.application";
96 const PREF_VIDEO_SELECTED_WEB
= "browser.videoFeeds.handlers.webservice";
97 const PREF_VIDEO_SELECTED_ACTION
= "browser.videoFeeds.handler";
98 const PREF_VIDEO_SELECTED_READER
= "browser.videoFeeds.handler.default";
100 const PREF_AUDIO_SELECTED_APP
= "browser.audioFeeds.handlers.application";
101 const PREF_AUDIO_SELECTED_WEB
= "browser.audioFeeds.handlers.webservice";
102 const PREF_AUDIO_SELECTED_ACTION
= "browser.audioFeeds.handler";
103 const PREF_AUDIO_SELECTED_READER
= "browser.audioFeeds.handler.default";
105 const PREF_SHOW_FIRST_RUN_UI
= "browser.feeds.showFirstRunUI";
107 const TITLE_ID
= "feedTitleText";
108 const SUBTITLE_ID
= "feedSubtitleText";
110 function getPrefAppForType(t
) {
112 case Ci
.nsIFeed
.TYPE_VIDEO
:
113 return PREF_VIDEO_SELECTED_APP
;
115 case Ci
.nsIFeed
.TYPE_AUDIO
:
116 return PREF_AUDIO_SELECTED_APP
;
119 return PREF_SELECTED_APP
;
123 function getPrefWebForType(t
) {
125 case Ci
.nsIFeed
.TYPE_VIDEO
:
126 return PREF_VIDEO_SELECTED_WEB
;
128 case Ci
.nsIFeed
.TYPE_AUDIO
:
129 return PREF_AUDIO_SELECTED_WEB
;
132 return PREF_SELECTED_WEB
;
136 function getPrefActionForType(t
) {
138 case Ci
.nsIFeed
.TYPE_VIDEO
:
139 return PREF_VIDEO_SELECTED_ACTION
;
141 case Ci
.nsIFeed
.TYPE_AUDIO
:
142 return PREF_AUDIO_SELECTED_ACTION
;
145 return PREF_SELECTED_ACTION
;
149 function getPrefReaderForType(t
) {
151 case Ci
.nsIFeed
.TYPE_VIDEO
:
152 return PREF_VIDEO_SELECTED_READER
;
154 case Ci
.nsIFeed
.TYPE_AUDIO
:
155 return PREF_AUDIO_SELECTED_READER
;
158 return PREF_SELECTED_READER
;
163 * Converts a number of bytes to the appropriate unit that results in a
164 * number that needs fewer than 4 digits
166 * @return a pair: [new value with 3 sig. figs., its unit]
168 function convertByteUnits(aBytes
) {
169 var units
= ["bytes", "kilobyte", "megabyte", "gigabyte"];
172 // convert to next unit if it needs 4 digits (after rounding), but only if
173 // we know the name of the next unit
174 while ((aBytes
>= 999.5) && (unitIndex
< units
.length
- 1)) {
179 // Get rid of insignificant bits by truncating to 1 or 0 decimal points
180 // 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235
181 aBytes
= aBytes
.toFixed((aBytes
> 0) && (aBytes
< 100) ? 1 : 0);
183 return [aBytes
, units
[unitIndex
]];
186 function FeedWriter() {}
187 FeedWriter
.prototype = {
188 _mimeSvc
: Cc
["@mozilla.org/mime;1"].
189 getService(Ci
.nsIMIMEService
),
191 _getPropertyAsBag
: function FW__getPropertyAsBag(container
, property
) {
192 return container
.fields
.getProperty(property
).
193 QueryInterface(Ci
.nsIPropertyBag2
);
196 _getPropertyAsString
: function FW__getPropertyAsString(container
, property
) {
198 return container
.fields
.getPropertyAsAString(property
);
205 _setContentText
: function FW__setContentText(id
, text
) {
206 this._contentSandbox
.element
= this._document
.getElementById(id
);
207 this._contentSandbox
.textNode
= this._document
.createTextNode(text
);
209 "while (element.hasChildNodes()) " +
210 " element.removeChild(element.firstChild);" +
211 "element.appendChild(textNode);";
212 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
213 this._contentSandbox
.element
= null;
214 this._contentSandbox
.textNode
= null;
218 * Safely sets the href attribute on an anchor tag, providing the URI
219 * specified can be loaded according to rules.
221 * The element to set a URI attribute on
223 * The attribute of the element to set the URI to, e.g. href or src
225 * The URI spec to set as the href
227 _safeSetURIAttribute
:
228 function FW__safeSetURIAttribute(element
, attribute
, uri
) {
229 var secman
= Cc
["@mozilla.org/scriptsecuritymanager;1"].
230 getService(Ci
.nsIScriptSecurityManager
);
231 const flags
= Ci
.nsIScriptSecurityManager
.DISALLOW_INHERIT_PRINCIPAL
;
233 secman
.checkLoadURIStrWithPrincipal(this._feedPrincipal
, uri
, flags
);
234 // checkLoadURIStrWithPrincipal will throw if the link URI should not be
235 // loaded, either because our feedURI isn't allowed to load it or per
236 // the rules specified in |flags|, so we'll never "linkify" the link...
239 // Not allowed to load this link because secman.checkLoadURIStr threw
243 this._contentSandbox
.element
= element
;
244 this._contentSandbox
.uri
= uri
;
245 var codeStr
= "element.setAttribute('" + attribute
+ "', uri);";
246 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
250 * Use this sandbox to run any dom manipulation code on nodes which
251 * are already inserted into the content document.
253 __contentSandbox
: null,
254 get _contentSandbox() {
255 if (!this.__contentSandbox
)
256 this.__contentSandbox
= new Cu
.Sandbox(this._window
);
258 return this.__contentSandbox
;
262 * Calls doCommand for a the given XUL element within the context of the
266 * the XUL element to call doCommand() on.
268 _safeDoCommand
: function FW___safeDoCommand(aElement
) {
269 this._contentSandbox
.element
= aElement
;
270 Cu
.evalInSandbox("element.doCommand();", this._contentSandbox
);
271 this._contentSandbox
.element
= null;
274 __faviconService
: null,
275 get _faviconService() {
276 if (!this.__faviconService
)
277 this.__faviconService
= Cc
["@mozilla.org/browser/favicon-service;1"].
278 getService(Ci
.nsIFaviconService
);
280 return this.__faviconService
;
285 if (!this.__bundle
) {
286 this.__bundle
= Cc
["@mozilla.org/intl/stringbundle;1"].
287 getService(Ci
.nsIStringBundleService
).
288 createBundle(URI_BUNDLE
);
290 return this.__bundle
;
293 _getFormattedString
: function FW__getFormattedString(key
, params
) {
294 return this._bundle
.formatStringFromName(key
, params
, params
.length
);
297 _getString
: function FW__getString(key
) {
298 return this._bundle
.GetStringFromName(key
);
301 /* Magic helper methods to be used instead of xbl properties */
302 _getSelectedItemFromMenulist
: function FW__getSelectedItemFromList(aList
) {
303 var node
= aList
.firstChild
.firstChild
;
305 if (node
.localName
== "menuitem" && node
.getAttribute("selected") == "true")
308 node
= node
.nextSibling
;
314 _setCheckboxCheckedState
: function FW__setCheckboxCheckedState(aCheckbox
, aValue
) {
315 // see checkbox.xml, xbl bindings are not applied within the sandbox!
316 this._contentSandbox
.checkbox
= aCheckbox
;
318 var change
= (aValue
!= (aCheckbox
.getAttribute('checked') == 'true'));
320 codeStr
= "checkbox.setAttribute('checked', 'true'); ";
322 codeStr
= "checkbox.removeAttribute('checked'); ";
325 this._contentSandbox
.document
= this._document
;
326 codeStr
+= "var event = document.createEvent('Events'); " +
327 "event.initEvent('CheckboxStateChange', true, true);" +
328 "checkbox.dispatchEvent(event);"
331 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
335 * Returns a date suitable for displaying in the feed preview.
336 * If the date cannot be parsed, the return value is "false".
338 * A date as extracted from a feed entry. (entry.updated)
340 _parseDate
: function FW__parseDate(dateString
) {
341 // Convert the date into the user's local time zone
342 dateObj
= new Date(dateString
);
344 // Make sure the date we're given is valid.
345 if (!dateObj
.getTime())
348 var dateService
= Cc
["@mozilla.org/intl/scriptabledateformat;1"].
349 getService(Ci
.nsIScriptableDateFormat
);
350 return dateService
.FormatDateTime("", dateService
.dateFormatLong
, dateService
.timeFormatNoSeconds
,
351 dateObj
.getFullYear(), dateObj
.getMonth()+1, dateObj
.getDate(),
352 dateObj
.getHours(), dateObj
.getMinutes(), dateObj
.getSeconds());
356 * Returns the feed type.
359 _getFeedType
: function FW__getFeedType() {
360 if (this.__feedType
!= null)
361 return this.__feedType
;
364 // grab the feed because it's got the feed.type in it.
365 var container
= this._getContainer();
366 var feed
= container
.QueryInterface(Ci
.nsIFeed
);
367 this.__feedType
= feed
.type
;
371 return Ci
.nsIFeed
.TYPE_FEED
;
375 * Maps a feed type to a maybe-feed mimetype.
377 _getMimeTypeForFeedType
: function FW__getMimeTypeForFeedType() {
378 switch (this._getFeedType()) {
379 case Ci
.nsIFeed
.TYPE_VIDEO
:
380 return TYPE_MAYBE_VIDEO_FEED
;
382 case Ci
.nsIFeed
.TYPE_AUDIO
:
383 return TYPE_MAYBE_AUDIO_FEED
;
386 return TYPE_MAYBE_FEED
;
391 * Writes the feed title into the preview document.
395 _setTitleText
: function FW__setTitleText(container
) {
396 if (container
.title
) {
397 var title
= container
.title
.plainText();
398 this._setContentText(TITLE_ID
, title
);
399 this._contentSandbox
.document
= this._document
;
400 this._contentSandbox
.title
= title
;
401 var codeStr
= "document.title = title;"
402 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
405 var feed
= container
.QueryInterface(Ci
.nsIFeed
);
406 if (feed
&& feed
.subtitle
)
407 this._setContentText(SUBTITLE_ID
, container
.subtitle
.plainText());
411 * Writes the title image into the preview document if one is present.
415 _setTitleImage
: function FW__setTitleImage(container
) {
417 var parts
= container
.image
;
419 // Set up the title image (supplied by the feed)
420 var feedTitleImage
= this._document
.getElementById("feedTitleImage");
421 this._safeSetURIAttribute(feedTitleImage
, "src",
422 parts
.getPropertyAsAString("url"));
424 // Set up the title image link
425 var feedTitleLink
= this._document
.getElementById("feedTitleLink");
427 var titleText
= this._getFormattedString("linkTitleTextFormat",
428 [parts
.getPropertyAsAString("title")]);
429 this._contentSandbox
.feedTitleLink
= feedTitleLink
;
430 this._contentSandbox
.titleText
= titleText
;
431 this._contentSandbox
.feedTitleText
= this._document
.getElementById("feedTitleText");
432 this._contentSandbox
.titleImageWidth
= parseInt(parts
.getPropertyAsAString("width")) + 15;
434 // Fix the margin on the main title, so that the image doesn't run over
436 var codeStr
= "feedTitleLink.setAttribute('title', titleText); " +
437 "feedTitleText.style.marginRight = titleImageWidth + 'px';";
438 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
439 this._contentSandbox
.feedTitleLink
= null;
440 this._contentSandbox
.titleText
= null;
441 this._contentSandbox
.feedTitleText
= null;
442 this._contentSandbox
.titleImageWidth
= null;
444 this._safeSetURIAttribute(feedTitleLink
, "href",
445 parts
.getPropertyAsAString("link"));
448 LOG("Failed to set Title Image (this is benign): " + e
);
453 * Writes all entries contained in the feed.
455 * The container of entries in the feed
457 _writeFeedContent
: function FW__writeFeedContent(container
) {
458 // Build the actual feed content
459 var feed
= container
.QueryInterface(Ci
.nsIFeed
);
460 if (feed
.items
.length
== 0)
463 this._contentSandbox
.feedContent
=
464 this._document
.getElementById("feedContent");
466 for (var i
= 0; i
< feed
.items
.length
; ++i
) {
467 var entry
= feed
.items
.queryElementAt(i
, Ci
.nsIFeedEntry
);
468 entry
.QueryInterface(Ci
.nsIFeedContainer
);
470 var entryContainer
= this._document
.createElementNS(HTML_NS
, "div");
471 entryContainer
.className
= "entry";
473 // If the entry has a title, make it a link
475 var a
= this._document
.createElementNS(HTML_NS
, "a");
476 a
.appendChild(this._document
.createTextNode(entry
.title
.plainText()));
478 // Entries are not required to have links, so entry.link can be null.
480 this._safeSetURIAttribute(a
, "href", entry
.link
.spec
);
482 var title
= this._document
.createElementNS(HTML_NS
, "h3");
483 title
.appendChild(a
);
485 var lastUpdated
= this._parseDate(entry
.updated
);
487 var dateDiv
= this._document
.createElementNS(HTML_NS
, "div");
488 dateDiv
.className
= "lastUpdated";
489 dateDiv
.textContent
= lastUpdated
;
490 title
.appendChild(dateDiv
);
493 entryContainer
.appendChild(title
);
496 var body
= this._document
.createElementNS(HTML_NS
, "div");
497 var summary
= entry
.summary
|| entry
.content
;
498 var docFragment
= null;
501 body
.setAttributeNS(XML_NS
, "base", summary
.base
.spec
);
504 docFragment
= summary
.createDocumentFragment(body
);
506 body
.appendChild(docFragment
);
508 // If the entry doesn't have a title, append a # permalink
509 // See http://scripting.com/rss.xml for an example
510 if (!entry
.title
&& entry
.link
) {
511 var a
= this._document
.createElementNS(HTML_NS
, "a");
512 a
.appendChild(this._document
.createTextNode("#"));
513 this._safeSetURIAttribute(a
, "href", entry
.link
.spec
);
514 body
.appendChild(this._document
.createTextNode(" "));
519 body
.className
= "feedEntryContent";
520 entryContainer
.appendChild(body
);
522 if (entry
.enclosures
&& entry
.enclosures
.length
> 0) {
523 var enclosuresDiv
= this._buildEnclosureDiv(entry
);
524 entryContainer
.appendChild(enclosuresDiv
);
527 this._contentSandbox
.entryContainer
= entryContainer
;
528 this._contentSandbox
.clearDiv
=
529 this._document
.createElementNS(HTML_NS
, "div");
530 this._contentSandbox
.clearDiv
.style
.clear
= "both";
532 var codeStr
= "feedContent.appendChild(entryContainer); " +
533 "feedContent.appendChild(clearDiv);"
534 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
537 this._contentSandbox
.feedContent
= null;
538 this._contentSandbox
.entryContainer
= null;
539 this._contentSandbox
.clearDiv
= null;
543 * Takes a url to a media item and returns the best name it can come up with.
544 * Frequently this is the filename portion (e.g. passing in
545 * http://example.com/foo.mpeg would return "foo.mpeg"), but in more complex
546 * cases, this will return the entire url (e.g. passing in
547 * http://example.com/somedirectory/ would return
548 * http://example.com/somedirectory/).
550 * The URL string from which to create a display name
553 _getURLDisplayName
: function FW__getURLDisplayName(aURL
) {
554 var url
= makeURI(aURL
);
555 url
.QueryInterface(Ci
.nsIURL
);
556 if (url
== null || url
.fileName
.length
== 0)
559 return decodeURI(url
.fileName
);
563 * Takes a FeedEntry with enclosures, generates the HTML code to represent
564 * them, and returns that.
566 * FeedEntry with enclosures
569 _buildEnclosureDiv
: function FW__buildEnclosureDiv(entry
) {
570 var enclosuresDiv
= this._document
.createElementNS(HTML_NS
, "div");
571 enclosuresDiv
.className
= "enclosures";
573 enclosuresDiv
.appendChild(this._document
.createTextNode(this._getString("mediaLabel")));
575 var roundme = function(n
) {
576 return (Math
.round(n
* 100) / 100).toLocaleString();
579 for (var i_enc
= 0; i_enc
< entry
.enclosures
.length
; ++i_enc
) {
580 var enc
= entry
.enclosures
.queryElementAt(i_enc
, Ci
.nsIWritablePropertyBag2
);
582 if (!(enc
.hasKey("url")))
585 var enclosureDiv
= this._document
.createElementNS(HTML_NS
, "div");
586 enclosureDiv
.setAttribute("class", "enclosure");
588 var mozicon
= "moz-icon://.txt?size=16";
589 var type_text
= null;
590 var size_text
= null;
592 if (enc
.hasKey("type")) {
593 type_text
= enc
.get("type");
595 var handlerInfoWrapper
= this._mimeSvc
.getFromTypeAndExtension(enc
.get("type"), null);
597 if (handlerInfoWrapper
)
598 type_text
= handlerInfoWrapper
.description
;
600 if (type_text
&& type_text
.length
> 0)
601 mozicon
= "moz-icon://goat?size=16&contentType=" + enc
.get("type");
607 if (enc
.hasKey("length") && /^[0-9]+$/.test(enc
.get("length"))) {
608 var enc_size
= convertByteUnits(parseInt(enc
.get("length")));
610 var size_text
= this._getFormattedString("enclosureSizeText",
611 [enc_size
[0], this._getString(enc_size
[1])]);
614 var iconimg
= this._document
.createElementNS(HTML_NS
, "img");
615 iconimg
.setAttribute("src", mozicon
);
616 iconimg
.setAttribute("class", "type-icon");
617 enclosureDiv
.appendChild(iconimg
);
619 enclosureDiv
.appendChild(this._document
.createTextNode( " " ));
621 var enc_href
= this._document
.createElementNS(HTML_NS
, "a");
622 enc_href
.appendChild(this._document
.createTextNode(this._getURLDisplayName(enc
.get("url"))));
623 this._safeSetURIAttribute(enc_href
, "href", enc
.get("url"));
624 enclosureDiv
.appendChild(enc_href
);
626 if (type_text
&& size_text
)
627 enclosureDiv
.appendChild(this._document
.createTextNode( " (" + type_text
+ ", " + size_text
+ ")"));
630 enclosureDiv
.appendChild(this._document
.createTextNode( " (" + type_text
+ ")"))
633 enclosureDiv
.appendChild(this._document
.createTextNode( " (" + size_text
+ ")"))
635 enclosuresDiv
.appendChild(enclosureDiv
);
638 return enclosuresDiv
;
642 * Gets a valid nsIFeedContainer object from the parsed nsIFeedResult.
643 * Displays error information if there was one.
645 * The parsed feed result
646 * @returns A valid nsIFeedContainer object containing the contents of
649 _getContainer
: function FW__getContainer(result
) {
651 Cc
["@mozilla.org/browser/feeds/result-service;1"].
652 getService(Ci
.nsIFeedResultService
);
656 feedService
.getFeedResult(this._getOriginalURI(this._window
));
659 LOG("Subscribe Preview: feed not available?!");
663 LOG("Subscribe Preview: feed result is bozo?!");
667 var container
= result
.doc
;
670 LOG("Subscribe Preview: no result.doc? Why didn't the original reload?");
677 * Get the human-readable display name of a file. This could be the
680 * A nsIFile to look up the name of
681 * @returns The display name of the application represented by the file.
683 _getFileDisplayName
: function FW__getFileDisplayName(file
) {
685 if (file
instanceof Ci
.nsILocalFileWin
) {
687 return file
.getVersionInfoField("FileDescription");
694 var lfm
= file
.QueryInterface(Ci
.nsILocalFileMac
);
696 return lfm
.bundleDisplayName
;
699 // fall through to the file name
703 Cc
["@mozilla.org/network/io-service;1"].
704 getService(Ci
.nsIIOService
);
705 var url
= ios
.newFileURI(file
).QueryInterface(Ci
.nsIURL
);
710 * Get moz-icon url for a file
712 * A nsIFile object for which the moz-icon:// is returned
713 * @returns moz-icon url of the given file as a string
715 _getFileIconURL
: function FW__getFileIconURL(file
) {
716 var ios
= Cc
["@mozilla.org/network/io-service;1"].
717 getService(Components
.interfaces
.nsIIOService
);
718 var fph
= ios
.getProtocolHandler("file")
719 .QueryInterface(Ci
.nsIFileProtocolHandler
);
720 var urlSpec
= fph
.getURLSpecFromFile(file
);
721 return "moz-icon://" + urlSpec
+ "?size=16";
725 * Helper method to set the selected application and system default
726 * reader menuitems details from a file object
728 * The menuitem on which the attributes should be set
730 * The menuitem's associated file
732 _initMenuItemWithFile: function(aMenuItem
, aFile
) {
733 this._contentSandbox
.menuitem
= aMenuItem
;
734 this._contentSandbox
.label
= this._getFileDisplayName(aFile
);
735 this._contentSandbox
.image
= this._getFileIconURL(aFile
);
736 var codeStr
= "menuitem.setAttribute('label', label); " +
737 "menuitem.setAttribute('image', image);"
738 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
742 * Displays a prompt from which the user may choose a (client) feed reader.
743 * @return - true if a feed reader was selected, false otherwise.
745 _chooseClientApp
: function FW__chooseClientApp() {
747 var fp
= Cc
["@mozilla.org/filepicker;1"].createInstance(Ci
.nsIFilePicker
);
748 fp
.init(this._window
,
749 this._getString("chooseApplicationDialogTitle"),
750 Ci
.nsIFilePicker
.modeOpen
);
751 fp
.appendFilters(Ci
.nsIFilePicker
.filterApps
);
753 if (fp
.show() == Ci
.nsIFilePicker
.returnOK
) {
754 this._selectedApp
= fp
.file
;
755 if (this._selectedApp
) {
756 // XXXben - we need to compare this with the running instance executable
757 // just don't know how to do that via script...
758 // XXXmano TBD: can probably add this to nsIShellService
760 #expand
if (fp
.file
.leafName
!= "__MOZ_APP_NAME__.exe") {
763 #expand
if (fp
.file
.leafName
!= "__MOZ_APP_DISPLAYNAME__.app") {
765 #expand
if (fp
.file
.leafName
!= "__MOZ_APP_NAME__-bin") {
768 this._initMenuItemWithFile(this._contentSandbox
.selectedAppMenuItem
,
771 // Show and select the selected application menuitem
772 var codeStr
= "selectedAppMenuItem.hidden = false;" +
773 "selectedAppMenuItem.doCommand();"
774 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
785 _setAlwaysUseCheckedState
: function FW__setAlwaysUseCheckedState(feedType
) {
786 var checkbox
= this._document
.getElementById("alwaysUse");
788 var alwaysUse
= false;
790 var prefs
= Cc
["@mozilla.org/preferences-service;1"].
791 getService(Ci
.nsIPrefBranch
);
792 if (prefs
.getCharPref(getPrefActionForType(feedType
)) != "ask")
796 this._setCheckboxCheckedState(checkbox
, alwaysUse
);
800 _setSubscribeUsingLabel
: function FW__setSubscribeUsingLabel() {
801 var stringLabel
= "subscribeFeedUsing";
802 switch (this._getFeedType()) {
803 case Ci
.nsIFeed
.TYPE_VIDEO
:
804 stringLabel
= "subscribeVideoPodcastUsing";
807 case Ci
.nsIFeed
.TYPE_AUDIO
:
808 stringLabel
= "subscribeAudioPodcastUsing";
812 this._contentSandbox
.subscribeUsing
=
813 this._document
.getElementById("subscribeUsingDescription");
814 this._contentSandbox
.label
= this._getString(stringLabel
);
815 var codeStr
= "subscribeUsing.setAttribute('value', label);"
816 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
819 _setAlwaysUseLabel
: function FW__setAlwaysUseLabel() {
820 var checkbox
= this._document
.getElementById("alwaysUse");
822 var handlersMenuList
= this._document
.getElementById("handlersMenuList");
823 if (handlersMenuList
) {
824 var handlerName
= this._getSelectedItemFromMenulist(handlersMenuList
)
825 .getAttribute("label");
826 var stringLabel
= "alwaysUseForFeeds";
827 switch (this._getFeedType()) {
828 case Ci
.nsIFeed
.TYPE_VIDEO
:
829 stringLabel
= "alwaysUseForVideoPodcasts";
832 case Ci
.nsIFeed
.TYPE_AUDIO
:
833 stringLabel
= "alwaysUseForAudioPodcasts";
837 this._contentSandbox
.checkbox
= checkbox
;
838 this._contentSandbox
.label
= this._getFormattedString(stringLabel
, [handlerName
]);
840 var codeStr
= "checkbox.setAttribute('label', label);";
841 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
846 // nsIDomEventListener
847 handleEvent: function(event
) {
848 // see comments in init()
849 event
= new XPCNativeWrapper(event
);
850 if (event
.target
.ownerDocument
!= this._document
) {
851 LOG("FeedWriter.handleEvent: Someone passed the feed writer as a listener to the events of another document!");
855 if (event
.type
== "command") {
856 switch (event
.target
.id
) {
857 case "subscribeButton":
860 case "chooseApplicationMenuItem":
861 /* Bug 351263: Make sure to not steal focus if the "Choose
862 * Application" item is being selected with the keyboard. We do this
863 * by ignoring command events while the dropdown is closed (user
864 * arrowing through the combobox), but handling them while the
865 * combobox dropdown is open (user pressed enter when an item was
866 * selected). If we don't show the filepicker here, it will be shown
867 * when clicking "Subscribe Now".
869 var popupbox
= this._document
.getElementById("handlersMenuList")
870 .firstChild
.boxObject
;
871 popupbox
.QueryInterface(Components
.interfaces
.nsIPopupBoxObject
);
872 if (popupbox
.popupState
== "hiding" && !this._chooseClientApp()) {
873 // Select the (per-prefs) selected handler if no application was
875 this._setSelectedHandler(this._getFeedType());
879 this._setAlwaysUseLabel();
884 _setSelectedHandler
: function FW__setSelectedHandler(feedType
) {
886 Cc
["@mozilla.org/preferences-service;1"].
887 getService(Ci
.nsIPrefBranch
);
889 var handler
= "bookmarks";
891 handler
= prefs
.getCharPref(getPrefReaderForType(feedType
));
897 var handlersMenuList
= this._document
.getElementById("handlersMenuList");
898 if (handlersMenuList
) {
899 var url
= prefs
.getComplexValue(getPrefWebForType(feedType
), Ci
.nsISupportsString
).data
;
901 handlersMenuList
.getElementsByAttribute("webhandlerurl", url
);
902 if (handlers
.length
== 0) {
903 LOG("FeedWriter._setSelectedHandler: selected web handler isn't in the menulist")
907 this._safeDoCommand(handlers
[0]);
914 prefs
.getComplexValue(getPrefAppForType(feedType
), Ci
.nsILocalFile
);
917 this._selectedApp
= null;
920 if (this._selectedApp
) {
921 this._initMenuItemWithFile(this._contentSandbox
.selectedAppMenuItem
,
923 var codeStr
= "selectedAppMenuItem.hidden = false; " +
924 "selectedAppMenuItem.doCommand(); ";
926 // Only show the default reader menuitem if the default reader
927 // isn't the selected application
928 if (this._defaultSystemReader
) {
930 this._defaultSystemReader
.path
== this._selectedApp
.path
;
931 codeStr
+= "defaultHandlerMenuItem.hidden = " + shouldHide
+ ";"
933 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
939 var liveBookmarksMenuItem
= this._document
.getElementById("liveBookmarksMenuItem");
940 if (liveBookmarksMenuItem
)
941 this._safeDoCommand(liveBookmarksMenuItem
);
946 _initSubscriptionUI
: function FW__initSubscriptionUI() {
947 var handlersMenuPopup
= this._document
.getElementById("handlersMenuPopup");
948 if (!handlersMenuPopup
)
951 var feedType
= this._getFeedType();
954 // change the background
955 var header
= this._document
.getElementById("feedHeader");
956 this._contentSandbox
.header
= header
;
958 case Ci
.nsIFeed
.TYPE_VIDEO
:
959 codeStr
= "header.className = 'videoPodcastBackground'; ";
962 case Ci
.nsIFeed
.TYPE_AUDIO
:
963 codeStr
= "header.className = 'audioPodcastBackground'; ";
967 codeStr
= "header.className = 'feedBackground'; ";
971 // Last-selected application
972 var menuItem
= this._document
.createElementNS(XUL_NS
, "menuitem");
973 menuItem
.id
= "selectedAppMenuItem";
974 menuItem
.className
= "menuitem-iconic";
975 menuItem
.setAttribute("handlerType", "client");
977 var prefs
= Cc
["@mozilla.org/preferences-service;1"].
978 getService(Ci
.nsIPrefBranch
);
979 this._selectedApp
= prefs
.getComplexValue(getPrefAppForType(feedType
),
982 if (this._selectedApp
.exists())
983 this._initMenuItemWithFile(menuItem
, this._selectedApp
);
985 // Hide the menuitem if the last selected application doesn't exist
986 menuItem
.setAttribute("hidden", true);
990 // Hide the menuitem until an application is selected
991 menuItem
.setAttribute("hidden", true);
993 this._contentSandbox
.handlersMenuPopup
= handlersMenuPopup
;
994 this._contentSandbox
.selectedAppMenuItem
= menuItem
;
996 codeStr
+= "handlersMenuPopup.appendChild(selectedAppMenuItem); ";
998 // List the default feed reader
1000 this._defaultSystemReader
= Cc
["@mozilla.org/browser/shell-service;1"].
1001 getService(Ci
.nsIShellService
).
1003 menuItem
= this._document
.createElementNS(XUL_NS
, "menuitem");
1004 menuItem
.id
= "defaultHandlerMenuItem";
1005 menuItem
.className
= "menuitem-iconic";
1006 menuItem
.setAttribute("handlerType", "client");
1008 this._initMenuItemWithFile(menuItem
, this._defaultSystemReader
);
1010 // Hide the default reader item if it points to the same application
1011 // as the last-selected application
1012 if (this._selectedApp
&&
1013 this._selectedApp
.path
== this._defaultSystemReader
.path
)
1014 menuItem
.hidden
= true;
1016 catch(ex
) { menuItem
= null; /* no default reader */ }
1019 this._contentSandbox
.defaultHandlerMenuItem
= menuItem
;
1020 codeStr
+= "handlersMenuPopup.appendChild(defaultHandlerMenuItem); ";
1023 // "Choose Application..." menuitem
1024 menuItem
= this._document
.createElementNS(XUL_NS
, "menuitem");
1025 menuItem
.id
= "chooseApplicationMenuItem";
1026 menuItem
.setAttribute("label", this._getString("chooseApplicationMenuItem"));
1028 this._contentSandbox
.chooseAppMenuItem
= menuItem
;
1029 codeStr
+= "handlersMenuPopup.appendChild(chooseAppMenuItem); ";
1032 this._contentSandbox
.chooseAppSep
=
1033 this._document
.createElementNS(XUL_NS
, "menuseparator")
1034 codeStr
+= "handlersMenuPopup.appendChild(chooseAppSep); ";
1036 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
1038 var historySvc
= Cc
["@mozilla.org/browser/nav-history-service;1"].
1039 getService(Ci
.nsINavHistoryService
);
1040 historySvc
.addObserver(this, false);
1042 // List of web handlers
1043 var wccr
= Cc
["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
1044 getService(Ci
.nsIWebContentConverterService
);
1045 var handlers
= wccr
.getContentHandlers(this._getMimeTypeForFeedType(feedType
), {});
1046 if (handlers
.length
!= 0) {
1047 for (var i
= 0; i
< handlers
.length
; ++i
) {
1048 menuItem
= this._document
.createElementNS(XUL_NS
, "menuitem");
1049 menuItem
.className
= "menuitem-iconic";
1050 menuItem
.setAttribute("label", handlers
[i
].name
);
1051 menuItem
.setAttribute("handlerType", "web");
1052 menuItem
.setAttribute("webhandlerurl", handlers
[i
].uri
);
1053 this._contentSandbox
.menuItem
= menuItem
;
1054 codeStr
= "handlersMenuPopup.appendChild(menuItem);";
1055 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
1057 // For privacy reasons we cannot set the image attribute directly
1058 // to the icon url, see Bug 358878
1059 var uri
= makeURI(handlers
[i
].uri
);
1060 if (!this._setFaviconForWebReader(uri
, menuItem
)) {
1061 if (uri
&& /^https?/.test(uri
.scheme
)) {
1062 var iconURL
= makeURI(uri
.prePath
+ "/favicon.ico");
1063 this._faviconService
.setAndLoadFaviconForPage(uri
, iconURL
, true);
1067 this._contentSandbox
.menuItem
= null;
1070 this._setSelectedHandler(feedType
);
1072 // "Subscribe using..."
1073 this._setSubscribeUsingLabel();
1075 // "Always use..." checkbox initial state
1076 this._setAlwaysUseCheckedState(feedType
);
1077 this._setAlwaysUseLabel();
1079 // We update the "Always use.." checkbox label whenever the selected item
1080 // in the list is changed
1081 handlersMenuPopup
.addEventListener("command", this, false);
1083 // Set up the "Subscribe Now" button
1085 .getElementById("subscribeButton")
1086 .addEventListener("command", this, false);
1089 var showFirstRunUI
= true;
1091 showFirstRunUI
= prefs
.getBoolPref(PREF_SHOW_FIRST_RUN_UI
);
1094 if (showFirstRunUI
) {
1095 var textfeedinfo1
, textfeedinfo2
;
1097 case Ci
.nsIFeed
.TYPE_VIDEO
:
1098 textfeedinfo1
= "feedSubscriptionVideoPodcast1";
1099 textfeedinfo2
= "feedSubscriptionVideoPodcast2";
1101 case Ci
.nsIFeed
.TYPE_AUDIO
:
1102 textfeedinfo1
= "feedSubscriptionAudioPodcast1";
1103 textfeedinfo2
= "feedSubscriptionAudioPodcast2";
1106 textfeedinfo1
= "feedSubscriptionFeed1";
1107 textfeedinfo2
= "feedSubscriptionFeed2";
1110 this._contentSandbox
.feedinfo1
=
1111 this._document
.getElementById("feedSubscriptionInfo1");
1112 this._contentSandbox
.feedinfo1Str
= this._getString(textfeedinfo1
);
1113 this._contentSandbox
.feedinfo2
=
1114 this._document
.getElementById("feedSubscriptionInfo2");
1115 this._contentSandbox
.feedinfo2Str
= this._getString(textfeedinfo2
);
1116 this._contentSandbox
.header
= header
;
1117 codeStr
= "feedinfo1.value = feedinfo1Str; " +
1118 "feedinfo2.value = feedinfo2Str; " +
1119 "header.setAttribute('firstrun', 'true');"
1120 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
1121 prefs
.setBoolPref(PREF_SHOW_FIRST_RUN_UI
, false);
1126 * Returns the original URI object of the feed and ensures that this
1127 * component is only ever invoked from the preview document.
1129 * The window of the document invoking the BrowserFeedWriter
1131 _getOriginalURI
: function FW__getOriginalURI(aWindow
) {
1132 var chan
= aWindow
.QueryInterface(Ci
.nsIInterfaceRequestor
).
1133 getInterface(Ci
.nsIWebNavigation
).
1134 QueryInterface(Ci
.nsIDocShell
).currentDocumentChannel
;
1136 var uri
= makeURI(SUBSCRIBE_PAGE_URI
);
1137 var resolvedURI
= Cc
["@mozilla.org/chrome/chrome-registry;1"].
1138 getService(Ci
.nsIChromeRegistry
).
1139 convertChromeURL(uri
);
1141 if (resolvedURI
.equals(chan
.URI
))
1142 return chan
.originalURI
;
1150 _feedPrincipal
: null,
1153 init
: function FW_init(aWindow
) {
1154 // Explicitly wrap |window| in an XPCNativeWrapper to make sure
1155 // it's a real native object! This will throw an exception if we
1156 // get a non-native object.
1157 var window
= new XPCNativeWrapper(aWindow
);
1158 this._feedURI
= this._getOriginalURI(window
);
1162 this._window
= window
;
1163 this._document
= window
.document
;
1165 var secman
= Cc
["@mozilla.org/scriptsecuritymanager;1"].
1166 getService(Ci
.nsIScriptSecurityManager
);
1167 this._feedPrincipal
= secman
.getCodebasePrincipal(this._feedURI
);
1169 LOG("Subscribe Preview: feed uri = " + this._window
.location
.href
);
1171 // Set up the subscription UI
1172 this._initSubscriptionUI();
1173 var prefs
= Cc
["@mozilla.org/preferences-service;1"].
1174 getService(Ci
.nsIPrefBranch2
);
1175 prefs
.addObserver(PREF_SELECTED_ACTION
, this, false);
1176 prefs
.addObserver(PREF_SELECTED_READER
, this, false);
1177 prefs
.addObserver(PREF_SELECTED_WEB
, this, false);
1178 prefs
.addObserver(PREF_SELECTED_APP
, this, false);
1179 prefs
.addObserver(PREF_VIDEO_SELECTED_ACTION
, this, false);
1180 prefs
.addObserver(PREF_VIDEO_SELECTED_READER
, this, false);
1181 prefs
.addObserver(PREF_VIDEO_SELECTED_WEB
, this, false);
1182 prefs
.addObserver(PREF_VIDEO_SELECTED_APP
, this, false);
1184 prefs
.addObserver(PREF_AUDIO_SELECTED_ACTION
, this, false);
1185 prefs
.addObserver(PREF_AUDIO_SELECTED_READER
, this, false);
1186 prefs
.addObserver(PREF_AUDIO_SELECTED_WEB
, this, false);
1187 prefs
.addObserver(PREF_AUDIO_SELECTED_APP
, this, false);
1190 writeContent
: function FW_writeContent() {
1195 // Set up the feed content
1196 var container
= this._getContainer();
1200 this._setTitleText(container
);
1201 this._setTitleImage(container
);
1202 this._writeFeedContent(container
);
1205 this._removeFeedFromCache();
1209 close
: function FW_close() {
1211 .getElementById("handlersMenuPopup")
1212 .removeEventListener("command", this, false);
1214 .getElementById("subscribeButton")
1215 .removeEventListener("command", this, false);
1216 this._document
= null;
1217 this._window
= null;
1218 var prefs
= Cc
["@mozilla.org/preferences-service;1"].
1219 getService(Ci
.nsIPrefBranch2
);
1220 prefs
.removeObserver(PREF_SELECTED_ACTION
, this);
1221 prefs
.removeObserver(PREF_SELECTED_READER
, this);
1222 prefs
.removeObserver(PREF_SELECTED_WEB
, this);
1223 prefs
.removeObserver(PREF_SELECTED_APP
, this);
1224 prefs
.removeObserver(PREF_VIDEO_SELECTED_ACTION
, this);
1225 prefs
.removeObserver(PREF_VIDEO_SELECTED_READER
, this);
1226 prefs
.removeObserver(PREF_VIDEO_SELECTED_WEB
, this);
1227 prefs
.removeObserver(PREF_VIDEO_SELECTED_APP
, this);
1229 prefs
.removeObserver(PREF_AUDIO_SELECTED_ACTION
, this);
1230 prefs
.removeObserver(PREF_AUDIO_SELECTED_READER
, this);
1231 prefs
.removeObserver(PREF_AUDIO_SELECTED_WEB
, this);
1232 prefs
.removeObserver(PREF_AUDIO_SELECTED_APP
, this);
1234 this._removeFeedFromCache();
1235 this.__faviconService
= null;
1236 this.__bundle
= null;
1237 this._feedURI
= null;
1238 this.__contentSandbox
= null;
1240 var historySvc
= Cc
["@mozilla.org/browser/nav-history-service;1"].
1241 getService(Ci
.nsINavHistoryService
);
1242 historySvc
.removeObserver(this);
1245 _removeFeedFromCache
: function FW__removeFeedFromCache() {
1246 if (this._feedURI
) {
1247 var feedService
= Cc
["@mozilla.org/browser/feeds/result-service;1"].
1248 getService(Ci
.nsIFeedResultService
);
1249 feedService
.removeFeedResult(this._feedURI
);
1250 this._feedURI
= null;
1254 subscribe
: function FW_subscribe() {
1255 var feedType
= this._getFeedType();
1257 // Subscribe to the feed using the selected handler and save prefs
1258 var prefs
= Cc
["@mozilla.org/preferences-service;1"].
1259 getService(Ci
.nsIPrefBranch
);
1260 var defaultHandler
= "reader";
1261 var useAsDefault
= this._document
.getElementById("alwaysUse")
1262 .getAttribute("checked");
1264 var handlersMenuList
= this._document
.getElementById("handlersMenuList");
1265 var selectedItem
= this._getSelectedItemFromMenulist(handlersMenuList
);
1267 // Show the file picker before subscribing if the
1268 // choose application menuitem was choosen using the keyboard
1269 if (selectedItem
.id
== "chooseApplicationMenuItem") {
1270 if (!this._chooseClientApp())
1273 selectedItem
= this._getSelectedItemFromMenulist(handlersMenuList
);
1276 if (selectedItem
.hasAttribute("webhandlerurl")) {
1277 var webURI
= selectedItem
.getAttribute("webhandlerurl");
1278 prefs
.setCharPref(getPrefReaderForType(feedType
), "web");
1280 var supportsString
= Cc
["@mozilla.org/supports-string;1"].
1281 createInstance(Ci
.nsISupportsString
);
1282 supportsString
.data
= webURI
;
1283 prefs
.setComplexValue(getPrefWebForType(feedType
), Ci
.nsISupportsString
,
1286 var wccr
= Cc
["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
1287 getService(Ci
.nsIWebContentConverterService
);
1288 var handler
= wccr
.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType
), webURI
);
1291 wccr
.setAutoHandler(this._getMimeTypeForFeedType(feedType
), handler
);
1293 this._window
.location
.href
= handler
.getHandlerURI(this._window
.location
.href
);
1297 switch (selectedItem
.id
) {
1298 case "selectedAppMenuItem":
1299 prefs
.setComplexValue(getPrefAppForType(feedType
), Ci
.nsILocalFile
,
1301 prefs
.setCharPref(getPrefReaderForType(feedType
), "client");
1303 case "defaultHandlerMenuItem":
1304 prefs
.setComplexValue(getPrefAppForType(feedType
), Ci
.nsILocalFile
,
1305 this._defaultSystemReader
);
1306 prefs
.setCharPref(getPrefReaderForType(feedType
), "client");
1308 case "liveBookmarksMenuItem":
1309 defaultHandler
= "bookmarks";
1310 prefs
.setCharPref(getPrefReaderForType(feedType
), "bookmarks");
1313 var feedService
= Cc
["@mozilla.org/browser/feeds/result-service;1"].
1314 getService(Ci
.nsIFeedResultService
);
1316 // Pull the title and subtitle out of the document
1317 var feedTitle
= this._document
.getElementById(TITLE_ID
).textContent
;
1318 var feedSubtitle
= this._document
.getElementById(SUBTITLE_ID
).textContent
;
1319 feedService
.addToClientReader(this._window
.location
.href
, feedTitle
, feedSubtitle
, feedType
);
1322 // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
1323 // to either "reader" (If a web reader or if an application is selected),
1324 // or to "bookmarks" (if the live bookmarks option is selected).
1325 // Otherwise, we should set it to "ask"
1327 prefs
.setCharPref(getPrefActionForType(feedType
), defaultHandler
);
1329 prefs
.setCharPref(getPrefActionForType(feedType
), "ask");
1333 observe
: function FW_observe(subject
, topic
, data
) {
1335 subject
= new XPCNativeWrapper(subject
);
1337 if (!this._window
) {
1338 // this._window is null unless this.init was called with a trusted
1343 var feedType
= this._getFeedType();
1345 if (topic
== "nsPref:changed") {
1347 case PREF_SELECTED_READER
:
1348 case PREF_SELECTED_WEB
:
1349 case PREF_SELECTED_APP
:
1350 case PREF_VIDEO_SELECTED_READER
:
1351 case PREF_VIDEO_SELECTED_WEB
:
1352 case PREF_VIDEO_SELECTED_APP
:
1353 case PREF_AUDIO_SELECTED_READER
:
1354 case PREF_AUDIO_SELECTED_WEB
:
1355 case PREF_AUDIO_SELECTED_APP
:
1356 this._setSelectedHandler(feedType
);
1358 case PREF_SELECTED_ACTION
:
1359 case PREF_VIDEO_SELECTED_ACTION
:
1360 case PREF_AUDIO_SELECTED_ACTION
:
1361 this._setAlwaysUseCheckedState(feedType
);
1367 * Sets the icon for the given web-reader item in the readers menu
1368 * if the favicon-service has the necessary icon stored.
1372 * the reader item in the readers menulist.
1373 * @return true if the icon was set, false otherwise.
1375 _setFaviconForWebReader
:
1376 function FW__setFaviconForWebReader(aURI
, aMenuItem
) {
1377 var faviconsSvc
= this._faviconService
;
1378 var faviconURI
= null;
1380 faviconURI
= faviconsSvc
.getFaviconForPage(aURI
);
1385 var dataURL
= faviconsSvc
.getFaviconDataAsDataURL(faviconURI
);
1387 this._contentSandbox
.menuItem
= aMenuItem
;
1388 this._contentSandbox
.dataURL
= dataURL
;
1389 var codeStr
= "menuItem.setAttribute('image', dataURL);";
1390 Cu
.evalInSandbox(codeStr
, this._contentSandbox
);
1391 this._contentSandbox
.menuItem
= null;
1392 this._contentSandbox
.dataURL
= null;
1401 // nsINavHistoryService
1402 onPageChanged
: function FW_onPageChanged(aURI
, aWhat
, aValue
) {
1404 aURI
= new XPCNativeWrapper(aURI
);
1406 if (aWhat
== Ci
.nsINavHistoryObserver
.ATTRIBUTE_FAVICON
) {
1407 // Go through the readers menu and look for the corresponding
1408 // reader menu-item for the page if any.
1409 var spec
= aURI
.spec
;
1410 var handlersMenulist
= this._document
.getElementById("handlersMenuList");
1411 var possibleHandlers
= handlersMenulist
.firstChild
.childNodes
;
1412 for (var i
=0; i
< possibleHandlers
.length
; i
++) {
1413 if (possibleHandlers
[i
].getAttribute("webhandlerurl") == spec
) {
1414 this._setFaviconForWebReader(aURI
, possibleHandlers
[i
]);
1421 onBeginUpdateBatch: function() { },
1422 onEndUpdateBatch: function() { },
1423 onVisit: function() { },
1424 onTitleChanged: function() { },
1425 onDeleteURI: function() { },
1426 onClearHistory: function() { },
1427 onPageExpired: function() { },
1430 getInterfaces
: function FW_getInterfaces(countRef
) {
1431 var interfaces
= [Ci
.nsIFeedWriter
, Ci
.nsIClassInfo
, Ci
.nsISupports
];
1432 countRef
.value
= interfaces
.length
;
1435 getHelperForLanguage
: function FW_getHelperForLanguage(language
) null,
1436 contractID
: "@mozilla.org/browser/feeds/result-writer;1",
1437 classDescription
: "Feed Writer",
1438 classID
: Components
.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"),
1439 implementationLanguage
: Ci
.nsIProgrammingLanguage
.JAVASCRIPT
,
1440 flags
: Ci
.nsIClassInfo
.DOM_OBJECT
,
1441 _xpcom_categories
: [{ category
: "JavaScript global constructor",
1442 entry
: "BrowserFeedWriter"}],
1443 QueryInterface
: XPCOMUtils
.generateQI([Ci
.nsIFeedWriter
, Ci
.nsIClassInfo
,
1444 Ci
.nsIDOMEventListener
, Ci
.nsIObserver
,
1445 Ci
.nsINavHistoryObserver
])
1448 function NSGetModule(cm
, file
)
1449 XPCOMUtils
.generateModule([FeedWriter
]);