🐛 Sidebar sites now appear in new windows

Fixes #187
This commit is contained in:
TrickyPR 2023-07-13 19:33:26 +10:00
parent 2e9d6dd09e
commit b7d38c4094
2 changed files with 108 additions and 103 deletions

View File

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Pinned vertical tabs are no longer positioned. Sorta defeats their purpose, but it stops a semi-major bug
- Sidebar sites now appear on new windows
## 1.0.0-a.75

View File

@ -5,17 +5,17 @@
//@ts-check
/// <reference types="./experiment.d.ts">
"use strict";
const sidebargetaroundUrl = "chrome://browser/content/webext-panels.xhtml";
'use strict'
const sidebargetaroundUrl = 'chrome://browser/content/webext-panels.xhtml'
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
'resource://gre/modules/ExtensionParent.jsm'
)
var { ContextMenu } = ChromeUtils.import(
"resource://gre/modules/ContextMenu.jsm"
);
'resource://gre/modules/ContextMenu.jsm'
)
var { IconDetails, StartupCache } = ExtensionParent;
var { IconDetails, StartupCache } = ExtensionParent
class Sidebar {
/**
@ -38,99 +38,103 @@ class Sidebar {
isBottom,
browserStyle
) {
this.extentionIndex = id;
this.extension = extention;
this.extensionName = extention.name;
this.title = name;
this.webviewUrl = webviewUrl;
this.iconUrl = iconUrl;
this.isBottom = isBottom;
this.browserStyle = browserStyle;
this.extentionIndex = id
this.extension = extention
this.extensionName = extention.name
this.title = name
this.webviewUrl = webviewUrl
this.iconUrl = iconUrl
this.isBottom = isBottom
this.browserStyle = browserStyle
this.baseId = `${this.extensionName.replaceAll(" ", "-")}-index-${
this.baseId = `${this.extensionName.replaceAll(' ', '-')}-index-${
this.extentionIndex
}`;
this.keyId = `ext-key-id-${this.baseId}`;
this.menuId = `ext-menu-id-${this.baseId}`;
this.buttonId = `ext-button-id-${this.baseId}`;
}`
this.keyId = `ext-key-id-${this.baseId}`
this.menuId = `ext-menu-id-${this.baseId}`
this.buttonId = `ext-button-id-${this.baseId}`
this.defaults = {
enabled: true,
title: this.title,
icon: IconDetails.normalize({ path: this.iconUrl }, this.extension),
panel: this.webviewUrl || "",
panel: this.webviewUrl || '',
isBottom: this.isBottom,
};
this.globals = Object.create(this.defaults);
}
this.globals = Object.create(this.defaults)
this.onRemoveEvents = [];
this.onRemoveEvents = []
this.tabContext = new TabContext(target => {
let window = target.ownerGlobal;
this.tabContext = new TabContext((target) => {
let window = target.ownerGlobal
if (target === window) {
return this.globals;
return this.globals
}
return this.tabContext.get(window);
});
return this.tabContext.get(window)
})
/**
* @type {ContextMenu}
*/
this.contextMenu = new ContextMenu([
{
l10nId: "sidebar-context-delete",
callId: "delete",
l10nId: 'sidebar-context-delete',
callId: 'delete',
},
]);
])
this.contextMenu.addEvent(callId => {
if (callId === "delete") {
this.contextMenu.addEvent((callId) => {
if (callId === 'delete') {
for (let window of windowTracker.browserWindows()) {
this.removeFromBrowserWindow(window);
this.removeFromBrowserWindow(window)
}
}
this.onRemoveEvents.filter(e => e).forEach(e => e(this.extentionIndex));
});
this.onRemoveEvents
.filter((e) => e)
.forEach((e) => e(this.extentionIndex))
})
windowTracker.addOpenListener((window) => this.addToBrowserWindow(window))
}
updateHeader(event) {
let window = event.target.ownerGlobal;
let details = this.tabContext.get(window.gBrowser.selectedTab);
let header = window.document.getElementById("sidebar-switcher-target");
let window = event.target.ownerGlobal
let details = this.tabContext.get(window.gBrowser.selectedTab)
let header = window.document.getElementById('sidebar-switcher-target')
if (window.SidebarUI.currentID === this.keyId) {
this.setMenuIcon(header, details);
this.setMenuIcon(header, details)
}
}
getIcon(size) {
return IconDetails.escapeUrl(
IconDetails.getPreferredIcon(this.iconUrl, this.extension, size).icon
);
)
}
setMenuIcon(menuitem, icon) {
menuitem.setAttribute(
"style",
'style',
`
--webextension-menuitem-image: url("${this.getIcon(16)}");
--webextension-menuitem-image-2x: url("${this.getIcon(32)}");
`
);
)
}
async removeFromBrowserWindow(window) {
let { document, SidebarUI } = window;
SidebarUI.sidebars.delete(this.keyId);
document.getElementById("sidebar-background-" + this.keyId).remove();
let { document, SidebarUI } = window
SidebarUI.sidebars.delete(this.keyId)
document.getElementById('sidebar-background-' + this.keyId).remove()
document
.getElementById("sidebar-switcher-target")
.removeEventListener("SidebarShown", this.updateHeader.bind(this));
SidebarUI.hide();
.getElementById('sidebar-switcher-target')
.removeEventListener('SidebarShown', this.updateHeader.bind(this))
SidebarUI.hide()
}
async addToBrowserWindow(window) {
// Theft the sidebar UI from the window object
let { document, SidebarUI } = window;
let { document, SidebarUI } = window
// Add sidebar information to SidebarUI
SidebarUI.sidebars.set(this.keyId, {
@ -144,41 +148,41 @@ class Sidebar {
iconurl: this.getIcon(32),
panel: this.webviewUrl,
isBottom: this.isBottom,
});
})
// Generate the header information
let header = document.getElementById("sidebar-switcher-target");
header.addEventListener("SidebarShown", this.updateHeader.bind(this));
let header = document.getElementById('sidebar-switcher-target')
header.addEventListener('SidebarShown', this.updateHeader.bind(this))
// Insert a menuitem for View->Show Sidebars.
let menuitem = document.createXULElement("menuitem");
menuitem.setAttribute("id", this.menuId);
menuitem.setAttribute("type", "checkbox");
menuitem.setAttribute("label", this.title);
let menuitem = document.createXULElement('menuitem')
menuitem.setAttribute('id', this.menuId)
menuitem.setAttribute('type', 'checkbox')
menuitem.setAttribute('label', this.title)
menuitem.setAttribute(
"oncommand",
'oncommand',
`SidebarUI.toggle("${this.extentionIndex}");`
);
menuitem.setAttribute("class", "menuitem-iconic webextension-menuitem");
menuitem.setAttribute("key", this.keyId);
this.setMenuIcon(menuitem, this.iconUrl);
document.getElementById("viewSidebarMenu").appendChild(menuitem);
)
menuitem.setAttribute('class', 'menuitem-iconic webextension-menuitem')
menuitem.setAttribute('key', this.keyId)
this.setMenuIcon(menuitem, this.iconUrl)
document.getElementById('viewSidebarMenu').appendChild(menuitem)
// Add to the sidebar tabs on the side of the window
await SidebarUI.createSidebarItem(
this.keyId,
SidebarUI.sidebars.get(this.keyId)
);
)
// Get the element based on the id of `sidebar-background-${this.keyId}`
// Set the attribute 'context' to 'hello'
this.contextMenu.addToBrowser(window);
this.contextMenu.addToBrowser(window)
let sidebar = window.document.getElementById(
`sidebar-background-${this.keyId}`
);
sidebar.setAttribute("context", this.contextMenu.contextMenuId);
)
sidebar.setAttribute('context', this.contextMenu.contextMenuId)
return menuitem;
return menuitem
}
}
@ -187,44 +191,44 @@ class ConfigAPI extends ExtensionAPI {
* @param {any} extension
*/
constructor(extension) {
super(extension);
super(extension)
this.onRemoveEvents = [];
this.onRemoveEvents = []
this.currentIndex = 0;
this.currentIndex = 0
/** @type {Map<number, Sidebar>} */
this.sidebars = new Map();
this.sidebars = new Map()
}
/**
* @param {any} context
*/
getAPI(context) {
let { extension } = context;
let { extension } = context
return {
sidebars: {
/**
* @param {{ title: string, iconUrl: string, webviewUrl: string, isBottom?: boolean, browserStyle?: boolean }} config The config provided by the programer
*/
add: async config => {
add: async (config) => {
// Get a url that can be used by the browser for this specific panel
// to work correctly
const url = context.uri.resolve(config.webviewUrl);
const url = context.uri.resolve(config.webviewUrl)
if (!context.checkLoadURL(url)) {
return Promise.reject({
message: `Access to the url ${url} (from ${config.webviewUrl}) was denied`,
});
})
}
// Get the icon url
const iconUrl = IconDetails.normalize(
{ path: config.iconUrl },
extension
);
)
const id = ++this.currentIndex;
const id = ++this.currentIndex
const sidebar = new Sidebar(
id,
extension,
@ -233,16 +237,16 @@ class ConfigAPI extends ExtensionAPI {
iconUrl,
config.isBottom || false,
config.browserStyle || false
);
sidebar.onRemoveEvents = this.onRemoveEvents;
)
sidebar.onRemoveEvents = this.onRemoveEvents
for (let window of windowTracker.browserWindows()) {
sidebar.addToBrowserWindow(window);
sidebar.addToBrowserWindow(window)
}
this.sidebars.set(id, sidebar);
this.sidebars.set(id, sidebar)
return id;
return id
},
get: async (/** @type {any} */ id) => {
@ -253,49 +257,49 @@ class ConfigAPI extends ExtensionAPI {
webviewUrl: this.sidebars.get(id).webviewUrl,
isBottom: this.sidebars.get(id).isBottom,
browserStyle: this.sidebars.get(id).browserStyle,
};
}
},
list: async () => {
return [...this.sidebars.keys()];
return [...this.sidebars.keys()]
},
remove: async (/** @type {any} */ id) => {
const sidebar = this.sidebars.get(id);
const sidebar = this.sidebars.get(id)
for (let window of windowTracker.browserWindows()) {
sidebar.removeFromBrowserWindow(window);
sidebar.removeFromBrowserWindow(window)
}
this.sidebars.delete(id);
this.sidebars.delete(id)
},
onRemove: new EventManager({
context,
name: "sidebars.onRemove",
register: fire => {
const callback = value => {
fire.async(value);
};
const eventId = this.onRemoveEvents.length;
this.onRemoveEvents.push(callback);
name: 'sidebars.onRemove',
register: (fire) => {
const callback = (value) => {
fire.async(value)
}
const eventId = this.onRemoveEvents.length
this.onRemoveEvents.push(callback)
for (const sidebar of this.sidebars.values()) {
sidebar.onRemoveEvents = this.onRemoveEvents;
sidebar.onRemoveEvents = this.onRemoveEvents
}
return () => {
this.onRemoveEvents[eventId] = null;
this.onRemoveEvents[eventId] = null
for (const sidebar of this.sidebars.values()) {
sidebar.onRemoveEvents = this.onRemoveEvents;
sidebar.onRemoveEvents = this.onRemoveEvents
}
};
}
},
}).api(),
},
};
}
}
}
var sidebars;
sidebars = ConfigAPI;
var sidebars
sidebars = ConfigAPI