// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Mobile Browser. * * The Initial Developer of the Original Code is * Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2008 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Mark Finkle * Matt Brubeck * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); [ ["AllPagesList", "popup_autocomplete", "cmd_openLocation"], ["HistoryList", "history-items", "cmd_history"], ["BookmarkList", "bookmarks-items", "cmd_bookmarks"], #ifdef MOZ_SERVICES_SYNC ["RemoteTabsList", "remotetabs-items", "cmd_remoteTabs"] #endif ].forEach(function(aPanel) { let [name, id, command] = aPanel; XPCOMUtils.defineLazyGetter(window, name, function() { return new AwesomePanel(id, command); }); }); /** * Cache of commonly used elements. */ let Elements = {}; [ ["contentShowing", "bcast_contentShowing"], ["urlbarState", "bcast_urlbarState"], ["stack", "stack"], ["tabs", "tabs-container"], ["controls", "browser-controls"], ["panelUI", "panel-container"], ["toolbarContainer", "toolbar-container"], ["browsers", "browsers"], ["contentViewport", "content-viewport"], ["contentNavigator", "content-navigator"] ].forEach(function (aElementGlobal) { let [name, id] = aElementGlobal; XPCOMUtils.defineLazyGetter(Elements, name, function() { return document.getElementById(id); }); }); /** * Cache of commonly used string bundles. */ var Strings = {}; [ ["browser", "chrome://browser/locale/browser.properties"], ["brand", "chrome://branding/locale/brand.properties"] ].forEach(function (aStringBundle) { let [name, bundle] = aStringBundle; XPCOMUtils.defineLazyGetter(Strings, name, function() { return Services.strings.createBundle(bundle); }); }); const TOOLBARSTATE_LOADING = 1; const TOOLBARSTATE_LOADED = 2; var BrowserUI = { _edit: null, _title: null, _throbber: null, _favicon: null, _dialogs: [], _domWillOpenModalDialog: function(aBrowser) { // We're about to open a modal dialog, make sure the opening // tab is brought to the front. for (let i = 0; i < Browser.tabs.length; i++) { if (Browser._tabs[i].browser == aBrowser) { Browser.selectedTab = Browser.tabs[i]; break; } } }, _titleChanged: function(aBrowser) { let browser = Browser.selectedBrowser; if (browser && aBrowser != browser) return; let url = this.getDisplayURI(browser); let caption = browser.contentTitle || url; if (browser.contentTitle == "" && !Util.isURLEmpty(browser.userTypedValue)) caption = browser.userTypedValue; else if (Util.isURLEmpty(url)) caption = ""; if (caption) { this._title.value = caption; this._title.classList.remove("placeholder"); } else { this._title.value = this._title.getAttribute("placeholder"); this._title.classList.add("placeholder"); } }, /* * Dispatched by window.close() to allow us to turn window closes into tabs * closes. */ _domWindowClose: function(aBrowser) { // Find the relevant tab, and close it. let browsers = Browser.browsers; for (let i = 0; i < browsers.length; i++) { if (browsers[i] == aBrowser) { Browser.closeTab(Browser.getTabAtIndex(i)); return { preventDefault: true }; } } }, _updateButtons: function(aBrowser) { let back = document.getElementById("cmd_back"); let forward = document.getElementById("cmd_forward"); back.setAttribute("disabled", !aBrowser.canGoBack); forward.setAttribute("disabled", !aBrowser.canGoForward); }, _updateToolbar: function _updateToolbar() { let mode = Elements.urlbarState.getAttribute("mode"); if (mode == "edit" && this.activePanel) return; if (Browser.selectedTab.isLoading() && mode != "loading") Elements.urlbarState.setAttribute("mode", "loading"); else if (mode != "view") Elements.urlbarState.setAttribute("mode", "view"); }, _tabSelect: function(aEvent) { let browser = Browser.selectedBrowser; this._titleChanged(browser); this._updateToolbar(); this._updateButtons(browser); this._updateIcon(browser.mIconURL); this.updateStar(); }, _toolbarLocked: 0, isToolbarLocked: function isToolbarLocked() { return this._toolbarLocked; }, lockToolbar: function lockToolbar() { this._toolbarLocked++; document.getElementById("toolbar-moveable-container").top = "0"; if (this._toolbarLocked == 1) Browser.forceChromeReflow(); }, unlockToolbar: function unlockToolbar() { if (!this._toolbarLocked) return; this._toolbarLocked--; if (!this._toolbarLocked) document.getElementById("toolbar-moveable-container").top = ""; }, _setURL: function _setURL(aURL) { if (this.activePanel) this._edit.defaultValue = aURL; else this._edit.value = aURL; }, _editURI: function _editURI(aEdit) { Elements.urlbarState.setAttribute("mode", "edit"); this._edit.defaultValue = this._edit.value; }, _showURI: function _showURI() { // Replace the web page title by the url of the page let urlString = this.getDisplayURI(Browser.selectedBrowser); if (Util.isURLEmpty(urlString)) urlString = ""; this._edit.value = urlString; }, updateAwesomeHeader: function updateAwesomeHeader(aString) { document.getElementById("awesome-header").hidden = (aString != ""); // During an awesome search we always show the popup_autocomplete/AllPagesList // panel since this looks in every places and the rationale behind typing // is to find something, whereever it is. if (this.activePanel != AllPagesList) { let inputField = this._edit; let oldClickSelectsAll = inputField.clickSelectsAll; inputField.clickSelectsAll = false; this.activePanel = AllPagesList; // changing the searchString property call updateAwesomeHeader again inputField.controller.searchString = aString; inputField.readOnly = false; inputField.clickSelectsAll = oldClickSelectsAll; return; } let event = document.createEvent("Events"); event.initEvent("onsearchbegin", true, true); this._edit.dispatchEvent(event); }, _closeOrQuit: function _closeOrQuit() { // Close active dialog, if we have one. If not then close the application. if (this.activePanel) { this.activePanel = null; } else if (this.activeDialog) { this.activeDialog.close(); } else { // Check to see if we should really close the window if (Browser.closing()) window.close(); } }, _activePanel: null, get activePanel() { return this._activePanel; }, set activePanel(aPanel) { if (this._activePanel == aPanel) return; let awesomePanel = document.getElementById("awesome-panels"); let awesomeHeader = document.getElementById("awesome-header"); let willShowPanel = (!this._activePanel && aPanel); if (willShowPanel) { this.pushDialog(aPanel); this._edit.attachController(); this._editURI(); awesomePanel.hidden = awesomeHeader.hidden = false; }; if (aPanel) { aPanel.open(); if (this._edit.value == "") this._showURI(); } let willHidePanel = (this._activePanel && !aPanel); if (willHidePanel) { awesomePanel.hidden = true; awesomeHeader.hidden = false; this._edit.reset(); this._edit.detachController(); this.popDialog(); } if (this._activePanel) this._activePanel.close(); // The readOnly state of the field enabled/disabled the VKB let isReadOnly = !(aPanel == AllPagesList && Util.isPortrait() && (willShowPanel || !this._edit.readOnly)); this._edit.readOnly = isReadOnly; if (isReadOnly) this._edit.blur(); this._activePanel = aPanel; if (willHidePanel || willShowPanel) { let event = document.createEvent("UIEvents"); event.initUIEvent("NavigationPanel" + (willHidePanel ? "Hidden" : "Shown"), true, true, window, false); window.dispatchEvent(event); } }, get activeDialog() { // Return the topmost dialog if (this._dialogs.length) return this._dialogs[this._dialogs.length - 1]; return null; }, pushDialog: function pushDialog(aDialog) { // If we have a dialog push it on the stack and set the attr for CSS if (aDialog) { this.lockToolbar(); this._dialogs.push(aDialog); document.getElementById("toolbar-main").setAttribute("dialog", "true"); Elements.contentShowing.setAttribute("disabled", "true"); } }, popDialog: function popDialog() { if (this._dialogs.length) { this._dialogs.pop(); this.unlockToolbar(); } // If no more dialogs are being displayed, remove the attr for CSS if (!this._dialogs.length) { document.getElementById("toolbar-main").removeAttribute("dialog"); Elements.contentShowing.removeAttribute("disabled"); } }, pushPopup: function pushPopup(aPanel, aElements) { this._hidePopup(); this._popup = { "panel": aPanel, "elements": (aElements instanceof Array) ? aElements : [aElements] }; this._dispatchPopupChanged(true); }, popPopup: function popPopup(aPanel) { if (!this._popup || aPanel != this._popup.panel) return; this._popup = null; this._dispatchPopupChanged(false); }, _dispatchPopupChanged: function _dispatchPopupChanged(aVisible) { let stack = document.getElementById("stack"); let event = document.createEvent("UIEvents"); event.initUIEvent("PopupChanged", true, true, window, aVisible); event.popup = this._popup; stack.dispatchEvent(event); }, _hidePopup: function _hidePopup() { if (!this._popup) return; let panel = this._popup.panel; if (panel.hide) panel.hide(); }, _isEventInsidePopup: function _isEventInsidePopup(aEvent) { if (!this._popup) return false; let elements = this._popup.elements; let targetNode = aEvent ? aEvent.target : null; while (targetNode && elements.indexOf(targetNode) == -1) targetNode = targetNode.parentNode; return targetNode ? true : false; }, switchPane: function switchPane(aPanelId) { let button = document.getElementsByAttribute("linkedpanel", aPanelId)[0]; if (button) button.checked = true; this.blurFocusedElement(); let pane = document.getElementById(aPanelId); document.getElementById("panel-items").selectedPanel = pane; }, get toolbarH() { if (!this._toolbarH) { let toolbar = document.getElementById("toolbar-main"); this._toolbarH = toolbar.boxObject.height; } return this._toolbarH; }, get sidebarW() { delete this._sidebarW; return this._sidebarW = Elements.controls.getBoundingClientRect().width; }, get starButton() { delete this.starButton; return this.starButton = document.getElementById("tool-star"); }, sizeControls: function(windowW, windowH) { // tabs document.getElementById("tabs").resize(); // awesomebar and related panels let popup = document.getElementById("awesome-panels"); popup.top = this.toolbarH; popup.height = windowH - this.toolbarH; popup.width = windowW; // content navigator helper let contentHelper = document.getElementById("content-navigator"); contentHelper.top = windowH - contentHelper.getBoundingClientRect().height; }, init: function() { this._edit = document.getElementById("urlbar-edit"); this._title = document.getElementById("urlbar-title"); this._throbber = document.getElementById("urlbar-throbber"); this._favicon = document.getElementById("urlbar-favicon"); this._favicon.addEventListener("error", this, false); this._edit.addEventListener("click", this, false); this._edit.addEventListener("mousedown", this, false); window.addEventListener("NavigationPanelShown", this, false); window.addEventListener("NavigationPanelHidden", this, false); Elements.tabs.addEventListener("TabSelect", this, true); Elements.tabs.addEventListener("TabOpen", this, true); Elements.browsers.addEventListener("PanFinished", this, true); #if MOZ_PLATFORM_MAEMO == 6 Elements.browsers.addEventListener("SizeChanged", this, true); #endif // listen content messages messageManager.addMessageListener("DOMLinkAdded", this); messageManager.addMessageListener("DOMTitleChanged", this); messageManager.addMessageListener("DOMWillOpenModalDialog", this); messageManager.addMessageListener("DOMWindowClose", this); messageManager.addMessageListener("Browser:OpenURI", this); messageManager.addMessageListener("Browser:SaveAs:Return", this); // listening mousedown for automatically dismiss some popups (e.g. larry) window.addEventListener("mousedown", this, true); // listening escape to dismiss dialog on VK_ESCAPE window.addEventListener("keypress", this, true); // listening AppCommand to handle special keys window.addEventListener("AppCommand", this, true); // We can delay some initialization until after startup. We wait until // the first page is shown, then dispatch a UIReadyDelayed event. messageManager.addMessageListener("pageshow", function() { if (getBrowser().currentURI.spec == "about:blank") return; messageManager.removeMessageListener("pageshow", arguments.callee, true); setTimeout(function() { let event = document.createEvent("Events"); event.initEvent("UIReadyDelayed", true, false); window.dispatchEvent(event); }, 0); }); // Delay the panel UI and Sync initialization. window.addEventListener("UIReadyDelayed", function(aEvent) { window.removeEventListener(aEvent.type, arguments.callee, false); // We unhide the panelUI so the XBL and settings can initialize Elements.panelUI.hidden = false; // Init the views ExtensionsView.init(); DownloadsView.init(); PreferencesView.init(); ConsoleView.init(); #ifdef MOZ_IPC // Pre-start the content process Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime) .ensureContentProcess(); #endif #ifdef MOZ_SERVICES_SYNC // Init the sync system WeaveGlue.init(); #endif // Init helpers BadgeHandlers.register(BrowserUI._edit.popup); FormHelperUI.init(); FindHelperUI.init(); PageActions.init(); FullScreenVideo.init(); NewTabPopup.init(); #ifdef MOZ_UPDATER // Check for updates in progress let updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"].createInstance(Ci.nsIUpdatePrompt); updatePrompt.checkForUpdates(); #endif }, false); #ifndef MOZ_OFFICIAL_BRANDING setTimeout(function() { let startup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup_MOZILLA_2_0).getStartupInfo(); for (let name in startup) { if (name != "process") Services.console.logStringMessage("[timing] " + name + ": " + (startup[name] - startup.process) + "ms"); } }, 3000); #endif }, uninit: function() { ExtensionsView.uninit(); ConsoleView.uninit(); }, update: function(aState) { let browser = Browser.selectedBrowser; switch (aState) { case TOOLBARSTATE_LOADED: this._updateToolbar(); this._updateIcon(browser.mIconURL); this.unlockToolbar(); break; case TOOLBARSTATE_LOADING: this._updateToolbar(); browser.mIconURL = ""; this._updateIcon(); this.lockToolbar(); break; } }, _updateIcon: function(aIconSrc) { this._favicon.src = aIconSrc || ""; if (Browser.selectedTab.isLoading()) { this._throbber.hidden = false; this._throbber.setAttribute("loading", "true"); this._favicon.hidden = true; } else { this._favicon.hidden = false; this._throbber.hidden = true; this._throbber.removeAttribute("loading"); } }, getDisplayURI: function(browser) { let uri = browser.currentURI; try { uri = gURIFixup.createExposableURI(uri); } catch (ex) {} return uri.spec; }, /* Set the location to the current content */ updateURI: function() { let browser = Browser.selectedBrowser; // FIXME: deckbrowser should not fire TabSelect on the initial tab (bug 454028) if (!browser.currentURI) return; // Update the navigation buttons this._updateButtons(browser); // Check for a bookmarked page this.updateStar(); let urlString = this.getDisplayURI(browser); if (Util.isURLEmpty(urlString)) urlString = ""; this._setURL(urlString); }, goToURI: function(aURI) { aURI = aURI || this._edit.value; if (!aURI) return; // Make sure we're online before attempting to load Util.forceOnline(); // Give the new page lots of room Browser.hideSidebars(); this.closeAutoComplete(); this._edit.value = aURI; let postData = {}; aURI = Browser.getShortcutOrURI(aURI, postData); Browser.loadURI(aURI, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, postData: postData }); // Delay doing the fixup so the raw URI is passed to loadURIWithFlags // and the proper third-party fixup can be done let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; let uri = gURIFixup.createFixupURI(aURI, fixupFlags); gHistSvc.markPageAsTyped(uri); this._titleChanged(Browser.selectedBrowser); }, showAutoComplete: function showAutoComplete() { if (this.isAutoCompleteOpen()) return; this.hidePanel(); this._hidePopup(); this.activePanel = AllPagesList; }, closeAutoComplete: function closeAutoComplete() { if (this.isAutoCompleteOpen()) this._edit.popup.closePopup(); this.activePanel = null; }, isAutoCompleteOpen: function isAutoCompleteOpen() { return this.activePanel == AllPagesList; }, doOpenSearch: function doOpenSearch(aName) { // save the current value of the urlbar let searchValue = this._edit.value; // Give the new page lots of room Browser.hideSidebars(); this.closeAutoComplete(); // Make sure we're online before attempting to load Util.forceOnline(); let engine = Services.search.getEngineByName(aName); let submission = engine.getSubmission(searchValue, null); Browser.selectedBrowser.userTypedValue = submission.uri.spec; Browser.loadURI(submission.uri.spec, { postData: submission.postData }); this._titleChanged(Browser.selectedBrowser); }, updateUIFocus: function _updateUIFocus() { if (Elements.contentShowing.getAttribute("disabled") == "true") Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:Blur", { }); }, updateStar: function() { PlacesUtils.asyncGetBookmarkIds(getBrowser().currentURI, function (aItemIds) { if (aItemIds.length) this.starButton.setAttribute("starred", "true"); else this.starButton.removeAttribute("starred"); }, this); }, newTab: function newTab(aURI, aOwner) { aURI = aURI || "about:blank"; let tab = Browser.addTab(aURI, true, aOwner); this.hidePanel(); if (aURI == "about:blank") { // Display awesomebar UI this.showAutoComplete(); } else { // Give the new page lots of room Browser.hideSidebars(); this.closeAutoComplete(); } return tab; }, newOrSelectTab: function newOrSelectTab(aURI, aOwner) { let tabs = Browser.tabs; for (let i = 0; i < tabs.length; i++) { if (tabs[i].browser.currentURI.spec == aURI) { Browser.selectedTab = tabs[i]; return; } } this.newTab(aURI, aOwner); }, closeTab: function closeTab(aTab) { // If no tab is passed in, assume the current tab Browser.closeTab(aTab || Browser.selectedTab); }, selectTab: function selectTab(aTab) { this.activePanel = null; Browser.selectedTab = aTab; }, undoCloseTab: function undoCloseTab(aIndex) { let tab = null; let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); if (ss.getClosedTabCount(window) > (aIndex || 0)) { let chromeTab = ss.undoCloseTab(window, aIndex || 0); tab = Browser.getTabFromChrome(chromeTab); } return tab; }, isTabsVisible: function isTabsVisible() { // The _1, _2 and _3 are to make the js2 emacs mode happy let [leftvis,_1,_2,_3] = Browser.computeSidebarVisibility(); return (leftvis > 0.002); }, showPanel: function showPanel(aPage) { if (this.activePanel) this.activePanel = null; Elements.panelUI.left = 0; Elements.panelUI.hidden = false; Elements.contentShowing.setAttribute("disabled", "true"); if (aPage) { this.switchPane(aPage); } else { // Fire a "select" event anyway so listeners know when the panel is opened. let event = document.createEvent("Events"); event.initEvent("select", true, true); document.getElementById("panel-items").dispatchEvent(event); } }, hidePanel: function hidePanel() { if (!this.isPanelVisible()) return; Elements.panelUI.hidden = true; Elements.contentShowing.removeAttribute("disabled"); this.blurFocusedElement(); }, isPanelVisible: function isPanelVisible() { return (!Elements.panelUI.hidden && Elements.panelUI.left == 0); }, blurFocusedElement: function blurFocusedElement() { let focusedElement = document.commandDispatcher.focusedElement; if (focusedElement) focusedElement.blur(); }, switchTask: function switchTask() { try { let phone = Cc["@mozilla.org/phone/support;1"].createInstance(Ci.nsIPhoneSupport); phone.switchTask(); } catch(e) { } }, handleEscape: function (aEvent) { aEvent.stopPropagation(); // Check open popups if (this._popup) { this._hidePopup(); return; } // Check active panel if (this.activePanel) { this.activePanel = null; return; } // Check open dialogs let dialog = this.activeDialog; if (dialog) { dialog.close(); return; } // Check open modal elements let modalElementsLength = document.getElementsByClassName("modal-block").length; if (modalElementsLength > 0) return; // Check open panel if (this.isPanelVisible()) { this.hidePanel(); return; } // Check content helper let contentHelper = document.getElementById("content-navigator"); if (contentHelper.isActive) { contentHelper.model.hide(); return; } // Only if there are no dialogs, popups, or panels open let tab = Browser.selectedTab; let browser = tab.browser; if (browser.canGoBack) { browser.goBack(); } else if (tab.owner) { this.closeTab(tab); } #ifdef ANDROID else { window.QueryInterface(Ci.nsIDOMChromeWindow).minimize(); if (tab.closeOnExit) this.closeTab(tab); } #endif }, handleEvent: function handleEvent(aEvent) { switch (aEvent.type) { // Browser events case "TabSelect": this._tabSelect(aEvent); break; case "TabOpen": { // Workaround to hide the tabstrip if it is partially visible // See bug 524469 let [tabsVisibility,,,] = Browser.computeSidebarVisibility(); if (tabsVisibility > 0.0 && tabsVisibility < 1.0) Browser.hideSidebars(); break; } case "PanFinished": let [tabsVisibility,,,] = Browser.computeSidebarVisibility(); if (tabsVisibility == 0.0) document.getElementById("tabs").removeClosedTab(); break; case "SizeChanged": this.sizeControls(ViewableAreaObserver.width, ViewableAreaObserver.height); break; // Window events case "keypress": if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) this.handleEscape(aEvent); break; case "AppCommand": aEvent.stopPropagation(); switch (aEvent.command) { case "Menu": this.doCommand("cmd_menu"); break; case "Search": if (!this.activePanel) AllPagesList.doCommand(); else this.doCommand("cmd_opensearch"); break; default: break; } break; // URL textbox events case "click": if (this._edit.readOnly) this._edit.readOnly = false; break; case "mousedown": if (!this._isEventInsidePopup(aEvent)) this._hidePopup(); break; // Favicon events case "error": this._favicon.src = ""; break; // Awesome popup event case "NavigationPanelShown": this._edit.collapsed = false; this._title.collapsed = true; if (!this._edit.readOnly) this._edit.focus(); // Disabled the search button if no search engines are available let button = document.getElementById("urlbar-icons"); if (BrowserSearch.engines.length) button.removeAttribute("disabled"); else button.setAttribute("disabled", "true"); break; case "NavigationPanelHidden": { this._edit.collapsed = true; this._title.collapsed = false; this._updateToolbar(); let button = document.getElementById("urlbar-icons"); button.removeAttribute("open"); button.removeAttribute("disabled"); break; } } }, receiveMessage: function receiveMessage(aMessage) { let browser = aMessage.target; let json = aMessage.json; switch (aMessage.name) { case "DOMTitleChanged": this._titleChanged(browser); break; case "DOMWillOpenModalDialog": return this._domWillOpenModalDialog(browser); break; case "DOMWindowClose": return this._domWindowClose(browser); break; case "DOMLinkAdded": if (Browser.selectedBrowser == browser) this._updateIcon(Browser.selectedBrowser.mIconURL); break; case "Browser:SaveAs:Return": if (json.type != Ci.nsIPrintSettings.kOutputFormatPDF) return; let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); let db = dm.DBConnection; let stmt = db.createStatement("UPDATE moz_downloads SET endTime = :endTime, state = :state WHERE id = :id"); stmt.params.endTime = Date.now() * 1000; stmt.params.state = Ci.nsIDownloadManager.DOWNLOAD_FINISHED; stmt.params.id = json.id; stmt.execute(); stmt.finalize(); let download = dm.getDownload(json.id); #ifdef ANDROID // since our content process doesn't have write permissions to the // downloads dir, we save it to the tmp dir and then move it here let dlFile = download.targetFile; if (!dlFile.exists()) dlFile.create(file.NORMAL_FILE_TYPE, 0666); let tmpDir = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile); let tmpFile = tmpDir.clone(); tmpFile.append(dlFile.leafName); // we sometimes race with the content process, so make sure its finished // creating/writing the file while (!tmpFile.exists()); tmpFile.moveTo(dlFile.parent, dlFile.leafName); #endif try { DownloadsView.downloadCompleted(download); let element = DownloadsView.getElementForDownload(json.id); element.setAttribute("state", Ci.nsIDownloadManager.DOWNLOAD_FINISHED); element.setAttribute("endTime", Date.now()); element.setAttribute("referrer", json.referrer); DownloadsView._updateTime(element); DownloadsView._updateStatus(element); } catch(e) {} Services.obs.notifyObservers(download, "dl-done", null); break; case "Browser:OpenURI": let referrerURI = null; if (json.referrer) referrerURI = Services.io.newURI(json.referrer, null, null); Browser.addTab(json.uri, json.bringFront, Browser.selectedTab, { referrerURI: referrerURI }); break; } }, supportsCommand : function(cmd) { var isSupported = false; switch (cmd) { case "cmd_back": case "cmd_forward": case "cmd_reload": case "cmd_forceReload": case "cmd_stop": case "cmd_go": case "cmd_openLocation": case "cmd_star": case "cmd_opensearch": case "cmd_bookmarks": case "cmd_history": case "cmd_remoteTabs": case "cmd_quit": case "cmd_close": case "cmd_menu": case "cmd_newTab": case "cmd_closeTab": case "cmd_undoCloseTab": case "cmd_actions": case "cmd_panel": case "cmd_sanitize": case "cmd_zoomin": case "cmd_zoomout": case "cmd_volumeLeft": case "cmd_volumeRight": case "cmd_lockscreen": isSupported = true; break; default: isSupported = false; break; } return isSupported; }, isCommandEnabled : function(cmd) { let elem = document.getElementById(cmd); if (elem && (elem.getAttribute("disabled") == "true")) return false; return true; }, doCommand : function(cmd) { if (!this.isCommandEnabled(cmd)) return; let browser = getBrowser(); switch (cmd) { case "cmd_back": browser.goBack(); break; case "cmd_forward": browser.goForward(); break; case "cmd_reload": browser.reload(); break; case "cmd_forceReload": { // Simulate a new page browser.lastLocation = null; const reloadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; browser.reloadWithFlags(reloadFlags); break; } case "cmd_stop": browser.stop(); break; case "cmd_go": this.goToURI(); break; case "cmd_openLocation": this.showAutoComplete(); break; case "cmd_star": { BookmarkPopup.toggle(); if (!this.starButton.hasAttribute("starred")) { this.starButton.setAttribute("starred", "true"); BookmarkPopup.autoHide(); } let bookmarkURI = browser.currentURI; PlacesUtils.asyncGetBookmarkIds(bookmarkURI, function (aItemIds) { if (!aItemIds.length) { let bookmarkTitle = browser.contentTitle || bookmarkURI.spec; try { let bookmarkService = PlacesUtils.bookmarks; let bookmarkId = bookmarkService.insertBookmark(BookmarkList.panel.mobileRoot, bookmarkURI, bookmarkService.DEFAULT_INDEX, bookmarkTitle); } catch (e) { // Insert failed; reset the star state. this.updateStar(); } // XXX Used for browser-chrome tests let event = document.createEvent("Events"); event.initEvent("BookmarkCreated", true, false); window.dispatchEvent(event); } }, this); break; } case "cmd_opensearch": this.blurFocusedElement(); BrowserSearch.toggle(); break; case "cmd_bookmarks": this.activePanel = BookmarkList; break; case "cmd_history": this.activePanel = HistoryList; break; case "cmd_remoteTabs": // remove the checked state set by the click it will be reset by setting // checked on the command element if we decide to show this panel (see AwesomePanel.js) document.getElementById("remotetabs-button").removeAttribute("checked"); if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) { this.activePanel = null; WeaveGlue.open(); } else if (!Weave.Service.isLoggedIn) { this.activePanel = null; BrowserUI.showPanel("prefs-container"); let prefsBox = document.getElementById("prefs-list"); let syncArea = document.getElementById("prefs-sync"); if (prefsBox && syncArea) { let prefsBoxY = prefsBox.firstChild.boxObject.screenY; let syncAreaY = syncArea.boxObject.screenY; setTimeout(function() { prefsBox.scrollBoxObject.scrollTo(0, syncAreaY - prefsBoxY); }, 0); } } else { this.activePanel = RemoteTabsList; } break; case "cmd_quit": GlobalOverlay.goQuitApplication(); break; case "cmd_close": this._closeOrQuit(); break; case "cmd_menu": AppMenu.toggle(); break; case "cmd_newTab": this.newTab(); break; case "cmd_closeTab": this.closeTab(); break; case "cmd_undoCloseTab": this.undoCloseTab(); break; case "cmd_sanitize": { let title = Strings.browser.GetStringFromName("clearPrivateData.title"); let message = Strings.browser.GetStringFromName("clearPrivateData.message"); let clear = Services.prompt.confirm(window, title, message); if (clear) { // disable the button temporarily to indicate something happened let button = document.getElementById("prefs-clear-data"); button.disabled = true; setTimeout(function() { button.disabled = false; }, 5000); Sanitizer.sanitize(); } break; } case "cmd_panel": { if (BrowserUI.isPanelVisible()) this.hidePanel(); else this.showPanel(); break; } case "cmd_zoomin": Browser.zoom(-1); break; case "cmd_zoomout": Browser.zoom(1); break; case "cmd_volumeLeft": // Zoom in (portrait) or out (landscape) Browser.zoom(Util.isPortrait() ? -1 : 1); break; case "cmd_volumeRight": // Zoom out (portrait) or in (landscape) Browser.zoom(Util.isPortrait() ? 1 : -1); break; case "cmd_lockscreen": { let locked = Services.prefs.getBoolPref("toolkit.screen.lock"); Services.prefs.setBoolPref("toolkit.screen.lock", !locked); let strings = Strings.browser; let alerts = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService); alerts.showAlertNotification(null, strings.GetStringFromName("alertLockScreen"), strings.GetStringFromName("alertLockScreen." + (!locked ? "locked" : "unlocked")), false, "", null); break; } } } };