michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: "use strict"; michael@0: michael@0: this.EXPORTED_SYMBOLS = ["View"]; michael@0: michael@0: Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); michael@0: Components.utils.import("resource:///modules/colorUtils.jsm"); michael@0: Components.utils.import("resource://gre/modules/Services.jsm"); michael@0: Components.utils.import("resource://gre/modules/Task.jsm"); michael@0: michael@0: // -------------------------------- michael@0: // module helpers michael@0: // michael@0: michael@0: function makeURI(aURL, aOriginCharset, aBaseURI) { michael@0: return Services.io.newURI(aURL, aOriginCharset, aBaseURI); michael@0: } michael@0: michael@0: // -------------------------------- michael@0: michael@0: michael@0: // -------------------------------- michael@0: // View prototype for shared functionality michael@0: michael@0: function View(aSet) { michael@0: this._set = aSet; michael@0: this._set.controller = this; michael@0: this._window = aSet.ownerDocument.defaultView; michael@0: this._maxTiles = 8; michael@0: this._tilePrefName = "unknown"; michael@0: michael@0: this.onResize = () => this._adjustDOMforViewState(); michael@0: this._window.addEventListener("resize", this.onResize); michael@0: michael@0: ColorUtils.init(); michael@0: this._adjustDOMforViewState(); michael@0: } michael@0: michael@0: View.prototype = { michael@0: set maxTiles(aVal) { michael@0: this._maxTiles = aVal; michael@0: }, michael@0: michael@0: get maxTiles() { michael@0: return this._maxTiles; michael@0: }, michael@0: michael@0: set showing(aFlag) { michael@0: // 'vbox' must be defined on objects that inherit from us michael@0: this.vbox.setAttribute("hidden", aFlag ? "false" : "true"); michael@0: }, michael@0: michael@0: set tilePrefName(aStr) { michael@0: // Should be called once on init by objects that inherit from us michael@0: this._tilePrefName = aStr; michael@0: this._maxTiles = Services.prefs.getIntPref(this._tilePrefName); michael@0: Services.prefs.addObserver(this._tilePrefName, this, false); michael@0: }, michael@0: michael@0: destruct: function () { michael@0: this._window.removeEventListener("resize", this.onResize); michael@0: if (this._tilePrefName != "unknown") { michael@0: Services.prefs.removeObserver(this._tilePrefName, this); michael@0: } michael@0: }, michael@0: michael@0: _adjustDOMforViewState: function _adjustDOMforViewState(aState) { michael@0: let grid = this._set; michael@0: if (!grid) { michael@0: return; michael@0: } michael@0: if (!aState) { michael@0: aState = grid.getAttribute("viewstate"); michael@0: } michael@0: switch (aState) { michael@0: case "snapped": michael@0: grid.setAttribute("nocontext", true); michael@0: grid.selectNone(); michael@0: grid.disableCrossSlide(); michael@0: break; michael@0: case "portrait": michael@0: grid.removeAttribute("nocontext"); michael@0: grid.setAttribute("vertical", true); michael@0: grid.enableCrossSlide(); michael@0: break; michael@0: default: michael@0: grid.removeAttribute("nocontext"); michael@0: grid.removeAttribute("vertical"); michael@0: grid.enableCrossSlide(); michael@0: } michael@0: if ("arrangeItems" in grid) { michael@0: grid.arrangeItems(); michael@0: } michael@0: }, michael@0: michael@0: _updateFavicon: function pv__updateFavicon(aItem, aUri) { michael@0: if ("string" == typeof aUri) { michael@0: aUri = makeURI(aUri); michael@0: } michael@0: PlacesUtils.favicons.getFaviconURLForPage(aUri, this._gotIcon.bind(this, aItem)); michael@0: }, michael@0: michael@0: _gotIcon: function pv__gotIcon(aItem, aIconUri) { michael@0: if (!aIconUri) { michael@0: aItem.removeAttribute("iconURI"); michael@0: if (aItem.refresh) { michael@0: aItem.refresh(); michael@0: } michael@0: return; michael@0: } michael@0: if ("string" == typeof aIconUri) { michael@0: aIconUri = makeURI(aIconUri); michael@0: } michael@0: let faviconURL = (PlacesUtils.favicons.getFaviconLinkForIcon(aIconUri)).spec; michael@0: aItem.iconSrc = faviconURL; michael@0: michael@0: let xpFaviconURI = makeURI(faviconURL.replace("moz-anno:favicon:","")); michael@0: Task.spawn(function() { michael@0: let colorInfo = yield ColorUtils.getForegroundAndBackgroundIconColors(xpFaviconURI); michael@0: if (!(colorInfo && colorInfo.background && colorInfo.foreground)) { michael@0: return; michael@0: } michael@0: let { background, foreground } = colorInfo; michael@0: aItem.style.color = foreground; //color text michael@0: aItem.setAttribute("customColor", background); michael@0: let matteColor = 0xffffff; // white michael@0: let alpha = 0.04; // the tint weight michael@0: let [,r,g,b] = background.match(/rgb\((\d+),(\d+),(\d+)/); michael@0: // get the rgb value that represents this color at given opacity over a white matte michael@0: let tintColor = ColorUtils.addRgbColors(matteColor, ColorUtils.createDecimalColorWord(r,g,b,alpha)); michael@0: aItem.setAttribute("tintColor", ColorUtils.convertDecimalToRgbColor(tintColor)); michael@0: // when bound, use the setter to propogate the color change through the tile michael@0: if ('color' in aItem) { michael@0: aItem.color = background; michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: refreshView: function () { michael@0: }, michael@0: michael@0: observe: function (aSubject, aTopic, aState) { michael@0: switch (aTopic) { michael@0: case "nsPref:changed": { michael@0: if (aState == this._tilePrefName) { michael@0: let count = Services.prefs.getIntPref(this._tilePrefName); michael@0: this.maxTiles = count; michael@0: this.showing = this.maxTiles > 0; michael@0: this.refreshView(); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: };