Skip to content
This repository has been archived by the owner on Oct 22, 2020. It is now read-only.

Commit

Permalink
Replaced _tagStack with _contentFlags, tweaked DefaultHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
fb55 committed Nov 5, 2011
1 parent 5ce005d commit b0276b3
Showing 1 changed file with 78 additions and 81 deletions.
159 changes: 78 additions & 81 deletions Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ function Parser(handler, options){

this._buffer = "";
this._prevTagSep = "";
this._contentFlags = 0;
this._done = false;
this._tagStack = [];
this._elements = [];
this._current = 0;
this._location = {
Expand Down Expand Up @@ -64,10 +64,10 @@ Parser.prototype.done = function(){
var rawData = this._buffer;
this._buffer = "";
var element = {
raw: rawData
, data: this._parseState === ElementType.Text ? rawData : rawData.trim()
, type: this._parseState
};
raw: rawData,
data: this._parseState === ElementType.Text ? rawData : rawData.trim(),
type: this._parseState
};
if(tagTypes[this._parseState]){
element.name = parseTagName(element.data);
var attrs = parseAttributes(element.data);
Expand All @@ -76,7 +76,7 @@ Parser.prototype.done = function(){
this._elements.push(element);
}

this.writeHandler(true);
this.writeHandler();
this._handler.done();
};

Expand All @@ -86,14 +86,14 @@ Parser.prototype.reset = function(){
this._prevTagSep = "";
this._done = false;
this._current = 0;
this._contentFlags = 0;
this._location = {
row: 0
, col: 0
, charOffset: 0
, inBuffer: 0
};
this._parseState = ElementType.Text;
this._tagStack = [];
this._elements = [];
this._handler.reset();
};
Expand Down Expand Up @@ -125,11 +125,18 @@ var parseTagName = function(data){
return match[1] + match[2];
};

//Special tags that are threated differently
var SpecialTags = {};
SpecialTags[ElementType.Style] = 1; //2^0
SpecialTags[ElementType.Script] = 2; //2^1
SpecialTags["w"] = 4; //2^2 - if set, append prev tag sep to data
SpecialTags[ElementType.Comment] = 8; //2^8

//Parses through HTML text and returns an array of found elements
Parser.prototype.parseTags = function(){
var buffer = this._buffer, stack = this._tagStack;
var buffer = this._buffer;

var next, type, tagSep, rawData, element, elementName, prevElement, elementType, elementData, attributes, includeName = false;
var next, tagSep, rawData, element, elementName, prevElement, elementType, elementData, attributes, includeName = false;

var opening = buffer.indexOf("<"), closing = buffer.indexOf(">");

Expand All @@ -155,55 +162,44 @@ Parser.prototype.parseTags = function(){
elementData = rawData;
elementName = "";
}

type = stack[stack.length-1];


//This section inspects the current tag stack and modifies the current
//element if we're actually parsing a special area (script/comment/style tag)
if(type === ElementType.Comment){ //We're currently in a comment tag

prevElement = this._elements[this._elements.length - 1];
if(this._contentFlags === 0){ /*do nothing*/ }
else if(this._contentFlags >= SpecialTags[ElementType.Comment]){ //We're currently in a comment tag
elementType = ElementType.Comment; //Change the current element's type to a comment

if(tagSep === ">" && rawData.substr(-2) === "--"){ //comment ends
stack.pop();
rawData = rawData.slice(0, -2);
//If the previous element is a comment, append the current text to it
if(prevElement && prevElement.type === ElementType.Comment){ //Previous element was a comment
prevElement.data = prevElement.raw += rawData;
//This causes the current element to not be added to the element list
rawData = elementData = "";
elementType = ElementType.Text;
}
else elementType = ElementType.Comment; //Change the current element's type to a comment
}
else { //Still in a comment tag
elementType = ElementType.Comment;
//If the previous element is a comment, append the current text to it
if(prevElement && prevElement.type === ElementType.Comment){
prevElement.data = prevElement.raw += rawData + tagSep;
//This causes the current element to not be added to the element list
rawData = elementData = "";
elementType = ElementType.Text;
}
else elementData = rawData += tagSep;
this._contentFlags -= SpecialTags[ElementType.Comment];
elementData = rawData = rawData.slice(0, -2);
}
else elementData = rawData += tagSep;
this._prevTagSep = tagSep;
}
else if(type === ElementType.Script && elementName === "/script") stack.pop();
else if(type === ElementType.Style && elementName === "/style") stack.pop();
else if(!this._options.xmlMode && (type === ElementType.Script || type === ElementType.Style)){
//special behaviour for script & style tags
if(rawData.substring(0, 3) !== "!--"){ //Make sure we're not in a comment
//All data from here to style close is now a text element
elementType = ElementType.Text;
//If the previous element is text, append the current text to it
prevElement = this._elements[this._elements.length - 1];
if(prevElement && prevElement.type === ElementType.Text){
prevElement.data = prevElement.raw += this._prevTagSep + rawData;
//This causes the current element to not be added to the element list
rawData = elementData = "";
} else elementData = rawData; //The previous element was not text
//if it's a closing tag, remove the flag
else if(this._contentFlags >= SpecialTags[ElementType.Script] && elementName === "/script"){
this._contentFlags %= SpecialTags["w"]; //remove the written flag
this._contentFlags -= SpecialTags[ElementType.Script];
}
else if(this._contentFlags >= SpecialTags[ElementType.Style] && elementName === "/style"){
this._contentFlags %= SpecialTags["w"]; //remove the written flag
this._contentFlags -= SpecialTags[ElementType.Style];
}
//special behaviour for script & style tags
//Make sure we're not in a comment
else if(!this._options.xmlMode && rawData.substring(0, 3) !== "!--"){
//All data from here to style close is now a text element
elementType = ElementType.Text;
//If the previous element is text, append the last tag sep to element
if(this._contentFlags >= SpecialTags["w"]){
elementData = rawData = this._prevTagSep + rawData;
}
else{ //The previous element was not text
this._contentFlags += SpecialTags["w"];
elementData = rawData;
}
this._prevTagSep = tagSep;
}


Expand All @@ -212,13 +208,14 @@ Parser.prototype.parseTags = function(){
if(elementType === ElementType.Tag){
if(rawData.substring(0, 3) === "!--"){ //This tag is really comment
elementType = ElementType.Comment;
elementData = rawData = rawData.substr(3);
this._contentFlags %= SpecialTags["w"]; //remove the written flag
//Check if the comment is terminated in the current element
if(tagSep === ">" && rawData.substr(-2) === "--")
elementData = rawData = rawData.slice(0, -2);
elementData = rawData = rawData.slice(3, -2);
else { //It's not so push the comment onto the tag stack
rawData += tagSep;
stack.push(ElementType.Comment);
elementData = rawData = rawData.substr(3) + tagSep;
this._contentFlags += SpecialTags[ElementType.Comment];
this._prevTagSep = tagSep;
}
}
else {
Expand All @@ -236,12 +233,18 @@ Parser.prototype.parseTags = function(){
else if(elementName === "script"){
elementType = ElementType.Script;
//Special tag, push onto the tag stack if not terminated
if(elementData.substr(-1) !== "/") stack.push(ElementType.Script);
if(elementData.substr(-1) !== "/"){
this._contentFlags += SpecialTags[ElementType.Script];
this._prevTagSep = tagSep;
}
}
else if(elementName === "style"){
elementType = ElementType.Style;
//Special tag, push onto the tag stack if not terminated
if(elementData.substr(-1) !== "/") stack.push(ElementType.Style);
if(elementData.substr(-1) !== "/"){
this._contentFlags += SpecialTags[ElementType.Style];
this._prevTagSep = tagSep;
}
}
}
}
Expand Down Expand Up @@ -271,42 +274,35 @@ Parser.prototype.parseTags = function(){
/*
switch(elementType){
case ElementType.Text:
this._handler.ontext(rawData);
break;
case ElementType.Tag:
case ElementType.Style:
case ElementType.Script:
if(elementName[0] === "/") this._handler.onclosetag(elementName.substr(1));
else this._handler.onopentag(elementName, parseAttributes(elementData));
this._handler.writeText(element);
break;
case ElementType.Comment:
this._handler.oncomment(rawData);
this._handler.writeComment(element);
break;
case ElementType.Directive:
this._handler.onprocessinginstruction(rawData);
this._handler.writeDirective(element);
break;
default: throw Error("Unsupported type: " + elementType);
//case ElementType.Tag:
//case ElementType.Style:
//case ElementType.Script:
default:
if(elementName[0] === "/") this._handler._closeTag(elementName.substr(1));
else this._handler._openTag(elementName, parseAttributes(elementData));
}
*/

//If tag self-terminates, add an explicit, separate closing tag
if( elementType !== ElementType.Text
&& elementType !== ElementType.Comment
&& elementType !== ElementType.Directive
&& elementData.substr(-1) === "/"
){
//this._handler.onclosetag(elementName);
if(tagTypes[elementType] && elementData.substr(-1) === "/"){
//this._handler._closeTag(elementName);
this._elements.push({
raw: elementName = "/" + elementName
, data: elementName
, name: elementName
, type: elementType
raw: elementName = "/" + elementName,
data: elementName, name: elementName,
type: elementType
});
}
}
this._parseState = (tagSep === "<") ? ElementType.Tag : ElementType.Text;
this._current = next + 1;
this._prevTagSep = tagSep;
}

if(this._options.includeLocation){
Expand All @@ -332,15 +328,18 @@ Parser.prototype.getLocation = function(startTag){
chunk = false;
}

var rows = this._buffer.substring(l.charOffset, l.charOffset = end).split("\n"),
var rows = this._buffer.substring(l.charOffset, end).split("\n"),
rowNum = rows.length - 1;

l.charOffset = end;
l.inBuffer += rowNum;

var num = rows[rowNum].replace(_reRow,"").length;
if(rowNum == 0) l.col += num;
if(rowNum === 0) l.col += num;
else l.col = num;

if(arguments.length === 0) return;

return {
line: l.row + l.inBuffer + 1,
col: l.col + (chunk ? 0: 1)
Expand All @@ -358,9 +357,7 @@ var validateHandler = function(handler){
};

//Writes parsed elements out to the handler
Parser.prototype.writeHandler = function(forceFlush){
if(this._tagStack.length && !forceFlush)
return;
Parser.prototype.writeHandler = function(){
while (this._elements.length){
var element = this._elements.shift();
switch (element.type){
Expand Down

0 comments on commit b0276b3

Please sign in to comment.