FeedWriter.js
Go to the documentation of this file.
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
4 #
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/
9 #
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
13 # License.
14 #
15 # The Original Code is the Feed Writer.
16 #
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.
20 #
21 # Contributor(s):
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>
28 #
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.
40 #
41 # ***** END LICENSE BLOCK ***** */
42 
43 const Cc = Components.classes;
44 const Ci = Components.interfaces;
45 const Cr = Components.results;
46 const Cu = Components.utils;
47 
48 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
49 
50 function LOG(str) {
51  var prefB = Cc["@mozilla.org/preferences-service;1"].
52  getService(Ci.nsIPrefBranch);
53 
54  var shouldLog = false;
55  try {
56  shouldLog = prefB.getBoolPref("feeds.log");
57  }
58  catch (ex) {
59  }
60 
61  if (shouldLog)
62  dump("*** Feeds: " + str + "\n");
63 }
64 
71 function makeURI(aURLSpec, aCharset) {
72  var ios = Cc["@mozilla.org/network/io-service;1"].
73  getService(Ci.nsIIOService);
74  try {
75  return ios.newURI(aURLSpec, aCharset, null);
76  } catch (ex) { }
77 
78  return null;
79 }
80 
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";
89 
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";
94 
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";
99 
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";
104 
105 const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
106 
107 const TITLE_ID = "feedTitleText";
108 const SUBTITLE_ID = "feedSubtitleText";
109 
110 function getPrefAppForType(t) {
111  switch (t) {
112  case Ci.nsIFeed.TYPE_VIDEO:
114 
115  case Ci.nsIFeed.TYPE_AUDIO:
117 
118  default:
119  return PREF_SELECTED_APP;
120  }
121 }
122 
123 function getPrefWebForType(t) {
124  switch (t) {
125  case Ci.nsIFeed.TYPE_VIDEO:
127 
128  case Ci.nsIFeed.TYPE_AUDIO:
130 
131  default:
132  return PREF_SELECTED_WEB;
133  }
134 }
135 
137  switch (t) {
138  case Ci.nsIFeed.TYPE_VIDEO:
140 
141  case Ci.nsIFeed.TYPE_AUDIO:
143 
144  default:
145  return PREF_SELECTED_ACTION;
146  }
147 }
148 
150  switch (t) {
151  case Ci.nsIFeed.TYPE_VIDEO:
153 
154  case Ci.nsIFeed.TYPE_AUDIO:
156 
157  default:
158  return PREF_SELECTED_READER;
159  }
160 }
161 
168 function convertByteUnits(aBytes) {
169  var units = ["bytes", "kilobyte", "megabyte", "gigabyte"];
170  let unitIndex = 0;
171 
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)) {
175  aBytes /= 1024;
176  unitIndex++;
177  }
178 
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);
182 
183  return [aBytes, units[unitIndex]];
184 }
185 
186 function FeedWriter() {}
187 FeedWriter.prototype = {
188  _mimeSvc : Cc["@mozilla.org/mime;1"].
189  getService(Ci.nsIMIMEService),
190 
191  _getPropertyAsBag: function FW__getPropertyAsBag(container, property) {
192  return container.fields.getProperty(property).
193  QueryInterface(Ci.nsIPropertyBag2);
194  },
195 
196  _getPropertyAsString: function FW__getPropertyAsString(container, property) {
197  try {
198  return container.fields.getPropertyAsAString(property);
199  }
200  catch (e) {
201  }
202  return "";
203  },
204 
205  _setContentText: function FW__setContentText(id, text) {
206  this._contentSandbox.element = this._document.getElementById(id);
207  this._contentSandbox.textNode = this._document.createTextNode(text);
208  var codeStr =
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;
215  },
216 
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;
232  try {
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...
237  }
238  catch (e) {
239  // Not allowed to load this link because secman.checkLoadURIStr threw
240  return;
241  }
242 
243  this._contentSandbox.element = element;
244  this._contentSandbox.uri = uri;
245  var codeStr = "element.setAttribute('" + attribute + "', uri);";
246  Cu.evalInSandbox(codeStr, this._contentSandbox);
247  },
248 
254  get _contentSandbox() {
255  if (!this.__contentSandbox)
256  this.__contentSandbox = new Cu.Sandbox(this._window);
257 
258  return this.__contentSandbox;
259  },
260 
268  _safeDoCommand: function FW___safeDoCommand(aElement) {
269  this._contentSandbox.element = aElement;
270  Cu.evalInSandbox("element.doCommand();", this._contentSandbox);
271  this._contentSandbox.element = null;
272  },
273 
275  get _faviconService() {
276  if (!this.__faviconService)
277  this.__faviconService = Cc["@mozilla.org/browser/favicon-service;1"].
278  getService(Ci.nsIFaviconService);
279 
280  return this.__faviconService;
281  },
282 
283  __bundle: null,
284  get _bundle() {
285  if (!this.__bundle) {
286  this.__bundle = Cc["@mozilla.org/intl/stringbundle;1"].
287  getService(Ci.nsIStringBundleService).
288  createBundle(URI_BUNDLE);
289  }
290  return this.__bundle;
291  },
292 
293  _getFormattedString: function FW__getFormattedString(key, params) {
294  return this._bundle.formatStringFromName(key, params, params.length);
295  },
296 
297  _getString: function FW__getString(key) {
298  return this._bundle.GetStringFromName(key);
299  },
300 
301  /* Magic helper methods to be used instead of xbl properties */
302  _getSelectedItemFromMenulist: function FW__getSelectedItemFromList(aList) {
303  var node = aList.firstChild.firstChild;
304  while (node) {
305  if (node.localName == "menuitem" && node.getAttribute("selected") == "true")
306  return node;
307 
308  node = node.nextSibling;
309  }
310 
311  return null;
312  },
313 
314  _setCheckboxCheckedState: function FW__setCheckboxCheckedState(aCheckbox, aValue) {
315  // see checkbox.xml, xbl bindings are not applied within the sandbox!
316  this._contentSandbox.checkbox = aCheckbox;
317  var codeStr;
318  var change = (aValue != (aCheckbox.getAttribute('checked') == 'true'));
319  if (aValue)
320  codeStr = "checkbox.setAttribute('checked', 'true'); ";
321  else
322  codeStr = "checkbox.removeAttribute('checked'); ";
323 
324  if (change) {
325  this._contentSandbox.document = this._document;
326  codeStr += "var event = document.createEvent('Events'); " +
327  "event.initEvent('CheckboxStateChange', true, true);" +
328  "checkbox.dispatchEvent(event);"
329  }
330 
331  Cu.evalInSandbox(codeStr, this._contentSandbox);
332  },
333 
340  _parseDate: function FW__parseDate(dateString) {
341  // Convert the date into the user's local time zone
342  dateObj = new Date(dateString);
343 
344  // Make sure the date we're given is valid.
345  if (!dateObj.getTime())
346  return false;
347 
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());
353  },
354 
358  __feedType: null,
359  _getFeedType: function FW__getFeedType() {
360  if (this.__feedType != null)
361  return this.__feedType;
362 
363  try {
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;
368  return feed.type;
369  } catch (ex) { }
370 
371  return Ci.nsIFeed.TYPE_FEED;
372  },
373 
377  _getMimeTypeForFeedType: function FW__getMimeTypeForFeedType() {
378  switch (this._getFeedType()) {
379  case Ci.nsIFeed.TYPE_VIDEO:
380  return TYPE_MAYBE_VIDEO_FEED;
381 
382  case Ci.nsIFeed.TYPE_AUDIO:
383  return TYPE_MAYBE_AUDIO_FEED;
384 
385  default:
386  return TYPE_MAYBE_FEED;
387  }
388  },
389 
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);
403  }
404 
405  var feed = container.QueryInterface(Ci.nsIFeed);
406  if (feed && feed.subtitle)
407  this._setContentText(SUBTITLE_ID, container.subtitle.plainText());
408  },
409 
415  _setTitleImage: function FW__setTitleImage(container) {
416  try {
417  var parts = container.image;
418 
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"));
423 
424  // Set up the title image link
425  var feedTitleLink = this._document.getElementById("feedTitleLink");
426 
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;
433 
434  // Fix the margin on the main title, so that the image doesn't run over
435  // the underline
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;
443 
444  this._safeSetURIAttribute(feedTitleLink, "href",
445  parts.getPropertyAsAString("link"));
446  }
447  catch (e) {
448  LOG("Failed to set Title Image (this is benign): " + e);
449  }
450  },
451 
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)
461  return;
462 
463  this._contentSandbox.feedContent =
464  this._document.getElementById("feedContent");
465 
466  for (var i = 0; i < feed.items.length; ++i) {
467  var entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry);
468  entry.QueryInterface(Ci.nsIFeedContainer);
469 
470  var entryContainer = this._document.createElementNS(HTML_NS, "div");
471  entryContainer.className = "entry";
472 
473  // If the entry has a title, make it a link
474  if (entry.title) {
475  var a = this._document.createElementNS(HTML_NS, "a");
476  a.appendChild(this._document.createTextNode(entry.title.plainText()));
477 
478  // Entries are not required to have links, so entry.link can be null.
479  if (entry.link)
480  this._safeSetURIAttribute(a, "href", entry.link.spec);
481 
482  var title = this._document.createElementNS(HTML_NS, "h3");
483  title.appendChild(a);
484 
485  var lastUpdated = this._parseDate(entry.updated);
486  if (lastUpdated) {
487  var dateDiv = this._document.createElementNS(HTML_NS, "div");
488  dateDiv.className = "lastUpdated";
489  dateDiv.textContent = lastUpdated;
490  title.appendChild(dateDiv);
491  }
492 
493  entryContainer.appendChild(title);
494  }
495 
496  var body = this._document.createElementNS(HTML_NS, "div");
497  var summary = entry.summary || entry.content;
498  var docFragment = null;
499  if (summary) {
500  if (summary.base)
501  body.setAttributeNS(XML_NS, "base", summary.base.spec);
502  else
503  LOG("no base?");
504  docFragment = summary.createDocumentFragment(body);
505  if (docFragment)
506  body.appendChild(docFragment);
507 
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(" "));
515  body.appendChild(a);
516  }
517 
518  }
519  body.className = "feedEntryContent";
520  entryContainer.appendChild(body);
521 
522  if (entry.enclosures && entry.enclosures.length > 0) {
523  var enclosuresDiv = this._buildEnclosureDiv(entry);
524  entryContainer.appendChild(enclosuresDiv);
525  }
526 
527  this._contentSandbox.entryContainer = entryContainer;
528  this._contentSandbox.clearDiv =
529  this._document.createElementNS(HTML_NS, "div");
530  this._contentSandbox.clearDiv.style.clear = "both";
531 
532  var codeStr = "feedContent.appendChild(entryContainer); " +
533  "feedContent.appendChild(clearDiv);"
534  Cu.evalInSandbox(codeStr, this._contentSandbox);
535  }
536 
537  this._contentSandbox.feedContent = null;
538  this._contentSandbox.entryContainer = null;
539  this._contentSandbox.clearDiv = null;
540  },
541 
553  _getURLDisplayName: function FW__getURLDisplayName(aURL) {
554  var url = makeURI(aURL);
555  url.QueryInterface(Ci.nsIURL);
556  if (url == null || url.fileName.length == 0)
557  return aURL;
558 
559  return decodeURI(url.fileName);
560  },
561 
569  _buildEnclosureDiv: function FW__buildEnclosureDiv(entry) {
570  var enclosuresDiv = this._document.createElementNS(HTML_NS, "div");
571  enclosuresDiv.className = "enclosures";
572 
573  enclosuresDiv.appendChild(this._document.createTextNode(this._getString("mediaLabel")));
574 
575  var roundme = function(n) {
576  return (Math.round(n * 100) / 100).toLocaleString();
577  }
578 
579  for (var i_enc = 0; i_enc < entry.enclosures.length; ++i_enc) {
580  var enc = entry.enclosures.queryElementAt(i_enc, Ci.nsIWritablePropertyBag2);
581 
582  if (!(enc.hasKey("url")))
583  continue;
584 
585  var enclosureDiv = this._document.createElementNS(HTML_NS, "div");
586  enclosureDiv.setAttribute("class", "enclosure");
587 
588  var mozicon = "moz-icon://.txt?size=16";
589  var type_text = null;
590  var size_text = null;
591 
592  if (enc.hasKey("type")) {
593  type_text = enc.get("type");
594  try {
595  var handlerInfoWrapper = this._mimeSvc.getFromTypeAndExtension(enc.get("type"), null);
596 
597  if (handlerInfoWrapper)
598  type_text = handlerInfoWrapper.description;
599 
600  if (type_text && type_text.length > 0)
601  mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type");
602 
603  } catch (ex) { }
604 
605  }
606 
607  if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) {
608  var enc_size = convertByteUnits(parseInt(enc.get("length")));
609 
610  var size_text = this._getFormattedString("enclosureSizeText",
611  [enc_size[0], this._getString(enc_size[1])]);
612  }
613 
614  var iconimg = this._document.createElementNS(HTML_NS, "img");
615  iconimg.setAttribute("src", mozicon);
616  iconimg.setAttribute("class", "type-icon");
617  enclosureDiv.appendChild(iconimg);
618 
619  enclosureDiv.appendChild(this._document.createTextNode( " " ));
620 
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);
625 
626  if (type_text && size_text)
627  enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ", " + size_text + ")"));
628 
629  else if (type_text)
630  enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ")"))
631 
632  else if (size_text)
633  enclosureDiv.appendChild(this._document.createTextNode( " (" + size_text + ")"))
634 
635  enclosuresDiv.appendChild(enclosureDiv);
636  }
637 
638  return enclosuresDiv;
639  },
640 
649  _getContainer: function FW__getContainer(result) {
650  var feedService =
651  Cc["@mozilla.org/browser/feeds/result-service;1"].
652  getService(Ci.nsIFeedResultService);
653 
654  try {
655  var result =
656  feedService.getFeedResult(this._getOriginalURI(this._window));
657  }
658  catch (e) {
659  LOG("Subscribe Preview: feed not available?!");
660  }
661 
662  if (result.bozo) {
663  LOG("Subscribe Preview: feed result is bozo?!");
664  }
665 
666  try {
667  var container = result.doc;
668  }
669  catch (e) {
670  LOG("Subscribe Preview: no result.doc? Why didn't the original reload?");
671  return null;
672  }
673  return container;
674  },
675 
683  _getFileDisplayName: function FW__getFileDisplayName(file) {
684 #ifdef XP_WIN
685  if (file instanceof Ci.nsILocalFileWin) {
686  try {
687  return file.getVersionInfoField("FileDescription");
688  }
689  catch (e) {
690  }
691  }
692 #endif
693 #ifdef XP_MACOSX
694  var lfm = file.QueryInterface(Ci.nsILocalFileMac);
695  try {
696  return lfm.bundleDisplayName;
697  }
698  catch (e) {
699  // fall through to the file name
700  }
701 #endif
702  var ios =
703  Cc["@mozilla.org/network/io-service;1"].
704  getService(Ci.nsIIOService);
705  var url = ios.newFileURI(file).QueryInterface(Ci.nsIURL);
706  return url.fileName;
707  },
708 
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";
722  },
723 
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);
739  },
740 
745  _chooseClientApp: function FW__chooseClientApp() {
746  try {
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);
752 
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
759 #ifdef XP_WIN
760 #expand if (fp.file.leafName != "__MOZ_APP_NAME__.exe") {
761 #else
762 #ifdef XP_MACOSX
763 #expand if (fp.file.leafName != "__MOZ_APP_DISPLAYNAME__.app") {
764 #else
765 #expand if (fp.file.leafName != "__MOZ_APP_NAME__-bin") {
766 #endif
767 #endif
768  this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem,
769  this._selectedApp);
770 
771  // Show and select the selected application menuitem
772  var codeStr = "selectedAppMenuItem.hidden = false;" +
773  "selectedAppMenuItem.doCommand();"
774  Cu.evalInSandbox(codeStr, this._contentSandbox);
775  return true;
776  }
777  }
778  }
779  }
780  catch(ex) { }
781 
782  return false;
783  },
784 
785  _setAlwaysUseCheckedState: function FW__setAlwaysUseCheckedState(feedType) {
786  var checkbox = this._document.getElementById("alwaysUse");
787  if (checkbox) {
788  var alwaysUse = false;
789  try {
790  var prefs = Cc["@mozilla.org/preferences-service;1"].
791  getService(Ci.nsIPrefBranch);
792  if (prefs.getCharPref(getPrefActionForType(feedType)) != "ask")
793  alwaysUse = true;
794  }
795  catch(ex) { }
796  this._setCheckboxCheckedState(checkbox, alwaysUse);
797  }
798  },
799 
800  _setSubscribeUsingLabel: function FW__setSubscribeUsingLabel() {
801  var stringLabel = "subscribeFeedUsing";
802  switch (this._getFeedType()) {
803  case Ci.nsIFeed.TYPE_VIDEO:
804  stringLabel = "subscribeVideoPodcastUsing";
805  break;
806 
807  case Ci.nsIFeed.TYPE_AUDIO:
808  stringLabel = "subscribeAudioPodcastUsing";
809  break;
810  }
811 
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);
817  },
818 
819  _setAlwaysUseLabel: function FW__setAlwaysUseLabel() {
820  var checkbox = this._document.getElementById("alwaysUse");
821  if (checkbox) {
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";
830  break;
831 
832  case Ci.nsIFeed.TYPE_AUDIO:
833  stringLabel = "alwaysUseForAudioPodcasts";
834  break;
835  }
836 
837  this._contentSandbox.checkbox = checkbox;
838  this._contentSandbox.label = this._getFormattedString(stringLabel, [handlerName]);
839 
840  var codeStr = "checkbox.setAttribute('label', label);";
841  Cu.evalInSandbox(codeStr, this._contentSandbox);
842  }
843  }
844  },
845 
846  // nsIDomEventListener
847  handleEvent: function(event) {
848  if (event.target.ownerDocument != this._document) {
849  LOG("FeedWriter.handleEvent: Someone passed the feed writer as a listener to the events of another document!");
850  return;
851  }
852 
853  if (event.type == "command") {
854  switch (event.target.id) {
855  case "subscribeButton":
856  this.subscribe();
857  break;
858  case "chooseApplicationMenuItem":
859  /* Bug 351263: Make sure to not steal focus if the "Choose
860  * Application" item is being selected with the keyboard. We do this
861  * by ignoring command events while the dropdown is closed (user
862  * arrowing through the combobox), but handling them while the
863  * combobox dropdown is open (user pressed enter when an item was
864  * selected). If we don't show the filepicker here, it will be shown
865  * when clicking "Subscribe Now".
866  */
867  var popupbox = this._document.getElementById("handlersMenuList")
868  .firstChild.boxObject;
869  popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
870  if (popupbox.popupState == "hiding" && !this._chooseClientApp()) {
871  // Select the (per-prefs) selected handler if no application was
872  // selected
873  this._setSelectedHandler(this._getFeedType());
874  }
875  break;
876  default:
877  this._setAlwaysUseLabel();
878  }
879  }
880  },
881 
882  _setSelectedHandler: function FW__setSelectedHandler(feedType) {
883  var prefs =
884  Cc["@mozilla.org/preferences-service;1"].
885  getService(Ci.nsIPrefBranch);
886 
887  var handler = "bookmarks";
888  try {
889  handler = prefs.getCharPref(getPrefReaderForType(feedType));
890  }
891  catch (ex) { }
892 
893  switch (handler) {
894  case "web": {
895  var handlersMenuList = this._document.getElementById("handlersMenuList");
896  if (handlersMenuList) {
897  var url = prefs.getComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString).data;
898  var handlers =
899  handlersMenuList.getElementsByAttribute("webhandlerurl", url);
900  if (handlers.length == 0) {
901  LOG("FeedWriter._setSelectedHandler: selected web handler isn't in the menulist")
902  return;
903  }
904 
905  this._safeDoCommand(handlers[0]);
906  }
907  break;
908  }
909  case "client": {
910  try {
911  this._selectedApp =
912  prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile);
913  }
914  catch(ex) {
915  this._selectedApp = null;
916  }
917 
918  if (this._selectedApp) {
919  this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem,
920  this._selectedApp);
921  var codeStr = "selectedAppMenuItem.hidden = false; " +
922  "selectedAppMenuItem.doCommand(); ";
923 
924  // Only show the default reader menuitem if the default reader
925  // isn't the selected application
926  if (this._defaultSystemReader) {
927  var shouldHide =
928  this._defaultSystemReader.path == this._selectedApp.path;
929  codeStr += "defaultHandlerMenuItem.hidden = " + shouldHide + ";"
930  }
931  Cu.evalInSandbox(codeStr, this._contentSandbox);
932  break;
933  }
934  }
935  case "bookmarks":
936  default: {
937  var liveBookmarksMenuItem = this._document.getElementById("liveBookmarksMenuItem");
938  if (liveBookmarksMenuItem)
939  this._safeDoCommand(liveBookmarksMenuItem);
940  }
941  }
942  },
943 
944  _initSubscriptionUI: function FW__initSubscriptionUI() {
945  var handlersMenuPopup = this._document.getElementById("handlersMenuPopup");
946  if (!handlersMenuPopup)
947  return;
948 
949  var feedType = this._getFeedType();
950  var codeStr;
951 
952  // change the background
953  var header = this._document.getElementById("feedHeader");
954  this._contentSandbox.header = header;
955  switch (feedType) {
956  case Ci.nsIFeed.TYPE_VIDEO:
957  codeStr = "header.className = 'videoPodcastBackground'; ";
958  break;
959 
960  case Ci.nsIFeed.TYPE_AUDIO:
961  codeStr = "header.className = 'audioPodcastBackground'; ";
962  break;
963 
964  default:
965  codeStr = "header.className = 'feedBackground'; ";
966  }
967 
968 
969  // Last-selected application
970  var menuItem = this._document.createElementNS(XUL_NS, "menuitem");
971  menuItem.id = "selectedAppMenuItem";
972  menuItem.className = "menuitem-iconic";
973  menuItem.setAttribute("handlerType", "client");
974  try {
975  var prefs = Cc["@mozilla.org/preferences-service;1"].
976  getService(Ci.nsIPrefBranch);
977  this._selectedApp = prefs.getComplexValue(getPrefAppForType(feedType),
978  Ci.nsILocalFile);
979 
980  if (this._selectedApp.exists())
981  this._initMenuItemWithFile(menuItem, this._selectedApp);
982  else {
983  // Hide the menuitem if the last selected application doesn't exist
984  menuItem.setAttribute("hidden", true);
985  }
986  }
987  catch(ex) {
988  // Hide the menuitem until an application is selected
989  menuItem.setAttribute("hidden", true);
990  }
991  this._contentSandbox.handlersMenuPopup = handlersMenuPopup;
992  this._contentSandbox.selectedAppMenuItem = menuItem;
993 
994  codeStr += "handlersMenuPopup.appendChild(selectedAppMenuItem); ";
995 
996  // List the default feed reader
997  try {
998  this._defaultSystemReader = Cc["@mozilla.org/browser/shell-service;1"].
999  getService(Ci.nsIShellService).
1000  defaultFeedReader;
1001  menuItem = this._document.createElementNS(XUL_NS, "menuitem");
1002  menuItem.id = "defaultHandlerMenuItem";
1003  menuItem.className = "menuitem-iconic";
1004  menuItem.setAttribute("handlerType", "client");
1005 
1006  this._initMenuItemWithFile(menuItem, this._defaultSystemReader);
1007 
1008  // Hide the default reader item if it points to the same application
1009  // as the last-selected application
1010  if (this._selectedApp &&
1011  this._selectedApp.path == this._defaultSystemReader.path)
1012  menuItem.hidden = true;
1013  }
1014  catch(ex) { menuItem = null; /* no default reader */ }
1015 
1016  if (menuItem) {
1017  this._contentSandbox.defaultHandlerMenuItem = menuItem;
1018  codeStr += "handlersMenuPopup.appendChild(defaultHandlerMenuItem); ";
1019  }
1020 
1021  // "Choose Application..." menuitem
1022  menuItem = this._document.createElementNS(XUL_NS, "menuitem");
1023  menuItem.id = "chooseApplicationMenuItem";
1024  menuItem.className = "menuitem-iconic";
1025  menuItem.setAttribute("label", this._getString("chooseApplicationMenuItem"));
1026 
1027  this._contentSandbox.chooseAppMenuItem = menuItem;
1028  codeStr += "handlersMenuPopup.appendChild(chooseAppMenuItem); ";
1029 
1030  // separator
1031  this._contentSandbox.chooseAppSep =
1032  this._document.createElementNS(XUL_NS, "menuseparator")
1033  codeStr += "handlersMenuPopup.appendChild(chooseAppSep); ";
1034 
1035  Cu.evalInSandbox(codeStr, this._contentSandbox);
1036 
1037  var historySvc = Cc["@mozilla.org/browser/nav-history-service;1"].
1038  getService(Ci.nsINavHistoryService);
1039  historySvc.addObserver(this, false);
1040 
1041  // List of web handlers
1042  var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
1043  getService(Ci.nsIWebContentConverterService);
1044  var handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType), {});
1045  if (handlers.length != 0) {
1046  for (var i = 0; i < handlers.length; ++i) {
1047  menuItem = this._document.createElementNS(XUL_NS, "menuitem");
1048  menuItem.className = "menuitem-iconic";
1049  menuItem.setAttribute("label", handlers[i].name);
1050  menuItem.setAttribute("handlerType", "web");
1051  menuItem.setAttribute("webhandlerurl", handlers[i].uri);
1052  this._contentSandbox.menuItem = menuItem;
1053  codeStr = "handlersMenuPopup.appendChild(menuItem);";
1054  Cu.evalInSandbox(codeStr, this._contentSandbox);
1055 
1056  // For privacy reasons we cannot set the image attribute directly
1057  // to the icon url, see Bug 358878
1058  var uri = makeURI(handlers[i].uri);
1059  if (!this._setFaviconForWebReader(uri, menuItem)) {
1060  if (uri && /^https?/.test(uri.scheme)) {
1061  var iconURL = makeURI(uri.prePath + "/favicon.ico");
1062  this._faviconService.setAndLoadFaviconForPage(uri, iconURL, true);
1063  }
1064  }
1065  }
1066  this._contentSandbox.menuItem = null;
1067  }
1068 
1069  this._setSelectedHandler(feedType);
1070 
1071  // "Subscribe using..."
1072  this._setSubscribeUsingLabel();
1073 
1074  // "Always use..." checkbox initial state
1075  this._setAlwaysUseCheckedState(feedType);
1076  this._setAlwaysUseLabel();
1077 
1078  // We update the "Always use.." checkbox label whenever the selected item
1079  // in the list is changed
1080  handlersMenuPopup.addEventListener("command", this, false);
1081 
1082  // Set up the "Subscribe Now" button
1083  this._document
1084  .getElementById("subscribeButton")
1085  .addEventListener("command", this, false);
1086 
1087  // first-run ui
1088  var showFirstRunUI = true;
1089  try {
1090  showFirstRunUI = prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
1091  }
1092  catch (ex) { }
1093  if (showFirstRunUI) {
1094  var textfeedinfo1, textfeedinfo2;
1095  switch (feedType) {
1096  case Ci.nsIFeed.TYPE_VIDEO:
1097  textfeedinfo1 = "feedSubscriptionVideoPodcast1";
1098  textfeedinfo2 = "feedSubscriptionVideoPodcast2";
1099  break;
1100  case Ci.nsIFeed.TYPE_AUDIO:
1101  textfeedinfo1 = "feedSubscriptionAudioPodcast1";
1102  textfeedinfo2 = "feedSubscriptionAudioPodcast2";
1103  break;
1104  default:
1105  textfeedinfo1 = "feedSubscriptionFeed1";
1106  textfeedinfo2 = "feedSubscriptionFeed2";
1107  }
1108 
1109  this._contentSandbox.feedinfo1 =
1110  this._document.getElementById("feedSubscriptionInfo1");
1111  this._contentSandbox.feedinfo1Str = this._getString(textfeedinfo1);
1112  this._contentSandbox.feedinfo2 =
1113  this._document.getElementById("feedSubscriptionInfo2");
1114  this._contentSandbox.feedinfo2Str = this._getString(textfeedinfo2);
1115  this._contentSandbox.header = header;
1116  codeStr = "feedinfo1.textContent = feedinfo1Str; " +
1117  "feedinfo2.textContent = feedinfo2Str; " +
1118  "header.setAttribute('firstrun', 'true');"
1119  Cu.evalInSandbox(codeStr, this._contentSandbox);
1120  prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false);
1121  }
1122  },
1123 
1130  _getOriginalURI: function FW__getOriginalURI(aWindow) {
1131  var chan = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
1132  getInterface(Ci.nsIWebNavigation).
1133  QueryInterface(Ci.nsIDocShell).currentDocumentChannel;
1134 
1136  var resolvedURI = Cc["@mozilla.org/chrome/chrome-registry;1"].
1137  getService(Ci.nsIChromeRegistry).
1138  convertChromeURL(uri);
1139 
1140  if (resolvedURI.equals(chan.URI))
1141  return chan.originalURI;
1142 
1143  return null;
1144  },
1145 
1146  _window: null,
1147  _document: null,
1148  _feedURI: null,
1150 
1151  // nsIFeedWriter
1152  init: function FW_init(aWindow) {
1153  var window = aWindow;
1154  this._feedURI = this._getOriginalURI(window);
1155  if (!this._feedURI)
1156  return;
1157 
1158  this._window = window;
1159  this._document = window.document;
1160 
1161  var secman = Cc["@mozilla.org/scriptsecuritymanager;1"].
1162  getService(Ci.nsIScriptSecurityManager);
1163  this._feedPrincipal = secman.getCodebasePrincipal(this._feedURI);
1164 
1165  LOG("Subscribe Preview: feed uri = " + this._window.location.href);
1166 
1167  // Set up the subscription UI
1168  this._initSubscriptionUI();
1169  var prefs = Cc["@mozilla.org/preferences-service;1"].
1170  getService(Ci.nsIPrefBranch2);
1171  prefs.addObserver(PREF_SELECTED_ACTION, this, false);
1172  prefs.addObserver(PREF_SELECTED_READER, this, false);
1173  prefs.addObserver(PREF_SELECTED_WEB, this, false);
1174  prefs.addObserver(PREF_SELECTED_APP, this, false);
1175  prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, false);
1176  prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, false);
1177  prefs.addObserver(PREF_VIDEO_SELECTED_WEB, this, false);
1178  prefs.addObserver(PREF_VIDEO_SELECTED_APP, this, false);
1179 
1180  prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, false);
1181  prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, false);
1182  prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, false);
1183  prefs.addObserver(PREF_AUDIO_SELECTED_APP, this, false);
1184  },
1185 
1186  writeContent: function FW_writeContent() {
1187  if (!this._window)
1188  return;
1189 
1190  try {
1191  // Set up the feed content
1192  var container = this._getContainer();
1193  if (!container)
1194  return;
1195 
1196  this._setTitleText(container);
1197  this._setTitleImage(container);
1198  this._writeFeedContent(container);
1199  }
1200  finally {
1201  this._removeFeedFromCache();
1202  }
1203  },
1204 
1205  close: function FW_close() {
1206  this._document
1207  .getElementById("handlersMenuPopup")
1208  .removeEventListener("command", this, false);
1209  this._document
1210  .getElementById("subscribeButton")
1211  .removeEventListener("command", this, false);
1212  this._document = null;
1213  this._window = null;
1214  var prefs = Cc["@mozilla.org/preferences-service;1"].
1215  getService(Ci.nsIPrefBranch2);
1216  prefs.removeObserver(PREF_SELECTED_ACTION, this);
1217  prefs.removeObserver(PREF_SELECTED_READER, this);
1218  prefs.removeObserver(PREF_SELECTED_WEB, this);
1219  prefs.removeObserver(PREF_SELECTED_APP, this);
1220  prefs.removeObserver(PREF_VIDEO_SELECTED_ACTION, this);
1221  prefs.removeObserver(PREF_VIDEO_SELECTED_READER, this);
1222  prefs.removeObserver(PREF_VIDEO_SELECTED_WEB, this);
1223  prefs.removeObserver(PREF_VIDEO_SELECTED_APP, this);
1224 
1225  prefs.removeObserver(PREF_AUDIO_SELECTED_ACTION, this);
1226  prefs.removeObserver(PREF_AUDIO_SELECTED_READER, this);
1227  prefs.removeObserver(PREF_AUDIO_SELECTED_WEB, this);
1228  prefs.removeObserver(PREF_AUDIO_SELECTED_APP, this);
1229 
1230  this._removeFeedFromCache();
1232  this.__bundle = null;
1233  this._feedURI = null;
1235 
1236  var historySvc = Cc["@mozilla.org/browser/nav-history-service;1"].
1237  getService(Ci.nsINavHistoryService);
1238  historySvc.removeObserver(this);
1239  },
1240 
1241  _removeFeedFromCache: function FW__removeFeedFromCache() {
1242  if (this._feedURI) {
1243  var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
1244  getService(Ci.nsIFeedResultService);
1245  feedService.removeFeedResult(this._feedURI);
1246  this._feedURI = null;
1247  }
1248  },
1249 
1250  subscribe: function FW_subscribe() {
1251  var feedType = this._getFeedType();
1252 
1253  // Subscribe to the feed using the selected handler and save prefs
1254  var prefs = Cc["@mozilla.org/preferences-service;1"].
1255  getService(Ci.nsIPrefBranch);
1256  var defaultHandler = "reader";
1257  var useAsDefault = this._document.getElementById("alwaysUse")
1258  .getAttribute("checked");
1259 
1260  var handlersMenuList = this._document.getElementById("handlersMenuList");
1261  var selectedItem = this._getSelectedItemFromMenulist(handlersMenuList);
1262 
1263  // Show the file picker before subscribing if the
1264  // choose application menuitem was chosen using the keyboard
1265  if (selectedItem.id == "chooseApplicationMenuItem") {
1266  if (!this._chooseClientApp())
1267  return;
1268 
1269  selectedItem = this._getSelectedItemFromMenulist(handlersMenuList);
1270  }
1271 
1272  if (selectedItem.hasAttribute("webhandlerurl")) {
1273  var webURI = selectedItem.getAttribute("webhandlerurl");
1274  prefs.setCharPref(getPrefReaderForType(feedType), "web");
1275 
1276  var supportsString = Cc["@mozilla.org/supports-string;1"].
1277  createInstance(Ci.nsISupportsString);
1278  supportsString.data = webURI;
1279  prefs.setComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString,
1280  supportsString);
1281 
1282  var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
1283  getService(Ci.nsIWebContentConverterService);
1284  var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
1285  if (handler) {
1286  if (useAsDefault)
1287  wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
1288 
1289  this._window.location.href = handler.getHandlerURI(this._window.location.href);
1290  }
1291  }
1292  else {
1293  switch (selectedItem.id) {
1294  case "selectedAppMenuItem":
1295  prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
1296  this._selectedApp);
1297  prefs.setCharPref(getPrefReaderForType(feedType), "client");
1298  break;
1299  case "defaultHandlerMenuItem":
1300  prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
1301  this._defaultSystemReader);
1302  prefs.setCharPref(getPrefReaderForType(feedType), "client");
1303  break;
1304  case "liveBookmarksMenuItem":
1305  defaultHandler = "bookmarks";
1306  prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks");
1307  break;
1308  }
1309  var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
1310  getService(Ci.nsIFeedResultService);
1311 
1312  // Pull the title and subtitle out of the document
1313  var feedTitle = this._document.getElementById(TITLE_ID).textContent;
1314  var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
1315  feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType);
1316  }
1317 
1318  // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
1319  // to either "reader" (If a web reader or if an application is selected),
1320  // or to "bookmarks" (if the live bookmarks option is selected).
1321  // Otherwise, we should set it to "ask"
1322  if (useAsDefault)
1323  prefs.setCharPref(getPrefActionForType(feedType), defaultHandler);
1324  else
1325  prefs.setCharPref(getPrefActionForType(feedType), "ask");
1326  },
1327 
1328  // nsIObserver
1329  observe: function FW_observe(subject, topic, data) {
1330  if (!this._window) {
1331  // this._window is null unless this.init was called with a trusted
1332  // window object.
1333  return;
1334  }
1335 
1336  var feedType = this._getFeedType();
1337 
1338  if (topic == "nsPref:changed") {
1339  switch (data) {
1340  case PREF_SELECTED_READER:
1341  case PREF_SELECTED_WEB:
1342  case PREF_SELECTED_APP:
1349  this._setSelectedHandler(feedType);
1350  break;
1351  case PREF_SELECTED_ACTION:
1354  this._setAlwaysUseCheckedState(feedType);
1355  }
1356  }
1357  },
1358 
1368  _setFaviconForWebReader:
1369  function FW__setFaviconForWebReader(aURI, aMenuItem) {
1370  var faviconsSvc = this._faviconService;
1372  try {
1373  faviconURI = faviconsSvc.getFaviconForPage(aURI);
1374  }
1375  catch(ex) { }
1376 
1377  if (faviconURI) {
1378  var dataURL = faviconsSvc.getFaviconDataAsDataURL(faviconURI);
1379  if (dataURL) {
1380  this._contentSandbox.menuItem = aMenuItem;
1381  this._contentSandbox.dataURL = dataURL;
1382  var codeStr = "menuItem.setAttribute('image', dataURL);";
1383  Cu.evalInSandbox(codeStr, this._contentSandbox);
1384  this._contentSandbox.menuItem = null;
1385  this._contentSandbox.dataURL = null;
1386 
1387  return true;
1388  }
1389  }
1390 
1391  return false;
1392  },
1393 
1394  // nsINavHistoryService
1395  onPageChanged: function FW_onPageChanged(aURI, aWhat, aValue) {
1396  if (aWhat == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
1397  // Go through the readers menu and look for the corresponding
1398  // reader menu-item for the page if any.
1399  var spec = aURI.spec;
1400  var handlersMenulist = this._document.getElementById("handlersMenuList");
1401  var possibleHandlers = handlersMenulist.firstChild.childNodes;
1402  for (var i=0; i < possibleHandlers.length ; i++) {
1403  if (possibleHandlers[i].getAttribute("webhandlerurl") == spec) {
1404  this._setFaviconForWebReader(aURI, possibleHandlers[i]);
1405  return;
1406  }
1407  }
1408  }
1409  },
1410 
1411  onBeginUpdateBatch: function() { },
1412  onEndUpdateBatch: function() { },
1413  onVisit: function() { },
1414  onTitleChanged: function() { },
1415  onBeforeDeleteURI: function() { },
1416  onDeleteURI: function() { },
1417  onClearHistory: function() { },
1418  onPageExpired: function() { },
1419 
1420  // nsIClassInfo
1421  getInterfaces: function FW_getInterfaces(countRef) {
1422  var interfaces = [Ci.nsIFeedWriter, Ci.nsIClassInfo, Ci.nsISupports];
1423  countRef.value = interfaces.length;
1424  return interfaces;
1425  },
1426  getHelperForLanguage: function FW_getHelperForLanguage(language) null,
1427  contractID: "@mozilla.org/browser/feeds/result-writer;1",
1428  classDescription: "Feed Writer",
1429  classID: Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"),
1430  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
1431  flags: Ci.nsIClassInfo.DOM_OBJECT,
1432  _xpcom_categories: [{ category: "JavaScript global constructor",
1433  entry: "BrowserFeedWriter"}],
1434  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter, Ci.nsIClassInfo,
1435  Ci.nsIDOMEventListener, Ci.nsIObserver,
1436  Ci.nsINavHistoryObserver])
1437 };
1438 
1439 function NSGetModule(cm, file)
1440  XPCOMUtils.generateModule([FeedWriter]);
const SUBSCRIBE_PAGE_URI
Definition: FeedWriter.js:88
classDescription entry
Definition: FeedWriter.js:1427
classDescription QueryInterface
Definition: FeedWriter.js:1427
const PREF_SELECTED_WEB
Definition: FeedWriter.js:91
this _writeFeedContent(container)
function convertByteUnits(aBytes)
Definition: FeedWriter.js:168
var faviconURI
Definition: FeedWriter.js:1371
getHelperForLanguage contractID
Definition: FeedWriter.js:1425
var wccr
Definition: FeedWriter.js:1042
onPageChanged onVisit
Definition: FeedWriter.js:1395
const URI_BUNDLE
Definition: FeedWriter.js:87
function getPrefWebForType(t)
Definition: FeedWriter.js:123
const XUL_NS
Definition: FeedWriter.js:83
var menuItem
Definition: FeedWriter.js:970
classDescription flags
Definition: FeedWriter.js:1427
onPageChanged aValue
Definition: FeedWriter.js:1395
const PREF_AUDIO_SELECTED_ACTION
Definition: FeedWriter.js:102
onPageChanged onEndUpdateBatch
Definition: FeedWriter.js:1395
FeedWriter _setAlwaysUseCheckedState
Definition: FeedWriter.js:187
const TYPE_MAYBE_VIDEO_FEED
Definition: FeedWriter.js:86
var historySvc
Definition: FeedWriter.js:1037
const PREF_VIDEO_SELECTED_APP
Definition: FeedWriter.js:95
function getPrefReaderForType(t)
Definition: FeedWriter.js:149
function LOG(str)
Definition: FeedWriter.js:50
this __bundle
Definition: FeedWriter.js:1232
var event
onPageChanged onBeforeDeleteURI
Definition: FeedWriter.js:1395
_window _feedPrincipal
Definition: FeedWriter.js:1144
sidebarFactory createInstance
Definition: nsSidebar.js:351
return interfaces
Definition: FeedWriter.js:1424
var handlers
Definition: FeedWriter.js:1044
var handlersMenuList
Definition: FeedWriter.js:1260
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
var header
Definition: FeedWriter.js:953
this __contentSandbox
Definition: FeedWriter.js:1234
const XML_NS
Definition: FeedWriter.js:81
var language
Definition: Info.js:44
var useAsDefault
Definition: FeedWriter.js:1257
const PREF_VIDEO_SELECTED_WEB
Definition: FeedWriter.js:96
const PREF_AUDIO_SELECTED_READER
Definition: FeedWriter.js:103
this _setSelectedHandler(feedType)
let window
const TYPE_MAYBE_FEED
Definition: FeedWriter.js:84
this _contentSandbox handlersMenuPopup
Definition: FeedWriter.js:991
function FeedWriter()
Definition: FeedWriter.js:186
var feedTitle
Definition: FeedWriter.js:1313
const SUBTITLE_ID
Definition: FeedWriter.js:108
const Cc
Definition: FeedWriter.js:43
const PREF_AUDIO_SELECTED_APP
Definition: FeedWriter.js:100
sbDeviceFirmwareAutoCheckForUpdate prototype getHelperForLanguage
_window init
Definition: FeedWriter.js:1144
this _window
Definition: FeedWriter.js:1158
const PREF_VIDEO_SELECTED_ACTION
Definition: FeedWriter.js:97
var t
var resolvedURI
Definition: FeedWriter.js:1136
getService(Ci.nsIPrefBranch)
this _selectedApp
Definition: FeedWriter.js:977
this _setTitleText(container)
function makeURI(aURLSpec, aCharset)
Definition: FeedWriter.js:71
classDescription classID
Definition: FeedWriter.js:1427
var feedSubtitle
Definition: FeedWriter.js:1314
this _setSubscribeUsingLabel()
var selectedItem
Definition: FeedWriter.js:1261
onPageChanged onPageExpired
Definition: FeedWriter.js:1395
this _initSubscriptionUI()
DataRemote prototype constructor
this _setTitleImage(container)
this _setAlwaysUseLabel()
const PREF_SELECTED_READER
Definition: FeedWriter.js:93
const PREF_SELECTED_ACTION
Definition: FeedWriter.js:92
onPageChanged aWhat
Definition: FeedWriter.js:1392
const PREF_SHOW_FIRST_RUN_UI
Definition: FeedWriter.js:105
onPageChanged onBeginUpdateBatch
Definition: FeedWriter.js:1395
return null
Definition: FeedWriter.js:1143
var codeStr
Definition: FeedWriter.js:815
var handler
Definition: FeedWriter.js:887
var showFirstRunUI
Definition: FeedWriter.js:1088
let node
var feedType
Definition: FeedWriter.js:949
function getPrefAppForType(t)
Definition: FeedWriter.js:110
onPageChanged onTitleChanged
Definition: FeedWriter.js:1395
function url(spec)
var uri
Definition: FeedWriter.js:1135
var prefs
Definition: FeedWriter.js:1169
onPageChanged getInterfaces
Definition: FeedWriter.js:1395
return aWindow document documentElement getAttribute(aAttribute)||dimension
this _removeFeedFromCache()
_setFaviconForWebReader aMenuItem
Definition: FeedWriter.js:1369
var defaultHandler
Definition: FeedWriter.js:1256
const PREF_AUDIO_SELECTED_WEB
Definition: FeedWriter.js:101
observe topic
Definition: FeedWriter.js:1326
const TITLE_ID
Definition: FeedWriter.js:107
_window _feedURI
Definition: FeedWriter.js:1144
var ios
Definition: head_feeds.js:5
this __faviconService
Definition: FeedWriter.js:1231
const Ci
Definition: FeedWriter.js:44
onPageChanged onDeleteURI
Definition: FeedWriter.js:1395
function getPrefActionForType(t)
Definition: FeedWriter.js:136
var browser
Definition: openLocation.js:42
const PREF_VIDEO_SELECTED_READER
Definition: FeedWriter.js:98
observe data
Definition: FeedWriter.js:1329
var secman
Definition: FeedWriter.js:1161
_window _document
Definition: FeedWriter.js:1144
const PREF_SELECTED_APP
Definition: FeedWriter.js:90
_getSelectedPageStyle s i
onPageChanged onClearHistory
Definition: FeedWriter.js:1395
const Cr
Definition: FeedWriter.js:45
this _initMenuItemWithFile(menuItem, this._defaultSystemReader)
const TYPE_MAYBE_AUDIO_FEED
Definition: FeedWriter.js:85
var file
sbDeviceFirmwareAutoCheckForUpdate prototype observe
const Cu
Definition: FeedWriter.js:46