Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- `Ferrum::Frame#lifecycle_events` provides a list of frame's events like init, networkIdle, firstPaint, etc. [#583]
- `Ferrum::Frame#idle?` whether frame was loaded [#583]

### Fixed
- `Ferrum::Node#type` / `Ferrum::Keyboard` now trigger the select-all editing shortcut (`Ctrl`/`Cmd`+`A`) by naming the CDP `commands` field, so selecting and replacing text in inputs and contenteditables works.

### Changed
- `Ferrum::PendingConnectionsError` and `Ferrum::TimeoutError` were swallowed even though happening when traffic iterator results in empty array. [#583]

Expand Down
19 changes: 19 additions & 0 deletions lib/ferrum/keyboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ def normalize_keys(keys, pressed_keys = [], memo = [])
modifiers: pressed.map { |k| MODIFIERS[k] }.reduce(0, :|)
)

# Synthetic key events alone do not trigger the browser's editing
# shortcuts (e.g. select-all). When the chord matches a platform
# accelerator, name the editing command explicitly so Chrome
# executes it via the CDP `commands` field.
command = editing_command(pressed, char)
key = key.merge(commands: [command]) if command

modifiers = pressed.map { |k| to_options(KEYS.fetch(KEYS_MAPPING[k.to_sym])) }
modifiers + [to_options(key)]
end.flatten
Expand All @@ -157,5 +164,17 @@ def combine_strings(keys)
def to_options(hash)
hash.inject({}) { |memo, (k, v)| memo.merge(k.to_sym => v) }
end

# Names the CDP editing command for a modifier chord, or nil if the chord
# is not an editing accelerator. The accelerator modifier is Cmd on macOS
# and Ctrl elsewhere, matching Chrome's own key bindings. Currently only
# select-all is mapped; extend the guard for further commands as needed.
def editing_command(pressed, char)
return unless char.casecmp?("a")
return if pressed.include?("shift")
Comment thread
myabc marked this conversation as resolved.

accelerator = Utils::Platform.mac? ? MODIFIERS["meta"] : MODIFIERS["ctrl"]
"selectAll" if pressed.map { |k| MODIFIERS[k] }.compact.uniq == [accelerator]
end
end
end
18 changes: 18 additions & 0 deletions spec/node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,15 @@
expect(input.value).to eq("Text appended")
end

it "selects all in an input with the command modifier then clears" do
input = browser.at_css("#filled_input")
modifier = Ferrum::Utils::Platform.mac? ? :meta : :ctrl

input.focus.type([modifier, "a"], :backspace)

expect(input.value).to eq("")
end

it "sends keys to empty textarea" do
input = browser.at_css("#empty_textarea")

Expand Down Expand Up @@ -643,6 +652,15 @@
expect(input.text).to eq("Content appended")
end

it "selects all with the command modifier then clears" do
input = browser.at_css("#filled_div")
modifier = Ferrum::Utils::Platform.mac? ? :meta : :ctrl

input.focus.type([modifier, "a"], :backspace)

expect(input.text).to eq("")
end

it "sets content" do
input = browser.at_css("#filled_div")

Expand Down
Loading