Skip to content

Commit

Permalink
✨ Page action popup panel
Browse files Browse the repository at this point in the history
  • Loading branch information
trickypr committed Dec 15, 2023
1 parent ff33991 commit bf249a5
Show file tree
Hide file tree
Showing 6 changed files with 361 additions and 100 deletions.
100 changes: 99 additions & 1 deletion src/content/browser/components/omnibox/PageAction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,108 @@
<script lang="ts">
import type { PageAction } from 'resource://app/modules/EPageActions.sys.mjs'
import ToolbarButton from '@shared/components/ToolbarButton.svelte'
import {
createBrowser,
getBrowserRemoteType,
setURI,
} from '@browser/lib/xul/browser'
import { resource } from '@browser/lib/resources'
import { spinLock } from '@browser/lib/spinlock'
import { MessageReviver } from '@shared/xul/messageReciver'
import { onMount } from 'svelte'
export let pageAction: PageAction
let panel: any
let browser: XULBrowserElement
let button: HTMLButtonElement
const messageReceiver = new MessageReviver(({ name, data }) => {
switch (name) {
case 'Extension:BrowserResized':
const { width, height } = data as { height: number; width: number }
browser.style.width = `${width}px`
browser.style.height = `${height}px`
break
}
})
async function buildPanelBrowser() {
if (browser) {
browser.remove()
}
console.log(pageAction.popupUrl)
if (!pageAction.popupUrl) return
const uri = resource.NetUtil.newURI(pageAction.popupUrl)
const lBrowser = createBrowser({
remoteType: getBrowserRemoteType(uri),
attributes: {
disableglobalhistory: 'true',
messagemanagergroup: 'todo',
'webextension-view-type': 'popup',
},
})
lBrowser.addEventListener('DidChangeBrowserRemoteness', () =>
console.log('ChangeRemoteness'),
)
await spinLock(() => panel)
panel.appendChild(lBrowser)
browser = lBrowser
lBrowser.messageManager.addMessageListener(
'Extension:BrowserResized',
messageReceiver,
)
lBrowser.messageManager.loadFrameScript(
'chrome://extensions/content/ext-browser-content.js',
false,
true,
)
lBrowser.messageManager.sendAsyncMessage('Extension:InitBrowser', {
allowScriptsToClose: true,
maxWidth: 800,
maxHeight: 600,
})
lBrowser.style.borderRadius = 'inherit'
await spinLock(() => lBrowser.mInitialized)
setURI(lBrowser, uri)
}
const OPEN_PANEL = async () => {
await buildPanelBrowser()
panel.openPopup(button, 'bottomright topright')
}
onMount(() => () => {
if (browser) {
browser.messageManager.removeMessageListener(
'Extension:BrowserResized',
messageReceiver,
)
browser.remove()
}
})
</script>

<ToolbarButton kind="page-icon">
<ToolbarButton kind="page-icon" bind:button on:click={OPEN_PANEL}>
<i class="ri-puzzle-line"></i>
</ToolbarButton>

{#if pageAction.popupUrl}
<xul:panel bind:this={panel} class="popup"></xul:panel>
{/if}

<style>
.popup {
--panel-shadow-margin: 0;
--panel-padding: 0;
--panel-border-radius: 0.5rem;
}
</style>
23 changes: 18 additions & 5 deletions src/content/browser/lib/xul/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,32 @@ export function getBrowserRemoteType(uri: nsIURIType) {
)
}

export function createBrowser({ remoteType }: { remoteType?: string } = {}) {
export function createBrowser({
remoteType,
attributes,
}: {
remoteType?: string
attributes?: {
disableglobalhistory?: string
messagemanagergroup?: string
['webextension-view-type']?: string
}
} = {}): XULBrowserElement {
const browser = document.createXULElement('browser')
if (remoteType) {
browser.setAttribute('remoteType', remoteType)
browser.setAttribute('remote', true)
}

for (const attribute in DEFAULT_BROWSER_ATTRIBUTES)
const mergedAttributes = {
...DEFAULT_BROWSER_ATTRIBUTES,
...(attributes || {}),
}

for (const attribute in mergedAttributes)
browser.setAttribute(
attribute,
DEFAULT_BROWSER_ATTRIBUTES[
attribute as keyof typeof DEFAULT_BROWSER_ATTRIBUTES
],
mergedAttributes[attribute as keyof typeof mergedAttributes],
)

if (useRemoteTabs) browser.setAttribute('maychangeremoteness', 'true')
Expand Down
10 changes: 10 additions & 0 deletions src/content/shared/xul/messageReciver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class MessageReviver<
Cb extends (argument: ReceiveMessageArgument) => unknown,
> implements MessageListener
{
receiveMessage: Cb

constructor(callback: Cb) {
this.receiveMessage = callback
}
}
99 changes: 5 additions & 94 deletions src/link.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

/// <reference types="gecko-types" />

/// <reference path="./types/MatchPattern.d.ts" />
/// <reference path="./types/MessageManager.d.ts" />

declare module 'resource://app/modules/FaviconLoader.sys.mjs' {
export const FaviconLoader: typeof import('./modules/FaviconLoader').FaviconLoader
}
Expand Down Expand Up @@ -82,6 +85,8 @@ declare interface XULBrowserElement extends HTMLElement {

docShell: unknown
swapDocShells(aOtherBrowser: XULBrowserElement)

messageManager: ChromeMessageSender
}

declare interface XULFindBarElement extends HTMLElement {
Expand Down Expand Up @@ -632,97 +637,3 @@ declare module ChromeUtils {
): T
}

interface MatchPatternOptions {
/**
* If true, the path portion of the pattern is ignored, and replaced with a
* wildcard. The `pattern` property is updated to reflect this.
*/
ignorePath?: boolean

/**
* If true, the set of schemes this pattern can match is restricted to
* those accessible by WebExtensions.
*/
restrictSchemes?: boolean
}

interface MatchPattern {
// eslint-disable-next-line @typescript-eslint/no-misused-new
constructor(pattern: string, options?: MatchPatternOptions)

/**
* Returns true if the given URI matches the pattern.
*
* If explicit is true, only explicit domain matches, without wildcards, are
* considered.
*/
matches(uri: URI, explicit?: boolean): boolean
matches(url: string, explicit?: boolean): boolean

/**
* Returns true if a URL exists which a) would be able to access the given
* cookie, and b) would be matched by this match pattern.
*/
matchesCookie(cookie: Cookie): boolean

/**
* Returns true if this pattern will match any host which would be matched
* by the given pattern.
*/
subsumes(pattern: MatchPattern): boolean

/**
* Returns true if this pattern will match any host which would be matched
* by the given pattern, ignoring the scheme.
*/
subsumesDomain(pattern: MatchPattern): boolean

/**
* Returns true if there is any host which would be matched by both this
* pattern and the given pattern.
*/
overlaps(pattern: MatchPattern): boolean

/**
* The match pattern string represented by this pattern.
*/
readonly pattern: string

/**
* Whether the match pattern matches all http(s) URLs.
*/
readonly matchesAllWebUrls: boolean
}

class MatchPatternSet {
// eslint-disable-next-line @typescript-eslint/no-misused-new
constructor(
patterns: Array<string | MatchPattern>,
options?: MatchPatternOptions,
)

matches(uri: URI, explicit?: boolean): boolean
matches(url: string, explicit?: boolean): boolean

matchesCookie(cookie: Cookie): boolean

subsumes(pattern: MatchPattern): boolean

subsumesDomain(pattern: MatchPattern): boolean

overlaps(pattern: MatchPattern): boolean

overlaps(patternSet: MatchPatternSet): boolean

overlapsAll(patternSet: MatchPatternSet): boolean

readonly patterns: Array<MatchPattern>

readonly matchesAllWebUrls: boolean
}

declare global {
interface Window {
MatchPatternSet: typeof MatchPatternSet
}
}
94 changes: 94 additions & 0 deletions src/types/MatchPattern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
interface MatchPatternOptions {
/**
* If true, the path portion of the pattern is ignored, and replaced with a
* wildcard. The `pattern` property is updated to reflect this.
*/
ignorePath?: boolean

/**
* If true, the set of schemes this pattern can match is restricted to
* those accessible by WebExtensions.
*/
restrictSchemes?: boolean
}

interface MatchPattern {
// eslint-disable-next-line @typescript-eslint/no-misused-new
constructor(pattern: string, options?: MatchPatternOptions)

/**
* Returns true if the given URI matches the pattern.
*
* If explicit is true, only explicit domain matches, without wildcards, are
* considered.
*/
matches(uri: URI, explicit?: boolean): boolean
matches(url: string, explicit?: boolean): boolean

/**
* Returns true if a URL exists which a) would be able to access the given
* cookie, and b) would be matched by this match pattern.
*/
matchesCookie(cookie: Cookie): boolean

/**
* Returns true if this pattern will match any host which would be matched
* by the given pattern.
*/
subsumes(pattern: MatchPattern): boolean

/**
* Returns true if this pattern will match any host which would be matched
* by the given pattern, ignoring the scheme.
*/
subsumesDomain(pattern: MatchPattern): boolean

/**
* Returns true if there is any host which would be matched by both this
* pattern and the given pattern.
*/
overlaps(pattern: MatchPattern): boolean

/**
* The match pattern string represented by this pattern.
*/
readonly pattern: string

/**
* Whether the match pattern matches all http(s) URLs.
*/
readonly matchesAllWebUrls: boolean
}

class MatchPatternSet {
// eslint-disable-next-line @typescript-eslint/no-misused-new
constructor(
patterns: Array<string | MatchPattern>,
options?: MatchPatternOptions,
)

matches(uri: URI, explicit?: boolean): boolean
matches(url: string, explicit?: boolean): boolean

matchesCookie(cookie: Cookie): boolean

subsumes(pattern: MatchPattern): boolean

subsumesDomain(pattern: MatchPattern): boolean

overlaps(pattern: MatchPattern): boolean

overlaps(patternSet: MatchPatternSet): boolean

overlapsAll(patternSet: MatchPatternSet): boolean

readonly patterns: Array<MatchPattern>

readonly matchesAllWebUrls: boolean
}

declare global {
interface Window {
MatchPatternSet: typeof MatchPatternSet
}
}
Loading

0 comments on commit bf249a5

Please sign in to comment.