Skip to content

Commit

Permalink
[gem-devtools] Support gem panel edit value
Browse files Browse the repository at this point in the history
  • Loading branch information
mantou132 committed Dec 2, 2023
1 parent 4071b34 commit 4cb3fb5
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 70 deletions.
4 changes: 2 additions & 2 deletions packages/gem-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"build": "vite build",
"watch": "yarn build --watch",
"build:zip": "yarn build && web-ext build",
"browser": "web-ext run",
"start": "concurrently npm:watch npm:browser"
"browser": "web-ext run --target=chromium --target=firefox-desktop",
"start": "yarn build && concurrently -k npm:watch npm:browser"
},
"dependencies": {
"@mantou/gem": "^1.7.0",
Expand Down
22 changes: 21 additions & 1 deletion packages/gem-devtools/src/common.ts
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
export const isFirefox = navigator.userAgent.includes('Firefox');
import { devtools } from 'webextension-polyfill';

/**
* execution script in page
* @param func A function that can be converted into a string and does not rely on external variables
* @param args Array serializable using JSON
*/
export async function execution<Func extends (...rest: any) => any>(
func: Func,
args: Parameters<Func>,
): Promise<ReturnType<Func>> {
const source = func.toString();
const [data, errorInfo] = await devtools.inspectedWindow.eval(`(${source}).apply(null, ${JSON.stringify(args)})`);
if (errorInfo) {
throw {
source,
...errorInfo,
};
}
return data;
}
5 changes: 5 additions & 0 deletions packages/gem-devtools/src/content.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// 作为静态资源输出
import './manifest.json?url';
// 实时更新
import './manifest.json';

type DevToolsHookStore = {
customElementMap: Map<string, CustomElementConstructor>;
currentElementsMap: Map<string, Element>;
Expand Down
91 changes: 75 additions & 16 deletions packages/gem-devtools/src/elements/section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import {
createCSSSheet,
css,
customElement,
Emitter,
GemElement,
globalemitter,
html,
kebabToCamelCase,
property,
SheetToken,
} from '@mantou/gem';

import { Item, Path, BuildIn } from '../store';
import { Item, Path, BuildIn, panelStore } from '../store';
import { theme } from '../theme';
import { inspectValue } from '../scripts/inspect-value';
import { execution } from '../common';
import { setValue } from '../scripts/set-value';

const maybeBuildInPrefix = '[[Gem?]] ';
const buildInPrefix = '[[Gem]] ';
Expand Down Expand Up @@ -121,21 +124,32 @@ export const style = createCSSSheet(css`
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0;
background: none;
border: none;
outline: none;
}
.string {
color: ${theme.stringValueColor};
}
.string:empty::after {
content: '<empty string>';
.string::placeholder {
color: ${theme.valueColor};
font-style: italic;
}
.number {
color: ${theme.numberValueColor};
}
.number::-webkit-inner-spin-button,
.number::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.boolean {
color: ${theme.booleanValueColor};
}
.boolean:hover {
cursor: pointer;
}
.object {
color: ${theme.objectValueColor};
}
Expand All @@ -158,7 +172,6 @@ export class Section extends GemElement {
@attribute tip: string;
@property data: Item[] = [];
@property path: Path | undefined;
@globalemitter valueclick: Emitter<Path>;

renderTip = () => {
if (!this.tip) return '';
Expand All @@ -172,7 +185,7 @@ export class Section extends GemElement {
class="inspect"
title="Inspect"
@click=${(e: Event) => {
this.valueclick(path);
execution(inspectValue, [path, String(SheetToken)]);
e.preventDefault();
}}
>
Expand All @@ -191,19 +204,65 @@ export class Section extends GemElement {
}
};

renderItemValue = (item: Item) => {
const path =
this.data === panelStore.staticMember
? ['constructor', item.name]
: this.data === panelStore.state
? ['state', item.name]
: this.data === panelStore.observedAttributes || this.data === panelStore.cssStates
? [kebabToCamelCase(item.name)]
: [item.name];
const onInput = (evt: Event) => {
execution(setValue, [path, (evt.target as HTMLInputElement).value]);
};
const onInputNumber = (evt: Event) => {
execution(setValue, [path, Number((evt.target as HTMLInputElement).value)]);
};
const toggleValue = (evt: MouseEvent) => {
execution(setValue, [path, (evt.target as HTMLInputElement).textContent?.trim() === 'true' ? false : true]);
};
switch (item.type) {
case 'string':
return html`
<input
class="value ${item.type}"
title="Click to edit"
placeholder="<empty string>"
@input=${onInput}
value=${item.value}
/>
`;
case 'number':
return html`
<input
class="value ${item.type}"
title="Click to edit"
type="number"
@input=${onInputNumber}
value=${item.value}
/>
`;
case 'boolean':
return html`
<span class="value ${item.type}" title="Click to toggle" @click=${toggleValue}>${item.value}</span>
`;
default:
return html`<span class="value ${item.type}" title=${item.value}>${item.value}</span>`;
}
};

renderItem = (data: Item[]) => {
return html`
<ul>
${data.map(
(e) =>
html`
<li>
<span class="name">${this.renderBuildInMark(e.buildIn)}${e.name}</span>
<span class="sp">:</span>
<span class="value ${e.type}" title=${e.value}>${e.value}</span>
${this.renderInspect(e.path)}
</li>
`,
(e) => html`
<li>
<span class="name">${this.renderBuildInMark(e.buildIn)}${e.name}</span>
<span class="sp">:</span>
${this.renderItemValue(e)} ${this.renderInspect(e.path)}
</li>
`,
)}
</ul>
`;
Expand Down
20 changes: 6 additions & 14 deletions packages/gem-devtools/src/elements/statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,16 @@ import {
connectStore,
attribute,
property,
Emitter,
globalemitter,
boolattribute,
classMap,
} from '@mantou/gem';

import { panelStore } from '../store';
import { DomStatInfo, inspectDom } from '../scripts/inspect-ele';
import { execution } from '../common';

import { style } from './section';

type DomStatType = 'ele' | 'con';
export type DomStatInfo = {
type: DomStatType;
id: string;
};

/**
* @customElement devtools-statistics
*/
Expand All @@ -31,12 +25,10 @@ export type DomStatInfo = {
export class devtoolsStatisticsElement extends GemElement {
@attribute name: string;
@boolattribute ignore: boolean;
@attribute type: DomStatType = 'ele';
@attribute type: DomStatInfo['type'] = 'ele';
@property value = new Array<string>();
@property highlight?: Array<string>;

@globalemitter inspectdom: Emitter<DomStatInfo>;

#parse = (v: string) => {
// scripts/dom-stat
return v.split(',');
Expand All @@ -48,7 +40,7 @@ export class devtoolsStatisticsElement extends GemElement {
class="inspect"
title="Inspect"
@click=${(e: Event) => {
this.inspectdom({ id, type: this.type });
execution(inspectDom, [{ id, type: this.type }]);
e.preventDefault();
}}
>
Expand Down Expand Up @@ -92,8 +84,8 @@ export class devtoolsStatisticsElement extends GemElement {
${this.ignore
? html`<div class="nodata">ignore</div>`
: value.length
? this.renderItem(value)
: html`<div class="nodata">no data</div>`}
? this.renderItem(value)
: html`<div class="nodata">no data</div>`}
</div>
</details>
`;
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/gem-devtools/src/scripts/get-gem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const getSelectedGem = function (data: PanelStore, gemElementSymbols: str
data.state.push({
name: k,
value: objectToString(value),
type: 'boolean',
type: typeof value,
});
});
return;
Expand Down
7 changes: 5 additions & 2 deletions packages/gem-devtools/src/scripts/inspect-ele.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { DomStatInfo } from '../elements/statistics';

declare function inspect(arg: any): void;

export type DomStatInfo = {
type: 'ele' | 'con';
id: string;
};

export function inspectDom({ id, type }: DomStatInfo) {
const { __GEM_DEVTOOLS__STORE__, __GEM_DEVTOOLS__HOOK__ } = window;
if (!__GEM_DEVTOOLS__STORE__ || !__GEM_DEVTOOLS__HOOK__) return;
Expand Down
28 changes: 28 additions & 0 deletions packages/gem-devtools/src/scripts/set-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Path } from '../store';

// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/devtools/inspectedWindow/eval#helpers
declare let $0: any;

export const setValue = (path: Path, value: string | number | boolean | null) => {
const key = String(path.pop());

// 同 inspect-value
const obj = path.reduce((p, c, index) => {
if (typeof p === 'function' && path[index - 1] !== 'constructor') {
if (Array.isArray(c)) {
return p(...c);
} else {
return p(c);
}
} else {
if (Array.isArray(c)) {
return c.reduce((pp, cc) => pp || (cc === '' ? p : p[cc]), undefined);
} else {
const value = p[c];
return typeof value === 'function' && c !== 'constructor' ? value.bind(p) : value;
}
}
}, $0);

obj[key] = value;
};
36 changes: 3 additions & 33 deletions packages/gem-devtools/src/sidebarpanel.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,14 @@
import { devtools } from 'webextension-polyfill';
import { customElement, GemElement, html, render, SheetToken } from '@mantou/gem';
import { customElement, GemElement, html, render } from '@mantou/gem';

import { getSelectedGem } from './scripts/get-gem';
import { inspectValue } from './scripts/inspect-value';
import { changeStore, PanelStore, Path } from './store';
import { changeStore, PanelStore } from './store';
import { getDomStat } from './scripts/dom-stat';
import { inspectDom } from './scripts/inspect-ele';
import { theme } from './theme';
import { DomStatInfo } from './elements/statistics';
import { execution } from './common';

import './modules/panel';

/**
* execution script in page
* @param func A function that can be converted into a string and does not rely on external variables
* @param args Array serializable using JSON
*/
async function execution<Func extends (...rest: any) => any>(
func: Func,
args: Parameters<Func>,
): Promise<ReturnType<Func>> {
const source = func.toString();
const [data, errorInfo] = await devtools.inspectedWindow.eval(`(${source}).apply(null, ${JSON.stringify(args)})`);
if (errorInfo) {
throw {
source,
...errorInfo,
};
}
return data;
}

@customElement('devtools-gem-discover')
class GemDiscover extends GemElement {}

Expand All @@ -52,14 +30,6 @@ devtools.panels.elements.onSelectionChanged.addListener(() => {
updateElementProperties();
setInterval(updateElementProperties, 300);

addEventListener('valueclick', ({ detail }: CustomEvent<Path>) => {
execution(inspectValue, [detail, String(SheetToken)]);
});

addEventListener('inspectdom', ({ detail }: CustomEvent<DomStatInfo>) => {
execution(inspectDom, [detail]);
});

render(
html`
<style>
Expand Down
2 changes: 2 additions & 0 deletions packages/gem-devtools/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default defineConfig({
root: 'src',
publicDir: resolve(process.cwd(), 'public'),
build: {
assetsInlineLimit: 0,
polyfillModulePreload: false,
target: 'es2020',
rollupOptions: {
Expand All @@ -17,6 +18,7 @@ export default defineConfig({
content: resolve(__dirname, 'src/content.ts'),
},
output: {
assetFileNames: '[name].[ext]',
chunkFileNames(info) {
return info.name + '.js';
},
Expand Down
3 changes: 2 additions & 1 deletion packages/gem-devtools/web-ext-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ module.exports = {
verbose: true,
run: {
devtools: false,
firefox: 'firefox',
// run on chrome: web-ext run --target=chromium
// https://github.com/mozilla/web-ext/issues/1862
startUrl: ['about:debugging', 'https://gemjs.org/'],
},
build: {
Expand Down

0 comments on commit 4cb3fb5

Please sign in to comment.