summaryrefslogtreecommitdiffstats
path: root/application/basilisk/base/content/browser-feeds.js
diff options
context:
space:
mode:
Diffstat (limited to 'application/basilisk/base/content/browser-feeds.js')
-rw-r--r--application/basilisk/base/content/browser-feeds.js646
1 files changed, 0 insertions, 646 deletions
diff --git a/application/basilisk/base/content/browser-feeds.js b/application/basilisk/base/content/browser-feeds.js
deleted file mode 100644
index 6f29d8915..000000000
--- a/application/basilisk/base/content/browser-feeds.js
+++ /dev/null
@@ -1,646 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
- "resource://gre/modules/DeferredTask.jsm");
-
-const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
-const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
-const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
-
-const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
-
-const PREF_SELECTED_APP = "browser.feeds.handlers.application";
-const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
-const PREF_SELECTED_ACTION = "browser.feeds.handler";
-const PREF_SELECTED_READER = "browser.feeds.handler.default";
-
-const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
-const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
-const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
-const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
-
-const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
-const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
-const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
-const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
-
-const PREF_UPDATE_DELAY = 2000;
-
-const SETTABLE_PREFS = new Set([
- PREF_VIDEO_SELECTED_ACTION,
- PREF_AUDIO_SELECTED_ACTION,
- PREF_SELECTED_ACTION,
- PREF_VIDEO_SELECTED_READER,
- PREF_AUDIO_SELECTED_READER,
- PREF_SELECTED_READER,
- PREF_VIDEO_SELECTED_WEB,
- PREF_AUDIO_SELECTED_WEB,
- PREF_SELECTED_WEB
-]);
-
-const EXECUTABLE_PREFS = new Set([
- PREF_SELECTED_APP,
- PREF_VIDEO_SELECTED_APP,
- PREF_AUDIO_SELECTED_APP
-]);
-
-const VALID_ACTIONS = new Set(["ask", "reader", "bookmarks"]);
-const VALID_READERS = new Set(["web", "client", "default", "bookmarks"]);
-
-XPCOMUtils.defineLazyPreferenceGetter(this, "SHOULD_LOG",
- "feeds.log", false);
-
-function LOG(str) {
- if (SHOULD_LOG)
- dump("*** Feeds: " + str + "\n");
-}
-
-function getPrefActionForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_ACTION;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_ACTION;
-
- default:
- return PREF_SELECTED_ACTION;
- }
-}
-
-function getPrefReaderForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_READER;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_READER;
-
- default:
- return PREF_SELECTED_READER;
- }
-}
-
-function getPrefWebForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_WEB;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_WEB;
-
- default:
- return PREF_SELECTED_WEB;
- }
-}
-
-function getPrefAppForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_APP;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_APP;
-
- default:
- return PREF_SELECTED_APP;
- }
-}
-
-/**
- * Maps a feed type to a maybe-feed mimetype.
- */
-function getMimeTypeForFeedType(aFeedType) {
- switch (aFeedType) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return TYPE_MAYBE_VIDEO_FEED;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return TYPE_MAYBE_AUDIO_FEED;
-
- default:
- return TYPE_MAYBE_FEED;
- }
-}
-
-/**
- * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
- * and shows UI when they are discovered.
- */
-var FeedHandler = {
- _prefChangeCallback: null,
-
- /** Called when the user clicks on the Subscribe to This Page... menu item,
- * or when the user clicks the feed button when the page contains multiple
- * feeds.
- * Builds a menu of unique feeds associated with the page, and if there
- * is only one, shows the feed inline in the browser window.
- * @param container
- * The feed list container (menupopup or subview) to be populated.
- * @param isSubview
- * Whether we're creating a subview (true) or menu (false/undefined)
- * @return true if the menu/subview should be shown, false if there was only
- * one feed and the feed should be shown inline in the browser
- * window (do not show the menupopup/subview).
- */
- buildFeedList(container, isSubview) {
- let feeds = gBrowser.selectedBrowser.feeds;
- if (!isSubview && feeds == null) {
- // XXX hack -- menu opening depends on setting of an "open"
- // attribute, and the menu refuses to open if that attribute is
- // set (because it thinks it's already open). onpopupshowing gets
- // called after the attribute is unset, and it doesn't get unset
- // if we return false. so we unset it here; otherwise, the menu
- // refuses to work past this point.
- container.parentNode.removeAttribute("open");
- return false;
- }
-
- for (let i = container.childNodes.length - 1; i >= 0; --i) {
- let node = container.childNodes[i];
- if (isSubview && node.localName == "label")
- continue;
- container.removeChild(node);
- }
-
- if (!feeds || feeds.length <= 1)
- return false;
-
- // Build the menu showing the available feed choices for viewing.
- let itemNodeType = isSubview ? "toolbarbutton" : "menuitem";
- for (let feedInfo of feeds) {
- let item = document.createElement(itemNodeType);
- let baseTitle = feedInfo.title || feedInfo.href;
- item.setAttribute("label", baseTitle);
- item.setAttribute("feed", feedInfo.href);
- item.setAttribute("tooltiptext", feedInfo.href);
- item.setAttribute("crop", "center");
- let className = "feed-" + itemNodeType;
- if (isSubview) {
- className += " subviewbutton";
- }
- item.setAttribute("class", className);
- container.appendChild(item);
- }
- return true;
- },
-
- /**
- * Subscribe to a given feed. Called when
- * 1. Page has a single feed and user clicks feed icon in location bar
- * 2. Page has a single feed and user selects Subscribe menu item
- * 3. Page has multiple feeds and user selects from feed icon popup (or subview)
- * 4. Page has multiple feeds and user selects from Subscribe submenu
- * @param href
- * The feed to subscribe to. May be null, in which case the
- * event target's feed attribute is examined.
- * @param event
- * The event this method is handling. Used to decide where
- * to open the preview UI. (Optional, unless href is null)
- */
- subscribeToFeed(href, event) {
- // Just load the feed in the content area to either subscribe or show the
- // preview UI
- if (!href)
- href = event.target.getAttribute("feed");
- urlSecurityCheck(href, gBrowser.contentPrincipal,
- Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
- let feedURI = makeURI(href, document.characterSet);
- // Use the feed scheme so X-Moz-Is-Feed will be set
- // The value doesn't matter
- if (/^https?$/.test(feedURI.scheme))
- href = "feed:" + href;
- this.loadFeed(href, event);
- },
-
- loadFeed(href, event) {
- let feeds = gBrowser.selectedBrowser.feeds;
- try {
- openUILink(href, event, { ignoreAlt: true });
- }
- finally {
- // We might default to a livebookmarks modal dialog,
- // so reset that if the user happens to click it again
- gBrowser.selectedBrowser.feeds = feeds;
- }
- },
-
- get _feedMenuitem() {
- delete this._feedMenuitem;
- return this._feedMenuitem = document.getElementById("singleFeedMenuitemState");
- },
-
- get _feedMenupopup() {
- delete this._feedMenupopup;
- return this._feedMenupopup = document.getElementById("multipleFeedsMenuState");
- },
-
- /**
- * Update the browser UI to show whether or not feeds are available when
- * a page is loaded or the user switches tabs to a page that has feeds.
- */
- updateFeeds() {
- if (this._updateFeedTimeout)
- clearTimeout(this._updateFeedTimeout);
-
- let feeds = gBrowser.selectedBrowser.feeds;
- let haveFeeds = feeds && feeds.length > 0;
-
- let feedButton = document.getElementById("feed-button");
- if (feedButton) {
- if (haveFeeds) {
- feedButton.removeAttribute("disabled");
- } else {
- feedButton.setAttribute("disabled", "true");
- }
- }
-
- if (!haveFeeds) {
- this._feedMenuitem.setAttribute("disabled", "true");
- this._feedMenuitem.removeAttribute("hidden");
- this._feedMenupopup.setAttribute("hidden", "true");
- return;
- }
-
- if (feeds.length > 1) {
- this._feedMenuitem.setAttribute("hidden", "true");
- this._feedMenupopup.removeAttribute("hidden");
- } else {
- this._feedMenuitem.setAttribute("feed", feeds[0].href);
- this._feedMenuitem.removeAttribute("disabled");
- this._feedMenuitem.removeAttribute("hidden");
- this._feedMenupopup.setAttribute("hidden", "true");
- }
- },
-
- addFeed(link, browserForLink) {
- if (!browserForLink.feeds)
- browserForLink.feeds = [];
-
- browserForLink.feeds.push({ href: link.href, title: link.title });
-
- // If this addition was for the current browser, update the UI. For
- // background browsers, we'll update on tab switch.
- if (browserForLink == gBrowser.selectedBrowser) {
- // Batch updates to avoid updating the UI for multiple onLinkAdded events
- // fired within 100ms of each other.
- if (this._updateFeedTimeout)
- clearTimeout(this._updateFeedTimeout);
- this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
- }
- },
-
- /**
- * Get the human-readable display name of a file. This could be the
- * application name.
- * @param file
- * A nsIFile to look up the name of
- * @return The display name of the application represented by the file.
- */
- _getFileDisplayName(file) {
- switch (AppConstants.platform) {
- case "win":
- if (file instanceof Ci.nsILocalFileWin) {
- try {
- return file.getVersionInfoField("FileDescription");
- } catch (e) {}
- }
- break;
- case "macosx":
- if (file instanceof Ci.nsILocalFileMac) {
- try {
- return file.bundleDisplayName;
- } catch (e) {}
- }
- break;
- }
-
- return file.leafName;
- },
-
- _chooseClientApp(aTitle, aTypeName, aBrowser) {
- const prefName = getPrefAppForType(aTypeName);
- let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-
- fp.init(window, aTitle, Ci.nsIFilePicker.modeOpen);
- fp.appendFilters(Ci.nsIFilePicker.filterApps);
-
- fp.open((aResult) => {
- if (aResult == Ci.nsIFilePicker.returnOK) {
- let selectedApp = fp.file;
- if (selectedApp) {
- // XXXben - we need to compare this with the running instance
- // executable just don't know how to do that via script
- // XXXmano TBD: can probably add this to nsIShellService
- let appName = "";
- switch (AppConstants.platform) {
- case "win":
- appName = AppConstants.MOZ_APP_NAME + ".exe";
- break;
- case "macosx":
- appName = AppConstants.MOZ_MACBUNDLE_NAME;
- break;
- default:
- appName = AppConstants.MOZ_APP_NAME + "-bin";
- break;
- }
-
- if (fp.file.leafName != appName) {
- Services.prefs.setComplexValue(prefName, Ci.nsILocalFile, selectedApp);
- aBrowser.messageManager.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
- { name: this._getFileDisplayName(selectedApp),
- type: "SelectedAppMenuItem" });
- }
- }
- }
- });
-
- },
-
- executeClientApp(aSpec, aTitle, aSubtitle, aFeedHandler) {
- // aFeedHandler is either "default", indicating the system default reader, or a pref-name containing
- // an nsILocalFile pointing to the feed handler's executable.
-
- let clientApp = null;
- if (aFeedHandler == "default") {
- clientApp = Cc["@mozilla.org/browser/shell-service;1"]
- .getService(Ci.nsIShellService)
- .defaultFeedReader;
- } else {
- clientApp = Services.prefs.getComplexValue(aFeedHandler, Ci.nsILocalFile);
- }
-
- // For the benefit of applications that might know how to deal with more
- // URLs than just feeds, send feed: URLs in the following format:
- //
- // http urls: replace scheme with feed, e.g.
- // http://foo.com/index.rdf -> feed://foo.com/index.rdf
- // other urls: prepend feed: scheme, e.g.
- // https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
- let feedURI = NetUtil.newURI(aSpec);
- if (feedURI.schemeIs("http")) {
- feedURI.scheme = "feed";
- aSpec = feedURI.spec;
- } else {
- aSpec = "feed:" + aSpec;
- }
-
- // Retrieving the shell service might fail on some systems, most
- // notably systems where GNOME is not installed.
- try {
- let ss = Cc["@mozilla.org/browser/shell-service;1"]
- .getService(Ci.nsIShellService);
- ss.openApplicationWithURI(clientApp, aSpec);
- } catch (e) {
- // If we couldn't use the shell service, fallback to using a
- // nsIProcess instance
- let p = Cc["@mozilla.org/process/util;1"]
- .createInstance(Ci.nsIProcess);
- p.init(clientApp);
- p.run(false, [aSpec], 1);
- }
- },
-
- // nsISupports
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
- Ci.nsISupportsWeakReference]),
-
- init() {
- window.messageManager.addMessageListener("FeedWriter:ChooseClientApp", this);
- window.messageManager.addMessageListener("FeedWriter:GetSubscriptionUI", this);
- window.messageManager.addMessageListener("FeedWriter:SetFeedPrefsAndSubscribe", this);
- window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
-
- Services.ppmm.addMessageListener("FeedConverter:ExecuteClientApp", this);
-
- const prefs = Services.prefs;
- prefs.addObserver(PREF_SELECTED_ACTION, this, true);
- prefs.addObserver(PREF_SELECTED_READER, this, true);
- prefs.addObserver(PREF_SELECTED_WEB, this, true);
- prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, true);
- prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, true);
- prefs.addObserver(PREF_VIDEO_SELECTED_WEB, this, true);
- prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, true);
- prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, true);
- prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, true);
- },
-
- uninit() {
- Services.ppmm.removeMessageListener("FeedConverter:ExecuteClientApp", this);
-
- this._prefChangeCallback = null;
- },
-
- // nsIObserver
- observe(subject, topic, data) {
- if (topic == "nsPref:changed") {
- LOG(`Pref changed ${data}`)
- if (this._prefChangeCallback) {
- this._prefChangeCallback.disarm();
- }
- // Multiple prefs are set at the same time, debounce to reduce noise
- // This can happen in one feed and we want to message all feed pages
- this._prefChangeCallback = new DeferredTask(() => {
- this._prefChanged(data);
- }, PREF_UPDATE_DELAY);
- this._prefChangeCallback.arm();
- }
- },
-
- _prefChanged(prefName) {
- // Don't observe for PREF_*SELECTED_APP as user likely just picked one
- // That is also handled by SetApplicationLauncherMenuItem call
- // Rather than the others which happen on subscription
- switch (prefName) {
- case PREF_SELECTED_READER:
- case PREF_SELECTED_WEB:
- case PREF_VIDEO_SELECTED_READER:
- case PREF_VIDEO_SELECTED_WEB:
- case PREF_AUDIO_SELECTED_READER:
- case PREF_AUDIO_SELECTED_WEB:
- case PREF_SELECTED_ACTION:
- case PREF_VIDEO_SELECTED_ACTION:
- case PREF_AUDIO_SELECTED_ACTION:
- const response = {
- default: this._getReaderForType(Ci.nsIFeed.TYPE_FEED),
- [Ci.nsIFeed.TYPE_AUDIO]: this._getReaderForType(Ci.nsIFeed.TYPE_AUDIO),
- [Ci.nsIFeed.TYPE_VIDEO]: this._getReaderForType(Ci.nsIFeed.TYPE_VIDEO)
- };
- Services.mm.broadcastAsyncMessage("FeedWriter:PreferenceUpdated",
- response);
- break;
- }
- },
-
- _initSubscriptionUIResponse(feedType) {
- const wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
- getService(Ci.nsIWebContentConverterService);
- const handlersRaw = wccr.getContentHandlers(getMimeTypeForFeedType(feedType));
- const handlers = [];
- for (let handler of handlersRaw) {
- LOG(`Handler found: ${handler}`);
- handlers.push({
- name: handler.name,
- uri: handler.uri
- });
- }
- let showFirstRunUI = true;
- // eslint-disable-next-line mozilla/use-default-preference-values
- try {
- showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
- } catch (ex) { }
- const response = { handlers, showFirstRunUI };
- let selectedClientApp;
- const feedTypePref = getPrefAppForType(feedType);
- try {
- selectedClientApp = Services.prefs.getComplexValue(feedTypePref, Ci.nsILocalFile);
- } catch (ex) {
- // Just do nothing, then we won't bother populating
- }
-
- let defaultClientApp = null;
- try {
- // This can sometimes not exist
- defaultClientApp = Cc["@mozilla.org/browser/shell-service;1"]
- .getService(Ci.nsIShellService)
- .defaultFeedReader;
- } catch (ex) {
- // Just do nothing, then we don't bother populating
- }
-
- if (selectedClientApp && selectedClientApp.exists()) {
- if (defaultClientApp && selectedClientApp.path != defaultClientApp.path) {
- // Only set the default menu item if it differs from the selected one
- response.defaultMenuItem = this._getFileDisplayName(defaultClientApp);
- }
- response.selectedMenuItem = this._getFileDisplayName(selectedClientApp);
- }
- response.reader = this._getReaderForType(feedType);
- return response;
- },
-
- _setPref(aPrefName, aPrefValue, aIsComplex = false) {
- LOG(`FeedWriter._setPref ${aPrefName}`);
- // Ensure we have a pref that is settable
- if (aPrefName && SETTABLE_PREFS.has(aPrefName)) {
- if (aIsComplex) {
- const supportsString = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- supportsString.data = aPrefValue;
- Services.prefs.setComplexValue(aPrefName, Ci.nsISupportsString, supportsString);
- } else {
- Services.prefs.setCharPref(aPrefName, aPrefValue);
- }
- } else {
- LOG(`FeedWriter._setPref ${aPrefName} not allowed`);
- }
- },
-
- _getReaderForType(feedType) {
- let prefs = Services.prefs;
- let handler = "bookmarks";
- let url;
- // eslint-disable-next-line mozilla/use-default-preference-values
- try {
- handler = prefs.getCharPref(getPrefReaderForType(feedType));
- } catch (ex) { }
-
- if (handler === "web") {
- try {
- url = prefs.getComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString).data;
- } catch (ex) {
- LOG("FeedWriter._setSelectedHandler: invalid or no handler in prefs");
- url = null;
- }
- }
- const alwaysUse = this._getAlwaysUseState(feedType);
- const action = prefs.getCharPref(getPrefActionForType(feedType));
- return { handler, url, alwaysUse, action };
- },
-
- _getAlwaysUseState(feedType) {
- try {
- return Services.prefs.getCharPref(getPrefActionForType(feedType)) != "ask";
- } catch (ex) { }
- return false;
- },
-
- receiveMessage(msg) {
- let handler;
- switch (msg.name) {
- case "FeedWriter:GetSubscriptionUI":
- const response = this._initSubscriptionUIResponse(msg.data.feedType);
- msg.target.messageManager
- .sendAsyncMessage("FeedWriter:GetSubscriptionUIResponse",
- response);
- break;
- case "FeedWriter:ChooseClientApp":
- this._chooseClientApp(msg.data.title, msg.data.feedType, msg.target);
- break;
- case "FeedWriter:ShownFirstRun":
- Services.prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false);
- break;
- case "FeedWriter:SetFeedPrefsAndSubscribe":
- const settings = msg.data;
- if (!settings.action || !VALID_ACTIONS.has(settings.action)) {
- LOG(`Invalid action ${settings.action}`);
- return;
- }
- if (!settings.reader || !VALID_READERS.has(settings.reader)) {
- LOG(`Invalid reader ${settings.reader}`);
- return;
- }
- const actionPref = getPrefActionForType(settings.feedType);
- this._setPref(actionPref, settings.action);
- const readerPref = getPrefReaderForType(settings.feedType);
- this._setPref(readerPref, settings.reader);
- handler = null;
-
- switch (settings.reader) {
- case "web":
- // This is a web set URI by content using window.registerContentHandler()
- // Lets make sure we know about it before setting it
- const webPref = getPrefWebForType(settings.feedType);
- let wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
- getService(Ci.nsIWebContentConverterService);
- // If the user provided an invalid web URL this function won't give us a reference
- handler = wccr.getWebContentHandlerByURI(getMimeTypeForFeedType(settings.feedType), settings.uri);
- if (handler) {
- this._setPref(webPref, settings.uri, true);
- if (settings.useAsDefault) {
- wccr.setAutoHandler(getMimeTypeForFeedType(settings.feedType), handler);
- }
- msg.target.messageManager
- .sendAsyncMessage("FeedWriter:SetFeedPrefsAndSubscribeResponse",
- { redirect: handler.getHandlerURI(settings.feedLocation) });
- } else {
- LOG(`No handler found for web ${settings.feedType} ${settings.uri}`);
- }
- break;
- default:
- const feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
- getService(Ci.nsIFeedResultService);
-
- feedService.addToClientReader(settings.feedLocation,
- settings.feedTitle,
- settings.feedSubtitle,
- settings.feedType,
- settings.reader);
- }
- break;
- case "FeedConverter:ExecuteClientApp":
- // Always check feedHandler is from a set array of executable prefs
- if (EXECUTABLE_PREFS.has(msg.data.feedHandler)) {
- this.executeClientApp(msg.data.spec, msg.data.title,
- msg.data.subtitle, msg.data.feedHandler);
- } else {
- LOG(`FeedConverter:ExecuteClientApp - Will not exec ${msg.data.feedHandler}`);
- }
- break;
- }
- },
-};