Move custom behaviors behind checkbox (#2545)

WIP for https://github.com/webrecorder/browsertrix/issues/2541

## Changes

- Moves custom behaviors table to behind "Use Custom Behaviors"
checkbox.
- Updates autoclick selector to match checkbox reveal layout.
- Adds minimum viable user guide documentation of custom behaviors.
This commit is contained in:
sua yoo 2025-04-08 15:16:02 -07:00 committed by GitHub
parent ba57b85322
commit 58749602ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 109 additions and 105 deletions

View File

@ -166,7 +166,7 @@ The crawl will be gracefully stopped after reaching this set size in GB.
Customize how and when the browser performs specific operations on a page.
**Built-in Behaviors**
_**Behaviors**_
Behaviors are browser operations that can be enabled for additional page interactivity.
@ -187,13 +187,17 @@ When clicking a link-like element that would normally result in navigation, auto
- Websites that use `<a>` in place of a `<button>` to reveal in-page content.
### Click Selector
#### Click Selector
When autoclick is enabled, you can customize which element is automatically clicked by specifying a CSS selector.
See [Basic CSS selectors (MDN)](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors) for examples of valid CSS selectors.
**Page Timing**
### Use Custom Behaviors
Enable custom behaviors to add your own behavior scripts. See [webrecorder/browsertrix-behaviors](https://github.com/webrecorder/browsertrix-behaviors) for more information.
_**Page Timing**_
Page timing gives you more granular control over how long the browser should stay on a page and when behaviors should run on a page. Add limits to decrease the amount of time the browser spends on a page, and add delays to increase the amount of time the browser waits on a page. Adding delays will increase the total amount of time spent on a crawl and may impact your overall crawl minutes.

View File

@ -1267,7 +1267,7 @@ https://archiveweb.page/images/${"logo.svg"}`}
`;
}
private renderBehaviors() {
private renderPageBehavior() {
return html`
${this.renderSectionHeading(labelFor.behaviors)}
${inputCol(
@ -1284,77 +1284,65 @@ https://archiveweb.page/images/${"logo.svg"}`}
)}
${inputCol(
html`<sl-checkbox
name="autoclickBehavior"
?checked=${this.formState.autoclickBehavior}
>
${labelFor.autoclickBehavior}
</sl-checkbox>`,
name="autoclickBehavior"
?checked=${this.formState.autoclickBehavior}
>
${labelFor.autoclickBehavior}
</sl-checkbox>
${when(
this.formState.autoclickBehavior,
() =>
html`<div class="mt-3">
<btrix-syntax-input
name="clickSelector"
label=${labelFor.clickSelector}
language="css"
value=${this.formState.clickSelector}
placeholder="${msg("Default:")} ${DEFAULT_AUTOCLICK_SELECTOR}"
disableTooltip
@btrix-change=${(
e: BtrixChangeEvent<typeof this.formState.clickSelector>,
) => {
const el = e.target as SyntaxInput;
const value = e.detail.value.trim();
if (value) {
try {
// Validate selector
this.cssParser(value);
this.updateFormState(
{
clickSelector: e.detail.value,
},
true,
);
} catch {
el.setCustomValidity(
msg("Please enter a valid CSS selector"),
);
}
}
}}
></btrix-syntax-input>
</div> `,
)} `,
)}
${this.renderHelpTextCol(
msg(
`Automatically click on all link-like elements without navigating away from the page.`,
),
false,
)}
${when(
this.formState.autoclickBehavior,
() => html`
${inputCol(
html`<btrix-syntax-input
name="clickSelector"
label=${labelFor.clickSelector}
language="css"
value=${this.formState.clickSelector}
placeholder="${msg("Default:")} ${DEFAULT_AUTOCLICK_SELECTOR}"
disableTooltip
@btrix-change=${(
e: BtrixChangeEvent<typeof this.formState.clickSelector>,
) => {
const el = e.target as SyntaxInput;
const value = e.detail.value.trim();
if (value) {
try {
// Validate selector
this.cssParser(value);
this.updateFormState(
{
clickSelector: e.detail.value,
},
true,
);
this.clickSelector?.removeAttribute("data-invalid");
this.clickSelector?.removeAttribute("data-user-invalid");
} catch {
el.setCustomValidity(
msg("Please enter a valid CSS selector"),
);
}
}
}}
@btrix-invalid=${() => {
/**
* HACK Set data attribute manually so that
* table works with `syncTabErrorState`
*
* FIXME Should be fixed with
* https://github.com/webrecorder/browsertrix/issues/2497
* or
* https://github.com/webrecorder/browsertrix/issues/2536
*/
this.clickSelector?.setAttribute("data-invalid", "true");
this.clickSelector?.setAttribute("data-user-invalid", "true");
}}
></btrix-syntax-input>`,
html`
${msg(
`Automatically click on all link-like elements without navigating away from the page.`,
)}
${this.renderHelpTextCol(
html`${msg(
`Customize the CSS selector used to autoclick elements.`,
)} <span class="sr-only">${msg('Defaults to "a".')}</span>`,
${when(
this.formState.autoclickBehavior,
() =>
html`<br /><br />${msg(
`Optionally, specify the CSS selector used to autoclick elements.`,
)} <span class="sr-only">${msg('Defaults to "a".')}</span>`,
)}
`,
false,
)}
${this.renderCustomBehaviors()}
${this.renderSectionHeading(msg("Page Timing"))}
@ -1421,32 +1409,29 @@ https://archiveweb.page/images/${"logo.svg"}`}
private renderCustomBehaviors() {
return html`
${this.renderSectionHeading(labelFor.customBehaviors)}
${inputCol(
html`<btrix-custom-behaviors-table
.customBehaviors=${this.initialWorkflow?.config.customBehaviors || []}
editable
@btrix-change=${() => {
this.customBehaviorsTable?.removeAttribute("data-invalid");
this.customBehaviorsTable?.removeAttribute("data-user-invalid");
}}
@btrix-invalid=${() => {
/**
* HACK Set data attribute manually so that
* table works with `syncTabErrorState`
*
* FIXME Should be fixed with
* https://github.com/webrecorder/browsertrix/issues/2497
* or
* https://github.com/webrecorder/browsertrix/issues/2536
*/
this.customBehaviorsTable?.setAttribute("data-invalid", "true");
this.customBehaviorsTable?.setAttribute(
"data-user-invalid",
"true",
);
}}
></btrix-custom-behaviors-table>`,
html`<sl-checkbox
?checked=${this.formState.customBehavior}
@sl-change=${() =>
this.updateFormState({
customBehavior: !this.formState.customBehavior,
})}
>
${msg("Use Custom Behaviors")}
</sl-checkbox>
${when(
this.formState.customBehavior,
() => html`
<div class="mt-3">
<btrix-custom-behaviors-table
.customBehaviors=${this.initialWorkflow?.config
.customBehaviors || []}
editable
></btrix-custom-behaviors-table>
</div>
`,
)} `,
)}
${this.renderHelpTextCol(
msg(
@ -1809,7 +1794,7 @@ https://archiveweb.page/images/${"logo.svg"}`}
{
name: "behaviors",
desc: msg("Customize how the browser loads and interacts with a page."),
render: this.renderBehaviors,
render: this.renderPageBehavior,
},
{
name: "browserSettings",
@ -2208,20 +2193,30 @@ https://archiveweb.page/images/${"logo.svg"}`}
// See https://github.com/webrecorder/browsertrix/issues/2536
if (
this.formState.autoclickBehavior &&
!this.clickSelector?.checkValidity()
this.clickSelector
) {
this.clickSelector?.reportValidity();
return;
if (!this.clickSelector.checkValidity()) {
this.clickSelector.reportValidity();
return;
}
}
// Wait for custom behaviors validation to finish
// TODO Move away from manual validation check
// See https://github.com/webrecorder/browsertrix/issues/2536
try {
await this.customBehaviorsTable?.taskComplete;
} catch {
this.customBehaviorsTable?.reportValidity();
return;
if (this.formState.customBehavior && this.customBehaviorsTable) {
if (!this.customBehaviorsTable.checkValidity()) {
this.customBehaviorsTable.reportValidity();
return;
}
try {
await this.customBehaviorsTable.taskComplete;
} catch {
this.customBehaviorsTable.reportValidity();
return;
}
}
const isValid = await this.checkFormValidity(this.formElem);

View File

@ -1,7 +1,7 @@
import { msg } from "@lit/localize";
export const labelFor = {
behaviors: msg("Built-in Behaviors"),
behaviors: msg("Behaviors"),
customBehaviors: msg("Custom Behaviors"),
autoscrollBehavior: msg("Autoscroll"),
autoclickBehavior: msg("Autoclick"),

View File

@ -89,6 +89,7 @@ export type FormState = {
description: WorkflowParams["description"];
autoscrollBehavior: boolean;
autoclickBehavior: boolean;
customBehavior: boolean;
userAgent: string | null;
crawlerChannel: string;
proxyId: string | null;
@ -151,6 +152,7 @@ export const getDefaultFormState = (): FormState => ({
proxyId: null,
selectLinks: DEFAULT_SELECT_LINKS,
clickSelector: DEFAULT_AUTOCLICK_SELECTOR,
customBehavior: false,
});
export const mapSeedToUrl = (arr: Seed[]) =>
@ -296,6 +298,9 @@ export function getInitialFormState(params: {
autoclickBehavior: params.initialWorkflow.config.behaviors
? params.initialWorkflow.config.behaviors.includes(Behavior.AutoClick)
: defaultFormState.autoclickBehavior,
customBehavior: Boolean(
params.initialWorkflow.config.customBehaviors.length,
),
selectLinks: params.initialWorkflow.config.selectLinks,
clickSelector: params.initialWorkflow.config.clickSelector,
userAgent: