@@ -56,6 +56,35 @@ function castValue(value: string, trim?: boolean, number?: boolean | null) {
5656 return value
5757}
5858
59+ const stripASCIIWhitespace = ( value : string ) =>
60+ value . replace ( / ^ [ \t \n \f \r ] + | [ \t \n \f \r ] + $ / g, '' )
61+
62+ // Returns what the browser exposes as `value` for the server-rendered
63+ // `defaultValue`, or undefined for types whose value sanitization algorithm
64+ // rewrites the value in ways `defaultValue` cannot be compared against
65+ // (number, date, color, range...).
66+ // https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm
67+ function sanitizeDefaultValue (
68+ el : HTMLInputElement | HTMLTextAreaElement ,
69+ ) : string | undefined {
70+ const value = el . defaultValue
71+ switch ( el . type ) {
72+ case 'textarea' :
73+ return value . replace ( / \r \n ? / g, '\n' )
74+ case 'text' :
75+ case 'search' :
76+ case 'tel' :
77+ case 'password' :
78+ return value . replace ( / [ \r \n ] / g, '' )
79+ case 'url' :
80+ return stripASCIIWhitespace ( value . replace ( / [ \r \n ] / g, '' ) )
81+ case 'email' :
82+ return ( el as HTMLInputElement ) . multiple
83+ ? value . split ( ',' ) . map ( stripASCIIWhitespace ) . join ( ',' )
84+ : stripASCIIWhitespace ( value . replace ( / [ \r \n ] / g, '' ) )
85+ }
86+ }
87+
5988// We are exporting the v-model runtime directly as vnode hooks so that it can
6089// be tree-shaken in case v-model is never used.
6190export const vModelText : ModelDirective <
@@ -65,13 +94,7 @@ export const vModelText: ModelDirective<
6594 created ( el , { modifiers : { lazy, trim, number } } , vnode ) {
6695 // During hydration, created runs on an element already in the DOM.
6796 if ( el . parentNode ) {
68- if ( el . type === 'text' ) {
69- // Text inputs strip CR/LF from value, while defaultValue retains them.
70- el [ initialValueKey ] = el . defaultValue . replace ( / [ \r \n ] / g, '' )
71- } else if ( el . type === 'textarea' ) {
72- // Textareas normalize CRLF/CR to LF in value.
73- el [ initialValueKey ] = el . defaultValue . replace ( / \r \n ? / g, '\n' )
74- }
97+ el [ initialValueKey ] = sanitizeDefaultValue ( el )
7598 }
7699 el [ assignKey ] = getModelAssigner ( vnode )
77100 const castToNumber =
@@ -100,11 +123,7 @@ export const vModelText: ModelDirective<
100123 const newValue = value == null ? '' : value
101124 const initialValue = el [ initialValueKey ]
102125 delete el [ initialValueKey ]
103- if (
104- initialValue !== undefined &&
105- ( el . type === 'text' || el . type === 'textarea' ) &&
106- el . value !== initialValue
107- ) {
126+ if ( initialValue !== undefined && el . value !== initialValue ) {
108127 el [ assignKey ] ( castValue ( el . value , trim , number ) )
109128 } else {
110129 el . value = newValue
0 commit comments