mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
233 lines
7.1 KiB
JavaScript
233 lines
7.1 KiB
JavaScript
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
|
|
|
function FontInspector(inspector, window)
|
|
{
|
|
this.inspector = inspector;
|
|
this.chromeDoc = window.document;
|
|
this.init();
|
|
}
|
|
|
|
FontInspector.prototype = {
|
|
init: function FI_init() {
|
|
this.update = this.update.bind(this);
|
|
this.onNewNode = this.onNewNode.bind(this);
|
|
this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
|
|
this.inspector.selection.on("new-node", this.onNewNode);
|
|
this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
|
|
if (this.inspector.highlighter) {
|
|
this.inspector.highlighter.on("locked", this.onHighlighterLocked);
|
|
}
|
|
this.update();
|
|
},
|
|
|
|
/**
|
|
* Is the fontinspector visible in the sidebar?
|
|
*/
|
|
isActive: function FI_isActive() {
|
|
return this.inspector.sidebar &&
|
|
this.inspector.sidebar.getCurrentTabID() == "fontinspector";
|
|
},
|
|
|
|
/**
|
|
* Remove listeners.
|
|
*/
|
|
destroy: function FI_destroy() {
|
|
this.chromeDoc = null;
|
|
this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
|
|
this.inspector.selection.off("new-node", this.onNewNode);
|
|
if (this.inspector.highlighter) {
|
|
this.inspector.highlighter.off("locked", this.onHighlighterLocked);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Selection 'new-node' event handler.
|
|
*/
|
|
onNewNode: function FI_onNewNode() {
|
|
if (this.isActive() &&
|
|
this.inspector.selection.isLocal() &&
|
|
this.inspector.selection.isConnected() &&
|
|
this.inspector.selection.isElementNode() &&
|
|
this.inspector.selection.reason != "highlighter") {
|
|
this.undim();
|
|
this.update();
|
|
} else {
|
|
this.dim();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Highlighter 'locked' event handler
|
|
*/
|
|
onHighlighterLocked: function FI_onHighlighterLocked() {
|
|
this.undim();
|
|
this.update();
|
|
},
|
|
|
|
/**
|
|
* Hide the font list. No node are selected.
|
|
*/
|
|
dim: function FI_dim() {
|
|
this.chromeDoc.body.classList.add("dim");
|
|
this.chromeDoc.querySelector("#all-fonts").innerHTML = "";
|
|
},
|
|
|
|
/**
|
|
* Show the font list. A node is selected.
|
|
*/
|
|
undim: function FI_undim() {
|
|
this.chromeDoc.body.classList.remove("dim");
|
|
},
|
|
|
|
/**
|
|
* Retrieve all the font related info we have for the selected
|
|
* node and display them.
|
|
*/
|
|
update: function FI_update() {
|
|
if (!this.isActive() ||
|
|
!this.inspector.selection.isConnected() ||
|
|
!this.inspector.selection.isElementNode() ||
|
|
this.chromeDoc.body.classList.contains("dim")) {
|
|
return;
|
|
}
|
|
|
|
let node = this.inspector.selection.node;
|
|
let contentDocument = node.ownerDocument;
|
|
|
|
// We don't get fonts for a node, but for a range
|
|
let rng = contentDocument.createRange();
|
|
rng.selectNode(node);
|
|
let fonts = DOMUtils.getUsedFontFaces(rng);
|
|
let fontsArray = [];
|
|
for (let i = 0; i < fonts.length; i++) {
|
|
fontsArray.push(fonts.item(i));
|
|
}
|
|
fontsArray = fontsArray.sort(function(a, b) {
|
|
return a.srcIndex < b.srcIndex;
|
|
});
|
|
this.chromeDoc.querySelector("#all-fonts").innerHTML = "";
|
|
for (let f of fontsArray) {
|
|
this.render(f, contentDocument);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Display the information of one font.
|
|
*/
|
|
render: function FI_render(font, document) {
|
|
let s = this.chromeDoc.querySelector("#template > section");
|
|
s = s.cloneNode(true);
|
|
|
|
s.querySelector(".font-name").textContent = font.name;
|
|
s.querySelector(".font-css-name").textContent = font.CSSFamilyName;
|
|
s.querySelector(".font-format").textContent = font.format;
|
|
|
|
if (font.srcIndex == -1) {
|
|
s.classList.add("is-local");
|
|
} else {
|
|
s.classList.add("is-remote");
|
|
}
|
|
|
|
s.querySelector(".font-url").value = font.URI;
|
|
|
|
let iframe = s.querySelector(".font-preview");
|
|
if (font.rule) {
|
|
// This is the @font-face{…} code.
|
|
let cssText = font.rule.style.parentRule.cssText;
|
|
|
|
s.classList.add("has-code");
|
|
s.querySelector(".font-css-code").textContent = cssText;
|
|
|
|
// We guess the base URL of the stylesheet to make
|
|
// sure the font will be accessible in the preview.
|
|
// If the font-face is in an inline <style>, we get
|
|
// the location of the page.
|
|
let origin = font.rule.style.parentRule.parentStyleSheet.href;
|
|
if (!origin) { // Inline stylesheet
|
|
origin = document.location.href;
|
|
}
|
|
// We remove the last part of the URL to get a correct base.
|
|
let base = origin.replace(/\/[^\/]*$/,"/")
|
|
|
|
// From all this information, we build a preview.
|
|
this.buildPreview(iframe, font.CSSFamilyName, cssText, base);
|
|
} else {
|
|
this.buildPreview(iframe, font.CSSFamilyName, "", "");
|
|
}
|
|
|
|
this.chromeDoc.querySelector("#all-fonts").appendChild(s);
|
|
},
|
|
|
|
/**
|
|
* Show a preview of the font in an iframe.
|
|
*/
|
|
buildPreview: function FI_buildPreview(iframe, name, cssCode, base) {
|
|
/* The HTML code of the preview is:
|
|
* <!DOCTYPE HTML>
|
|
* <head>
|
|
* <base href="{base}"></base>
|
|
* </head>
|
|
* <style>
|
|
* p {font-family: {name};}
|
|
* * {font-size: 40px;line-height:60px;padding:0 10px;margin:0};
|
|
* </style>
|
|
* <p contenteditable spellcheck='false'>Abc</p>
|
|
*/
|
|
let extraCSS = "* {padding:0;margin:0}";
|
|
extraCSS += ".theme-dark {color: white}";
|
|
extraCSS += "p {font-size: 40px;line-height:60px;padding:0 10px;margin:0;}";
|
|
cssCode += extraCSS;
|
|
let src = "data:text/html;charset=utf-8,<!DOCTYPE HTML><head><base></base></head><style></style><p contenteditable spellcheck='false'>Abc</p>";
|
|
iframe.addEventListener("load", function onload() {
|
|
iframe.removeEventListener("load", onload, true);
|
|
let doc = iframe.contentWindow.document;
|
|
// We could have done that earlier, but we want to avoid any URL-encoding
|
|
// nightmare.
|
|
doc.querySelector("base").href = base;
|
|
doc.querySelector("style").textContent = cssCode;
|
|
doc.querySelector("p").style.fontFamily = name;
|
|
// Forward theme
|
|
doc.documentElement.className = document.documentElement.className;
|
|
}, true);
|
|
iframe.src = src;
|
|
},
|
|
|
|
/**
|
|
* Select the <body> to show all the fonts included in the document.
|
|
*/
|
|
showAll: function FI_showAll() {
|
|
if (!this.isActive() ||
|
|
!this.inspector.selection.isConnected() ||
|
|
!this.inspector.selection.isElementNode()) {
|
|
return;
|
|
}
|
|
let node = this.inspector.selection.node;
|
|
let contentDocument = node.ownerDocument;
|
|
let root = contentDocument.documentElement;
|
|
if (contentDocument.body) {
|
|
root = contentDocument.body;
|
|
}
|
|
this.inspector.selection.setNode(root, "fontinspector");
|
|
},
|
|
}
|
|
|
|
|
|
window.setPanel = function(panel) {
|
|
window.fontInspector = new FontInspector(panel, window);
|
|
}
|
|
|
|
window.onunload = function() {
|
|
if (window.fontInspector) {
|
|
window.fontInspector.destroy();
|
|
}
|
|
}
|