@@ -11,8 +11,8 @@ function Parser(handler, options) {
11
11
12
12
this . _buffer = "" ;
13
13
this . _prevTagSep = "" ;
14
+ this . _contentFlags = 0 ;
14
15
this . _done = false ;
15
- this . _tagStack = [ ] ;
16
16
this . _elements = [ ] ;
17
17
this . _current = 0 ;
18
18
this . _location = {
@@ -82,7 +82,7 @@ Parser.prototype.done = function() {
82
82
this . _elements . push ( element ) ;
83
83
}
84
84
85
- this . writeHandler ( true ) ;
85
+ this . writeHandler ( ) ;
86
86
this . _handler . done ( ) ;
87
87
} ;
88
88
@@ -92,14 +92,14 @@ Parser.prototype.reset = function() {
92
92
this . _prevTagSep = "" ;
93
93
this . _done = false ;
94
94
this . _current = 0 ;
95
+ this . _contentFlags = 0 ;
95
96
this . _location = {
96
97
row : 0 ,
97
98
col : 0 ,
98
99
charOffset : 0 ,
99
100
inBuffer : 0
100
101
} ;
101
102
this . _parseState = ElementType . Text ;
102
- this . _tagStack = [ ] ;
103
103
this . _elements = [ ] ;
104
104
this . _handler . reset ( ) ;
105
105
} ;
@@ -132,13 +132,18 @@ var parseTagName = function(data) {
132
132
return match [ 1 ] + match [ 2 ] ;
133
133
} ;
134
134
135
+ //Special tags that are threated differently
136
+ var SpecialTags = { } ;
137
+ SpecialTags [ ElementType . Style ] = 1 ; //2^0
138
+ SpecialTags [ ElementType . Script ] = 2 ; //2^1
139
+ SpecialTags [ "w" ] = 4 ; //2^2 - if set, append prev tag sep to data
140
+ SpecialTags [ ElementType . Comment ] = 8 ; //2^8
141
+
135
142
//Parses through HTML text and returns an array of found elements
136
143
Parser . prototype . parseTags = function ( ) {
137
- var buffer = this . _buffer ,
138
- stack = this . _tagStack ;
144
+ var buffer = this . _buffer ;
139
145
140
146
var next ,
141
- type ,
142
147
tagSep ,
143
148
rawData ,
144
149
element ,
@@ -174,75 +179,65 @@ Parser.prototype.parseTags = function() {
174
179
elementName = "" ;
175
180
}
176
181
177
- type = stack [ stack . length - 1 ] ;
178
-
179
182
//This section inspects the current tag stack and modifies the current
180
183
//element if we're actually parsing a special area (script/comment/style tag)
181
- if ( type === ElementType . Comment ) {
184
+ if ( this . _contentFlags === 0 ) {
185
+ /*do nothing*/
186
+ } else if ( this . _contentFlags >= SpecialTags [ ElementType . Comment ] ) {
182
187
//We're currently in a comment tag
183
-
184
- prevElement = this . _elements [ this . _elements . length - 1 ] ;
188
+ elementType = ElementType . Comment ; //Change the current element's type to a comment
185
189
186
190
if ( tagSep === ">" && rawData . substr ( - 2 ) === "--" ) {
187
191
//comment ends
188
- stack . pop ( ) ;
189
- rawData = rawData . slice ( 0 , - 2 ) ;
190
- //If the previous element is a comment, append the current text to it
191
- if ( prevElement && prevElement . type === ElementType . Comment ) {
192
- //Previous element was a comment
193
- prevElement . data = prevElement . raw += rawData ;
194
- //This causes the current element to not be added to the element list
195
- rawData = elementData = "" ;
196
- elementType = ElementType . Text ;
197
- } else elementType = ElementType . Comment ; //Change the current element's type to a comment
198
- } else {
199
- //Still in a comment tag
200
- elementType = ElementType . Comment ;
201
- //If the previous element is a comment, append the current text to it
202
- if ( prevElement && prevElement . type === ElementType . Comment ) {
203
- prevElement . data = prevElement . raw += rawData + tagSep ;
204
- //This causes the current element to not be added to the element list
205
- rawData = elementData = "" ;
206
- elementType = ElementType . Text ;
207
- } else elementData = rawData += tagSep ;
208
- }
209
- } else if ( type === ElementType . Script && elementName === "/script" )
210
- stack . pop ( ) ;
211
- else if ( type === ElementType . Style && elementName === "/style" )
212
- stack . pop ( ) ;
192
+ this . _contentFlags -= SpecialTags [ ElementType . Comment ] ;
193
+ elementData = rawData = rawData . slice ( 0 , - 2 ) ;
194
+ } else elementData = rawData += tagSep ;
195
+ this . _prevTagSep = tagSep ;
196
+ }
197
+ //if it's a closing tag, remove the flag
213
198
else if (
214
- ! this . _options . xmlMode &&
215
- ( type === ElementType . Script || type === ElementType . Style )
199
+ this . _contentFlags >= SpecialTags [ ElementType . Script ] &&
200
+ elementName === "/script"
201
+ ) {
202
+ this . _contentFlags %= SpecialTags [ "w" ] ; //remove the written flag
203
+ this . _contentFlags -= SpecialTags [ ElementType . Script ] ;
204
+ } else if (
205
+ this . _contentFlags >= SpecialTags [ ElementType . Style ] &&
206
+ elementName === "/style"
216
207
) {
217
- //special behaviour for script & style tags
218
- if ( rawData . substring ( 0 , 3 ) !== "!--" ) {
219
- //Make sure we're not in a comment
220
- //All data from here to style close is now a text element
221
- elementType = ElementType . Text ;
222
- //If the previous element is text, append the current text to it
223
- prevElement = this . _elements [ this . _elements . length - 1 ] ;
224
- if ( prevElement && prevElement . type === ElementType . Text ) {
225
- prevElement . data = prevElement . raw +=
226
- this . _prevTagSep + rawData ;
227
- //This causes the current element to not be added to the element list
228
- rawData = elementData = "" ;
229
- } else elementData = rawData ; //The previous element was not text
208
+ this . _contentFlags %= SpecialTags [ "w" ] ; //remove the written flag
209
+ this . _contentFlags -= SpecialTags [ ElementType . Style ] ;
210
+ }
211
+ //special behaviour for script & style tags
212
+ //Make sure we're not in a comment
213
+ else if ( ! this . _options . xmlMode && rawData . substring ( 0 , 3 ) !== "!--" ) {
214
+ //All data from here to style close is now a text element
215
+ elementType = ElementType . Text ;
216
+ //If the previous element is text, append the last tag sep to element
217
+ if ( this . _contentFlags >= SpecialTags [ "w" ] ) {
218
+ elementData = rawData = this . _prevTagSep + rawData ;
219
+ } else {
220
+ //The previous element was not text
221
+ this . _contentFlags += SpecialTags [ "w" ] ;
222
+ elementData = rawData ;
230
223
}
224
+ this . _prevTagSep = tagSep ;
231
225
}
232
226
233
227
//Processing of non-special tags
234
228
if ( elementType === ElementType . Tag ) {
235
229
if ( rawData . substring ( 0 , 3 ) === "!--" ) {
236
230
//This tag is really comment
237
231
elementType = ElementType . Comment ;
238
- elementData = rawData = rawData . substr ( 3 ) ;
232
+ this . _contentFlags %= SpecialTags [ "w" ] ; //remove the written flag
239
233
//Check if the comment is terminated in the current element
240
234
if ( tagSep === ">" && rawData . substr ( - 2 ) === "--" )
241
- elementData = rawData = rawData . slice ( 0 , - 2 ) ;
235
+ elementData = rawData = rawData . slice ( 3 , - 2 ) ;
242
236
else {
243
237
//It's not so push the comment onto the tag stack
244
- rawData += tagSep ;
245
- stack . push ( ElementType . Comment ) ;
238
+ elementData = rawData = rawData . substr ( 3 ) + tagSep ;
239
+ this . _contentFlags += SpecialTags [ ElementType . Comment ] ;
240
+ this . _prevTagSep = tagSep ;
246
241
}
247
242
} else {
248
243
includeName = true ;
@@ -259,13 +254,17 @@ Parser.prototype.parseTags = function() {
259
254
} else if ( elementName === "script" ) {
260
255
elementType = ElementType . Script ;
261
256
//Special tag, push onto the tag stack if not terminated
262
- if ( elementData . substr ( - 1 ) !== "/" )
263
- stack . push ( ElementType . Script ) ;
257
+ if ( elementData . substr ( - 1 ) !== "/" ) {
258
+ this . _contentFlags += SpecialTags [ ElementType . Script ] ;
259
+ this . _prevTagSep = tagSep ;
260
+ }
264
261
} else if ( elementName === "style" ) {
265
262
elementType = ElementType . Style ;
266
263
//Special tag, push onto the tag stack if not terminated
267
- if ( elementData . substr ( - 1 ) !== "/" )
268
- stack . push ( ElementType . Style ) ;
264
+ if ( elementData . substr ( - 1 ) !== "/" ) {
265
+ this . _contentFlags += SpecialTags [ ElementType . Style ] ;
266
+ this . _prevTagSep = tagSep ;
267
+ }
269
268
}
270
269
}
271
270
}
@@ -298,32 +297,26 @@ Parser.prototype.parseTags = function() {
298
297
/*
299
298
switch(elementType){
300
299
case ElementType.Text:
301
- this._handler.ontext(rawData);
302
- break;
303
- case ElementType.Tag:
304
- case ElementType.Style:
305
- case ElementType.Script:
306
- if(elementName[0] === "/") this._handler.onclosetag(elementName.substr(1));
307
- else this._handler.onopentag(elementName, parseAttributes(elementData));
300
+ this._handler.writeText(element);
308
301
break;
309
302
case ElementType.Comment:
310
- this._handler.oncomment(rawData );
303
+ this._handler.writeComment(element );
311
304
break;
312
305
case ElementType.Directive:
313
- this._handler.onprocessinginstruction(rawData );
306
+ this._handler.writeDirective(element );
314
307
break;
315
- default: throw Error("Unsupported type: " + elementType);
308
+ //case ElementType.Tag:
309
+ //case ElementType.Style:
310
+ //case ElementType.Script:
311
+ default:
312
+ if(elementName[0] === "/") this._handler._closeTag(elementName.substr(1));
313
+ else this._handler._openTag(elementName, parseAttributes(elementData));
316
314
}
317
315
*/
318
316
319
317
//If tag self-terminates, add an explicit, separate closing tag
320
- if (
321
- elementType !== ElementType . Text &&
322
- elementType !== ElementType . Comment &&
323
- elementType !== ElementType . Directive &&
324
- elementData . substr ( - 1 ) === "/"
325
- ) {
326
- //this._handler.onclosetag(elementName);
318
+ if ( tagTypes [ elementType ] && elementData . substr ( - 1 ) === "/" ) {
319
+ //this._handler._closeTag(elementName);
327
320
this . _elements . push ( {
328
321
raw : ( elementName = "/" + elementName ) ,
329
322
data : elementName ,
@@ -334,7 +327,6 @@ Parser.prototype.parseTags = function() {
334
327
}
335
328
this . _parseState = tagSep === "<" ? ElementType . Tag : ElementType . Text ;
336
329
this . _current = next + 1 ;
337
- this . _prevTagSep = tagSep ;
338
330
}
339
331
340
332
if ( this . _options . includeLocation ) {
@@ -360,17 +352,18 @@ Parser.prototype.getLocation = function(startTag) {
360
352
( end = this . _current ) , ( chunk = false ) ;
361
353
}
362
354
363
- var rows = this . _buffer
364
- . substring ( l . charOffset , ( l . charOffset = end ) )
365
- . split ( "\n" ) ,
355
+ var rows = this . _buffer . substring ( l . charOffset , end ) . split ( "\n" ) ,
366
356
rowNum = rows . length - 1 ;
367
357
358
+ l . charOffset = end ;
368
359
l . inBuffer += rowNum ;
369
360
370
361
var num = rows [ rowNum ] . replace ( _reRow , "" ) . length ;
371
- if ( rowNum == 0 ) l . col += num ;
362
+ if ( rowNum === 0 ) l . col += num ;
372
363
else l . col = num ;
373
364
365
+ if ( arguments . length === 0 ) return ;
366
+
374
367
return {
375
368
line : l . row + l . inBuffer + 1 ,
376
369
col : l . col + ( chunk ? 0 : 1 )
@@ -394,8 +387,7 @@ var validateHandler = function(handler) {
394
387
} ;
395
388
396
389
//Writes parsed elements out to the handler
397
- Parser . prototype . writeHandler = function ( forceFlush ) {
398
- if ( this . _tagStack . length && ! forceFlush ) return ;
390
+ Parser . prototype . writeHandler = function ( ) {
399
391
while ( this . _elements . length ) {
400
392
var element = this . _elements . shift ( ) ;
401
393
switch ( element . type ) {
0 commit comments