mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-19 07:15:36 -04:00
428 lines
13 KiB
JavaScript
428 lines
13 KiB
JavaScript
/* 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/. */
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
|
Services: "resource://gre/modules/Services.jsm",
|
|
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
|
});
|
|
|
|
/**
|
|
* Executes a XUL command on the top window. Called by the callbacks in each
|
|
* TouchBarInput.
|
|
* @param {string} commandName
|
|
* A XUL command.
|
|
* @param {string} telemetryKey
|
|
* A string describing the command, sent for telemetry purposes.
|
|
* Intended to be shorter and more readable than the XUL command.
|
|
*/
|
|
function execCommand(commandName, telemetryKey) {
|
|
let win = BrowserWindowTracker.getTopWindow();
|
|
let command = win.document.getElementById(commandName);
|
|
if (command) {
|
|
command.doCommand();
|
|
}
|
|
let telemetry = Services.telemetry.getHistogramById(
|
|
"TOUCHBAR_BUTTON_PRESSES"
|
|
);
|
|
telemetry.add(telemetryKey);
|
|
}
|
|
|
|
/**
|
|
* Static helper function to convert a hexadecimal string to its integer
|
|
* value. Used to convert colours to a format accepted by Apple's NSColor code.
|
|
* @param {string} hexString
|
|
* A hexadecimal string, optionally beginning with '#'.
|
|
*/
|
|
function hexToInt(hexString) {
|
|
if (!hexString) {
|
|
return null;
|
|
}
|
|
if (hexString.charAt(0) == "#") {
|
|
hexString = hexString.slice(1);
|
|
}
|
|
let val = parseInt(hexString, 16);
|
|
return isNaN(val) ? null : val;
|
|
}
|
|
|
|
/**
|
|
* An object containing all implemented TouchBarInput objects.
|
|
*/
|
|
const kBuiltInInputs = {
|
|
Back: {
|
|
title: "back",
|
|
image: "back.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("Browser:Back", "Back"),
|
|
},
|
|
Forward: {
|
|
title: "forward",
|
|
image: "forward.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("Browser:Forward", "Forward"),
|
|
},
|
|
Reload: {
|
|
title: "reload",
|
|
image: "refresh.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("Browser:Reload", "Reload"),
|
|
},
|
|
Home: {
|
|
title: "home",
|
|
image: "home.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("Browser:Home", "Home"),
|
|
},
|
|
Fullscreen: {
|
|
title: "fullscreen",
|
|
image: "fullscreen.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("View:FullScreen", "Fullscreen"),
|
|
},
|
|
Find: {
|
|
title: "find",
|
|
image: "search.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("cmd_find", "Find"),
|
|
},
|
|
NewTab: {
|
|
title: "new-tab",
|
|
image: "new.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("cmd_newNavigatorTabNoEvent", "NewTab"),
|
|
},
|
|
Sidebar: {
|
|
title: "open-bookmarks-sidebar",
|
|
image: "sidebar-left.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("viewBookmarksSidebar", "Sidebar"),
|
|
},
|
|
AddBookmark: {
|
|
title: "add-bookmark",
|
|
image: "bookmark.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("Browser:AddBookmarkAs", "AddBookmark"),
|
|
},
|
|
ReaderView: {
|
|
title: "reader-view",
|
|
image: "reader-mode.pdf",
|
|
type: "button",
|
|
callback: () => execCommand("View:ReaderView", "ReaderView"),
|
|
disabled: true, // Updated when the page is found to be Reader View-able.
|
|
},
|
|
OpenLocation: {
|
|
title: "open-location",
|
|
image: "search.pdf",
|
|
type: "mainButton",
|
|
callback: () => execCommand("Browser:OpenLocation", "OpenLocation"),
|
|
},
|
|
// This is a special-case `type: "scrubber"` element.
|
|
// Scrubbers are not yet generally implemented.
|
|
// See follow-up bug 1502539.
|
|
Share: {
|
|
title: "share",
|
|
type: "scrubber",
|
|
image: "share.pdf",
|
|
callback: () => execCommand("cmd_share", "Share"),
|
|
},
|
|
};
|
|
|
|
const kHelperObservers = new Set([
|
|
"bookmark-icon-updated",
|
|
"reader-mode-available",
|
|
"touchbar-location-change",
|
|
"quit-application",
|
|
"intl:app-locales-changed",
|
|
]);
|
|
|
|
/**
|
|
* JS-implemented TouchBarHelper class.
|
|
* Provides services to the Mac Touch Bar.
|
|
*/
|
|
class TouchBarHelper {
|
|
constructor() {
|
|
for (let topic of kHelperObservers) {
|
|
Services.obs.addObserver(this, topic);
|
|
}
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"_touchBarLayout",
|
|
"ui.touchbar.layout",
|
|
"Back,Forward,Reload,OpenLocation,NewTab,Share"
|
|
);
|
|
}
|
|
|
|
destructor() {
|
|
for (let topic of kHelperObservers) {
|
|
Services.obs.removeObserver(this, topic);
|
|
}
|
|
}
|
|
|
|
get activeTitle() {
|
|
let tabbrowser = this.window.ownerGlobal.gBrowser;
|
|
let activeTitle;
|
|
if (tabbrowser) {
|
|
activeTitle = tabbrowser.selectedBrowser.contentTitle;
|
|
}
|
|
return activeTitle;
|
|
}
|
|
|
|
get layout() {
|
|
let prefArray = this.storedLayout;
|
|
let layoutItems = Cc["@mozilla.org/array;1"].createInstance(
|
|
Ci.nsIMutableArray
|
|
);
|
|
|
|
for (let inputName of prefArray) {
|
|
if (typeof kBuiltInInputs[inputName].context == "function") {
|
|
inputName = kBuiltInInputs[inputName].context();
|
|
}
|
|
let input = this.getTouchBarInput(inputName);
|
|
if (!input) {
|
|
continue;
|
|
}
|
|
layoutItems.appendElement(input);
|
|
}
|
|
|
|
return layoutItems;
|
|
}
|
|
|
|
get window() {
|
|
return BrowserWindowTracker.getTopWindow();
|
|
}
|
|
|
|
get bookmarkingUI() {
|
|
return this.window.BookmarkingUI;
|
|
}
|
|
|
|
/**
|
|
* Returns a string array of the user's Touch Bar layout preference.
|
|
* Set by a pref ui.touchbar.layout and returned in an array.
|
|
*/
|
|
get storedLayout() {
|
|
let prefArray = this._touchBarLayout.split(",");
|
|
prefArray = prefArray.map(str => str.trim());
|
|
// Remove duplicates.
|
|
prefArray = Array.from(new Set(prefArray));
|
|
|
|
// Remove unimplemented/mispelled inputs.
|
|
prefArray = prefArray.filter(input =>
|
|
Object.keys(kBuiltInInputs).includes(input)
|
|
);
|
|
this._storedLayout = prefArray;
|
|
return this._storedLayout;
|
|
}
|
|
|
|
getTouchBarInput(inputName) {
|
|
// inputName might be undefined if an input's context() returns undefined.
|
|
if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
|
|
return null;
|
|
}
|
|
|
|
// context() may specify that one named input "point" to another.
|
|
if (typeof kBuiltInInputs[inputName].context == "function") {
|
|
inputName = kBuiltInInputs[inputName].context();
|
|
}
|
|
|
|
if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
|
|
return null;
|
|
}
|
|
|
|
let inputData = kBuiltInInputs[inputName];
|
|
|
|
let item = new TouchBarInput(inputData);
|
|
|
|
// Skip localization if there is already a cached localized title.
|
|
if (kBuiltInInputs[inputName].hasOwnProperty("localTitle")) {
|
|
return item;
|
|
}
|
|
|
|
// Async l10n fills in the localized input labels after the initial load.
|
|
this._l10n.formatValue(item.key).then(result => {
|
|
item.title = result;
|
|
kBuiltInInputs[inputName].localTitle = result; // Cache result.
|
|
// Checking this.window since this callback can fire after all windows are closed.
|
|
if (this.window) {
|
|
let baseWindow = this.window.docShell.treeOwner.QueryInterface(
|
|
Ci.nsIBaseWindow
|
|
);
|
|
let updater = Cc["@mozilla.org/widget/touchbarupdater;1"].getService(
|
|
Ci.nsITouchBarUpdater
|
|
);
|
|
updater.updateTouchBarInputs(baseWindow, [item]);
|
|
}
|
|
});
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* Fetches a specific Touch Bar Input by name and updates it on the Touch Bar.
|
|
* @param {string} inputName
|
|
* A key to a value in the kBuiltInInputs object in this file.
|
|
* @param {...*} [otherInputs] (optional)
|
|
* Additional keys to values in the kBuiltInInputs object in this file.
|
|
*/
|
|
_updateTouchBarInputs(...inputNames) {
|
|
if (!this.window) {
|
|
return;
|
|
}
|
|
|
|
let inputs = [];
|
|
for (let inputName of inputNames) {
|
|
// Updating Touch Bar items isn't cheap in terms of performance, so
|
|
// only consider this input if it's actually part of the layout.
|
|
if (!this._storedLayout.includes(inputName)) {
|
|
continue;
|
|
}
|
|
|
|
let input = this.getTouchBarInput(inputName);
|
|
if (!input) {
|
|
continue;
|
|
}
|
|
inputs.push(input);
|
|
}
|
|
|
|
let baseWindow = this.window.docShell.treeOwner.QueryInterface(
|
|
Ci.nsIBaseWindow
|
|
);
|
|
let updater = Cc["@mozilla.org/widget/touchbarupdater;1"].getService(
|
|
Ci.nsITouchBarUpdater
|
|
);
|
|
updater.updateTouchBarInputs(baseWindow, inputs);
|
|
}
|
|
|
|
observe(subject, topic, data) {
|
|
switch (topic) {
|
|
case "touchbar-location-change":
|
|
this.activeUrl = data;
|
|
// ReaderView button is disabled on every location change since
|
|
// Reader View must determine if the new page can be Reader Viewed.
|
|
kBuiltInInputs.ReaderView.disabled = !data.startsWith("about:reader");
|
|
kBuiltInInputs.Back.disabled = !this.window.gBrowser.canGoBack;
|
|
kBuiltInInputs.Forward.disabled = !this.window.gBrowser.canGoForward;
|
|
this._updateTouchBarInputs("ReaderView", "Back", "Forward");
|
|
break;
|
|
case "bookmark-icon-updated":
|
|
data == "starred"
|
|
? (kBuiltInInputs.AddBookmark.image = "bookmark-filled.pdf")
|
|
: (kBuiltInInputs.AddBookmark.image = "bookmark.pdf");
|
|
this._updateTouchBarInputs("AddBookmark");
|
|
break;
|
|
case "reader-mode-available":
|
|
kBuiltInInputs.ReaderView.disabled = false;
|
|
this._updateTouchBarInputs("ReaderView");
|
|
break;
|
|
case "intl:app-locales-changed":
|
|
// On locale change, refresh all inputs after loading new localTitle.
|
|
for (let inputName of this._storedLayout) {
|
|
delete kBuiltInInputs[inputName].localTitle;
|
|
}
|
|
this._updateTouchBarInputs(...this._storedLayout);
|
|
break;
|
|
case "quit-application":
|
|
this.destructor();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
const helperProto = TouchBarHelper.prototype;
|
|
helperProto.classDescription = "Services the Mac Touch Bar";
|
|
helperProto.classID = Components.ID("{ea109912-3acc-48de-b679-c23b6a122da5}");
|
|
helperProto.contractID = "@mozilla.org/widget/touchbarhelper;1";
|
|
helperProto.QueryInterface = ChromeUtils.generateQI([Ci.nsITouchBarHelper]);
|
|
helperProto._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
|
|
|
|
/**
|
|
* A representation of a Touch Bar input.
|
|
* Uses async update() in lieu of a constructor to accomodate async l10n code.
|
|
* @param {object} input
|
|
* An object representing a Touch Bar Input.
|
|
* Contains listed properties.
|
|
* @param {string} input.title
|
|
* The lookup key for the button's localized text title.
|
|
* @param {string} input.image
|
|
* The name of a icon file added to
|
|
* /widget/cocoa/resources/touchbar_icons.
|
|
* @param {string} input.type
|
|
* The type of Touch Bar input represented by the object.
|
|
* One of `button`, `mainButton`.
|
|
* @param {Function} input.callback
|
|
* A callback invoked when a touchbar item is touched.
|
|
* @param {string} input.color (optional)
|
|
* A string in hex format specifying the button's background color.
|
|
* If omitted, the default background color is used.
|
|
* @param {bool} input.disabled (optional)
|
|
* If `true`, the Touch Bar input is greyed out and inoperable.
|
|
*/
|
|
class TouchBarInput {
|
|
constructor(input) {
|
|
this._key = input.title;
|
|
this._title = input.hasOwnProperty("localTitle") ? input.localTitle : "";
|
|
this._image = input.image;
|
|
this._type = input.type;
|
|
this._callback = input.callback;
|
|
this._color = hexToInt(input.color);
|
|
this._disabled = input.hasOwnProperty("disabled") ? input.disabled : false;
|
|
}
|
|
|
|
get key() {
|
|
return this._key;
|
|
}
|
|
get title() {
|
|
return this._title;
|
|
}
|
|
set title(title) {
|
|
this._title = title;
|
|
}
|
|
get image() {
|
|
return this._image;
|
|
}
|
|
set image(image) {
|
|
this._image = image;
|
|
}
|
|
get type() {
|
|
return this._type == "" ? "button" : this._type;
|
|
}
|
|
set type(type) {
|
|
this._type = type;
|
|
}
|
|
get callback() {
|
|
return this._callback;
|
|
}
|
|
set callback(callback) {
|
|
this._callback = callback;
|
|
}
|
|
get color() {
|
|
return this._color;
|
|
}
|
|
set color(color) {
|
|
this._color = this.hexToInt(color);
|
|
}
|
|
get disabled() {
|
|
return this._disabled || false;
|
|
}
|
|
set disabled(disabled) {
|
|
this._disabled = disabled;
|
|
}
|
|
}
|
|
|
|
const inputProto = TouchBarInput.prototype;
|
|
inputProto.classDescription = "Represents an input on the Mac Touch Bar";
|
|
inputProto.classID = Components.ID("{77441d17-f29c-49d7-982f-f20a5ab5a900}");
|
|
inputProto.contractID = "@mozilla.org/widget/touchbarinput;1";
|
|
inputProto.QueryInterface = ChromeUtils.generateQI([Ci.nsITouchBarInput]);
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
|
|
TouchBarHelper,
|
|
TouchBarInput,
|
|
]);
|