Skip to content

Commit

Permalink
🚧 Possibly functional tab query api
Browse files Browse the repository at this point in the history
  • Loading branch information
trickypr committed Apr 12, 2024
1 parent af2f76c commit 3615034
Show file tree
Hide file tree
Showing 14 changed files with 564 additions and 21 deletions.
3 changes: 3 additions & 0 deletions apps/content/src/browser/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// @ts-check
import BrowserWindow from './BrowserWindow.svelte'
import './browser.css'
import { browserImports } from './browserImports.js'
import * as WindowTabs from './windowApi/WindowTabs.js'
import { registerEventBus } from './windowApi/eventBus.js'

Expand All @@ -27,3 +28,5 @@ WindowTabs.initialize(initialUrls)
registerEventBus()

new BrowserWindow({ target: document.body })

browserImports.WindowTracker.registerWindow(window)
1 change: 1 addition & 0 deletions apps/content/src/browser/browserImports.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const browserImports = lazyESModuleGetters({
EPageActions: 'resource://app/modules/EPageActions.sys.mjs',
NetUtil: 'resource://gre/modules/NetUtil.sys.mjs',
PageThumbs: 'resource://gre/modules/PageThumbs.sys.mjs',
WindowTracker: 'resource://app/modules/BrowserWindowTracker.sys.mjs',
})
14 changes: 5 additions & 9 deletions apps/content/src/browser/windowApi/WindowTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@
* 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/. */
// @ts-check
import { writable } from '@amadeus-it-group/tansu'
import { derived } from 'svelte/store'
import { derived, writable } from '@amadeus-it-group/tansu'

import { browserImports } from '../browserImports.js'
import * as WebsiteViewApi from './WebsiteView.js'

/**
* @typedef {object} WebsiteTab
* @property {'website'} kind
* @property {WebsiteView} view
*/

export const activeTabId = writable(0)

/**
Expand Down Expand Up @@ -53,7 +46,7 @@ activeTabId.subscribe((activeId) => {
})

/**
* @type {import('@amadeus-it-group/tansu').WritableSignal<WebsiteTab[]>}
* @type {import('@amadeus-it-group/tansu').WritableSignal<import('@browser/tabs').WindowTabs>}
*/
export const windowTabs = writable([])

Expand All @@ -63,6 +56,9 @@ export const activeTab = derived(
$windowTabs.find((tab) => tab.view.windowBrowserId === $activeTabId),
)

window.windowTabs = windowTabs
window.activeTab = activeTab

/**
* @param {string[]} urls
*/
Expand Down
6 changes: 6 additions & 0 deletions apps/extensions/lib/ext-browser.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@
"scopes": ["addon_parent"],
"manifest": ["page_action"],
"paths": [["pageAction"]]
},
"tabs": {
"schema": "chrome://bextensions/content/schemas/tabs.json",
"url": "chrome://bextensions/content/parent/ext-tabs.js",
"scopes": "addon_parent",
"paths": [["tabs"]]
}
}
2 changes: 0 additions & 2 deletions apps/extensions/lib/parent/ext-pageAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ this.pageAction = class extends ExtensionAPIPersistent {
*/
onClicked({ fire }) {
const callback = async (_name, clickInfo) => {
console.log(fire, fire.wakeup, !!fire.wakeup)
if (fire.wakeup) await fire.wakeup()
console.log('fire')
fire.sync(clickInfo)
}

Expand Down
98 changes: 98 additions & 0 deletions apps/extensions/lib/parent/ext-tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// @ts-check
/// <reference path="../types/index.d.ts" />
/// <reference path="./ext-browser.js" />
/// <reference path="../schemaTypes/tabs.d.ts" />

/**
* @param {tabs__tabs.QueryInfo} queryInfo
* @returns {[import("@browser/tabs").WindowTab, Window][]}
*/
function query(queryInfo) {
const windows = [...lazy.WindowTracker.registeredWindows.entries()]

const urlMatchSet =
(queryInfo.url &&
(Array.isArray(queryInfo.url)
? new MatchPatternSet(queryInfo.url)
: new MatchPatternSet([queryInfo.url]))) ||
null

return windows.flatMap(([windowId, window]) => {
const tabs = window.windowTabs()
const activeTab = window.activeTab()

if (
typeof queryInfo.windowId !== 'undefined' &&
queryInfo.windowId != windowId
) {
return []
}

return tabs
.filter((tab) => {
const active =
typeof queryInfo.active !== 'undefined'
? queryInfo.active
? tab === activeTab
: tab !== activeTab
: true
const title = queryInfo.title
? queryInfo.title === tab.view.title
: true
const url =
urlMatchSet === null
? true
: urlMatchSet.matches(tab.view.browser.browsingContext?.currentURI)

return active && title && url
})
.map(
/** @returns {[import("@browser/tabs").WindowTab, Window]} */ (tab) => [
tab,
window,
],
)
})
}

const serialize =
(extension) =>
/**
* @param {[import("@browser/tabs").WindowTab, Window]} in
* @returns {tabs__tabs.Tab}
*/
([tab, window]) => {
// TODO: Active tab & host permissions
const hasTabPermission = extension.hasPermission('tabs')

return {
id: tab.view.browserId,
index: window.windowTabs().findIndex((wTab) => wTab === tab),
active: window.activeTab() === tab,
highlighted: false, // TODO
title: hasTabPermission && tab.view.title,
url:
hasTabPermission &&
tab.view.browser.browsingContext?.currentURI.asciiSpec,
windowId: window.windowId,
}
}

this.tabs = class extends ExtensionAPIPersistent {
PERSISTENT_EVENTS = {}

/**
* @returns {tabs__tabs.ApiGetterReturn}
*/
getAPI(context) {
const { extension } = context

return {
tabs: {
async query(queryInfo) {
return query(queryInfo).map(serialize(extension))
},
},
}
}
}
29 changes: 29 additions & 0 deletions apps/extensions/lib/schemaTypes/tabs.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @not-mpl
// This file is generated from '../schemas/tabs.json'. This file inherits its license
// Please check that file's license
//
// DO NOT MODIFY MANUALLY

declare module tabs__tabs {
type Tab = {
id?: number
index: number
active: boolean
highlighted: boolean
title?: string
url?: string
windowId: number
}
type QueryInfo = {
active?: boolean
title?: string
url?: string | string[]
windowId?: number
}
type TabStatus = 'loading' | 'complete'
type ApiGetterReturn = {
tabs: {
query: (queryInfo: QueryInfo) => Promise<Tab[]>
}
}
}
95 changes: 95 additions & 0 deletions apps/extensions/lib/schemas/tabs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

[
{
"namespace": "tabs",
"description": "Provides access to information about currently open tabs",
"types": [
{
"id": "Tab",
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": -1,
"optional": true
},
"index": {
"type": "integer",
"minimum": -1
},
"active": {
"type": "boolean"
},
"highlighted": {
"type": "boolean"
},
"title": {
"type": "string",
"optional": true,
"permissions": ["tabs"]
},
"url": {
"type": "string",
"optional": true,
"permissions": ["tabs"]
},
"windowId": {
"type": "integer"
}
}
},
{
"type": "object",
"id": "QueryInfo",
"properties": {
"active": {
"type": "boolean",
"optional": true
},
"title": {
"type": "string",
"optional": true
},
"url": {
"choices": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
],
"optional": true
},
"windowId": {
"type": "integer",
"optional": true
}
}
},
{
"type": "string",
"id": "TabStatus",
"enum": [{ "name": "loading" }, { "name": "complete" }]
}
],
"functions": [
{
"name": "query",
"type": "function",
"async": true,
"parameters": [
{
"name": "queryInfo",
"$ref": "QueryInfo"
}
],
"returns": {
"type": "array",
"items": {
"$ref": "Tab"
}
}
}
]
}
]
12 changes: 11 additions & 1 deletion apps/extensions/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
{
"name": "extensions",
"type": "module",
"version": "1.0.0",
"scripts": {
"build": "node ./scripts/buildTypes.js",
"dev": "watch 'pnpm build' ./lib/schemas/"
},
"dependencies": {
"@browser/link": "workspace:*"
},
"license": "ISC"
"license": "ISC",
"devDependencies": {
"prettier": "^3.0.3",
"typescript": "^5.4.5",
"watch": "^1.0.2"
}
}
Loading

0 comments on commit 3615034

Please sign in to comment.