preserve input cursor selection when setting value

pull/4164/head
Tan Li Hau 6 years ago
parent b608148238
commit 791fcae184

@ -75,6 +75,7 @@ export default class AttributeWrapper {
const is_src = this.node.name === 'src'; // TODO retire this exception in favour of https://github.com/sveltejs/svelte/issues/3750
const is_select_value_attribute =
name === 'value' && element.node.name === 'select';
const is_update_input_value = (name === 'value') && (element.node.name === 'input' || element.node.name === 'textarea');
const should_cache = is_src || this.node.should_cache() || is_select_value_attribute; // TODO is this necessary?
@ -138,6 +139,15 @@ export default class AttributeWrapper {
updater = b`${method}(${element.var}, "${name}", ${should_cache ? last : value});`;
}
if (is_update_input_value) {
const selection = block.get_unique_name(`${element.var.name}_cursor_selection`);
updater = b`
const ${selection} = @save_input_selection(${element.var});
${updater}
@restore_input_selection(${element.var}, ${selection});
`;
}
if (dependencies.length > 0) {
let condition = block.renderer.dirty(dependencies);

@ -3,6 +3,7 @@ export * from './await_block';
export * from './dom';
export * from './environment';
export * from './globals';
export * from './input';
export * from './keyed_each';
export * from './lifecycle';
export * from './loop';
@ -12,4 +13,4 @@ export * from './ssr';
export * from './transitions';
export * from './utils';
export * from './Component';
export * from './dev';
export * from './dev';

@ -0,0 +1,34 @@
function has_selection_capabilities(input) {
const node_name = input.nodeName.toLowerCase();
return (
(node_name === 'input' &&
(input.type === 'text' ||
input.type === 'search' ||
input.type === 'tel' ||
input.type === 'url' ||
input.type === 'password')) ||
node_name === 'textarea'
);
}
function get_selection(input) {
return {
start: input.selectionStart,
end: input.selectionEnd,
};
}
export function restore_input_selection(input, offsets) {
let {start, end} = offsets;
if (end === undefined) {
end = start;
}
input.selectionStart = start;
input.selectionEnd = Math.min(end, input.value.length);
}
export function save_input_selection(input) {
return has_selection_capabilities(input) ? get_selection(input) : null;
}

@ -0,0 +1,81 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
append,
detach,
element,
init,
insert,
listen,
noop,
restore_input_selection,
safe_not_equal,
save_input_selection,
set_data,
space,
text
} from "svelte/internal";
function create_fragment(ctx) {
let input;
let t0;
let h1;
let t1;
let t2;
let dispose;
return {
c() {
input = element("input");
t0 = space();
h1 = element("h1");
t1 = text(/*name*/ ctx[0]);
t2 = text("!");
input.value = /*name*/ ctx[0];
dispose = listen(input, "input", /*onInput*/ ctx[1]);
},
m(target, anchor) {
insert(target, input, anchor);
insert(target, t0, anchor);
insert(target, h1, anchor);
append(h1, t1);
append(h1, t2);
},
p(ctx, [dirty]) {
if (dirty & /*name*/ 1) {
const input_cursor_selection = save_input_selection(input);
input.value = /*name*/ ctx[0];
restore_input_selection(input, input_cursor_selection);
}
if (dirty & /*name*/ 1) set_data(t1, /*name*/ ctx[0]);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(input);
if (detaching) detach(t0);
if (detaching) detach(h1);
dispose();
}
};
}
function instance($$self, $$props, $$invalidate) {
let name = "change me";
function onInput(event) {
$$invalidate(0, name = event.target.value);
}
return [name, onInput];
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,11 @@
<script>
let name = 'change me';
function onInput(event) {
name = event.target.value
}
</script>
<input value={name} on:input={onInput}>
<h1>{name}!</h1>
Loading…
Cancel
Save