// -*- 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 * * 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 ***** */ Components.utils.import("resource://gre/modules/utils.js"); const TOOLBARSTATE_LOADING = 1; const TOOLBARSTATE_LOADED = 2; const TOOLBARSTATE_INDETERMINATE = 3; const UIMODE_NONE = 0; const UIMODE_URLVIEW = 1; const UIMODE_URLEDIT = 2; const UIMODE_BOOKMARK = 3; const UIMODE_BOOKMARKLIST = 4; const UIMODE_TABS = 5; const UIMODE_CONTROLS = 6; const UIMODE_PANEL = 7; const kMaxEngines = 4; const kDefaultFavIconURL = "chrome://browser/skin/images/default-favicon.png"; [ ["gContentBox", "contentBox"], ].forEach(function (elementGlobal) { var [name, id] = elementGlobal; window.__defineGetter__(name, function () { var element = document.getElementById(id); if (!element) return null; delete window[name]; return window[name] = element; }); window.__defineSetter__(name, function (val) { delete window[name]; return window[name] = val; }); }); var BrowserUI = { _panel : null, _caption : null, _edit : null, _throbber : null, _autocompleteNavbuttons : null, _favicon : null, _faviconAdded : false, _setContentPosition : function (aProp, aValue) { let value = Math.round(aValue); if (aProp == "left") { gContentBox.style.marginLeft = value + "px"; gContentBox.style.marginRight = -value + "px"; } else if (aProp == "top") { gContentBox.style.marginTop = value + "px"; gContentBox.style.marginBottom = -value + "px"; } }, get _contentTop() { return parseInt(gContentBox.style.marginTop); }, _titleChanged : function(aDocument) { var browser = Browser.currentBrowser; if (browser && aDocument != browser.contentDocument) return; this._caption.value = aDocument.title; var docElem = document.documentElement; var title = ""; if (aDocument.title) title = aDocument.title + docElem.getAttribute("titleseparator"); document.title = title + docElem.getAttribute("titlemodifier"); }, _linkAdded : function(aEvent) { var link = aEvent.originalTarget; if (!link || !link.ownerDocument || !link.href) return; var rel = link.rel && link.rel.toLowerCase(); var rels = rel.split(/\s+/); if (rels.indexOf("icon") != -1) { this._setIcon(link.href); } }, _tabSelect : function(aEvent) { var browser = Browser.currentBrowser; this.setURI(); this._titleChanged(browser.contentDocument); this._favicon.src = browser.mIconURL || kDefaultFavIconURL; let toolbar = document.getElementById("toolbar-main"); if (Browser.content.currentTab.chromeTop) { // content box was panned, so let's reset it this._setContentPosition("top", Browser.content.currentTab.chromeTop); this._setContentPosition("left", 0); toolbar.top = this._contentTop - toolbar.boxObject.height; } else { // Must be initial conditions toolbar.top = 0; this._setContentPosition("top", toolbar.boxObject.height); this._setContentPosition("left", 0); } this.show(UIMODE_NONE); }, _setIcon : function(aURI) { var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var faviconURI = ios.newURI(aURI, null, null); var fis = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService); if (faviconURI.schemeIs("javascript") || fis.isFailedFavicon(faviconURI)) faviconURI = ios.newURI(kDefaultFavIconURL, null, null); var browser = getBrowser(); browser.mIconURL = faviconURI.spec; fis.setAndLoadFaviconForPage(browser.currentURI, faviconURI, true); this._favicon.src = faviconURI.spec; this._faviconAdded = true; }, _getBookmarks : function(aFolders) { var items = []; var hs = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService); var options = hs.getNewQueryOptions(); //options.resultType = options.RESULTS_AS_URI; var query = hs.getNewQuery(); query.setFolders(aFolders, 1); var result = hs.executeQuery(query, options); var rootNode = result.root; rootNode.containerOpen = true; var cc = rootNode.childCount; for (var i=0; i 0 && (toolbar.top > -toolbar.boxObject.height && !sidebarVisible)) { // Scroll the toolbar up unless it is already scrolled up newTop = this._dragData.sTop - dy; // Clip the adjustment to just enough to hide the toolbar if (newTop < -toolbar.boxObject.height) newTop = -toolbar.boxObject.height; // Reset the browser start point Browser.content.dragData.sX = aEvent.screenX; Browser.content.dragData.sY = aEvent.screenY; } else if (dy < 0 && (toolbar.top < 0 && !sidebarVisible)) { // Scroll the toolbar down unless it is already down newTop = this._dragData.sTop - dy; // Clip the adjustment to just enough to fully show the toolbar if (newTop > 0) newTop = 0; } // Update the toolbar and browser tops. Stop the mousemove from // getting to the deckbrowser. if (newTop != null) { toolbar.top = newTop; this._setContentPosition("top", newTop + toolbar.boxObject.height); // Cache the current top so we can use it when switching tabs Browser.content.currentTab.chromeTop = this._contentTop; pannedUI = true; } } if (this._dragData.dragging && (Browser.content.scrollX == 0 || (Browser.content.scrollX + viewportW) == scrollWidth)) { let tabbar = document.getElementById("tab-list-container"); let sidebar = document.getElementById("browser-controls"); let panelUI = document.getElementById("panel-container"); let toolbar = document.getElementById("toolbar-main"); let dx = this._dragData.lastX - aEvent.screenX; this._dragData.dragX += dx; if (Math.abs(this._dragData.screenX - aEvent.screenX) > 30) { let newLeft = this._dragData.sLeft - dx; let oldLeft = tabbar.left; let tabbarW = tabbar.boxObject.width; let sidebarW = sidebar.boxObject.width; let contentW = gContentBox.boxObject.width; // Limit the panning if (newLeft > 0) newLeft = 0; else if (newLeft < -(tabbarW + sidebarW)) newLeft = -(tabbarW + sidebarW); // Set the UI mode based on where we ended up if (newLeft > -(tabbarW - tabbarW / 3) && newLeft <= 0) { if (this._dragData.uiMode == UIMODE_CONTROLS) return; this.mode = UIMODE_TABS; } else if (newLeft >= -(tabbarW + sidebarW) && newLeft < -(tabbarW + sidebarW / 3)) { if (this._dragData.uiMode == UIMODE_TABS) return; this.mode = UIMODE_CONTROLS; } else this.mode = (gContentBox.style.marginTop == "0px" ? UIMODE_NONE : UIMODE_URLVIEW); tabbar.left = newLeft; // Never let the toolbar pan off the screen let newToolbarLeft = newLeft; if (newToolbarLeft < 0) newToolbarLeft = 0; toolbar.left = newToolbarLeft; // Make the toolbar appear/disappear depending on the state of the sidebars if (newLeft + tabbarW != 0) toolbar.top = 0; else toolbar.top = this._contentTop - toolbar.boxObject.height; this._setContentPosition("left", newLeft + tabbarW); sidebar.left = newLeft + tabbarW + contentW; panelUI.left = newLeft + tabbarW + contentW + sidebarW; pannedUI = true; } } if (pannedUI) { aEvent.stopPropagation(); // Force a sync redraw window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIDOMWindowUtils) .processUpdates(); } else { // Reset our start point while the browser is doing its panning this._dragData.lastX = aEvent.screenX; this._dragData.lastY = aEvent.screenY; } }, _showToolbar : function(aShow) { var toolbar = document.getElementById("toolbar-main"); if (aShow) { // Always show the toolbar, either by floating or panning if (toolbar.top == -toolbar.boxObject.height) { // Float the toolbar over content toolbar.top = 0; } else if (toolbar.top < 0) { // Partially showing, so show it completely toolbar.top = 0; this._setContentPosition("top", toolbar.boxObject.height); } } else { // If we are floating the toolbar, then hide it again if (gContentBox.style.marginTop == "0px") { toolbar.top = -toolbar.boxObject.height; } } }, _editToolbar : function(aEdit) { var toolbar = document.getElementById("toolbar-main"); if (aEdit) { toolbar.setAttribute("mode", "edit"); this._caption.hidden = true; this._edit.hidden = false; this._edit.inputField.focus(); } else { toolbar.setAttribute("mode", "view"); this._edit.hidden = true; this._edit.reallyClosePopup(); this._caption.hidden = false; } }, _showPanel : function(aMode) { let tabbar = document.getElementById("tab-list-container"); let sidebar = document.getElementById("browser-controls"); let panelUI = document.getElementById("panel-container"); let toolbar = document.getElementById("toolbar-main"); let tabbarW = tabbar.boxObject.width; let sidebarW = sidebar.boxObject.width; let contentW = gContentBox.boxObject.width; let newLeft = -tabbarW; switch (aMode) { case UIMODE_NONE: Shortcuts.deinit(); break; case UIMODE_PANEL: newLeft = -contentW; this._initPanel(); break; case UIMODE_CONTROLS: newLeft = -(tabbarW + sidebarW); break; case UIMODE_TABS: newLeft = 0; break; } tabbar.left = newLeft; let newToolbarLeft = newLeft; if (newToolbarLeft < 0 && aMode != UIMODE_PANEL) newToolbarLeft = 0; else if (newToolbarLeft < 0 && aMode == UIMODE_PANEL) newToolbarLeft += tabbarW + sidebarW; toolbar.left = newToolbarLeft; this._setContentPosition("left", newLeft + tabbarW); sidebar.left = newLeft + tabbarW + contentW; panelUI.left = newLeft + tabbarW + contentW + sidebarW; panelUI.width = contentW; }, _initPanel : function() { let addons = document.getElementById("addons-container"); if (!addons.hasAttribute("src")) addons.setAttribute("src", "chrome://mozapps/content/extensions/extensions.xul"); let dloads = document.getElementById("downloads-container"); if (!dloads.hasAttribute("src")) dloads.setAttribute("src", "chrome://mozapps/content/downloads/downloads.xul"); Shortcuts.init(); }, switchPane : function(id) { document.getElementById("panel-items").selectedPanel = document.getElementById(id); }, _sizeControls : function(aEvent) { var rect = document.getElementById("browser-container").getBoundingClientRect(); var containerW = rect.right - rect.left; var containerH = rect.bottom - rect.top; var toolbar = document.getElementById("toolbar-main"); var toolbarH = toolbar.boxObject.height; var sidebar = document.getElementById("browser-controls"); var panelUI = document.getElementById("panel-container"); var tabbar = document.getElementById("tab-list-container"); if (window == aEvent.target) { tabbar.left = -tabbar.boxObject.width; panelUI.left = containerW + sidebar.boxObject.width; sidebar.left = containerW; sidebar.height = tabbar.height = (panelUI.height = containerH) - toolbarH; } panelUI.width = containerW - sidebar.boxObject.width - tabbar.boxObject.width; var popup = document.getElementById("popup_autocomplete"); toolbar.width = containerW; popup.height = containerH - toolbarH; }, init : function() { this._caption = document.getElementById("urlbar-caption"); this._caption.addEventListener("click", this, false); this._edit = document.getElementById("urlbar-edit"); this._edit.addEventListener("blur", this, false); this._edit.addEventListener("keypress", this, true); this._edit.addEventListener("input", this, false); this._throbber = document.getElementById("urlbar-throbber"); this._favicon = document.getElementById("urlbar-favicon"); this._favicon.addEventListener("error", this, false); this._autocompleteNavbuttons = document.getElementById("autocomplete_navbuttons"); Browser.content.addEventListener("DOMTitleChanged", this, true); Browser.content.addEventListener("DOMLinkAdded", this, true); document.getElementById("tab-list").addEventListener("TabSelect", this, true); Browser.content.addEventListener("mousedown", this, true); Browser.content.addEventListener("mouseup", this, true); Browser.content.addEventListener("mousemove", this, true); window.addEventListener("resize", this, false); Shortcuts.restore(); }, update : function(aState, aBrowser) { if (aState == TOOLBARSTATE_INDETERMINATE) { this._faviconAdded = false; aState = TOOLBARSTATE_LOADED; this.setURI(); } var toolbar = document.getElementById("toolbar-main"); if (aState == TOOLBARSTATE_LOADING) { this.show(UIMODE_URLVIEW); Browser.content.setLoading(aBrowser); toolbar.top = 0; toolbar.setAttribute("mode", "loading"); document.getElementById("urlbar-image-deck").selectedIndex = 0; this._favicon.src = ""; this._throbber.setAttribute("loading", "true"); this._faviconAdded = false; } else if (aState == TOOLBARSTATE_LOADED) { this._setContentPosition("top", toolbar.boxObject.height); toolbar.setAttribute("mode", "view"); document.getElementById("urlbar-image-deck").selectedIndex = 1; this._throbber.removeAttribute("loading"); if (this._faviconAdded == false) { var faviconURI = aBrowser.currentURI.prePath + "/favicon.ico"; this._setIcon(faviconURI); } } }, /* Set the location to the current content */ setURI : function() { var browser = Browser.currentBrowser; // FIXME: deckbrowser should not fire TebSelect on the initial tab (bug 454028) if (!browser.currentURI) return; var back = document.getElementById("cmd_back"); var forward = document.getElementById("cmd_forward"); back.setAttribute("disabled", !browser.canGoBack); forward.setAttribute("disabled", !browser.canGoForward); // Check for a bookmarked page var star = document.getElementById("tool-star"); if (PlacesUtils.getMostRecentBookmarkForURI(browser.currentURI) != -1) { star.setAttribute("starred", "true"); } else { star.removeAttribute("starred"); } var uri = browser.currentURI; if (!this._URIFixup) this._URIFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); try { uri = this._URIFixup.createExposableURI(uri); } catch (ex) {} var urlString = uri.spec; if (urlString == "about:blank") { urlString = ""; this.show(UIMODE_URLEDIT); } this._caption.value = urlString; this._edit.value = urlString; }, goToURI : function(aURI) { this._edit.reallyClosePopup(); if (!aURI) aURI = this._edit.value; var flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; getBrowser().loadURIWithFlags(aURI, flags, null, null); this.show(UIMODE_URLVIEW); }, search : function() { var queryURI = "http://www.google.com/search?q=" + this._edit.value + "&hl=en&lr=&btnG=Search"; getBrowser().loadURI(queryURI, null, null, false); this.show(UIMODE_URLVIEW); }, updateAutoComplete : function(showDefault) { this.updateSearchEngines(); if (showDefault || this._edit.getAttribute("nomatch")) this._edit.showHistoryPopup(); }, doButtonSearch : function(button) { if (!("engine" in button) || !button.engine) return; var urlbar = this._edit; urlbar.open = false; var value = urlbar.value; var submission = button.engine.getSubmission(value, null); getBrowser().loadURI(submission.uri.spec, null, submission.postData, false); }, engines : null, updateSearchEngines : function () { if (this.engines) return; // XXXndeakin remove the try-catch once the search service is properly built try { var searchService = Cc["@mozilla.org/browser/search-service;1"]. getService(Ci.nsIBrowserSearchService); } catch (ex) { this.engines = [ ]; return; } var engines = searchService.getVisibleEngines({ }); this.engines = engines; const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var container = this._autocompleteNavbuttons; for (var e = 0; e < kMaxEngines && e < engines.length; e++) { var button = document.createElementNS(kXULNS, "toolbarbutton"); var engine = engines[e]; button.id = engine.name; button.setAttribute("label", engine.name); button.className = "searchengine"; if (engine.iconURI) button.setAttribute("image", engine.iconURI.spec); container.appendChild(button); button.engine = engine; } }, mode : UIMODE_NONE, show : function(aMode) { if (this.mode == aMode) return; if (this.mode == UIMODE_BOOKMARKLIST && aMode != UIMODE_BOOKMARKLIST) window.removeEventListener("keypress", BrowserUI.closePopup, false); this.mode = aMode; var toolbar = document.getElementById("toolbar-main"); var bookmark = document.getElementById("bookmark-container"); var urllist = document.getElementById("urllist-container"); var container = document.getElementById("browser-container"); if (aMode == UIMODE_URLVIEW) { this._showToolbar(true); this._editToolbar(false); bookmark.hidden = true; urllist.hidden = true; this._showPanel(UIMODE_NONE); } else if (aMode == UIMODE_URLEDIT) { this._showToolbar(true); this._editToolbar(true); bookmark.hidden = true; urllist.hidden = true; this._showPanel(UIMODE_NONE); } else if (aMode == UIMODE_BOOKMARK) { this._showToolbar(true); this._editToolbar(false); urllist.hidden = true; bookmark.hidden = false; bookmark.width = container.boxObject.width; this._showPanel(UIMODE_NONE); } else if (aMode == UIMODE_BOOKMARKLIST) { this._showToolbar(false); this._editToolbar(false); window.addEventListener("keypress", this.closePopup, false); bookmark.hidden = true; urllist.hidden = false; urllist.width = container.boxObject.width; urllist.height = container.boxObject.height; this._showPanel(UIMODE_NONE); } else if (aMode == UIMODE_PANEL) { this._showToolbar(true); this._editToolbar(false); bookmark.hidden = true; this._showPanel(aMode); } else if (aMode == UIMODE_TABS || aMode == UIMODE_CONTROLS) { this._showPanel(aMode); } else if (aMode == UIMODE_NONE) { this._showToolbar(false); this._edit.reallyClosePopup(); urllist.hidden = true; bookmark.hidden = true; this._showPanel(aMode); } }, _showPlaces : function(aItems) { var list = document.getElementById("urllist-items"); while (list.firstChild) { list.removeChild(list.firstChild); } var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var fis = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService); for (var i=0; i 0 || currentTags.length > 0) { var tagsToRemove = []; var tagsToAdd = []; var i; for (i=0; i 0) PlacesUtils.tagging.tagURI(this._uri, tagsToAdd); if (tagsToRemove.length > 0) PlacesUtils.tagging.untagURI(this._uri, tagsToRemove); } } }, close : function() { window.removeEventListener("keypress", this, true); document.getElementById("bookmark-form").removeEventListener("change", this, true); this._item = null; BrowserUI.show(UIMODE_NONE); }, handleEvent: function (aEvent) { switch (aEvent.type) { case "keypress": if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { document.getElementById("bookmark-close").focus(); this.close(); } break; case "change": this.save(); break; } } };