Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
michael@0 | 1 | # -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 5 | |
michael@0 | 6 | const Cc = Components.classes; |
michael@0 | 7 | const Ci = Components.interfaces; |
michael@0 | 8 | const Cr = Components.results; |
michael@0 | 9 | const Cu = Components.utils; |
michael@0 | 10 | |
michael@0 | 11 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 12 | |
michael@0 | 13 | const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"); |
michael@0 | 14 | const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1"; |
michael@0 | 15 | |
michael@0 | 16 | function LOG(str) { |
michael@0 | 17 | var prefB = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 18 | getService(Ci.nsIPrefBranch); |
michael@0 | 19 | |
michael@0 | 20 | var shouldLog = false; |
michael@0 | 21 | try { |
michael@0 | 22 | shouldLog = prefB.getBoolPref("feeds.log"); |
michael@0 | 23 | } |
michael@0 | 24 | catch (ex) { |
michael@0 | 25 | } |
michael@0 | 26 | |
michael@0 | 27 | if (shouldLog) |
michael@0 | 28 | dump("*** Feeds: " + str + "\n"); |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | /** |
michael@0 | 32 | * Wrapper function for nsIIOService::newURI. |
michael@0 | 33 | * @param aURLSpec |
michael@0 | 34 | * The URL string from which to create an nsIURI. |
michael@0 | 35 | * @returns an nsIURI object, or null if the creation of the URI failed. |
michael@0 | 36 | */ |
michael@0 | 37 | function makeURI(aURLSpec, aCharset) { |
michael@0 | 38 | var ios = Cc["@mozilla.org/network/io-service;1"]. |
michael@0 | 39 | getService(Ci.nsIIOService); |
michael@0 | 40 | try { |
michael@0 | 41 | return ios.newURI(aURLSpec, aCharset, null); |
michael@0 | 42 | } catch (ex) { } |
michael@0 | 43 | |
michael@0 | 44 | return null; |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | const XML_NS = "http://www.w3.org/XML/1998/namespace"; |
michael@0 | 48 | const HTML_NS = "http://www.w3.org/1999/xhtml"; |
michael@0 | 49 | const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; |
michael@0 | 50 | const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; |
michael@0 | 51 | const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed"; |
michael@0 | 52 | const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed"; |
michael@0 | 53 | const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties"; |
michael@0 | 54 | |
michael@0 | 55 | const PREF_SELECTED_APP = "browser.feeds.handlers.application"; |
michael@0 | 56 | const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice"; |
michael@0 | 57 | const PREF_SELECTED_ACTION = "browser.feeds.handler"; |
michael@0 | 58 | const PREF_SELECTED_READER = "browser.feeds.handler.default"; |
michael@0 | 59 | |
michael@0 | 60 | const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application"; |
michael@0 | 61 | const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice"; |
michael@0 | 62 | const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler"; |
michael@0 | 63 | const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default"; |
michael@0 | 64 | |
michael@0 | 65 | const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application"; |
michael@0 | 66 | const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice"; |
michael@0 | 67 | const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler"; |
michael@0 | 68 | const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default"; |
michael@0 | 69 | |
michael@0 | 70 | const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI"; |
michael@0 | 71 | |
michael@0 | 72 | const TITLE_ID = "feedTitleText"; |
michael@0 | 73 | const SUBTITLE_ID = "feedSubtitleText"; |
michael@0 | 74 | |
michael@0 | 75 | function getPrefAppForType(t) { |
michael@0 | 76 | switch (t) { |
michael@0 | 77 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 78 | return PREF_VIDEO_SELECTED_APP; |
michael@0 | 79 | |
michael@0 | 80 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 81 | return PREF_AUDIO_SELECTED_APP; |
michael@0 | 82 | |
michael@0 | 83 | default: |
michael@0 | 84 | return PREF_SELECTED_APP; |
michael@0 | 85 | } |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | function getPrefWebForType(t) { |
michael@0 | 89 | switch (t) { |
michael@0 | 90 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 91 | return PREF_VIDEO_SELECTED_WEB; |
michael@0 | 92 | |
michael@0 | 93 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 94 | return PREF_AUDIO_SELECTED_WEB; |
michael@0 | 95 | |
michael@0 | 96 | default: |
michael@0 | 97 | return PREF_SELECTED_WEB; |
michael@0 | 98 | } |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | function getPrefActionForType(t) { |
michael@0 | 102 | switch (t) { |
michael@0 | 103 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 104 | return PREF_VIDEO_SELECTED_ACTION; |
michael@0 | 105 | |
michael@0 | 106 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 107 | return PREF_AUDIO_SELECTED_ACTION; |
michael@0 | 108 | |
michael@0 | 109 | default: |
michael@0 | 110 | return PREF_SELECTED_ACTION; |
michael@0 | 111 | } |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | function getPrefReaderForType(t) { |
michael@0 | 115 | switch (t) { |
michael@0 | 116 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 117 | return PREF_VIDEO_SELECTED_READER; |
michael@0 | 118 | |
michael@0 | 119 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 120 | return PREF_AUDIO_SELECTED_READER; |
michael@0 | 121 | |
michael@0 | 122 | default: |
michael@0 | 123 | return PREF_SELECTED_READER; |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | /** |
michael@0 | 128 | * Converts a number of bytes to the appropriate unit that results in a |
michael@0 | 129 | * number that needs fewer than 4 digits |
michael@0 | 130 | * |
michael@0 | 131 | * @return a pair: [new value with 3 sig. figs., its unit] |
michael@0 | 132 | */ |
michael@0 | 133 | function convertByteUnits(aBytes) { |
michael@0 | 134 | var units = ["bytes", "kilobyte", "megabyte", "gigabyte"]; |
michael@0 | 135 | let unitIndex = 0; |
michael@0 | 136 | |
michael@0 | 137 | // convert to next unit if it needs 4 digits (after rounding), but only if |
michael@0 | 138 | // we know the name of the next unit |
michael@0 | 139 | while ((aBytes >= 999.5) && (unitIndex < units.length - 1)) { |
michael@0 | 140 | aBytes /= 1024; |
michael@0 | 141 | unitIndex++; |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | // Get rid of insignificant bits by truncating to 1 or 0 decimal points |
michael@0 | 145 | // 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235 |
michael@0 | 146 | aBytes = aBytes.toFixed((aBytes > 0) && (aBytes < 100) ? 1 : 0); |
michael@0 | 147 | |
michael@0 | 148 | return [aBytes, units[unitIndex]]; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | function FeedWriter() {} |
michael@0 | 152 | FeedWriter.prototype = { |
michael@0 | 153 | _mimeSvc : Cc["@mozilla.org/mime;1"]. |
michael@0 | 154 | getService(Ci.nsIMIMEService), |
michael@0 | 155 | |
michael@0 | 156 | _getPropertyAsBag: function FW__getPropertyAsBag(container, property) { |
michael@0 | 157 | return container.fields.getProperty(property). |
michael@0 | 158 | QueryInterface(Ci.nsIPropertyBag2); |
michael@0 | 159 | }, |
michael@0 | 160 | |
michael@0 | 161 | _getPropertyAsString: function FW__getPropertyAsString(container, property) { |
michael@0 | 162 | try { |
michael@0 | 163 | return container.fields.getPropertyAsAString(property); |
michael@0 | 164 | } |
michael@0 | 165 | catch (e) { |
michael@0 | 166 | } |
michael@0 | 167 | return ""; |
michael@0 | 168 | }, |
michael@0 | 169 | |
michael@0 | 170 | _setContentText: function FW__setContentText(id, text) { |
michael@0 | 171 | this._contentSandbox.element = this._document.getElementById(id); |
michael@0 | 172 | this._contentSandbox.textNode = text.createDocumentFragment(this._contentSandbox.element); |
michael@0 | 173 | var codeStr = |
michael@0 | 174 | "while (element.hasChildNodes()) " + |
michael@0 | 175 | " element.removeChild(element.firstChild);" + |
michael@0 | 176 | "element.appendChild(textNode);"; |
michael@0 | 177 | if (text.base) { |
michael@0 | 178 | this._contentSandbox.spec = text.base.spec; |
michael@0 | 179 | codeStr += "element.setAttributeNS('" + XML_NS + "', 'base', spec);"; |
michael@0 | 180 | } |
michael@0 | 181 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 182 | this._contentSandbox.element = null; |
michael@0 | 183 | this._contentSandbox.textNode = null; |
michael@0 | 184 | }, |
michael@0 | 185 | |
michael@0 | 186 | /** |
michael@0 | 187 | * Safely sets the href attribute on an anchor tag, providing the URI |
michael@0 | 188 | * specified can be loaded according to rules. |
michael@0 | 189 | * @param element |
michael@0 | 190 | * The element to set a URI attribute on |
michael@0 | 191 | * @param attribute |
michael@0 | 192 | * The attribute of the element to set the URI to, e.g. href or src |
michael@0 | 193 | * @param uri |
michael@0 | 194 | * The URI spec to set as the href |
michael@0 | 195 | */ |
michael@0 | 196 | _safeSetURIAttribute: |
michael@0 | 197 | function FW__safeSetURIAttribute(element, attribute, uri) { |
michael@0 | 198 | var secman = Cc["@mozilla.org/scriptsecuritymanager;1"]. |
michael@0 | 199 | getService(Ci.nsIScriptSecurityManager); |
michael@0 | 200 | const flags = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL; |
michael@0 | 201 | try { |
michael@0 | 202 | secman.checkLoadURIStrWithPrincipal(this._feedPrincipal, uri, flags); |
michael@0 | 203 | // checkLoadURIStrWithPrincipal will throw if the link URI should not be |
michael@0 | 204 | // loaded, either because our feedURI isn't allowed to load it or per |
michael@0 | 205 | // the rules specified in |flags|, so we'll never "linkify" the link... |
michael@0 | 206 | } |
michael@0 | 207 | catch (e) { |
michael@0 | 208 | // Not allowed to load this link because secman.checkLoadURIStr threw |
michael@0 | 209 | return; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | this._contentSandbox.element = element; |
michael@0 | 213 | this._contentSandbox.uri = uri; |
michael@0 | 214 | var codeStr = "element.setAttribute('" + attribute + "', uri);"; |
michael@0 | 215 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 216 | }, |
michael@0 | 217 | |
michael@0 | 218 | /** |
michael@0 | 219 | * Use this sandbox to run any dom manipulation code on nodes which |
michael@0 | 220 | * are already inserted into the content document. |
michael@0 | 221 | */ |
michael@0 | 222 | __contentSandbox: null, |
michael@0 | 223 | get _contentSandbox() { |
michael@0 | 224 | // This whole sandbox setup is totally archaic. It was introduced in bug |
michael@0 | 225 | // 360529, presumably before the existence of a solid security membrane, |
michael@0 | 226 | // since all of the manipulation of content here should be made safe by |
michael@0 | 227 | // Xrays. And now that anonymous content is no longer content-accessible, |
michael@0 | 228 | // manipulating the xml stylesheet content can't be done from content |
michael@0 | 229 | // anymore. |
michael@0 | 230 | // |
michael@0 | 231 | // The right solution would be to rip out all of this sandbox junk and |
michael@0 | 232 | // manipulate the DOM directly. But that's a big yak to shave, so for now, |
michael@0 | 233 | // we just give the sandbox an nsExpandedPrincipal with []. This has the |
michael@0 | 234 | // effect of giving it Xrays, and making it same-origin with the XBL scope, |
michael@0 | 235 | // thereby letting it manipulate anonymous content. |
michael@0 | 236 | if (!this.__contentSandbox) |
michael@0 | 237 | this.__contentSandbox = new Cu.Sandbox([this._window], |
michael@0 | 238 | {sandboxName: 'FeedWriter'}); |
michael@0 | 239 | |
michael@0 | 240 | return this.__contentSandbox; |
michael@0 | 241 | }, |
michael@0 | 242 | |
michael@0 | 243 | /** |
michael@0 | 244 | * Calls doCommand for a given XUL element within the context of the |
michael@0 | 245 | * content document. |
michael@0 | 246 | * |
michael@0 | 247 | * @param aElement |
michael@0 | 248 | * the XUL element to call doCommand() on. |
michael@0 | 249 | */ |
michael@0 | 250 | _safeDoCommand: function FW___safeDoCommand(aElement) { |
michael@0 | 251 | this._contentSandbox.element = aElement; |
michael@0 | 252 | Cu.evalInSandbox("element.doCommand();", this._contentSandbox); |
michael@0 | 253 | this._contentSandbox.element = null; |
michael@0 | 254 | }, |
michael@0 | 255 | |
michael@0 | 256 | __faviconService: null, |
michael@0 | 257 | get _faviconService() { |
michael@0 | 258 | if (!this.__faviconService) |
michael@0 | 259 | this.__faviconService = Cc["@mozilla.org/browser/favicon-service;1"]. |
michael@0 | 260 | getService(Ci.nsIFaviconService); |
michael@0 | 261 | |
michael@0 | 262 | return this.__faviconService; |
michael@0 | 263 | }, |
michael@0 | 264 | |
michael@0 | 265 | __bundle: null, |
michael@0 | 266 | get _bundle() { |
michael@0 | 267 | if (!this.__bundle) { |
michael@0 | 268 | this.__bundle = Cc["@mozilla.org/intl/stringbundle;1"]. |
michael@0 | 269 | getService(Ci.nsIStringBundleService). |
michael@0 | 270 | createBundle(URI_BUNDLE); |
michael@0 | 271 | } |
michael@0 | 272 | return this.__bundle; |
michael@0 | 273 | }, |
michael@0 | 274 | |
michael@0 | 275 | _getFormattedString: function FW__getFormattedString(key, params) { |
michael@0 | 276 | return this._bundle.formatStringFromName(key, params, params.length); |
michael@0 | 277 | }, |
michael@0 | 278 | |
michael@0 | 279 | _getString: function FW__getString(key) { |
michael@0 | 280 | return this._bundle.GetStringFromName(key); |
michael@0 | 281 | }, |
michael@0 | 282 | |
michael@0 | 283 | /* Magic helper methods to be used instead of xbl properties */ |
michael@0 | 284 | _getSelectedItemFromMenulist: function FW__getSelectedItemFromList(aList) { |
michael@0 | 285 | var node = aList.firstChild.firstChild; |
michael@0 | 286 | while (node) { |
michael@0 | 287 | if (node.localName == "menuitem" && node.getAttribute("selected") == "true") |
michael@0 | 288 | return node; |
michael@0 | 289 | |
michael@0 | 290 | node = node.nextSibling; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | return null; |
michael@0 | 294 | }, |
michael@0 | 295 | |
michael@0 | 296 | _setCheckboxCheckedState: function FW__setCheckboxCheckedState(aCheckbox, aValue) { |
michael@0 | 297 | // see checkbox.xml, xbl bindings are not applied within the sandbox! |
michael@0 | 298 | this._contentSandbox.checkbox = aCheckbox; |
michael@0 | 299 | var codeStr; |
michael@0 | 300 | var change = (aValue != (aCheckbox.getAttribute('checked') == 'true')); |
michael@0 | 301 | if (aValue) |
michael@0 | 302 | codeStr = "checkbox.setAttribute('checked', 'true'); "; |
michael@0 | 303 | else |
michael@0 | 304 | codeStr = "checkbox.removeAttribute('checked'); "; |
michael@0 | 305 | |
michael@0 | 306 | if (change) { |
michael@0 | 307 | this._contentSandbox.document = this._document; |
michael@0 | 308 | codeStr += "var event = document.createEvent('Events'); " + |
michael@0 | 309 | "event.initEvent('CheckboxStateChange', true, true);" + |
michael@0 | 310 | "checkbox.dispatchEvent(event);" |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 314 | }, |
michael@0 | 315 | |
michael@0 | 316 | /** |
michael@0 | 317 | * Returns a date suitable for displaying in the feed preview. |
michael@0 | 318 | * If the date cannot be parsed, the return value is "false". |
michael@0 | 319 | * @param dateString |
michael@0 | 320 | * A date as extracted from a feed entry. (entry.updated) |
michael@0 | 321 | */ |
michael@0 | 322 | _parseDate: function FW__parseDate(dateString) { |
michael@0 | 323 | // Convert the date into the user's local time zone |
michael@0 | 324 | dateObj = new Date(dateString); |
michael@0 | 325 | |
michael@0 | 326 | // Make sure the date we're given is valid. |
michael@0 | 327 | if (!dateObj.getTime()) |
michael@0 | 328 | return false; |
michael@0 | 329 | |
michael@0 | 330 | var dateService = Cc["@mozilla.org/intl/scriptabledateformat;1"]. |
michael@0 | 331 | getService(Ci.nsIScriptableDateFormat); |
michael@0 | 332 | return dateService.FormatDateTime("", dateService.dateFormatLong, dateService.timeFormatNoSeconds, |
michael@0 | 333 | dateObj.getFullYear(), dateObj.getMonth()+1, dateObj.getDate(), |
michael@0 | 334 | dateObj.getHours(), dateObj.getMinutes(), dateObj.getSeconds()); |
michael@0 | 335 | }, |
michael@0 | 336 | |
michael@0 | 337 | /** |
michael@0 | 338 | * Returns the feed type. |
michael@0 | 339 | */ |
michael@0 | 340 | __feedType: null, |
michael@0 | 341 | _getFeedType: function FW__getFeedType() { |
michael@0 | 342 | if (this.__feedType != null) |
michael@0 | 343 | return this.__feedType; |
michael@0 | 344 | |
michael@0 | 345 | try { |
michael@0 | 346 | // grab the feed because it's got the feed.type in it. |
michael@0 | 347 | var container = this._getContainer(); |
michael@0 | 348 | var feed = container.QueryInterface(Ci.nsIFeed); |
michael@0 | 349 | this.__feedType = feed.type; |
michael@0 | 350 | return feed.type; |
michael@0 | 351 | } catch (ex) { } |
michael@0 | 352 | |
michael@0 | 353 | return Ci.nsIFeed.TYPE_FEED; |
michael@0 | 354 | }, |
michael@0 | 355 | |
michael@0 | 356 | /** |
michael@0 | 357 | * Maps a feed type to a maybe-feed mimetype. |
michael@0 | 358 | */ |
michael@0 | 359 | _getMimeTypeForFeedType: function FW__getMimeTypeForFeedType() { |
michael@0 | 360 | switch (this._getFeedType()) { |
michael@0 | 361 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 362 | return TYPE_MAYBE_VIDEO_FEED; |
michael@0 | 363 | |
michael@0 | 364 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 365 | return TYPE_MAYBE_AUDIO_FEED; |
michael@0 | 366 | |
michael@0 | 367 | default: |
michael@0 | 368 | return TYPE_MAYBE_FEED; |
michael@0 | 369 | } |
michael@0 | 370 | }, |
michael@0 | 371 | |
michael@0 | 372 | /** |
michael@0 | 373 | * Writes the feed title into the preview document. |
michael@0 | 374 | * @param container |
michael@0 | 375 | * The feed container |
michael@0 | 376 | */ |
michael@0 | 377 | _setTitleText: function FW__setTitleText(container) { |
michael@0 | 378 | if (container.title) { |
michael@0 | 379 | var title = container.title.plainText(); |
michael@0 | 380 | this._setContentText(TITLE_ID, container.title); |
michael@0 | 381 | this._contentSandbox.document = this._document; |
michael@0 | 382 | this._contentSandbox.title = title; |
michael@0 | 383 | var codeStr = "document.title = title;" |
michael@0 | 384 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | var feed = container.QueryInterface(Ci.nsIFeed); |
michael@0 | 388 | if (feed && feed.subtitle) |
michael@0 | 389 | this._setContentText(SUBTITLE_ID, container.subtitle); |
michael@0 | 390 | }, |
michael@0 | 391 | |
michael@0 | 392 | /** |
michael@0 | 393 | * Writes the title image into the preview document if one is present. |
michael@0 | 394 | * @param container |
michael@0 | 395 | * The feed container |
michael@0 | 396 | */ |
michael@0 | 397 | _setTitleImage: function FW__setTitleImage(container) { |
michael@0 | 398 | try { |
michael@0 | 399 | var parts = container.image; |
michael@0 | 400 | |
michael@0 | 401 | // Set up the title image (supplied by the feed) |
michael@0 | 402 | var feedTitleImage = this._document.getElementById("feedTitleImage"); |
michael@0 | 403 | this._safeSetURIAttribute(feedTitleImage, "src", |
michael@0 | 404 | parts.getPropertyAsAString("url")); |
michael@0 | 405 | |
michael@0 | 406 | // Set up the title image link |
michael@0 | 407 | var feedTitleLink = this._document.getElementById("feedTitleLink"); |
michael@0 | 408 | |
michael@0 | 409 | var titleText = this._getFormattedString("linkTitleTextFormat", |
michael@0 | 410 | [parts.getPropertyAsAString("title")]); |
michael@0 | 411 | this._contentSandbox.feedTitleLink = feedTitleLink; |
michael@0 | 412 | this._contentSandbox.titleText = titleText; |
michael@0 | 413 | this._contentSandbox.feedTitleText = this._document.getElementById("feedTitleText"); |
michael@0 | 414 | this._contentSandbox.titleImageWidth = parseInt(parts.getPropertyAsAString("width")) + 15; |
michael@0 | 415 | |
michael@0 | 416 | // Fix the margin on the main title, so that the image doesn't run over |
michael@0 | 417 | // the underline |
michael@0 | 418 | var codeStr = "feedTitleLink.setAttribute('title', titleText); " + |
michael@0 | 419 | "feedTitleText.style.marginRight = titleImageWidth + 'px';"; |
michael@0 | 420 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 421 | this._contentSandbox.feedTitleLink = null; |
michael@0 | 422 | this._contentSandbox.titleText = null; |
michael@0 | 423 | this._contentSandbox.feedTitleText = null; |
michael@0 | 424 | this._contentSandbox.titleImageWidth = null; |
michael@0 | 425 | |
michael@0 | 426 | this._safeSetURIAttribute(feedTitleLink, "href", |
michael@0 | 427 | parts.getPropertyAsAString("link")); |
michael@0 | 428 | } |
michael@0 | 429 | catch (e) { |
michael@0 | 430 | LOG("Failed to set Title Image (this is benign): " + e); |
michael@0 | 431 | } |
michael@0 | 432 | }, |
michael@0 | 433 | |
michael@0 | 434 | /** |
michael@0 | 435 | * Writes all entries contained in the feed. |
michael@0 | 436 | * @param container |
michael@0 | 437 | * The container of entries in the feed |
michael@0 | 438 | */ |
michael@0 | 439 | _writeFeedContent: function FW__writeFeedContent(container) { |
michael@0 | 440 | // Build the actual feed content |
michael@0 | 441 | var feed = container.QueryInterface(Ci.nsIFeed); |
michael@0 | 442 | if (feed.items.length == 0) |
michael@0 | 443 | return; |
michael@0 | 444 | |
michael@0 | 445 | this._contentSandbox.feedContent = |
michael@0 | 446 | this._document.getElementById("feedContent"); |
michael@0 | 447 | |
michael@0 | 448 | for (var i = 0; i < feed.items.length; ++i) { |
michael@0 | 449 | var entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry); |
michael@0 | 450 | entry.QueryInterface(Ci.nsIFeedContainer); |
michael@0 | 451 | |
michael@0 | 452 | var entryContainer = this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 453 | entryContainer.className = "entry"; |
michael@0 | 454 | |
michael@0 | 455 | // If the entry has a title, make it a link |
michael@0 | 456 | if (entry.title) { |
michael@0 | 457 | var a = this._document.createElementNS(HTML_NS, "a"); |
michael@0 | 458 | var span = this._document.createElementNS(HTML_NS, "span"); |
michael@0 | 459 | a.appendChild(span); |
michael@0 | 460 | if (entry.title.base) |
michael@0 | 461 | span.setAttributeNS(XML_NS, "base", entry.title.base.spec); |
michael@0 | 462 | span.appendChild(entry.title.createDocumentFragment(a)); |
michael@0 | 463 | |
michael@0 | 464 | // Entries are not required to have links, so entry.link can be null. |
michael@0 | 465 | if (entry.link) |
michael@0 | 466 | this._safeSetURIAttribute(a, "href", entry.link.spec); |
michael@0 | 467 | |
michael@0 | 468 | var title = this._document.createElementNS(HTML_NS, "h3"); |
michael@0 | 469 | title.appendChild(a); |
michael@0 | 470 | |
michael@0 | 471 | var lastUpdated = this._parseDate(entry.updated); |
michael@0 | 472 | if (lastUpdated) { |
michael@0 | 473 | var dateDiv = this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 474 | dateDiv.className = "lastUpdated"; |
michael@0 | 475 | dateDiv.textContent = lastUpdated; |
michael@0 | 476 | title.appendChild(dateDiv); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | entryContainer.appendChild(title); |
michael@0 | 480 | } |
michael@0 | 481 | |
michael@0 | 482 | var body = this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 483 | var summary = entry.summary || entry.content; |
michael@0 | 484 | var docFragment = null; |
michael@0 | 485 | if (summary) { |
michael@0 | 486 | if (summary.base) |
michael@0 | 487 | body.setAttributeNS(XML_NS, "base", summary.base.spec); |
michael@0 | 488 | else |
michael@0 | 489 | LOG("no base?"); |
michael@0 | 490 | docFragment = summary.createDocumentFragment(body); |
michael@0 | 491 | if (docFragment) |
michael@0 | 492 | body.appendChild(docFragment); |
michael@0 | 493 | |
michael@0 | 494 | // If the entry doesn't have a title, append a # permalink |
michael@0 | 495 | // See http://scripting.com/rss.xml for an example |
michael@0 | 496 | if (!entry.title && entry.link) { |
michael@0 | 497 | var a = this._document.createElementNS(HTML_NS, "a"); |
michael@0 | 498 | a.appendChild(this._document.createTextNode("#")); |
michael@0 | 499 | this._safeSetURIAttribute(a, "href", entry.link.spec); |
michael@0 | 500 | body.appendChild(this._document.createTextNode(" ")); |
michael@0 | 501 | body.appendChild(a); |
michael@0 | 502 | } |
michael@0 | 503 | |
michael@0 | 504 | } |
michael@0 | 505 | body.className = "feedEntryContent"; |
michael@0 | 506 | entryContainer.appendChild(body); |
michael@0 | 507 | |
michael@0 | 508 | if (entry.enclosures && entry.enclosures.length > 0) { |
michael@0 | 509 | var enclosuresDiv = this._buildEnclosureDiv(entry); |
michael@0 | 510 | entryContainer.appendChild(enclosuresDiv); |
michael@0 | 511 | } |
michael@0 | 512 | |
michael@0 | 513 | this._contentSandbox.entryContainer = entryContainer; |
michael@0 | 514 | this._contentSandbox.clearDiv = |
michael@0 | 515 | this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 516 | this._contentSandbox.clearDiv.style.clear = "both"; |
michael@0 | 517 | |
michael@0 | 518 | var codeStr = "feedContent.appendChild(entryContainer); " + |
michael@0 | 519 | "feedContent.appendChild(clearDiv);" |
michael@0 | 520 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | this._contentSandbox.feedContent = null; |
michael@0 | 524 | this._contentSandbox.entryContainer = null; |
michael@0 | 525 | this._contentSandbox.clearDiv = null; |
michael@0 | 526 | }, |
michael@0 | 527 | |
michael@0 | 528 | /** |
michael@0 | 529 | * Takes a url to a media item and returns the best name it can come up with. |
michael@0 | 530 | * Frequently this is the filename portion (e.g. passing in |
michael@0 | 531 | * http://example.com/foo.mpeg would return "foo.mpeg"), but in more complex |
michael@0 | 532 | * cases, this will return the entire url (e.g. passing in |
michael@0 | 533 | * http://example.com/somedirectory/ would return |
michael@0 | 534 | * http://example.com/somedirectory/). |
michael@0 | 535 | * @param aURL |
michael@0 | 536 | * The URL string from which to create a display name |
michael@0 | 537 | * @returns a string |
michael@0 | 538 | */ |
michael@0 | 539 | _getURLDisplayName: function FW__getURLDisplayName(aURL) { |
michael@0 | 540 | var url = makeURI(aURL); |
michael@0 | 541 | url.QueryInterface(Ci.nsIURL); |
michael@0 | 542 | if (url == null || url.fileName.length == 0) |
michael@0 | 543 | return decodeURIComponent(aURL); |
michael@0 | 544 | |
michael@0 | 545 | return decodeURIComponent(url.fileName); |
michael@0 | 546 | }, |
michael@0 | 547 | |
michael@0 | 548 | /** |
michael@0 | 549 | * Takes a FeedEntry with enclosures, generates the HTML code to represent |
michael@0 | 550 | * them, and returns that. |
michael@0 | 551 | * @param entry |
michael@0 | 552 | * FeedEntry with enclosures |
michael@0 | 553 | * @returns element |
michael@0 | 554 | */ |
michael@0 | 555 | _buildEnclosureDiv: function FW__buildEnclosureDiv(entry) { |
michael@0 | 556 | var enclosuresDiv = this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 557 | enclosuresDiv.className = "enclosures"; |
michael@0 | 558 | |
michael@0 | 559 | enclosuresDiv.appendChild(this._document.createTextNode(this._getString("mediaLabel"))); |
michael@0 | 560 | |
michael@0 | 561 | var roundme = function(n) { |
michael@0 | 562 | return (Math.round(n * 100) / 100).toLocaleString(); |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | for (var i_enc = 0; i_enc < entry.enclosures.length; ++i_enc) { |
michael@0 | 566 | var enc = entry.enclosures.queryElementAt(i_enc, Ci.nsIWritablePropertyBag2); |
michael@0 | 567 | |
michael@0 | 568 | if (!(enc.hasKey("url"))) |
michael@0 | 569 | continue; |
michael@0 | 570 | |
michael@0 | 571 | var enclosureDiv = this._document.createElementNS(HTML_NS, "div"); |
michael@0 | 572 | enclosureDiv.setAttribute("class", "enclosure"); |
michael@0 | 573 | |
michael@0 | 574 | var mozicon = "moz-icon://.txt?size=16"; |
michael@0 | 575 | var type_text = null; |
michael@0 | 576 | var size_text = null; |
michael@0 | 577 | |
michael@0 | 578 | if (enc.hasKey("type")) { |
michael@0 | 579 | type_text = enc.get("type"); |
michael@0 | 580 | try { |
michael@0 | 581 | var handlerInfoWrapper = this._mimeSvc.getFromTypeAndExtension(enc.get("type"), null); |
michael@0 | 582 | |
michael@0 | 583 | if (handlerInfoWrapper) |
michael@0 | 584 | type_text = handlerInfoWrapper.description; |
michael@0 | 585 | |
michael@0 | 586 | if (type_text && type_text.length > 0) |
michael@0 | 587 | mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type"); |
michael@0 | 588 | |
michael@0 | 589 | } catch (ex) { } |
michael@0 | 590 | |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) { |
michael@0 | 594 | var enc_size = convertByteUnits(parseInt(enc.get("length"))); |
michael@0 | 595 | |
michael@0 | 596 | var size_text = this._getFormattedString("enclosureSizeText", |
michael@0 | 597 | [enc_size[0], this._getString(enc_size[1])]); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | var iconimg = this._document.createElementNS(HTML_NS, "img"); |
michael@0 | 601 | iconimg.setAttribute("src", mozicon); |
michael@0 | 602 | iconimg.setAttribute("class", "type-icon"); |
michael@0 | 603 | enclosureDiv.appendChild(iconimg); |
michael@0 | 604 | |
michael@0 | 605 | enclosureDiv.appendChild(this._document.createTextNode( " " )); |
michael@0 | 606 | |
michael@0 | 607 | var enc_href = this._document.createElementNS(HTML_NS, "a"); |
michael@0 | 608 | enc_href.appendChild(this._document.createTextNode(this._getURLDisplayName(enc.get("url")))); |
michael@0 | 609 | this._safeSetURIAttribute(enc_href, "href", enc.get("url")); |
michael@0 | 610 | enclosureDiv.appendChild(enc_href); |
michael@0 | 611 | |
michael@0 | 612 | if (type_text && size_text) |
michael@0 | 613 | enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ", " + size_text + ")")); |
michael@0 | 614 | |
michael@0 | 615 | else if (type_text) |
michael@0 | 616 | enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ")")) |
michael@0 | 617 | |
michael@0 | 618 | else if (size_text) |
michael@0 | 619 | enclosureDiv.appendChild(this._document.createTextNode( " (" + size_text + ")")) |
michael@0 | 620 | |
michael@0 | 621 | enclosuresDiv.appendChild(enclosureDiv); |
michael@0 | 622 | } |
michael@0 | 623 | |
michael@0 | 624 | return enclosuresDiv; |
michael@0 | 625 | }, |
michael@0 | 626 | |
michael@0 | 627 | /** |
michael@0 | 628 | * Gets a valid nsIFeedContainer object from the parsed nsIFeedResult. |
michael@0 | 629 | * Displays error information if there was one. |
michael@0 | 630 | * @param result |
michael@0 | 631 | * The parsed feed result |
michael@0 | 632 | * @returns A valid nsIFeedContainer object containing the contents of |
michael@0 | 633 | * the feed. |
michael@0 | 634 | */ |
michael@0 | 635 | _getContainer: function FW__getContainer(result) { |
michael@0 | 636 | var feedService = |
michael@0 | 637 | Cc["@mozilla.org/browser/feeds/result-service;1"]. |
michael@0 | 638 | getService(Ci.nsIFeedResultService); |
michael@0 | 639 | |
michael@0 | 640 | try { |
michael@0 | 641 | var result = |
michael@0 | 642 | feedService.getFeedResult(this._getOriginalURI(this._window)); |
michael@0 | 643 | } |
michael@0 | 644 | catch (e) { |
michael@0 | 645 | LOG("Subscribe Preview: feed not available?!"); |
michael@0 | 646 | } |
michael@0 | 647 | |
michael@0 | 648 | if (result.bozo) { |
michael@0 | 649 | LOG("Subscribe Preview: feed result is bozo?!"); |
michael@0 | 650 | } |
michael@0 | 651 | |
michael@0 | 652 | try { |
michael@0 | 653 | var container = result.doc; |
michael@0 | 654 | } |
michael@0 | 655 | catch (e) { |
michael@0 | 656 | LOG("Subscribe Preview: no result.doc? Why didn't the original reload?"); |
michael@0 | 657 | return null; |
michael@0 | 658 | } |
michael@0 | 659 | return container; |
michael@0 | 660 | }, |
michael@0 | 661 | |
michael@0 | 662 | /** |
michael@0 | 663 | * Get the human-readable display name of a file. This could be the |
michael@0 | 664 | * application name. |
michael@0 | 665 | * @param file |
michael@0 | 666 | * A nsIFile to look up the name of |
michael@0 | 667 | * @returns The display name of the application represented by the file. |
michael@0 | 668 | */ |
michael@0 | 669 | _getFileDisplayName: function FW__getFileDisplayName(file) { |
michael@0 | 670 | #ifdef XP_WIN |
michael@0 | 671 | if (file instanceof Ci.nsILocalFileWin) { |
michael@0 | 672 | try { |
michael@0 | 673 | return file.getVersionInfoField("FileDescription"); |
michael@0 | 674 | } catch (e) {} |
michael@0 | 675 | } |
michael@0 | 676 | #endif |
michael@0 | 677 | #ifdef XP_MACOSX |
michael@0 | 678 | if (file instanceof Ci.nsILocalFileMac) { |
michael@0 | 679 | try { |
michael@0 | 680 | return file.bundleDisplayName; |
michael@0 | 681 | } catch (e) {} |
michael@0 | 682 | } |
michael@0 | 683 | #endif |
michael@0 | 684 | return file.leafName; |
michael@0 | 685 | }, |
michael@0 | 686 | |
michael@0 | 687 | /** |
michael@0 | 688 | * Get moz-icon url for a file |
michael@0 | 689 | * @param file |
michael@0 | 690 | * A nsIFile object for which the moz-icon:// is returned |
michael@0 | 691 | * @returns moz-icon url of the given file as a string |
michael@0 | 692 | */ |
michael@0 | 693 | _getFileIconURL: function FW__getFileIconURL(file) { |
michael@0 | 694 | var ios = Cc["@mozilla.org/network/io-service;1"]. |
michael@0 | 695 | getService(Ci.nsIIOService); |
michael@0 | 696 | var fph = ios.getProtocolHandler("file") |
michael@0 | 697 | .QueryInterface(Ci.nsIFileProtocolHandler); |
michael@0 | 698 | var urlSpec = fph.getURLSpecFromFile(file); |
michael@0 | 699 | return "moz-icon://" + urlSpec + "?size=16"; |
michael@0 | 700 | }, |
michael@0 | 701 | |
michael@0 | 702 | /** |
michael@0 | 703 | * Helper method to set the selected application and system default |
michael@0 | 704 | * reader menuitems details from a file object |
michael@0 | 705 | * @param aMenuItem |
michael@0 | 706 | * The menuitem on which the attributes should be set |
michael@0 | 707 | * @param aFile |
michael@0 | 708 | * The menuitem's associated file |
michael@0 | 709 | */ |
michael@0 | 710 | _initMenuItemWithFile: function(aMenuItem, aFile) { |
michael@0 | 711 | this._contentSandbox.menuitem = aMenuItem; |
michael@0 | 712 | this._contentSandbox.label = this._getFileDisplayName(aFile); |
michael@0 | 713 | this._contentSandbox.image = this._getFileIconURL(aFile); |
michael@0 | 714 | var codeStr = "menuitem.setAttribute('label', label); " + |
michael@0 | 715 | "menuitem.setAttribute('image', image);" |
michael@0 | 716 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 717 | }, |
michael@0 | 718 | |
michael@0 | 719 | /** |
michael@0 | 720 | * Helper method to get an element in the XBL binding where the handler |
michael@0 | 721 | * selection UI lives |
michael@0 | 722 | */ |
michael@0 | 723 | _getUIElement: function FW__getUIElement(id) { |
michael@0 | 724 | return this._document.getAnonymousElementByAttribute( |
michael@0 | 725 | this._document.getElementById("feedSubscribeLine"), "anonid", id); |
michael@0 | 726 | }, |
michael@0 | 727 | |
michael@0 | 728 | /** |
michael@0 | 729 | * Displays a prompt from which the user may choose a (client) feed reader. |
michael@0 | 730 | * @param aCallback the callback method, passes in true if a feed reader was |
michael@0 | 731 | * selected, false otherwise. |
michael@0 | 732 | */ |
michael@0 | 733 | _chooseClientApp: function FW__chooseClientApp(aCallback) { |
michael@0 | 734 | try { |
michael@0 | 735 | let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); |
michael@0 | 736 | let fpCallback = function fpCallback_done(aResult) { |
michael@0 | 737 | if (aResult == Ci.nsIFilePicker.returnOK) { |
michael@0 | 738 | this._selectedApp = fp.file; |
michael@0 | 739 | if (this._selectedApp) { |
michael@0 | 740 | // XXXben - we need to compare this with the running instance |
michael@0 | 741 | // executable just don't know how to do that via script |
michael@0 | 742 | // XXXmano TBD: can probably add this to nsIShellService |
michael@0 | 743 | #ifdef XP_WIN |
michael@0 | 744 | #expand if (fp.file.leafName != "__MOZ_APP_NAME__.exe") { |
michael@0 | 745 | #else |
michael@0 | 746 | #ifdef XP_MACOSX |
michael@0 | 747 | #expand if (fp.file.leafName != "__MOZ_MACBUNDLE_NAME__") { |
michael@0 | 748 | #else |
michael@0 | 749 | #expand if (fp.file.leafName != "__MOZ_APP_NAME__-bin") { |
michael@0 | 750 | #endif |
michael@0 | 751 | #endif |
michael@0 | 752 | this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem, |
michael@0 | 753 | this._selectedApp); |
michael@0 | 754 | |
michael@0 | 755 | // Show and select the selected application menuitem |
michael@0 | 756 | let codeStr = "selectedAppMenuItem.hidden = false;" + |
michael@0 | 757 | "selectedAppMenuItem.doCommand();" |
michael@0 | 758 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 759 | if (aCallback) { |
michael@0 | 760 | aCallback(true); |
michael@0 | 761 | return; |
michael@0 | 762 | } |
michael@0 | 763 | } |
michael@0 | 764 | } |
michael@0 | 765 | } |
michael@0 | 766 | if (aCallback) { |
michael@0 | 767 | aCallback(false); |
michael@0 | 768 | } |
michael@0 | 769 | }.bind(this); |
michael@0 | 770 | |
michael@0 | 771 | fp.init(this._window, this._getString("chooseApplicationDialogTitle"), |
michael@0 | 772 | Ci.nsIFilePicker.modeOpen); |
michael@0 | 773 | fp.appendFilters(Ci.nsIFilePicker.filterApps); |
michael@0 | 774 | fp.open(fpCallback); |
michael@0 | 775 | } catch(ex) { |
michael@0 | 776 | } |
michael@0 | 777 | }, |
michael@0 | 778 | |
michael@0 | 779 | _setAlwaysUseCheckedState: function FW__setAlwaysUseCheckedState(feedType) { |
michael@0 | 780 | var checkbox = this._getUIElement("alwaysUse"); |
michael@0 | 781 | if (checkbox) { |
michael@0 | 782 | var alwaysUse = false; |
michael@0 | 783 | try { |
michael@0 | 784 | var prefs = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 785 | getService(Ci.nsIPrefBranch); |
michael@0 | 786 | if (prefs.getCharPref(getPrefActionForType(feedType)) != "ask") |
michael@0 | 787 | alwaysUse = true; |
michael@0 | 788 | } |
michael@0 | 789 | catch(ex) { } |
michael@0 | 790 | this._setCheckboxCheckedState(checkbox, alwaysUse); |
michael@0 | 791 | } |
michael@0 | 792 | }, |
michael@0 | 793 | |
michael@0 | 794 | _setSubscribeUsingLabel: function FW__setSubscribeUsingLabel() { |
michael@0 | 795 | var stringLabel = "subscribeFeedUsing"; |
michael@0 | 796 | switch (this._getFeedType()) { |
michael@0 | 797 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 798 | stringLabel = "subscribeVideoPodcastUsing"; |
michael@0 | 799 | break; |
michael@0 | 800 | |
michael@0 | 801 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 802 | stringLabel = "subscribeAudioPodcastUsing"; |
michael@0 | 803 | break; |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | this._contentSandbox.subscribeUsing = |
michael@0 | 807 | this._getUIElement("subscribeUsingDescription"); |
michael@0 | 808 | this._contentSandbox.label = this._getString(stringLabel); |
michael@0 | 809 | var codeStr = "subscribeUsing.setAttribute('value', label);" |
michael@0 | 810 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 811 | }, |
michael@0 | 812 | |
michael@0 | 813 | _setAlwaysUseLabel: function FW__setAlwaysUseLabel() { |
michael@0 | 814 | var checkbox = this._getUIElement("alwaysUse"); |
michael@0 | 815 | if (checkbox) { |
michael@0 | 816 | if (this._handlersMenuList) { |
michael@0 | 817 | var handlerName = this._getSelectedItemFromMenulist(this._handlersMenuList) |
michael@0 | 818 | .getAttribute("label"); |
michael@0 | 819 | var stringLabel = "alwaysUseForFeeds"; |
michael@0 | 820 | switch (this._getFeedType()) { |
michael@0 | 821 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 822 | stringLabel = "alwaysUseForVideoPodcasts"; |
michael@0 | 823 | break; |
michael@0 | 824 | |
michael@0 | 825 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 826 | stringLabel = "alwaysUseForAudioPodcasts"; |
michael@0 | 827 | break; |
michael@0 | 828 | } |
michael@0 | 829 | |
michael@0 | 830 | this._contentSandbox.checkbox = checkbox; |
michael@0 | 831 | this._contentSandbox.label = this._getFormattedString(stringLabel, [handlerName]); |
michael@0 | 832 | |
michael@0 | 833 | var codeStr = "checkbox.setAttribute('label', label);"; |
michael@0 | 834 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 835 | } |
michael@0 | 836 | } |
michael@0 | 837 | }, |
michael@0 | 838 | |
michael@0 | 839 | // nsIDomEventListener |
michael@0 | 840 | handleEvent: function(event) { |
michael@0 | 841 | if (event.target.ownerDocument != this._document) { |
michael@0 | 842 | LOG("FeedWriter.handleEvent: Someone passed the feed writer as a listener to the events of another document!"); |
michael@0 | 843 | return; |
michael@0 | 844 | } |
michael@0 | 845 | |
michael@0 | 846 | if (event.type == "command") { |
michael@0 | 847 | switch (event.target.getAttribute("anonid")) { |
michael@0 | 848 | case "subscribeButton": |
michael@0 | 849 | this.subscribe(); |
michael@0 | 850 | break; |
michael@0 | 851 | case "chooseApplicationMenuItem": |
michael@0 | 852 | /* Bug 351263: Make sure to not steal focus if the "Choose |
michael@0 | 853 | * Application" item is being selected with the keyboard. We do this |
michael@0 | 854 | * by ignoring command events while the dropdown is closed (user |
michael@0 | 855 | * arrowing through the combobox), but handling them while the |
michael@0 | 856 | * combobox dropdown is open (user pressed enter when an item was |
michael@0 | 857 | * selected). If we don't show the filepicker here, it will be shown |
michael@0 | 858 | * when clicking "Subscribe Now". |
michael@0 | 859 | */ |
michael@0 | 860 | var popupbox = this._handlersMenuList.firstChild.boxObject; |
michael@0 | 861 | popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject); |
michael@0 | 862 | if (popupbox.popupState == "hiding") { |
michael@0 | 863 | this._chooseClientApp(function(aResult) { |
michael@0 | 864 | if (!aResult) { |
michael@0 | 865 | // Select the (per-prefs) selected handler if no application |
michael@0 | 866 | // was selected |
michael@0 | 867 | this._setSelectedHandler(this._getFeedType()); |
michael@0 | 868 | } |
michael@0 | 869 | }.bind(this)); |
michael@0 | 870 | } |
michael@0 | 871 | break; |
michael@0 | 872 | default: |
michael@0 | 873 | this._setAlwaysUseLabel(); |
michael@0 | 874 | } |
michael@0 | 875 | } |
michael@0 | 876 | }, |
michael@0 | 877 | |
michael@0 | 878 | _setSelectedHandler: function FW__setSelectedHandler(feedType) { |
michael@0 | 879 | var prefs = |
michael@0 | 880 | Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 881 | getService(Ci.nsIPrefBranch); |
michael@0 | 882 | |
michael@0 | 883 | var handler = "bookmarks"; |
michael@0 | 884 | try { |
michael@0 | 885 | handler = prefs.getCharPref(getPrefReaderForType(feedType)); |
michael@0 | 886 | } |
michael@0 | 887 | catch (ex) { } |
michael@0 | 888 | |
michael@0 | 889 | switch (handler) { |
michael@0 | 890 | case "web": { |
michael@0 | 891 | if (this._handlersMenuList) { |
michael@0 | 892 | var url = prefs.getComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString).data; |
michael@0 | 893 | var handlers = |
michael@0 | 894 | this._handlersMenuList.getElementsByAttribute("webhandlerurl", url); |
michael@0 | 895 | if (handlers.length == 0) { |
michael@0 | 896 | LOG("FeedWriter._setSelectedHandler: selected web handler isn't in the menulist") |
michael@0 | 897 | return; |
michael@0 | 898 | } |
michael@0 | 899 | |
michael@0 | 900 | this._safeDoCommand(handlers[0]); |
michael@0 | 901 | } |
michael@0 | 902 | break; |
michael@0 | 903 | } |
michael@0 | 904 | case "client": { |
michael@0 | 905 | try { |
michael@0 | 906 | this._selectedApp = |
michael@0 | 907 | prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile); |
michael@0 | 908 | } |
michael@0 | 909 | catch(ex) { |
michael@0 | 910 | this._selectedApp = null; |
michael@0 | 911 | } |
michael@0 | 912 | |
michael@0 | 913 | if (this._selectedApp) { |
michael@0 | 914 | this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem, |
michael@0 | 915 | this._selectedApp); |
michael@0 | 916 | var codeStr = "selectedAppMenuItem.hidden = false; " + |
michael@0 | 917 | "selectedAppMenuItem.doCommand(); "; |
michael@0 | 918 | |
michael@0 | 919 | // Only show the default reader menuitem if the default reader |
michael@0 | 920 | // isn't the selected application |
michael@0 | 921 | if (this._defaultSystemReader) { |
michael@0 | 922 | var shouldHide = |
michael@0 | 923 | this._defaultSystemReader.path == this._selectedApp.path; |
michael@0 | 924 | codeStr += "defaultHandlerMenuItem.hidden = " + shouldHide + ";" |
michael@0 | 925 | } |
michael@0 | 926 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 927 | break; |
michael@0 | 928 | } |
michael@0 | 929 | } |
michael@0 | 930 | case "bookmarks": |
michael@0 | 931 | default: { |
michael@0 | 932 | var liveBookmarksMenuItem = this._getUIElement("liveBookmarksMenuItem"); |
michael@0 | 933 | if (liveBookmarksMenuItem) |
michael@0 | 934 | this._safeDoCommand(liveBookmarksMenuItem); |
michael@0 | 935 | } |
michael@0 | 936 | } |
michael@0 | 937 | }, |
michael@0 | 938 | |
michael@0 | 939 | _initSubscriptionUI: function FW__initSubscriptionUI() { |
michael@0 | 940 | var handlersMenuPopup = this._getUIElement("handlersMenuPopup"); |
michael@0 | 941 | if (!handlersMenuPopup) |
michael@0 | 942 | return; |
michael@0 | 943 | |
michael@0 | 944 | var feedType = this._getFeedType(); |
michael@0 | 945 | var codeStr; |
michael@0 | 946 | |
michael@0 | 947 | // change the background |
michael@0 | 948 | var header = this._document.getElementById("feedHeader"); |
michael@0 | 949 | this._contentSandbox.header = header; |
michael@0 | 950 | switch (feedType) { |
michael@0 | 951 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 952 | codeStr = "header.className = 'videoPodcastBackground'; "; |
michael@0 | 953 | break; |
michael@0 | 954 | |
michael@0 | 955 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 956 | codeStr = "header.className = 'audioPodcastBackground'; "; |
michael@0 | 957 | break; |
michael@0 | 958 | |
michael@0 | 959 | default: |
michael@0 | 960 | codeStr = "header.className = 'feedBackground'; "; |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | var liveBookmarksMenuItem = this._getUIElement("liveBookmarksMenuItem"); |
michael@0 | 964 | |
michael@0 | 965 | // Last-selected application |
michael@0 | 966 | var menuItem = liveBookmarksMenuItem.cloneNode(false); |
michael@0 | 967 | menuItem.removeAttribute("selected"); |
michael@0 | 968 | menuItem.setAttribute("anonid", "selectedAppMenuItem"); |
michael@0 | 969 | menuItem.className = "menuitem-iconic selectedAppMenuItem"; |
michael@0 | 970 | menuItem.setAttribute("handlerType", "client"); |
michael@0 | 971 | try { |
michael@0 | 972 | var prefs = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 973 | getService(Ci.nsIPrefBranch); |
michael@0 | 974 | this._selectedApp = prefs.getComplexValue(getPrefAppForType(feedType), |
michael@0 | 975 | Ci.nsILocalFile); |
michael@0 | 976 | |
michael@0 | 977 | if (this._selectedApp.exists()) |
michael@0 | 978 | this._initMenuItemWithFile(menuItem, this._selectedApp); |
michael@0 | 979 | else { |
michael@0 | 980 | // Hide the menuitem if the last selected application doesn't exist |
michael@0 | 981 | menuItem.setAttribute("hidden", true); |
michael@0 | 982 | } |
michael@0 | 983 | } |
michael@0 | 984 | catch(ex) { |
michael@0 | 985 | // Hide the menuitem until an application is selected |
michael@0 | 986 | menuItem.setAttribute("hidden", true); |
michael@0 | 987 | } |
michael@0 | 988 | this._contentSandbox.handlersMenuPopup = handlersMenuPopup; |
michael@0 | 989 | this._contentSandbox.selectedAppMenuItem = menuItem; |
michael@0 | 990 | |
michael@0 | 991 | codeStr += "handlersMenuPopup.appendChild(selectedAppMenuItem); "; |
michael@0 | 992 | |
michael@0 | 993 | // List the default feed reader |
michael@0 | 994 | try { |
michael@0 | 995 | this._defaultSystemReader = Cc["@mozilla.org/browser/shell-service;1"]. |
michael@0 | 996 | getService(Ci.nsIShellService). |
michael@0 | 997 | defaultFeedReader; |
michael@0 | 998 | menuItem = liveBookmarksMenuItem.cloneNode(false); |
michael@0 | 999 | menuItem.removeAttribute("selected"); |
michael@0 | 1000 | menuItem.setAttribute("anonid", "defaultHandlerMenuItem"); |
michael@0 | 1001 | menuItem.className = "menuitem-iconic defaultHandlerMenuItem"; |
michael@0 | 1002 | menuItem.setAttribute("handlerType", "client"); |
michael@0 | 1003 | |
michael@0 | 1004 | this._initMenuItemWithFile(menuItem, this._defaultSystemReader); |
michael@0 | 1005 | |
michael@0 | 1006 | // Hide the default reader item if it points to the same application |
michael@0 | 1007 | // as the last-selected application |
michael@0 | 1008 | if (this._selectedApp && |
michael@0 | 1009 | this._selectedApp.path == this._defaultSystemReader.path) |
michael@0 | 1010 | menuItem.hidden = true; |
michael@0 | 1011 | } |
michael@0 | 1012 | catch(ex) { menuItem = null; /* no default reader */ } |
michael@0 | 1013 | |
michael@0 | 1014 | if (menuItem) { |
michael@0 | 1015 | this._contentSandbox.defaultHandlerMenuItem = menuItem; |
michael@0 | 1016 | codeStr += "handlersMenuPopup.appendChild(defaultHandlerMenuItem); "; |
michael@0 | 1017 | } |
michael@0 | 1018 | |
michael@0 | 1019 | // "Choose Application..." menuitem |
michael@0 | 1020 | menuItem = liveBookmarksMenuItem.cloneNode(false); |
michael@0 | 1021 | menuItem.removeAttribute("selected"); |
michael@0 | 1022 | menuItem.setAttribute("anonid", "chooseApplicationMenuItem"); |
michael@0 | 1023 | menuItem.className = "menuitem-iconic chooseApplicationMenuItem"; |
michael@0 | 1024 | menuItem.setAttribute("label", this._getString("chooseApplicationMenuItem")); |
michael@0 | 1025 | |
michael@0 | 1026 | this._contentSandbox.chooseAppMenuItem = menuItem; |
michael@0 | 1027 | codeStr += "handlersMenuPopup.appendChild(chooseAppMenuItem); "; |
michael@0 | 1028 | |
michael@0 | 1029 | // separator |
michael@0 | 1030 | this._contentSandbox.chooseAppSep = |
michael@0 | 1031 | menuItem = liveBookmarksMenuItem.nextSibling.cloneNode(false); |
michael@0 | 1032 | codeStr += "handlersMenuPopup.appendChild(chooseAppSep); "; |
michael@0 | 1033 | |
michael@0 | 1034 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 1035 | |
michael@0 | 1036 | // List of web handlers |
michael@0 | 1037 | var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]. |
michael@0 | 1038 | getService(Ci.nsIWebContentConverterService); |
michael@0 | 1039 | var handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType)); |
michael@0 | 1040 | if (handlers.length != 0) { |
michael@0 | 1041 | for (var i = 0; i < handlers.length; ++i) { |
michael@0 | 1042 | menuItem = liveBookmarksMenuItem.cloneNode(false); |
michael@0 | 1043 | menuItem.removeAttribute("selected"); |
michael@0 | 1044 | menuItem.className = "menuitem-iconic"; |
michael@0 | 1045 | menuItem.setAttribute("label", handlers[i].name); |
michael@0 | 1046 | menuItem.setAttribute("handlerType", "web"); |
michael@0 | 1047 | menuItem.setAttribute("webhandlerurl", handlers[i].uri); |
michael@0 | 1048 | this._contentSandbox.menuItem = menuItem; |
michael@0 | 1049 | codeStr = "handlersMenuPopup.appendChild(menuItem);"; |
michael@0 | 1050 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 1051 | |
michael@0 | 1052 | this._setFaviconForWebReader(handlers[i].uri, menuItem); |
michael@0 | 1053 | } |
michael@0 | 1054 | this._contentSandbox.menuItem = null; |
michael@0 | 1055 | } |
michael@0 | 1056 | |
michael@0 | 1057 | this._setSelectedHandler(feedType); |
michael@0 | 1058 | |
michael@0 | 1059 | // "Subscribe using..." |
michael@0 | 1060 | this._setSubscribeUsingLabel(); |
michael@0 | 1061 | |
michael@0 | 1062 | // "Always use..." checkbox initial state |
michael@0 | 1063 | this._setAlwaysUseCheckedState(feedType); |
michael@0 | 1064 | this._setAlwaysUseLabel(); |
michael@0 | 1065 | |
michael@0 | 1066 | // We update the "Always use.." checkbox label whenever the selected item |
michael@0 | 1067 | // in the list is changed |
michael@0 | 1068 | handlersMenuPopup.addEventListener("command", this, false); |
michael@0 | 1069 | |
michael@0 | 1070 | // Set up the "Subscribe Now" button |
michael@0 | 1071 | this._getUIElement("subscribeButton") |
michael@0 | 1072 | .addEventListener("command", this, false); |
michael@0 | 1073 | |
michael@0 | 1074 | // first-run ui |
michael@0 | 1075 | var showFirstRunUI = true; |
michael@0 | 1076 | try { |
michael@0 | 1077 | showFirstRunUI = prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI); |
michael@0 | 1078 | } |
michael@0 | 1079 | catch (ex) { } |
michael@0 | 1080 | if (showFirstRunUI) { |
michael@0 | 1081 | var textfeedinfo1, textfeedinfo2; |
michael@0 | 1082 | switch (feedType) { |
michael@0 | 1083 | case Ci.nsIFeed.TYPE_VIDEO: |
michael@0 | 1084 | textfeedinfo1 = "feedSubscriptionVideoPodcast1"; |
michael@0 | 1085 | textfeedinfo2 = "feedSubscriptionVideoPodcast2"; |
michael@0 | 1086 | break; |
michael@0 | 1087 | case Ci.nsIFeed.TYPE_AUDIO: |
michael@0 | 1088 | textfeedinfo1 = "feedSubscriptionAudioPodcast1"; |
michael@0 | 1089 | textfeedinfo2 = "feedSubscriptionAudioPodcast2"; |
michael@0 | 1090 | break; |
michael@0 | 1091 | default: |
michael@0 | 1092 | textfeedinfo1 = "feedSubscriptionFeed1"; |
michael@0 | 1093 | textfeedinfo2 = "feedSubscriptionFeed2"; |
michael@0 | 1094 | } |
michael@0 | 1095 | |
michael@0 | 1096 | this._contentSandbox.feedinfo1 = |
michael@0 | 1097 | this._document.getElementById("feedSubscriptionInfo1"); |
michael@0 | 1098 | this._contentSandbox.feedinfo1Str = this._getString(textfeedinfo1); |
michael@0 | 1099 | this._contentSandbox.feedinfo2 = |
michael@0 | 1100 | this._document.getElementById("feedSubscriptionInfo2"); |
michael@0 | 1101 | this._contentSandbox.feedinfo2Str = this._getString(textfeedinfo2); |
michael@0 | 1102 | this._contentSandbox.header = header; |
michael@0 | 1103 | codeStr = "feedinfo1.textContent = feedinfo1Str; " + |
michael@0 | 1104 | "feedinfo2.textContent = feedinfo2Str; " + |
michael@0 | 1105 | "header.setAttribute('firstrun', 'true');" |
michael@0 | 1106 | Cu.evalInSandbox(codeStr, this._contentSandbox); |
michael@0 | 1107 | prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false); |
michael@0 | 1108 | } |
michael@0 | 1109 | }, |
michael@0 | 1110 | |
michael@0 | 1111 | /** |
michael@0 | 1112 | * Returns the original URI object of the feed and ensures that this |
michael@0 | 1113 | * component is only ever invoked from the preview document. |
michael@0 | 1114 | * @param aWindow |
michael@0 | 1115 | * The window of the document invoking the BrowserFeedWriter |
michael@0 | 1116 | */ |
michael@0 | 1117 | _getOriginalURI: function FW__getOriginalURI(aWindow) { |
michael@0 | 1118 | var chan = aWindow.QueryInterface(Ci.nsIInterfaceRequestor). |
michael@0 | 1119 | getInterface(Ci.nsIWebNavigation). |
michael@0 | 1120 | QueryInterface(Ci.nsIDocShell).currentDocumentChannel; |
michael@0 | 1121 | |
michael@0 | 1122 | var resolvedURI = Cc["@mozilla.org/network/io-service;1"]. |
michael@0 | 1123 | getService(Ci.nsIIOService). |
michael@0 | 1124 | newChannel("about:feeds", null, null).URI; |
michael@0 | 1125 | |
michael@0 | 1126 | if (resolvedURI.equals(chan.URI)) |
michael@0 | 1127 | return chan.originalURI; |
michael@0 | 1128 | |
michael@0 | 1129 | return null; |
michael@0 | 1130 | }, |
michael@0 | 1131 | |
michael@0 | 1132 | _window: null, |
michael@0 | 1133 | _document: null, |
michael@0 | 1134 | _feedURI: null, |
michael@0 | 1135 | _feedPrincipal: null, |
michael@0 | 1136 | _handlersMenuList: null, |
michael@0 | 1137 | |
michael@0 | 1138 | // BrowserFeedWriter WebIDL methods |
michael@0 | 1139 | init: function FW_init(aWindow) { |
michael@0 | 1140 | var window = aWindow; |
michael@0 | 1141 | this._feedURI = this._getOriginalURI(window); |
michael@0 | 1142 | if (!this._feedURI) |
michael@0 | 1143 | return; |
michael@0 | 1144 | |
michael@0 | 1145 | this._window = window; |
michael@0 | 1146 | this._document = window.document; |
michael@0 | 1147 | this._document.getElementById("feedSubscribeLine").offsetTop; |
michael@0 | 1148 | this._handlersMenuList = this._getUIElement("handlersMenuList"); |
michael@0 | 1149 | |
michael@0 | 1150 | var secman = Cc["@mozilla.org/scriptsecuritymanager;1"]. |
michael@0 | 1151 | getService(Ci.nsIScriptSecurityManager); |
michael@0 | 1152 | this._feedPrincipal = secman.getSimpleCodebasePrincipal(this._feedURI); |
michael@0 | 1153 | |
michael@0 | 1154 | LOG("Subscribe Preview: feed uri = " + this._window.location.href); |
michael@0 | 1155 | |
michael@0 | 1156 | // Set up the subscription UI |
michael@0 | 1157 | this._initSubscriptionUI(); |
michael@0 | 1158 | var prefs = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 1159 | getService(Ci.nsIPrefBranch); |
michael@0 | 1160 | prefs.addObserver(PREF_SELECTED_ACTION, this, false); |
michael@0 | 1161 | prefs.addObserver(PREF_SELECTED_READER, this, false); |
michael@0 | 1162 | prefs.addObserver(PREF_SELECTED_WEB, this, false); |
michael@0 | 1163 | prefs.addObserver(PREF_SELECTED_APP, this, false); |
michael@0 | 1164 | prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, false); |
michael@0 | 1165 | prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, false); |
michael@0 | 1166 | prefs.addObserver(PREF_VIDEO_SELECTED_WEB, this, false); |
michael@0 | 1167 | prefs.addObserver(PREF_VIDEO_SELECTED_APP, this, false); |
michael@0 | 1168 | |
michael@0 | 1169 | prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, false); |
michael@0 | 1170 | prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, false); |
michael@0 | 1171 | prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, false); |
michael@0 | 1172 | prefs.addObserver(PREF_AUDIO_SELECTED_APP, this, false); |
michael@0 | 1173 | }, |
michael@0 | 1174 | |
michael@0 | 1175 | writeContent: function FW_writeContent() { |
michael@0 | 1176 | if (!this._window) |
michael@0 | 1177 | return; |
michael@0 | 1178 | |
michael@0 | 1179 | try { |
michael@0 | 1180 | // Set up the feed content |
michael@0 | 1181 | var container = this._getContainer(); |
michael@0 | 1182 | if (!container) |
michael@0 | 1183 | return; |
michael@0 | 1184 | |
michael@0 | 1185 | this._setTitleText(container); |
michael@0 | 1186 | this._setTitleImage(container); |
michael@0 | 1187 | this._writeFeedContent(container); |
michael@0 | 1188 | } |
michael@0 | 1189 | finally { |
michael@0 | 1190 | this._removeFeedFromCache(); |
michael@0 | 1191 | } |
michael@0 | 1192 | }, |
michael@0 | 1193 | |
michael@0 | 1194 | close: function FW_close() { |
michael@0 | 1195 | this._getUIElement("handlersMenuPopup") |
michael@0 | 1196 | .removeEventListener("command", this, false); |
michael@0 | 1197 | this._getUIElement("subscribeButton") |
michael@0 | 1198 | .removeEventListener("command", this, false); |
michael@0 | 1199 | this._document = null; |
michael@0 | 1200 | this._window = null; |
michael@0 | 1201 | var prefs = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 1202 | getService(Ci.nsIPrefBranch); |
michael@0 | 1203 | prefs.removeObserver(PREF_SELECTED_ACTION, this); |
michael@0 | 1204 | prefs.removeObserver(PREF_SELECTED_READER, this); |
michael@0 | 1205 | prefs.removeObserver(PREF_SELECTED_WEB, this); |
michael@0 | 1206 | prefs.removeObserver(PREF_SELECTED_APP, this); |
michael@0 | 1207 | prefs.removeObserver(PREF_VIDEO_SELECTED_ACTION, this); |
michael@0 | 1208 | prefs.removeObserver(PREF_VIDEO_SELECTED_READER, this); |
michael@0 | 1209 | prefs.removeObserver(PREF_VIDEO_SELECTED_WEB, this); |
michael@0 | 1210 | prefs.removeObserver(PREF_VIDEO_SELECTED_APP, this); |
michael@0 | 1211 | |
michael@0 | 1212 | prefs.removeObserver(PREF_AUDIO_SELECTED_ACTION, this); |
michael@0 | 1213 | prefs.removeObserver(PREF_AUDIO_SELECTED_READER, this); |
michael@0 | 1214 | prefs.removeObserver(PREF_AUDIO_SELECTED_WEB, this); |
michael@0 | 1215 | prefs.removeObserver(PREF_AUDIO_SELECTED_APP, this); |
michael@0 | 1216 | |
michael@0 | 1217 | this._removeFeedFromCache(); |
michael@0 | 1218 | this.__faviconService = null; |
michael@0 | 1219 | this.__bundle = null; |
michael@0 | 1220 | this._feedURI = null; |
michael@0 | 1221 | this.__contentSandbox = null; |
michael@0 | 1222 | }, |
michael@0 | 1223 | |
michael@0 | 1224 | _removeFeedFromCache: function FW__removeFeedFromCache() { |
michael@0 | 1225 | if (this._feedURI) { |
michael@0 | 1226 | var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]. |
michael@0 | 1227 | getService(Ci.nsIFeedResultService); |
michael@0 | 1228 | feedService.removeFeedResult(this._feedURI); |
michael@0 | 1229 | this._feedURI = null; |
michael@0 | 1230 | } |
michael@0 | 1231 | }, |
michael@0 | 1232 | |
michael@0 | 1233 | subscribe: function FW_subscribe() { |
michael@0 | 1234 | var feedType = this._getFeedType(); |
michael@0 | 1235 | |
michael@0 | 1236 | // Subscribe to the feed using the selected handler and save prefs |
michael@0 | 1237 | var prefs = Cc["@mozilla.org/preferences-service;1"]. |
michael@0 | 1238 | getService(Ci.nsIPrefBranch); |
michael@0 | 1239 | var defaultHandler = "reader"; |
michael@0 | 1240 | var useAsDefault = this._getUIElement("alwaysUse").getAttribute("checked"); |
michael@0 | 1241 | |
michael@0 | 1242 | var selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList); |
michael@0 | 1243 | let subscribeCallback = function() { |
michael@0 | 1244 | if (selectedItem.hasAttribute("webhandlerurl")) { |
michael@0 | 1245 | var webURI = selectedItem.getAttribute("webhandlerurl"); |
michael@0 | 1246 | prefs.setCharPref(getPrefReaderForType(feedType), "web"); |
michael@0 | 1247 | |
michael@0 | 1248 | var supportsString = Cc["@mozilla.org/supports-string;1"]. |
michael@0 | 1249 | createInstance(Ci.nsISupportsString); |
michael@0 | 1250 | supportsString.data = webURI; |
michael@0 | 1251 | prefs.setComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString, |
michael@0 | 1252 | supportsString); |
michael@0 | 1253 | |
michael@0 | 1254 | var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]. |
michael@0 | 1255 | getService(Ci.nsIWebContentConverterService); |
michael@0 | 1256 | var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI); |
michael@0 | 1257 | if (handler) { |
michael@0 | 1258 | if (useAsDefault) { |
michael@0 | 1259 | wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler); |
michael@0 | 1260 | } |
michael@0 | 1261 | |
michael@0 | 1262 | this._window.location.href = handler.getHandlerURI(this._window.location.href); |
michael@0 | 1263 | } |
michael@0 | 1264 | } else { |
michael@0 | 1265 | switch (selectedItem.getAttribute("anonid")) { |
michael@0 | 1266 | case "selectedAppMenuItem": |
michael@0 | 1267 | prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile, |
michael@0 | 1268 | this._selectedApp); |
michael@0 | 1269 | prefs.setCharPref(getPrefReaderForType(feedType), "client"); |
michael@0 | 1270 | break; |
michael@0 | 1271 | case "defaultHandlerMenuItem": |
michael@0 | 1272 | prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile, |
michael@0 | 1273 | this._defaultSystemReader); |
michael@0 | 1274 | prefs.setCharPref(getPrefReaderForType(feedType), "client"); |
michael@0 | 1275 | break; |
michael@0 | 1276 | case "liveBookmarksMenuItem": |
michael@0 | 1277 | defaultHandler = "bookmarks"; |
michael@0 | 1278 | prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks"); |
michael@0 | 1279 | break; |
michael@0 | 1280 | } |
michael@0 | 1281 | var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]. |
michael@0 | 1282 | getService(Ci.nsIFeedResultService); |
michael@0 | 1283 | |
michael@0 | 1284 | // Pull the title and subtitle out of the document |
michael@0 | 1285 | var feedTitle = this._document.getElementById(TITLE_ID).textContent; |
michael@0 | 1286 | var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent; |
michael@0 | 1287 | feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType); |
michael@0 | 1288 | } |
michael@0 | 1289 | |
michael@0 | 1290 | // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION |
michael@0 | 1291 | // to either "reader" (If a web reader or if an application is selected), |
michael@0 | 1292 | // or to "bookmarks" (if the live bookmarks option is selected). |
michael@0 | 1293 | // Otherwise, we should set it to "ask" |
michael@0 | 1294 | if (useAsDefault) { |
michael@0 | 1295 | prefs.setCharPref(getPrefActionForType(feedType), defaultHandler); |
michael@0 | 1296 | } else { |
michael@0 | 1297 | prefs.setCharPref(getPrefActionForType(feedType), "ask"); |
michael@0 | 1298 | } |
michael@0 | 1299 | }.bind(this); |
michael@0 | 1300 | |
michael@0 | 1301 | // Show the file picker before subscribing if the |
michael@0 | 1302 | // choose application menuitem was chosen using the keyboard |
michael@0 | 1303 | if (selectedItem.getAttribute("anonid") == "chooseApplicationMenuItem") { |
michael@0 | 1304 | this._chooseClientApp(function(aResult) { |
michael@0 | 1305 | if (aResult) { |
michael@0 | 1306 | selectedItem = |
michael@0 | 1307 | this._getSelectedItemFromMenulist(this._handlersMenuList); |
michael@0 | 1308 | subscribeCallback(); |
michael@0 | 1309 | } |
michael@0 | 1310 | }.bind(this)); |
michael@0 | 1311 | } else { |
michael@0 | 1312 | subscribeCallback(); |
michael@0 | 1313 | } |
michael@0 | 1314 | }, |
michael@0 | 1315 | |
michael@0 | 1316 | // nsIObserver |
michael@0 | 1317 | observe: function FW_observe(subject, topic, data) { |
michael@0 | 1318 | if (!this._window) { |
michael@0 | 1319 | // this._window is null unless this.init was called with a trusted |
michael@0 | 1320 | // window object. |
michael@0 | 1321 | return; |
michael@0 | 1322 | } |
michael@0 | 1323 | |
michael@0 | 1324 | var feedType = this._getFeedType(); |
michael@0 | 1325 | |
michael@0 | 1326 | if (topic == "nsPref:changed") { |
michael@0 | 1327 | switch (data) { |
michael@0 | 1328 | case PREF_SELECTED_READER: |
michael@0 | 1329 | case PREF_SELECTED_WEB: |
michael@0 | 1330 | case PREF_SELECTED_APP: |
michael@0 | 1331 | case PREF_VIDEO_SELECTED_READER: |
michael@0 | 1332 | case PREF_VIDEO_SELECTED_WEB: |
michael@0 | 1333 | case PREF_VIDEO_SELECTED_APP: |
michael@0 | 1334 | case PREF_AUDIO_SELECTED_READER: |
michael@0 | 1335 | case PREF_AUDIO_SELECTED_WEB: |
michael@0 | 1336 | case PREF_AUDIO_SELECTED_APP: |
michael@0 | 1337 | this._setSelectedHandler(feedType); |
michael@0 | 1338 | break; |
michael@0 | 1339 | case PREF_SELECTED_ACTION: |
michael@0 | 1340 | case PREF_VIDEO_SELECTED_ACTION: |
michael@0 | 1341 | case PREF_AUDIO_SELECTED_ACTION: |
michael@0 | 1342 | this._setAlwaysUseCheckedState(feedType); |
michael@0 | 1343 | } |
michael@0 | 1344 | } |
michael@0 | 1345 | }, |
michael@0 | 1346 | |
michael@0 | 1347 | /** |
michael@0 | 1348 | * Sets the icon for the given web-reader item in the readers menu. |
michael@0 | 1349 | * The icon is fetched and stored through the favicon service. |
michael@0 | 1350 | * |
michael@0 | 1351 | * @param aReaderUrl |
michael@0 | 1352 | * the reader url. |
michael@0 | 1353 | * @param aMenuItem |
michael@0 | 1354 | * the reader item in the readers menulist. |
michael@0 | 1355 | * |
michael@0 | 1356 | * @note For privacy reasons we cannot set the image attribute directly |
michael@0 | 1357 | * to the icon url. See Bug 358878 for details. |
michael@0 | 1358 | */ |
michael@0 | 1359 | _setFaviconForWebReader: |
michael@0 | 1360 | function FW__setFaviconForWebReader(aReaderUrl, aMenuItem) { |
michael@0 | 1361 | var readerURI = makeURI(aReaderUrl); |
michael@0 | 1362 | if (!/^https?$/.test(readerURI.scheme)) { |
michael@0 | 1363 | // Don't try to get a favicon for non http(s) URIs. |
michael@0 | 1364 | return; |
michael@0 | 1365 | } |
michael@0 | 1366 | var faviconURI = makeURI(readerURI.prePath + "/favicon.ico"); |
michael@0 | 1367 | var self = this; |
michael@0 | 1368 | var usePrivateBrowsing = this._window.QueryInterface(Ci.nsIInterfaceRequestor) |
michael@0 | 1369 | .getInterface(Ci.nsIWebNavigation) |
michael@0 | 1370 | .QueryInterface(Ci.nsIDocShell) |
michael@0 | 1371 | .QueryInterface(Ci.nsILoadContext) |
michael@0 | 1372 | .usePrivateBrowsing; |
michael@0 | 1373 | this._faviconService.setAndFetchFaviconForPage(readerURI, faviconURI, false, |
michael@0 | 1374 | usePrivateBrowsing ? this._faviconService.FAVICON_LOAD_PRIVATE |
michael@0 | 1375 | : this._faviconService.FAVICON_LOAD_NON_PRIVATE, |
michael@0 | 1376 | function (aURI, aDataLen, aData, aMimeType) { |
michael@0 | 1377 | if (aDataLen > 0) { |
michael@0 | 1378 | var dataURL = "data:" + aMimeType + ";base64," + |
michael@0 | 1379 | btoa(String.fromCharCode.apply(null, aData)); |
michael@0 | 1380 | self._contentSandbox.menuItem = aMenuItem; |
michael@0 | 1381 | self._contentSandbox.dataURL = dataURL; |
michael@0 | 1382 | var codeStr = "menuItem.setAttribute('image', dataURL);"; |
michael@0 | 1383 | Cu.evalInSandbox(codeStr, self._contentSandbox); |
michael@0 | 1384 | self._contentSandbox.menuItem = null; |
michael@0 | 1385 | self._contentSandbox.dataURL = null; |
michael@0 | 1386 | } |
michael@0 | 1387 | }); |
michael@0 | 1388 | }, |
michael@0 | 1389 | |
michael@0 | 1390 | classID: FEEDWRITER_CID, |
michael@0 | 1391 | QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, Ci.nsIObserver, |
michael@0 | 1392 | Ci.nsINavHistoryObserver, |
michael@0 | 1393 | Ci.nsIDOMGlobalPropertyInitializer]) |
michael@0 | 1394 | }; |
michael@0 | 1395 | |
michael@0 | 1396 | this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]); |