feat: implement attribute, class list, dataset, and style views for H… - #19
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a write-through assignment surface for CDP-backed HTMLElement values, enabling direct property assignment (e.g. el.text = "...") and map-like nested assignment through attributes, style, classes, and dataset views that both snapshot reads and write through to the live DOM.
Changes:
- Implement
HTMLElement.Set(KeyWritable) for a limited set of writable element properties (text,html,value,checked,disabled,selected) and expose new dot-access keys (classes,dataset) for CDP elements. - Introduce
elementMapViewplus attribute/style/classList/dataset view wrappers that snapshot on read while writing through on assignment. - Add CDP JS templates for dataset and classList access/mutation, improve style templates for kebab-case vs camelCase, and update README + add integration/unit tests.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/modules/web/html/dynamic/element/assignment/views.fql | Integration fixture validating snapshot vs write-through semantics for views. |
| tests/modules/web/html/dynamic/element/assignment/invalid_class.fail.fql | Negative fixture for invalid class assignment type. |
| tests/modules/web/html/dynamic/element/assignment/direct.fql | Integration fixture validating direct element property assignment writes through. |
| modules/web/html/README.md | Documents new CDP-only write-through assignment surface and examples. |
| modules/web/html/drivers/read_only_contract_test.go | Updates driver contract test to assert only CDP elements are KeyWritable. |
| modules/web/html/drivers/cdp/templates/value.go | Adds templates for textContent and generic DOM property get/set. |
| modules/web/html/drivers/cdp/templates/styles.go | Enhances style get/set/remove to support kebab-case property names. |
| modules/web/html/drivers/cdp/templates/dataset.go | Adds dataset snapshot/get + set/remove property templates. |
| modules/web/html/drivers/cdp/templates/classes.go | Adds classList snapshot/get + toggle template. |
| modules/web/html/drivers/cdp/dom/view_keys.go | Adds dataset key normalization helper. |
| modules/web/html/drivers/cdp/dom/style_view.go | Adds style view wrapper around a snapshot with write-through mutations. |
| modules/web/html/drivers/cdp/dom/element_value.go | Adds CDP HTMLElement writable property handling and view exposure. |
| modules/web/html/drivers/cdp/dom/element_map_view.go | Adds generic snapshot+write-through map wrapper used by views. |
| modules/web/html/drivers/cdp/dom/element_map_view_test.go | Unit test for elementMapView snapshot/write-through behavior. |
| modules/web/html/drivers/cdp/dom/dataset_view.go | Adds dataset view wrapper around dataset snapshot with write-through mutations. |
| modules/web/html/drivers/cdp/dom/class_list_view.go | Adds class list view wrapper with write-through toggling. |
| modules/web/html/drivers/cdp/dom/attribute_view.go | Adds attribute view wrapper around attribute snapshot with write-through mutations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+20
to
+24
| elementMapView: newElementMapView( | ||
| snapshot, | ||
| func(ctx context.Context, key, value runtime.Value) (runtime.Value, bool, error) { | ||
| name := runtime.ToString(key) | ||
| if value == runtime.None { |
Comment on lines
+26
to
+30
| elementMapView: newElementMapView( | ||
| snapshot, | ||
| func(ctx context.Context, key, value runtime.Value) (runtime.Value, bool, error) { | ||
| name := datasetPropertyName(key) | ||
| if value == runtime.None { |
Comment on lines
+20
to
+30
| elementMapView: newElementMapView( | ||
| snapshot, | ||
| func(ctx context.Context, key, value runtime.Value) (runtime.Value, bool, error) { | ||
| name := datasetPropertyName(key) | ||
| if value == runtime.None { | ||
| return runtime.None, true, dataset.RemoveDatasetProperty(ctx, name) | ||
| } | ||
|
|
||
| next := runtime.ToString(value) | ||
|
|
||
| return next, false, dataset.SetDatasetProperty(ctx, name, next) |
| upperNext := false | ||
|
|
||
| for _, r := range name { | ||
| if r == '-' || r == '_' { |
| | `HTMLPage` | `response`, `mainFrame`, `document`, `frames`, `url`, `URL`, `cookies`, `title`, `isClosed`, plus document properties through the main frame. | | ||
| | `HTMLDocument` | `url`, `URL`, `name`, `title`, `parent`, `body`, `head`, `innerHTML`, `innerText`, plus node properties. | | ||
| | `HTMLElement` | `innerText`, `innerHTML`, `value`, `attributes`, `style`, `previousElementSibling`, `nextElementSibling`, `parentElement`, plus node properties. | | ||
| | `HTMLElement` | `innerText`, `innerHTML`, `textContent` (CDP), `value`, `checked` (CDP), `disabled` (CDP), `selected` (CDP), `attributes`, `style`, `classes` (CDP), `dataset` (CDP), `previousElementSibling`, `nextElementSibling`, `parentElement`, plus node properties. | |
Comment on lines
+333
to
+335
| button.textContent = "Continue" | ||
| button.innerHTML = "<strong>Continue</strong>" | ||
| button.disabled = FALSE |
…yles, and wait targets
… dataset manipulation
| upperNext := false | ||
|
|
||
| for _, r := range name { | ||
| if r == '-' || r == '_' { |
Comment on lines
+327
to
+335
| CDP-backed elements can also be mutated with normal assignment. Top-level assignment supports content/value properties plus `attributes`, `style`, `classes`, and `dataset`; nested assignment writes through snapshot views returned by those collection properties. A captured view keeps its read snapshot while writes through that view update the browser: | ||
|
|
||
| ```fql | ||
| LET page = DOCUMENT($url, { driver: "cdp" }) | ||
| LET button = ELEMENT(page, "button[type=submit]") | ||
|
|
||
| button.textContent = "Continue" | ||
| button.innerHTML = "<strong>Continue</strong>" | ||
| button.disabled = FALSE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces a significant refactor to how HTML element capabilities are resolved and accessed in the codebase, especially for CDP-backed elements. The main theme is to move away from direct interface implementation on elements and instead use provider methods to resolve capabilities like attributes, styles, and wait targets. This change enables a more flexible and extensible architecture for element capabilities, and is reflected in both the implementation and the documentation. Additionally, new view types are introduced for attribute, class, and dataset collections, supporting dynamic assignment and mutation. The documentation and tests are updated accordingly.
The most important changes are:
Capability Resolution Refactor
HTMLElementno longer directly implements interfaces such asAttributeTarget,StyleTarget, orWaitTarget. Instead, it provides provider methods (e.g.,AsAttributeTarget,AsStyleTarget,AsWaitTarget) which return the appropriate capability object. This enables more flexible capability resolution and easier extension in the future. [1] [2] [3] [4] [5]Attribute, Class, and Dataset View Implementations
attributeView), classes (classListView), and dataset (datasetView) that provide snapshot-based, mutable map-like interfaces to these collections. These support assignment and mutation patterns in a way that is consistent with browser behavior. [1] [2] [3] [4]Documentation Updates
README.mdto document the new assignment and mutation behavior for CDP-backed elements, including examples for mutating attributes, style, classes, and dataset properties directly through assignment. [1] [2] [3]Helper and Test Adjustments
snapshotElementHTML) to use the new capability provider pattern for accessing content and attributes, ensuring compatibility with the new architecture. [1] [2]These changes modernize the capability model for HTML elements, improve testability and extensibility, and provide a more ergonomic and powerful API for mutating DOM state in Ferret scripts.