endTag = /^<\/([\w:-]+)[^>]*>/,
attr = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,
doctype = /^<!DOCTYPE [^>]+>/i;
-
+
// Empty Elements - HTML 4.01
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");
// Special Elements (can contain anything)
var special = makeMap("script,style");
-
+
var reCache = { }, stackedTag, re;
var HTMLParser = global.HTMLParser = function( html, handler ) {
// Comment
if ( html.indexOf("<!--") === 0 ) {
index = html.indexOf("-->");
-
+
if ( index >= 0 ) {
if ( handler.comment )
handler.comment( html.substring( 4, index ) );
handler.doctype( match[0] );
html = html.substring( match[0].length );
chars = false;
-
+
// end tag
} else if ( html.indexOf("</") === 0 ) {
match = html.match( endTag );
-
+
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( endTag, parseEndTag );
prevTag = '/'+match[1];
chars = false;
}
-
+
// start tag
} else if ( html.indexOf("<") === 0 ) {
match = html.match( startTag );
-
+
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( startTag, parseStartTag );
if ( chars ) {
index = html.indexOf("<");
-
+
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? "" : html.substring( index );
-
+
// next tag
tagMatch = html.match( startTag );
if (tagMatch) {
nextTag = '';
}
}
-
+
if ( handler.chars )
handler.chars(text, prevTag, nextTag);
-
+
}
} else {
-
+
stackedTag = stack.last().toLowerCase();
reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp("([\\s\\S]*?)<\/" + stackedTag + "[^>]*>", "i"));
-
+
html = html.replace(reStackedTag, function(all, text) {
if (stackedTag !== 'script' && stackedTag !== 'style') {
text = text
throw "Parse Error: " + html;
last = html;
}
-
+
// Clean up any remaining tags
parseEndTag();
function parseStartTag( tag, tagName, rest, unary ) {
- if ( block[ tagName ] ) {
- while ( stack.last() && inline[ stack.last() ] ) {
- parseEndTag( "", stack.last() );
- }
- }
if ( closeSelf[ tagName ] && stack.last() == tagName ) {
parseEndTag( "", tagName );
if ( !unary )
stack.push( tagName );
-
+
if ( handler.start ) {
var attrs = [];
-
+
rest.replace(attr, function(match, name) {
var value = arguments[2] ? arguments[2] :
arguments[3] ? arguments[3] :
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
});
});
-
+
if ( handler.start )
handler.start( tagName, attrs, unary );
}
// If no tag name is provided, clean shop
if ( !tagName )
var pos = 0;
-
+
// Find the closest opened tag of the same type
else
for ( var pos = stack.length - 1; pos >= 0; pos-- )
if ( stack[ pos ] == tagName )
break;
-
+
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( var i = stack.length - 1; i >= pos; i-- )
if ( handler.end )
handler.end( stack[ i ] );
-
+
// Remove the open elements from the stack
stack.length = pos;
}
}
};
-
+
global.HTMLtoXML = function( html ) {
var results = "";
-
+
HTMLParser(html, {
start: function( tag, attrs, unary ) {
results += "<" + tag;
-
+
for ( var i = 0; i < attrs.length; i++ )
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
-
+
results += (unary ? "/" : "") + ">";
},
end: function( tag ) {
results += "<!--" + text + "-->";
}
});
-
+
return results;
};
-
+
global.HTMLtoDOM = function( html, doc ) {
// There can be only one of these elements
var one = makeMap("html,head,body,title");
-
+
// Enforce a structure for the document
var structure = {
link: "head",
base: "head"
};
-
+
if ( !doc ) {
if ( typeof DOMDocument != "undefined" )
doc = new DOMDocument();
doc = document.implementation.createDocument("", "", null);
else if ( typeof ActiveX != "undefined" )
doc = new ActiveXObject("Msxml.DOMDocument");
-
+
} else
doc = doc.ownerDocument ||
doc.getOwnerDocument && doc.getOwnerDocument() ||
doc;
-
+
var elems = [],
documentElement = doc.documentElement ||
doc.getDocumentElement && doc.getDocumentElement();
-
+
// If we're dealing with an empty document then we
// need to pre-populate it with the HTML document structure
if ( !documentElement && doc.createElement ) (function(){
html.appendChild( doc.createElement("body") );
doc.appendChild( html );
})();
-
+
// Find all the unique elements
if ( doc.getElementsByTagName )
for ( var i in one )
one[ i ] = doc.getElementsByTagName( i )[0];
-
+
// If we're working with a document, inject contents into
// the body element
var curParentNode = one.body;
-
+
HTMLParser( html, {
start: function( tagName, attrs, unary ) {
// If it's a pre-built element, then we can ignore
curParentNode = one[ tagName ];
return;
}
-
+
var elem = doc.createElement( tagName );
-
+
for ( var attr in attrs )
elem.setAttribute( attrs[ attr ].name, attrs[ attr ].value );
-
+
if ( structure[ tagName ] && typeof one[ structure[ tagName ] ] != "boolean" )
one[ structure[ tagName ] ].appendChild( elem );
-
+
else if ( curParentNode && curParentNode.appendChild )
curParentNode.appendChild( elem );
-
+
if ( !unary ) {
elems.push( elem );
curParentNode = elem;
},
end: function( tag ) {
elems.length -= 1;
-
+
// Init the new parentNode
curParentNode = elems[ elems.length - 1 ];
},
// create comment node
}
});
-
+
return doc;
};
endTag = /^<\/([\w:-]+)[^>]*>/,
attr = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,
doctype = /^<!DOCTYPE [^>]+>/i;
-
+
// Empty Elements - HTML 4.01
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");
// Special Elements (can contain anything)
var special = makeMap("script,style");
-
+
var reCache = { }, stackedTag, re;
var HTMLParser = global.HTMLParser = function( html, handler ) {
// Comment
if ( html.indexOf("<!--") === 0 ) {
index = html.indexOf("-->");
-
+
if ( index >= 0 ) {
if ( handler.comment )
handler.comment( html.substring( 4, index ) );
handler.doctype( match[0] );
html = html.substring( match[0].length );
chars = false;
-
+
// end tag
} else if ( html.indexOf("</") === 0 ) {
match = html.match( endTag );
-
+
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( endTag, parseEndTag );
prevTag = '/'+match[1];
chars = false;
}
-
+
// start tag
} else if ( html.indexOf("<") === 0 ) {
match = html.match( startTag );
-
+
if ( match ) {
html = html.substring( match[0].length );
match[0].replace( startTag, parseStartTag );
if ( chars ) {
index = html.indexOf("<");
-
+
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? "" : html.substring( index );
-
+
// next tag
tagMatch = html.match( startTag );
if (tagMatch) {
nextTag = '';
}
}
-
+
if ( handler.chars )
handler.chars(text, prevTag, nextTag);
-
+
}
} else {
-
+
stackedTag = stack.last().toLowerCase();
reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp("([\\s\\S]*?)<\/" + stackedTag + "[^>]*>", "i"));
-
+
html = html.replace(reStackedTag, function(all, text) {
if (stackedTag !== 'script' && stackedTag !== 'style') {
text = text
throw "Parse Error: " + html;
last = html;
}
-
+
// Clean up any remaining tags
parseEndTag();
function parseStartTag( tag, tagName, rest, unary ) {
- if ( block[ tagName ] ) {
- while ( stack.last() && inline[ stack.last() ] ) {
- parseEndTag( "", stack.last() );
- }
- }
if ( closeSelf[ tagName ] && stack.last() == tagName ) {
parseEndTag( "", tagName );
if ( !unary )
stack.push( tagName );
-
+
if ( handler.start ) {
var attrs = [];
-
+
rest.replace(attr, function(match, name) {
var value = arguments[2] ? arguments[2] :
arguments[3] ? arguments[3] :
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
});
});
-
+
if ( handler.start )
handler.start( tagName, attrs, unary );
}
// If no tag name is provided, clean shop
if ( !tagName )
var pos = 0;
-
+
// Find the closest opened tag of the same type
else
for ( var pos = stack.length - 1; pos >= 0; pos-- )
if ( stack[ pos ] == tagName )
break;
-
+
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( var i = stack.length - 1; i >= pos; i-- )
if ( handler.end )
handler.end( stack[ i ] );
-
+
// Remove the open elements from the stack
stack.length = pos;
}
}
};
-
+
global.HTMLtoXML = function( html ) {
var results = "";
-
+
HTMLParser(html, {
start: function( tag, attrs, unary ) {
results += "<" + tag;
-
+
for ( var i = 0; i < attrs.length; i++ )
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
-
+
results += (unary ? "/" : "") + ">";
},
end: function( tag ) {
results += "<!--" + text + "-->";
}
});
-
+
return results;
};
-
+
global.HTMLtoDOM = function( html, doc ) {
// There can be only one of these elements
var one = makeMap("html,head,body,title");
-
+
// Enforce a structure for the document
var structure = {
link: "head",
base: "head"
};
-
+
if ( !doc ) {
if ( typeof DOMDocument != "undefined" )
doc = new DOMDocument();
doc = document.implementation.createDocument("", "", null);
else if ( typeof ActiveX != "undefined" )
doc = new ActiveXObject("Msxml.DOMDocument");
-
+
} else
doc = doc.ownerDocument ||
doc.getOwnerDocument && doc.getOwnerDocument() ||
doc;
-
+
var elems = [],
documentElement = doc.documentElement ||
doc.getDocumentElement && doc.getDocumentElement();
-
+
// If we're dealing with an empty document then we
// need to pre-populate it with the HTML document structure
if ( !documentElement && doc.createElement ) (function(){
html.appendChild( doc.createElement("body") );
doc.appendChild( html );
})();
-
+
// Find all the unique elements
if ( doc.getElementsByTagName )
for ( var i in one )
one[ i ] = doc.getElementsByTagName( i )[0];
-
+
// If we're working with a document, inject contents into
// the body element
var curParentNode = one.body;
-
+
HTMLParser( html, {
start: function( tagName, attrs, unary ) {
// If it's a pre-built element, then we can ignore
curParentNode = one[ tagName ];
return;
}
-
+
var elem = doc.createElement( tagName );
-
+
for ( var attr in attrs )
elem.setAttribute( attrs[ attr ].name, attrs[ attr ].value );
-
+
if ( structure[ tagName ] && typeof one[ structure[ tagName ] ] != "boolean" )
one[ structure[ tagName ] ].appendChild( elem );
-
+
else if ( curParentNode && curParentNode.appendChild )
curParentNode.appendChild( elem );
-
+
if ( !unary ) {
elems.push( elem );
curParentNode = elem;
},
end: function( tag ) {
elems.length -= 1;
-
+
// Init the new parentNode
curParentNode = elems[ elems.length - 1 ];
},
// create comment node
}
});
-
+
return doc;
};
equal(minify('<a title="x"href=" ">foo</a>'), '<a title="x" href="">foo</a>');
equal(minify('<p id=""class=""title="">x'), '<p id="" class="" title="">x</p>');
equal(minify('<p x="x\'"">x</p>'), '<p x="x\'">x</p>', 'trailing quote should be ignored');
-
+ equal(minify('<a href="#"><p>Click me</p></a>'), '<a href="#"><p>Click me</p></a>');
+ equal(minify('<span><button>Hit me</button></span>'), '<span><button>Hit me</button></span>');
+
equal(minify('<ng-include src="x"></ng-include>'), '<ng-include src="x"></ng-include>');
equal(minify('<ng:include src="x"></ng:include>'), '<ng:include src="x"></ng:include>');
equal(minify('<ng-include src="\'views/partial-notification.html\'"></ng-include><div ng-view></div>'), '<ng-include src="\'views/partial-notification.html\'"></ng-include><div ng-view=""></div>');
input = '<p> foo bar</p>';
output = '<p>foo bar</p>';
equal(minify(input, { collapseWhitespace: true }), output);
-
+
input = '<p> foo <span> blah <i> 22</i> </span> bar <img src=""></p>';
output = '<p>foo <span>blah <i>22</i></span> bar <img src=""></p>';
equal(minify(input, { collapseWhitespace: true }), output);