michael@0: /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ 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: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu} = Components; michael@0: const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); michael@0: michael@0: function FontInspector(inspector, window) michael@0: { michael@0: this.inspector = inspector; michael@0: this.chromeDoc = window.document; michael@0: this.init(); michael@0: } michael@0: michael@0: FontInspector.prototype = { michael@0: init: function FI_init() { michael@0: this.update = this.update.bind(this); michael@0: this.onNewNode = this.onNewNode.bind(this); michael@0: this.inspector.selection.on("new-node", this.onNewNode); michael@0: this.inspector.sidebar.on("fontinspector-selected", this.onNewNode); michael@0: this.showAll = this.showAll.bind(this); michael@0: this.showAllButton = this.chromeDoc.getElementById("showall"); michael@0: this.showAllButton.addEventListener("click", this.showAll); michael@0: this.update(); michael@0: }, michael@0: michael@0: /** michael@0: * Is the fontinspector visible in the sidebar? michael@0: */ michael@0: isActive: function FI_isActive() { michael@0: return this.inspector.sidebar && michael@0: this.inspector.sidebar.getCurrentTabID() == "fontinspector"; michael@0: }, michael@0: michael@0: /** michael@0: * Remove listeners. michael@0: */ michael@0: destroy: function FI_destroy() { michael@0: this.chromeDoc = null; michael@0: this.inspector.sidebar.off("layoutview-selected", this.onNewNode); michael@0: this.inspector.selection.off("new-node", this.onNewNode); michael@0: this.showAllButton.removeEventListener("click", this.showAll); michael@0: }, michael@0: michael@0: /** michael@0: * Selection 'new-node' event handler. michael@0: */ michael@0: onNewNode: function FI_onNewNode() { michael@0: if (this.isActive() && michael@0: this.inspector.selection.isLocal() && michael@0: this.inspector.selection.isConnected() && michael@0: this.inspector.selection.isElementNode()) { michael@0: this.undim(); michael@0: this.update(); michael@0: } else { michael@0: this.dim(); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Hide the font list. No node are selected. michael@0: */ michael@0: dim: function FI_dim() { michael@0: this.chromeDoc.body.classList.add("dim"); michael@0: this.chromeDoc.querySelector("#all-fonts").innerHTML = ""; michael@0: }, michael@0: michael@0: /** michael@0: * Show the font list. A node is selected. michael@0: */ michael@0: undim: function FI_undim() { michael@0: this.chromeDoc.body.classList.remove("dim"); michael@0: }, michael@0: michael@0: /** michael@0: * Retrieve all the font related info we have for the selected michael@0: * node and display them. michael@0: */ michael@0: update: function FI_update() { michael@0: if (!this.isActive() || michael@0: !this.inspector.selection.isConnected() || michael@0: !this.inspector.selection.isElementNode() || michael@0: this.chromeDoc.body.classList.contains("dim")) { michael@0: return; michael@0: } michael@0: michael@0: let node = this.inspector.selection.node; michael@0: let contentDocument = node.ownerDocument; michael@0: michael@0: // We don't get fonts for a node, but for a range michael@0: let rng = contentDocument.createRange(); michael@0: rng.selectNode(node); michael@0: let fonts = DOMUtils.getUsedFontFaces(rng); michael@0: let fontsArray = []; michael@0: for (let i = 0; i < fonts.length; i++) { michael@0: fontsArray.push(fonts.item(i)); michael@0: } michael@0: fontsArray = fontsArray.sort(function(a, b) { michael@0: return a.srcIndex < b.srcIndex; michael@0: }); michael@0: this.chromeDoc.querySelector("#all-fonts").innerHTML = ""; michael@0: for (let f of fontsArray) { michael@0: this.render(f, contentDocument); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Display the information of one font. michael@0: */ michael@0: render: function FI_render(font, document) { michael@0: let s = this.chromeDoc.querySelector("#template > section"); michael@0: s = s.cloneNode(true); michael@0: michael@0: s.querySelector(".font-name").textContent = font.name; michael@0: s.querySelector(".font-css-name").textContent = font.CSSFamilyName; michael@0: s.querySelector(".font-format").textContent = font.format; michael@0: michael@0: if (font.srcIndex == -1) { michael@0: s.classList.add("is-local"); michael@0: } else { michael@0: s.classList.add("is-remote"); michael@0: } michael@0: michael@0: s.querySelector(".font-url").value = font.URI; michael@0: michael@0: let iframe = s.querySelector(".font-preview"); michael@0: if (font.rule) { michael@0: // This is the @font-face{…} code. michael@0: let cssText = font.rule.style.parentRule.cssText; michael@0: michael@0: s.classList.add("has-code"); michael@0: s.querySelector(".font-css-code").textContent = cssText; michael@0: michael@0: // We guess the base URL of the stylesheet to make michael@0: // sure the font will be accessible in the preview. michael@0: // If the font-face is in an inline michael@0: *
Abc
michael@0: */ michael@0: let extraCSS = "* {padding:0;margin:0}"; michael@0: extraCSS += ".theme-dark {color: white}"; michael@0: extraCSS += "p {font-size: 40px;line-height:60px;padding:0 10px;margin:0;}"; michael@0: cssCode += extraCSS; michael@0: let src = "data:text/html;charset=utf-8,Abc
"; michael@0: iframe.addEventListener("load", function onload() { michael@0: iframe.removeEventListener("load", onload, true); michael@0: let doc = iframe.contentWindow.document; michael@0: // We could have done that earlier, but we want to avoid any URL-encoding michael@0: // nightmare. michael@0: doc.querySelector("base").href = base; michael@0: doc.querySelector("style").textContent = cssCode; michael@0: doc.querySelector("p").style.fontFamily = name; michael@0: // Forward theme michael@0: doc.documentElement.className = document.documentElement.className; michael@0: }, true); michael@0: iframe.src = src; michael@0: }, michael@0: michael@0: /** michael@0: * Select the to show all the fonts included in the document. michael@0: */ michael@0: showAll: function FI_showAll() { michael@0: if (!this.isActive() || michael@0: !this.inspector.selection.isConnected() || michael@0: !this.inspector.selection.isElementNode()) { michael@0: return; michael@0: } michael@0: michael@0: // Select the body node to show all fonts michael@0: let walker = this.inspector.walker; michael@0: michael@0: walker.getRootNode().then(root => walker.querySelector(root, "body")).then(body => { michael@0: this.inspector.selection.setNodeFront(body, "fontinspector"); michael@0: }); michael@0: }, michael@0: } michael@0: michael@0: window.setPanel = function(panel) { michael@0: window.fontInspector = new FontInspector(panel, window); michael@0: } michael@0: michael@0: window.onunload = function() { michael@0: if (window.fontInspector) { michael@0: window.fontInspector.destroy(); michael@0: } michael@0: }