Skip to content

fix: jumping cursor #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 18, 2019
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Added helper `seed::canvas()`, and `seed::canvas_context()` helper functions
- Fixed `Url` parsing (resolves issue with hash routing)
- [BREAKING] `From<String> for Url` changed to `TryFrom<String> for Url`
- Fixed jumping cursor in inputs (#158)

## v0.4.2
- Added an `Init` struct, which can help with initial routing (Breaking)
Expand Down
84 changes: 45 additions & 39 deletions examples/server_integration/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/server_integration/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ futures = "^0.1.27"
shared = { path = "../shared"}

[dependencies.web-sys]
version = "^0.3.25"
version = "^0.3.31"
features = [
"Blob",
"Event",
Expand Down
55 changes: 48 additions & 7 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,9 @@ pub fn set_value(target: &web_sys::EventTarget, value: &str) -> Result<(), &'sta
// https://docs.rs/web-sys/0.3.25/web_sys/struct.HtmlMenuItemElement.html?search=set_value
// They should be ordered by expected frequency of use

set!(HtmlInputElement, |input: &HtmlInputElement| {
// https://www.w3schools.com/tags/att_input_value.asp
match input.type_().as_str() {
"file" => Err(r#"The value attribute cannot be used with <input type="file">."#),
_ => Ok(value),
}
});
if let Some(input) = target.dyn_ref::<HtmlInputElement>() {
return set_html_input_element_value(input, value);
}
set!(HtmlTextAreaElement);
set!(HtmlSelectElement);
set!(HtmlProgressElement, |_| value.parse().map_err(|_| {
Expand All @@ -187,6 +183,51 @@ pub fn set_value(target: &web_sys::EventTarget, value: &str) -> Result<(), &'sta
Err("Can't use function `set_value` for given element.")
}

fn set_html_input_element_value(
input: &web_sys::HtmlInputElement,
value: &str,
) -> Result<(), &'static str> {
// https://www.w3schools.com/tags/att_input_value.asp
if input.type_().as_str() == "file" {
return Err(r#"The value attribute cannot be used with <input type="file">."#);
}

let input_is_active =
document().active_element().as_ref() == input.dyn_ref::<web_sys::Element>();
// We don't want to set selection in inactive input because
// that input would "steal" focus from the active element on some platforms.
if input_is_active {
// We need to set selection manually because otherwise the cursor would jump at the end on some platforms.

// `selectionStart` and `selectionEnd`
// - "If this element is an input element, and selectionStart does not apply to this element, return null."
// - https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart
// - => return values if the element type is:
// - `text`, `search`, `url`, `tel`, `password` and probably also `week`, `month`
// - https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement
// - https://html.spec.whatwg.org/multipage/input.html#do-not-apply
let selection_start = input
.selection_start()
.expect("get `HtmlInputElement` selection start");
let selection_end = input
.selection_end()
.expect("get `HtmlInputElement` selection end");

input.set_value(value);

input
.set_selection_start(selection_start)
.expect("set `HtmlInputElement` selection start");
input
.set_selection_end(selection_end)
.expect("set `HtmlInputElement` selection end");
} else {
input.set_value(value);
}

Ok(())
}

/// Similar to `get_value`
#[allow(dead_code)]
pub fn get_checked(target: &web_sys::EventTarget) -> Result<bool, &'static str> {
Expand Down
1 change: 1 addition & 0 deletions src/websys_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ pub fn to_mouse_event(event: &web_sys::Event) -> &web_sys::MouseEvent {
impl<Ms> From<&web_sys::Element> for El<Ms> {
/// Create a vdom node from a `web_sys::Element`. Used in creating elements from html
/// and markdown strings. Includes children, recursively added.
#[allow(clippy::too_many_lines)]
fn from(ws_el: &web_sys::Element) -> Self {
// Result of tag_name is all caps, but tag From<String> expects lower.
// Probably is more pure to match by xlmns attribute instead.
Expand Down