167 lines
4.9 KiB
JavaScript
167 lines
4.9 KiB
JavaScript
((exports) => {
|
|
|
|
const eachFont = async (callback, afterAllCallback) => {
|
|
function localFontAccessUnavailable() {
|
|
FontDetective.each(callback);
|
|
FontDetective.all(afterAllCallback);
|
|
}
|
|
if (window.queryLocalFonts) {
|
|
let availableFonts;
|
|
try {
|
|
availableFonts = await window.queryLocalFonts();
|
|
} catch (error) {
|
|
console.log("queryLocalFonts failed:", error, "\nFalling back to FontDetective.");
|
|
localFontAccessUnavailable();
|
|
return;
|
|
}
|
|
if (availableFonts.length === 0) {
|
|
console.log("queryLocalFonts returned no fonts; falling back to FontDetective.");
|
|
localFontAccessUnavailable();
|
|
return;
|
|
}
|
|
const familyNames = new Set();
|
|
for (const font of availableFonts) {
|
|
if (familyNames.has(font.family)) {
|
|
continue;
|
|
}
|
|
familyNames.add(font.family);
|
|
callback({
|
|
name: font.family,
|
|
toString() {
|
|
return '"' + this.name.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + '"';
|
|
},
|
|
});
|
|
// This class is not exported by FontDetective.
|
|
// That said, this queryLocalFonts functionality should be moved into FontDetective.
|
|
// callback(new FontDetective.Font(font.family));
|
|
}
|
|
afterAllCallback();
|
|
} else {
|
|
console.log("queryLocalFonts unavailable; falling back to FontDetective.");
|
|
localFontAccessUnavailable();
|
|
}
|
|
};
|
|
|
|
function $FontBox() {
|
|
const $fb = $(E("div")).addClass("font-box");
|
|
|
|
const $family = $(E("select")).addClass("inset-deep").attr({
|
|
"aria-label": "Font Family",
|
|
"aria-description": localize("Selects the font used by the text."),
|
|
});
|
|
const $size = $(E("input")).addClass("inset-deep").attr({
|
|
type: "number",
|
|
min: 8,
|
|
max: 72,
|
|
value: text_tool_font.size,
|
|
"aria-label": "Font Size",
|
|
"aria-description": localize("Selects the point size of the text."),
|
|
}).css({
|
|
maxWidth: 50,
|
|
});
|
|
const $button_group = $(E("span")).addClass("text-toolbar-button-group");
|
|
// @TODO: localized labels
|
|
const $bold = $Toggle(0, "bold", "Bold", localize("Sets or clears the text bold attribute."));
|
|
const $italic = $Toggle(1, "italic", "Italic", localize("Sets or clears the text italic attribute."));
|
|
const $underline = $Toggle(2, "underline", "Underline", localize("Sets or clears the text underline attribute."));
|
|
const $vertical = $Toggle(3, "vertical", "Vertical Writing Mode", localize("Only a Far East font can be used for vertical editing."));
|
|
$vertical.attr("disabled", true);
|
|
|
|
$button_group.append($bold, $italic, $underline, $vertical);
|
|
$fb.append($family, $size, $button_group);
|
|
|
|
const update_font = () => {
|
|
text_tool_font.size = Number($size.val());
|
|
text_tool_font.family = $family.val();
|
|
$G.trigger("option-changed");
|
|
};
|
|
|
|
const originalFamily = text_tool_font.family;
|
|
eachFont(font => {
|
|
const $option = $(E("option"));
|
|
$option.val(font).text(font.name);
|
|
// Insert in alphabetical order
|
|
const $options = $family.children("option");
|
|
let i = 0;
|
|
for (; i < $options.length; i++) {
|
|
if ($options.eq(i).text().localeCompare(font.name) > 0) {
|
|
break;
|
|
}
|
|
}
|
|
if ($options.eq(i).length) {
|
|
$options.eq(i).before($option);
|
|
} else {
|
|
$family.append($option);
|
|
}
|
|
// Select the first known-available font, just in case FontDetective.each is slow.
|
|
if (!text_tool_font.family) {
|
|
update_font();
|
|
}
|
|
}, () => {
|
|
// All fonts have been added to the list. Now we can select the default font.
|
|
$family.val(originalFamily);
|
|
// Liberation Sans is designed to be metrically compatible with Arial,
|
|
// and is available in free operating systems like Ubuntu.
|
|
if (!$family.val()) {
|
|
$family.val('"Liberation Sans"');
|
|
}
|
|
// Fallback to the first font in the list. At least it's something.
|
|
if (!$family.val()) {
|
|
$family.val($family.children("option").eq(0).val());
|
|
}
|
|
update_font();
|
|
});
|
|
|
|
if (text_tool_font.family) {
|
|
$family.val(text_tool_font.family);
|
|
}
|
|
|
|
$family.on("change", update_font);
|
|
$size.on("change", update_font);
|
|
|
|
const $w = $ToolWindow();
|
|
$w.title(localize("Fonts"));
|
|
$w.$content.append($fb);
|
|
$w.center();
|
|
return $w;
|
|
|
|
|
|
function $Toggle(xi, thing, label, description) {
|
|
const $button = $(E("button")).addClass("toggle").attr({
|
|
"aria-pressed": false,
|
|
"aria-label": label,
|
|
"aria-description": description,
|
|
});
|
|
const $icon = $(E("span")).addClass("icon").appendTo($button);
|
|
$button.css({
|
|
width: 23,
|
|
height: 22,
|
|
padding: 0,
|
|
display: "inline-flex",
|
|
alignContent: "center",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
});
|
|
$icon.css({
|
|
flex: "0 0 auto",
|
|
display: "block",
|
|
width: 16,
|
|
height: 16,
|
|
"--icon-index": xi,
|
|
});
|
|
$button.on("click", () => {
|
|
$button.toggleClass("selected");
|
|
text_tool_font[thing] = $button.hasClass("selected");
|
|
$button.attr("aria-pressed", $button.hasClass("selected"));
|
|
update_font();
|
|
});
|
|
if (text_tool_font[thing]) {
|
|
$button.addClass("selected").attr("aria-pressed", true);
|
|
}
|
|
return $button;
|
|
}
|
|
}
|
|
|
|
exports.$FontBox = $FontBox;
|
|
|
|
})(window); |