@@ -63,6 +63,7 @@ export function parseHTML (html, handler) {
6363 const expectHTML = handler . expectHTML
6464 const isUnaryTag = handler . isUnaryTag || no
6565 const isSpecialTag = handler . isSpecialTag || special
66+ let index = 0
6667 let last , lastTag
6768 while ( html ) {
6869 last = html
@@ -75,7 +76,7 @@ export function parseHTML (html, handler) {
7576 const commentEnd = html . indexOf ( '-->' )
7677
7778 if ( commentEnd >= 0 ) {
78- html = html . substring ( commentEnd + 3 )
79+ advance ( commentEnd + 3 )
7980 continue
8081 }
8182 }
@@ -85,7 +86,7 @@ export function parseHTML (html, handler) {
8586 const conditionalEnd = html . indexOf ( ']>' )
8687
8788 if ( conditionalEnd >= 0 ) {
88- html = html . substring ( conditionalEnd + 2 )
89+ advance ( conditionalEnd + 2 )
8990 continue
9091 }
9192 }
@@ -96,22 +97,22 @@ export function parseHTML (html, handler) {
9697 if ( handler . doctype ) {
9798 handler . doctype ( doctypeMatch [ 0 ] )
9899 }
99- html = html . substring ( doctypeMatch [ 0 ] . length )
100+ advance ( doctypeMatch [ 0 ] . length )
100101 continue
101102 }
102103
103104 // End tag:
104105 const endTagMatch = html . match ( endTag )
105106 if ( endTagMatch ) {
106- html = html . substring ( endTagMatch [ 0 ] . length )
107- endTagMatch [ 0 ] . replace ( endTag , parseEndTag )
107+ const curIndex = index
108+ advance ( endTagMatch [ 0 ] . length )
109+ parseEndTag ( endTagMatch [ 0 ] , endTagMatch [ 1 ] , curIndex , index )
108110 continue
109111 }
110112
111113 // Start tag:
112- const startTagMatch = parseStartTag ( html )
114+ const startTagMatch = parseStartTag ( )
113115 if ( startTagMatch ) {
114- html = startTagMatch . rest
115116 handleStartTag ( startTagMatch )
116117 continue
117118 }
@@ -120,7 +121,7 @@ export function parseHTML (html, handler) {
120121 let text
121122 if ( textEnd >= 0 ) {
122123 text = html . substring ( 0 , textEnd )
123- html = html . substring ( textEnd )
124+ advance ( textEnd )
124125 } else {
125126 text = html
126127 html = ''
@@ -131,9 +132,10 @@ export function parseHTML (html, handler) {
131132 }
132133 } else {
133134 const stackedTag = lastTag . toLowerCase ( )
134- const reStackedTag = reCache [ stackedTag ] || ( reCache [ stackedTag ] = new RegExp ( '([\\s\\S]*?)</' + stackedTag + '[^>]*>' , 'i' ) )
135-
136- html = html . replace ( reStackedTag , function ( all , text ) {
135+ const reStackedTag = reCache [ stackedTag ] || ( reCache [ stackedTag ] = new RegExp ( '([\\s\\S]*?)(</' + stackedTag + '[^>]*>)' , 'i' ) )
136+ let endTagLength = 0
137+ const rest = html . replace ( reStackedTag , function ( all , text , endTag ) {
138+ endTagLength = endTag . length
137139 if ( stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript' ) {
138140 text = text
139141 . replace ( / < ! - - ( [ \s \S ] * ?) - - > / g, '$1' )
@@ -144,36 +146,42 @@ export function parseHTML (html, handler) {
144146 }
145147 return ''
146148 } )
147-
148- parseEndTag ( '</' + stackedTag + '>' , stackedTag )
149+ index += html . length - rest . length
150+ html = rest
151+ parseEndTag ( '</' + stackedTag + '>' , stackedTag , index - endTagLength , index )
149152 }
150153
151154 if ( html === last ) {
152155 throw new Error ( 'Error parsing template:\n\n' + html )
153156 }
154157 }
155158
156- if ( ! handler . partialMarkup ) {
157- // Clean up any remaining tags
158- parseEndTag ( )
159+ // Clean up any remaining tags
160+ parseEndTag ( )
161+
162+ function advance ( n ) {
163+ index += n
164+ html = html . substring ( n )
159165 }
160166
161- function parseStartTag ( input ) {
162- const start = input . match ( startTagOpen )
167+ function parseStartTag ( ) {
168+ const start = html . match ( startTagOpen )
163169 if ( start ) {
164170 const match = {
165171 tagName : start [ 1 ] ,
166- attrs : [ ]
172+ attrs : [ ] ,
173+ start : index
167174 }
168- input = input . slice ( start [ 0 ] . length )
175+ advance ( start [ 0 ] . length )
169176 let end , attr
170- while ( ! ( end = input . match ( startTagClose ) ) && ( attr = input . match ( attribute ) ) ) {
171- input = input . slice ( attr [ 0 ] . length )
177+ while ( ! ( end = html . match ( startTagClose ) ) && ( attr = html . match ( attribute ) ) ) {
178+ advance ( attr [ 0 ] . length )
172179 match . attrs . push ( attr )
173180 }
174181 if ( end ) {
175182 match . unarySlash = end [ 1 ]
176- match . rest = input . slice ( end [ 0 ] . length )
183+ advance ( end [ 0 ] . length )
184+ match . end = index
177185 return match
178186 }
179187 }
@@ -217,12 +225,14 @@ export function parseHTML (html, handler) {
217225 }
218226
219227 if ( handler . start ) {
220- handler . start ( tagName , attrs , unary , unarySlash )
228+ handler . start ( tagName , attrs , unary , match . start , match . end )
221229 }
222230 }
223231
224- function parseEndTag ( tag , tagName ) {
232+ function parseEndTag ( tag , tagName , start , end ) {
225233 let pos
234+ if ( start == null ) start = index
235+ if ( end == null ) end = index
226236
227237 // Find the closest opened tag of the same type
228238 if ( tagName ) {
@@ -241,7 +251,7 @@ export function parseHTML (html, handler) {
241251 // Close all the open elements, up the stack
242252 for ( let i = stack . length - 1 ; i >= pos ; i -- ) {
243253 if ( handler . end ) {
244- handler . end ( stack [ i ] . tag , stack [ i ] . attrs , i > pos || ! tag )
254+ handler . end ( stack [ i ] . tag , start , end )
245255 }
246256 }
247257
@@ -250,14 +260,14 @@ export function parseHTML (html, handler) {
250260 lastTag = pos && stack [ pos - 1 ] . tag
251261 } else if ( tagName . toLowerCase ( ) === 'br' ) {
252262 if ( handler . start ) {
253- handler . start ( tagName , [ ] , true , '' )
263+ handler . start ( tagName , [ ] , true , start , end )
254264 }
255265 } else if ( tagName . toLowerCase ( ) === 'p' ) {
256266 if ( handler . start ) {
257- handler . start ( tagName , [ ] , false , '' , true )
267+ handler . start ( tagName , [ ] , false , start , end )
258268 }
259269 if ( handler . end ) {
260- handler . end ( tagName , [ ] )
270+ handler . end ( tagName , start , end )
261271 }
262272 }
263273 }
0 commit comments