/* global NewTabWebChannel, NewTabPrefsProvider, PlacesProvider, PreviewProvider, NewTabSearchProvider, Preferences, XPCOMUtils, Task */ /* exported NewTabMessages */ "use strict"; const {utils: Cu} = Components; Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider", "resource:///modules/PlacesProvider.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PreviewProvider", "resource:///modules/PreviewProvider.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider", "resource:///modules/NewTabPrefsProvider.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NewTabSearchProvider", "resource:///modules/NewTabSearchProvider.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel", "resource:///modules/NewTabWebChannel.jsm"); this.EXPORTED_SYMBOLS = ["NewTabMessages"]; const PREF_ENABLED = "browser.newtabpage.remote"; const CURRENT_ENGINE = "browser-search-engine-modified"; // Action names are from the content's perspective. in from chrome == out from content // Maybe replace the ACTION objects by a bi-directional Map a bit later? const ACTIONS = { inboundActions: [ "REQUEST_PREFS", "REQUEST_THUMB", "REQUEST_FRECENT", "REQUEST_UISTRINGS", "REQUEST_SEARCH_SUGGESTIONS", "REQUEST_MANAGE_ENGINES", "REQUEST_SEARCH_STATE", "REQUEST_REMOVE_FORM_HISTORY", "REQUEST_PERFORM_SEARCH", "REQUEST_CYCLE_ENGINE", ], prefs: { inPrefs: "REQUEST_PREFS", outPrefs: "RECEIVE_PREFS", }, preview: { inThumb: "REQUEST_THUMB", outThumb: "RECEIVE_THUMB", }, links: { inFrecent: "REQUEST_FRECENT", outFrecent: "RECEIVE_FRECENT", outPlacesChange: "RECEIVE_PLACES_CHANGE", }, search: { inSearch: { UIStrings: "REQUEST_UISTRINGS", suggestions: "REQUEST_SEARCH_SUGGESTIONS", manageEngines: "REQUEST_MANAGE_ENGINES", state: "REQUEST_SEARCH_STATE", removeFormHistory: "REQUEST_REMOVE_FORM_HISTORY", performSearch: "REQUEST_PERFORM_SEARCH", cycleEngine: "REQUEST_CYCLE_ENGINE" }, outSearch: { UIStrings: "RECEIVE_UISTRINGS", suggestions: "RECEIVE_SEARCH_SUGGESTIONS", state: "RECEIVE_SEARCH_STATE", currentEngine: "RECEIVE_CURRENT_ENGINE" }, } }; let NewTabMessages = { _prefs: {}, /** NEWTAB EVENT HANDLERS **/ handleContentRequest(actionName, {data, target}) { switch (actionName) { case ACTIONS.prefs.inPrefs: // Return to the originator all newtabpage prefs let results = NewTabPrefsProvider.prefs.newtabPagePrefs; NewTabWebChannel.send(ACTIONS.prefs.outPrefs, results, target); break; case ACTIONS.preview.inThumb: // Return to the originator a preview URL PreviewProvider.getThumbnail(data).then(imgData => { NewTabWebChannel.send(ACTIONS.preview.outThumb, {url: data, imgData}, target); }); break; case ACTIONS.links.inFrecent: // Return to the originator the top frecent links PlacesProvider.links.getLinks().then(links => { NewTabWebChannel.send(ACTIONS.links.outFrecent, links, target); }); break; case ACTIONS.search.inSearch.UIStrings: // Return to the originator all search strings to display let strings = NewTabSearchProvider.search.searchSuggestionUIStrings; NewTabWebChannel.send(ACTIONS.search.outSearch.UIStrings, strings, target); break; case ACTIONS.search.inSearch.suggestions: // Return to the originator all search suggestions Task.spawn(function*() { try { let {engineName, searchString} = data; let suggestions = yield NewTabSearchProvider.search.asyncGetSuggestions(engineName, searchString, target); NewTabWebChannel.send(ACTIONS.search.outSearch.suggestions, suggestions, target); } catch (e) { Cu.reportError(e); } }); break; case ACTIONS.search.inSearch.manageEngines: // Open about:preferences to manage search state NewTabSearchProvider.search.manageEngines(target.browser); break; case ACTIONS.search.inSearch.state: // Return the state of the search component (i.e current engine and visible engine details) Task.spawn(function*() { try { let state = yield NewTabSearchProvider.search.asyncGetState(); NewTabWebChannel.broadcast(ACTIONS.search.outSearch.state, state); } catch (e) { Cu.reportError(e); } }); break; case ACTIONS.search.inSearch.removeFormHistory: // Remove a form history entry from the search component let suggestion = data; NewTabSearchProvider.search.removeFormHistory(target, suggestion); break; case ACTIONS.search.inSearch.performSearch: // Perform a search NewTabSearchProvider.search.asyncPerformSearch(target, data).catch(Cu.reportError); break; case ACTIONS.search.inSearch.cycleEngine: // Set the new current engine NewTabSearchProvider.search.asyncCycleEngine(data).catch(Cu.reportError); break; } }, /* * Broadcast places change to all open newtab pages */ handlePlacesChange(type, data) { NewTabWebChannel.broadcast(ACTIONS.links.outPlacesChange, {type, data}); }, /* * Broadcast current engine has changed to all open newtab pages */ _handleCurrentEngineChange(name, value) { // jshint unused: false let engine = value; NewTabWebChannel.broadcast(ACTIONS.search.outSearch.currentEngine, engine); }, /* * Broadcast preference changes to all open newtab pages */ handlePrefChange(actionName, value) { let prefChange = {}; prefChange[actionName] = value; NewTabWebChannel.broadcast(ACTIONS.prefs.outPrefs, prefChange); }, _handleEnabledChange(prefName, value) { if (prefName === PREF_ENABLED) { if (this._prefs.enabled && !value) { this.uninit(); } else if (!this._prefs.enabled && value) { this.init(); } } }, init() { this.handleContentRequest = this.handleContentRequest.bind(this); this._handleEnabledChange = this._handleEnabledChange.bind(this); this._handleCurrentEngineChange = this._handleCurrentEngineChange.bind(this); PlacesProvider.links.init(); NewTabPrefsProvider.prefs.init(); NewTabSearchProvider.search.init(); NewTabWebChannel.init(); this._prefs.enabled = Preferences.get(PREF_ENABLED, false); if (this._prefs.enabled) { for (let action of ACTIONS.inboundActions) { NewTabWebChannel.on(action, this.handleContentRequest); } NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handleEnabledChange); NewTabSearchProvider.search.on(CURRENT_ENGINE, this._handleCurrentEngineChange); for (let pref of NewTabPrefsProvider.newtabPagePrefSet) { NewTabPrefsProvider.prefs.on(pref, this.handlePrefChange); } PlacesProvider.links.on("deleteURI", this.handlePlacesChange); PlacesProvider.links.on("clearHistory", this.handlePlacesChange); PlacesProvider.links.on("linkChanged", this.handlePlacesChange); PlacesProvider.links.on("manyLinksChanged", this.handlePlacesChange); } }, uninit() { this._prefs.enabled = Preferences.get(PREF_ENABLED, false); if (this._prefs.enabled) { NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handleEnabledChange); NewTabSearchProvider.search.off(CURRENT_ENGINE, this._handleCurrentEngineChange); for (let action of ACTIONS.inboundActions) { NewTabWebChannel.off(action, this.handleContentRequest); } for (let pref of NewTabPrefsProvider.newtabPagePrefSet) { NewTabPrefsProvider.prefs.off(pref, this.handlePrefChange); } } NewTabPrefsProvider.prefs.uninit(); NewTabSearchProvider.search.uninit(); NewTabWebChannel.uninit(); } };