-/*
- * Original code by Erik John Resig (ejohn.org)
- * http://ejohn.org/blog/pure-javascript-html-parser/
- *
- */
-
-(function(){
-
- var alphabets = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
- whiteSpace = '\t\r\n\f\b ';
-
- // Empty Elements - HTML 4.01
- var empty = {area:1,base:1,basefont:1,br:1,col:1,frame:1,hr:1,img:1,input:1,isindex:1,link:1,meta:1,param:1,embed:1};
-
- // Block Elements - HTML 4.01
- var block = {address:1,applet:1,blockquote:1,button:1,center:1,dd:1,del:1,dir:1,div:1,dl:1,dt:1,fieldset:1,form:1,frameset:1,hr:1,iframe:1,ins:1,isindex:1,li:1,map:1,menu:1,noframes:1,noscript:1,object:1,ol:1,p:1,pre:1,script:1,table:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,ul:1};
-
- // Inline Elements - HTML 4.01
- var inline = {a:1,abbr:1,acronym:1,applet:1,b:1,basefont:1,bdo:1,big:1,br:1,button:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,iframe:1,img:1,input:1,ins:1,kbd:1,label:1,map:1,object:1,q:1,s:1,samp:1,script:1,select:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,textarea:1,tt:1,u:1,'var':1};
-
- // Elements that you can, intentionally, leave open
- // (and which close themselves)
- var closeSelf = {colgroup:1,dd:1,dt:1,li:1,options:1,p:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}; // add tbody
-
- var sisters = {
- th : { td : 1 },
- td : { th : 1 },
- dt : { dd : 1 },
- dd : { dt : 1 },
- colgroup : { caption : 1 },
- thead : { caption : 1, colgroup : 1 },
- tfoot : { caption : 1, colgroup : 1, thead : 1, tbody : 1 },
- tbody : { caption : 1, colgroup : 1, thead : 1, tfoot : 1 }
- };
- /*
- * http://www.tohoho-web.com/html/tbody.htm
- * HTML4.01では、ヘッダとフッタを先読みして表示するために、<tbody> よりも <tfoot> の方を先に記述しなくてはならないと定義されています。
- * IE5.0 などでは HEAD → BODY → FOOT の順に表示するのですが、
- * <tfoot> に未対応の古いブラウザでは、HEAD → FOOT → BODY の順に表示されてしまいます。
- * また、HTML5 では、<tfoot> と <tbody> の順番はどちらでもよいことになりました。
- */
-
- // Attributes that have their values filled in disabled="disabled"
- var fillAttrs = X.Dom.Attr.noValue; //{checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};
-
- // Special Elements (can contain anything)
- var special = {script:1,style:1};
-
- X.Dom.Parser = function( html, handler ) {
- var stack = [],
- lastHtml = html,
- chars, last, text, index;
-
- while ( html ) {
- chars = true;
- last = stack[ stack.length - 1 ];
-
- // Make sure we're not in a script or style element
- if ( last && special[ last ] === 1 ) {
- if( 0 <= ( index = _parseEndTag( stack, handler, html ) ) ){
- //handler.chars( html.substring( 0, index ) );
- html = html.substring( index );
- };
- } else {
- // Comment
- if ( html.indexOf("<!--") === 0 ) {
- if ( 0 < ( index = html.indexOf("-->") ) ) {
- handler.comment( html.substring( 4, index ) );
- html = html.substring( index + 3 );
- chars = false;
- };
-
- // end tag
- } else if ( html.indexOf("</") === 0 ) {
- if ( 2 < ( index = _parseEndTag( stack, handler, html ) ) ) {
- html = html.substring( index );
- chars = false;
- };
-
- // start tag
- } else if ( html.indexOf("<") === 0 ) {
- if( index = _parseStartTag( stack, last, handler, html ) ){
- html = html.substring( index );
- chars = false;
- } else
- if( index === false ){
- return;
- };
- };
-
- if ( chars ) {
- index = html.indexOf("<");
-
- text = index < 0 ? html : html.substring( 0, index );
- html = index < 0 ? '' : html.substring( index );
-
- handler.chars( text );
- };
-
- };
-
- if ( html === lastHtml ){
- handler.err( html );
- return;
- };
- lastHtml = html;
- };
-
- // Clean up any remaining tags
- parseEndTag( stack, handler );
- };
-
- function _parseStartTag( stack, last, handler, html ){
- var phase = 0,
- l = html.length,
- i = 0,
- attrs = [],
- tagName, empty,
- chr, start, attrName, quot, escape;
-
- while( i < l && phase < 9 ){
- chr = html.charAt( i );
- switch( phase ){
- case 0 :
- chr === '<' && ( ++phase );
- break;
- case 1 : // タグ名の開始を待つ
- alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );
- break;
- case 2 : // タグ名の終わりの空白文字を待つ
- whiteSpace.indexOf( chr ) !== -1 ?
- ( ++phase && ( tagName = html.substring( start, i ) ) ) :
- ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&
- ( ( tagName = html.substring( start, i ) ) && ( phase = 9 ) );
- break;
- case 3 : // 属性名の開始を待つ
- alphabets.indexOf( chr ) !== -1 ?
- ( ++phase && ( start = i ) ) :
- ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&
- ( phase = 9 );
- break;
- case 4 : // 属性名の終わりを待つ
- chr === '=' ?
- ( ( phase = 6 ) && ( attrName = html.substring( start, i ) ) ) :
- whiteSpace.indexOf( chr ) !== -1 &&
- ( ( phase = 5 ) && ( attrName = html.substring( start, i ) ) );
- break;
- case 5 : // 属性の = または次の属性または htmlタグの閉じ
- alphabets.indexOf( chr ) !== -1 ?
- ( ( phase = 4 ) && ( attrs[ attrs.length ] = attrName ) && ( start = i ) ) :
- chr === '=' ?
- ( phase = 6 ) :
- ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&
- ( ( phase = 9 ) && ( attrs[ attrs.length ] = attrName ) );
- break;
- case 6 : // 属性値の開始 quot を待つ
- ( chr === '"' || chr === "'" ) ?
- ( ( phase = 7 ) && ( quot = chr ) && ( start = i + 1 ) ):
- whiteSpace.indexOf( chr ) === -1 &&
- ( ( phase = 8 ) && ( start = i ) ); // no quot
- break;
- case 7 : //属性値の閉じ quot を待つ
- !escape && ( chr === quot ) && ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) );
- break;
- case 8 : //閉じ quot のない属性の値
- whiteSpace.indexOf( chr ) !== -1 ?
- ( ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) ) :
- ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&
- ( ( phase = 9 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) );
- break;
- };
- escape = chr === '\\' && !escape; // \\\\ is not escape for "
- ++i;
- };
- if( phase === 9 ){
- if( parseStartTag( stack, last, handler, tagName.toLowerCase(), attrs, empty, i ) === false ) return false;;
- return i;
- };
- return 0; // error
- };
-
- function _parseEndTag( stack, handler, html ){
- var phase = 0,
- l = html.length,
- i = 0,
- tagName,
- chr, start;
-
- while( i < l && phase < 9 ){
- chr = html.charAt( i );
- switch( phase ){
- case 0 :
- html.substr( i, 2 ) === '</' && ( ++phase && ++i );
- break;
- case 1 : // タグ名の開始を待つ
- alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );
- break;
- case 2 : // タグ名の終わりの空白文字を待つ
- whiteSpace.indexOf( chr ) !== -1 && ( ++phase );
- ( chr === '>' ) && ( phase = 9 );
- ( phase !== 2 ) && ( tagName = html.substring( start, i ) );
- break;
- case 3 : // 属性名の開始を待つ
- chr === '>' && ( phase = 9 );
- break;
- };
- ++i;
- };
- if( phase === 9 ){
- parseEndTag( stack, handler, tagName.toLowerCase() );
- return i;
- };
- return 0; // error
- };
-
- function saveAttr( attrs, name, value ){
- name = name.toLowerCase();
- value = fillAttrs[ name ] === 1 ? name : value;
- attrs[ attrs.length ] = {
- name : name,
- value : value,
- escaped :
- value.indexOf( '"' ) !== -1 ?
- value.split( '"' ).join( '\\"' ).split( '\\\\"' ).join( '\\"' ) :
- value
- };
- };
-
- function parseStartTag( stack, last, handler, tagName, attrs, unary, index ) {
- if ( block[ tagName ] === 1 ) {
- while ( last && inline[ last ] === 1 ) {
- parseEndTag( stack, handler, last );
- last = stack[ stack.length - 1 ];
- };
- };
- closeSelf[ tagName ] === 1 && ( last === tagName || ( sisters[ tagName ] && sisters[ tagName ][ last ] === 1 ) ) && parseEndTag( stack, handler, last );
- unary = empty[ tagName ] === 1 || !!unary;
- !unary && ( stack[ stack.length ] = tagName );
-
- return handler.start( tagName, attrs, unary, index );
- };
-
- function parseEndTag( stack, handler, tagName ) {
- var pos = 0, i = stack.length;
- // If no tag name is provided, clean shop
-
- // Find the closest opened tag of the same type
- if ( tagName )
- for ( pos = i; 0 <= pos; )
- if ( stack[ --pos ] === tagName )
- break;
-
- if ( 0 <= pos ) {
- // Close all the open elements, up the stack
- for ( ; pos < i; )
- handler.end( stack[ --i ] );
-
- // Remove the open elements from the stack
- stack.length = pos;
- };
- };
-
-})();
-
-X.Dom._htmlStringToXNode = {
- flat : null,
- nest : [],
- err : function( html ){
- this.flat.length = 0;
- this.ignoreError !== true && X.Notification.warn( 'X.Dom.Parser() error ' + html );
- },
- start : function( tagName, attrs, noChild, length ){
- var xnode,
- nest = this.nest,
- flat = this.flat,
- l = nest.length,
- _attrs = {},
- attr, name, i, toIndex;
- if( l ){
- xnode = nest[ l - 1 ].create( tagName );
- } else {
- xnode = flat[ flat.length ] = X.Dom.Node.create( tagName );
- };
- if( !noChild ) nest[ l ] = xnode;
- if( i = attrs.length ){
- toIndex = X.Dom.Attr.toIndex;
- for( ; i; ){
- attr = attrs[ --i ];
- if( attr ){
- if( typeof attr === 'string' ){
- name = attr;
- //i = toIndex[ name ];
- //_attrs[ ( i || i === 0 ) ? i : name ] = name;
- _attrs[ name ] = true;
- } else {
- name = attr.name;
- //i = toIndex[ name ];
- //_attrs[ ( i || i === 0 ) ? i : name ] = attr.escaped;
- _attrs[ name ] = attr.escaped;
- };
- };
- };
- //xnode._attrs = _attrs;
- xnode.attr( _attrs );
- // xnode.css()
- };
- },
- end : function(){
- 0 < this.nest.length && ( --this.nest.length );
- },
- chars : function( text ){
- if( this.nest.length ){
- this.nest[ this.nest.length - 1 ].createText( text );
- } else {
- this.flat[ this.flat.length ] = X.Dom.Node.createText( text );
- };
- },
- comment : function(){
-
- }
-};
-
-X.Dom.parse = function( html, ignoreError ){
- var worker = X.Dom._htmlStringToXNode, ret;
- worker.flat = [];
- worker.nest.length = 0;
- worker.ignoreError = ignoreError;
- X.Dom.Parser( html, worker );
- ret = worker.flat;
- delete worker.flat;
- return ret;
-};
-
+\r
+/*\r
+ * Original code by Erik John Resig (ejohn.org)\r
+ * http://ejohn.org/blog/pure-javascript-html-parser/\r
+ *\r
+ */\r
+\r
+X.Dom.Parser = {\r
+ alphabets : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\r
+ whiteSpace : '\t\r\n\f\b ',\r
+\r
+ // Empty Elements - HTML 4.01\r
+ empty : X.Dom.DTD.EMPTY,\r
+\r
+ // Block Elements - HTML 4.01\r
+ block : {address:1,applet:1,blockquote:1,button:1,center:1,dd:1,del:1,dir:1,div:1,dl:1,dt:1,fieldset:1,form:1,frameset:1,hr:1,iframe:1,ins:1,isindex:1,li:1,map:1,menu:1,noframes:1,noscript:1,object:1,ol:1,p:1,pre:1,script:1,table:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,ul:1},\r
+\r
+ // Inline Elements - HTML 4.01\r
+ inline : {a:1,abbr:1,acronym:1,applet:1,b:1,basefont:1,bdo:1,big:1,br:1,button:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,iframe:1,img:1,input:1,ins:1,kbd:1,label:1,map:1,object:1,q:1,s:1,samp:1,script:1,select:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,textarea:1,tt:1,u:1,'var':1},\r
+\r
+ // Elements that you can, intentionally, leave open\r
+ // (and which close themselves)\r
+ closeSelf : {colgroup:1,dd:1,dt:1,li:1,options:1,p:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}, // add tbody\r
+\r
+ sisters : {\r
+ th : { td : 1 },\r
+ td : { th : 1 },\r
+ dt : { dd : 1 },\r
+ dd : { dt : 1 },\r
+ colgroup : { caption : 1 },\r
+ thead : { caption : 1, colgroup : 1 },\r
+ tfoot : { caption : 1, colgroup : 1, thead : 1, tbody : 1 },\r
+ tbody : { caption : 1, colgroup : 1, thead : 1, tfoot : 1 }\r
+ },\r
+ /*\r
+ * http://www.tohoho-web.com/html/tbody.htm\r
+ * HTML4.01では、ヘッダとフッタを先読みして表示するために、<tbody> よりも <tfoot> の方を先に記述しなくてはならないと定義されています。\r
+ * IE5.0 などでは HEAD → BODY → FOOT の順に表示するのですが、\r
+ * <tfoot> に未対応の古いブラウザでは、HEAD → FOOT → BODY の順に表示されてしまいます。\r
+ * また、HTML5 では、<tfoot> と <tbody> の順番はどちらでもよいことになりました。\r
+ */\r
+\r
+ // Attributes that have their values filled in disabled="disabled"\r
+ fillAttrs : X.Dom.Attr.noValue, //{checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};\r
+\r
+ // Special Elements (can contain anything)\r
+ special : { script : 1, style : 1, plaintext : 1, xmp : 1, textarea : 1 },\r
+ \r
+ exec : function( html, handler, async ){\r
+ var special = X.Dom.Parser.special,\r
+ plainText = X.Dom.Parser.plainText,\r
+ startTime = async && X.getTime(),\r
+ _parseStartTag = X.Dom.Parser._parseStartTag,\r
+ _parseEndTag = X.Dom.Parser._parseEndTag,\r
+ stack = async ? async[ 1 ] : [],\r
+ lastHtml = html,\r
+ chars, last, text, index;\r
+\r
+ while ( html ) {\r
+ chars = true;\r
+ last = stack[ stack.length - 1 ];\r
+ \r
+ // Make sure we're not in a script or style element\r
+ if ( last && special[ last.toLowerCase() ] === 1 ) {\r
+ if( 0 <= ( index = html.toLowerCase().indexOf( '</' + last.toLowerCase() ) ) ){\r
+ handler.chars( html.substring( 0, index ) );\r
+ if( index = _parseEndTag( stack, handler, html ) ){\r
+ html = html.substring( index );\r
+ } else {\r
+ handler.chars( html );\r
+ html = '';\r
+ };\r
+ } else {\r
+ handler.chars( html );\r
+ html = '';\r
+ };\r
+ } else {\r
+ // Comment\r
+ if ( html.indexOf("<!--") === 0 ) {\r
+ if ( 0 < ( index = html.indexOf("-->") ) ) {\r
+ handler.comment( html.substring( 4, index ) );\r
+ html = html.substring( index + 3 );\r
+ chars = false;\r
+ };\r
+ \r
+ // end tag\r
+ } else if ( html.indexOf("</") === 0 ) {\r
+ if ( 2 < ( index = _parseEndTag( stack, handler, html ) ) ) {\r
+ html = html.substring( index );\r
+ chars = false;\r
+ };\r
+ \r
+ // start tag\r
+ } else if ( html.indexOf("<") === 0 ) {\r
+ if( index = _parseStartTag( stack, last, handler, html ) ){\r
+ html = html.substring( index );\r
+ chars = false;\r
+ } else\r
+ if( index === false ){\r
+ return;\r
+ };\r
+ };\r
+\r
+ if ( chars ) {\r
+ index = html.indexOf("<");\r
+ \r
+ text = index < 0 ? html : html.substring( 0, index );\r
+ html = index < 0 ? '' : html.substring( index );\r
+ \r
+ handler.chars( text );\r
+ };\r
+\r
+ };\r
+\r
+ if( html === lastHtml ){\r
+ handler.err( html );\r
+ return;\r
+ };\r
+ \r
+ if( async && startTime + 15 <= X.getTime() && html ){\r
+ handler.progress( 1 - html.length / async[ 0 ] );\r
+ X.Timer.once( 0, X.Dom.Parser.exec, [ html, handler, async ] );\r
+ return;\r
+ };\r
+ \r
+ lastHtml = html;\r
+ };\r
+ \r
+ // Clean up any remaining tags\r
+ X.Dom.Parser.parseEndTag( stack, handler );\r
+ \r
+ async && handler.complete();\r
+ },\r
+\r
+ _parseStartTag : function( stack, last, handler, html ){\r
+ var alphabets = X.Dom.Parser.alphabets,\r
+ whiteSpace = X.Dom.Parser.whiteSpace,\r
+ saveAttr = X.Dom.Parser.saveAttr,\r
+ uri = X.Dom.DTD.ATTR_VAL_IS_URI,\r
+ phase = 0,\r
+ l = html.length,\r
+ i = 0,\r
+ attrs = [],\r
+ tagName, empty = false,\r
+ chr, start, attrName, quot, escape;\r
+ \r
+ while( i < l && phase < 9 ){\r
+ chr = html.charAt( i );\r
+ switch( phase ){\r
+ case 0 :\r
+ chr === '<' && ( ++phase );\r
+ break;\r
+ case 1 : // タグ名の開始を待つ\r
+ alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );\r
+ break;\r
+ case 2 : // タグ名の終わりの空白文字を待つ\r
+ whiteSpace.indexOf( chr ) !== -1 ?\r
+ ( ++phase && ( tagName = html.substring( start, i ) ) ) :\r
+ ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&\r
+ ( ( tagName = html.substring( start, i ) ) && ( phase = 9 ) );\r
+ break;\r
+ case 3 : // 属性名の開始を待つ\r
+ alphabets.indexOf( chr ) !== -1 ?\r
+ ( ++phase && ( start = i ) ) :\r
+ ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&\r
+ ( phase = 9 );\r
+ break;\r
+ case 4 : // 属性名の終わりを待つ\r
+ chr === '=' ?\r
+ ( ( phase = 6 ) && ( attrName = html.substring( start, i ) ) ) :\r
+ whiteSpace.indexOf( chr ) !== -1 &&\r
+ ( ( phase = 5 ) && ( attrName = html.substring( start, i ) ) );\r
+ break;\r
+ case 5 : // 属性の = または次の属性または htmlタグの閉じ\r
+ whiteSpace.indexOf( chr ) !== -1 ?// ie4 未対応の属性には cite = http:// となる\r
+ 1 :\r
+ alphabets.indexOf( chr ) !== -1 ?\r
+ ( ( phase = 4 ) && ( attrs[ attrs.length ] = attrName ) && ( start = i ) ) :\r
+ chr === '=' ?\r
+ ( phase = 6 ) :\r
+ ( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&\r
+ ( ( phase = 9 ) && ( attrs[ attrs.length ] = attrName ) );\r
+ break;\r
+ case 6 : // 属性値の開始 quot を待つ\r
+ ( chr === '"' || chr === "'" ) ?\r
+ ( ( phase = 7 ) && ( quot = chr ) && ( start = i + 1 ) ):\r
+ whiteSpace.indexOf( chr ) === -1 &&\r
+ ( ( phase = 8 ) && ( start = i ) ); // no quot\r
+ break;\r
+ case 7 : //属性値の閉じ quot を待つ\r
+ !escape && ( chr === quot ) && ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) );\r
+ break;\r
+ case 8 : //閉じ quot のない属性の値\r
+ whiteSpace.indexOf( chr ) !== -1 ?\r
+ ( ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) ) :\r
+ ( chr === '>' ) ?\r
+ ( ( phase = 9 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) ) :\r
+ !escape && !uri[ attrName ] && ( empty = html.substr( i, 2 ) === '/>' ) && // attr の val が uri で / で終わりかつ、未対応属性の場合\r
+ ( phase = 9 );\r
+ break;\r
+ };\r
+ escape = chr === '\\' && !escape; // \\\\ is not escape for "\r
+ ++i;\r
+ };\r
+ if( phase === 9 ){\r
+ if( empty ) ++i;\r
+ if( X.Dom.Parser.parseStartTag( stack, last, handler, tagName, attrs, empty, i ) === false ) return false;\r
+ return i;\r
+ };\r
+ return 0; // error\r
+ },\r
+\r
+ _parseEndTag : function( stack, handler, html ){\r
+ var alphabets = X.Dom.Parser.alphabets,\r
+ whiteSpace = X.Dom.Parser.whiteSpace,\r
+ phase = 0,\r
+ l = html.length,\r
+ i = 0,\r
+ tagName,\r
+ chr, start;\r
+ \r
+ while( i < l && phase < 9 ){\r
+ chr = html.charAt( i );\r
+ switch( phase ){\r
+ case 0 :\r
+ html.substr( i, 2 ) === '</' && ( ++phase && ++i );\r
+ break;\r
+ case 1 : // タグ名の開始を待つ\r
+ alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );\r
+ break;\r
+ case 2 : // タグ名の終わりの空白文字を待つ\r
+ whiteSpace.indexOf( chr ) !== -1 && ( ++phase );\r
+ ( chr === '>' ) && ( phase = 9 );\r
+ ( phase !== 2 ) && ( tagName = html.substring( start, i ) );\r
+ break;\r
+ case 3 : // タグの終了を待つ\r
+ chr === '>' && ( phase = 9 );\r
+ break;\r
+ };\r
+ ++i;\r
+ };\r
+ if( phase === 9 ){\r
+ X.Dom.Parser.parseEndTag( stack, handler, tagName );\r
+ return i;\r
+ };\r
+ return 0; // error\r
+ },\r
+\r
+ saveAttr : function( attrs, name, value ){\r
+ name = name.toLowerCase();\r
+ value = X.Dom.Parser.fillAttrs[ name ] === 1 ? name : value;\r
+ attrs[ attrs.length ] = {\r
+ name : name,\r
+ value : value,\r
+ escaped :\r
+ value.indexOf( '"' ) !== -1 ?\r
+ value.split( '"' ).join( '\\"' ).split( '\\\\"' ).join( '\\"' ) :\r
+ value\r
+ };\r
+ },\r
+\r
+ parseStartTag : function( stack, last, handler, tagName, attrs, unary, index ) {\r
+ var tagLower = tagName.toLowerCase(),\r
+ inline = X.Dom.Parser.inline,\r
+ parseEndTag = X.Dom.Parser.parseEndTag,\r
+ sisters = X.Dom.Parser.sisters;\r
+ if ( X.Dom.Parser.block[ tagLower ] === 1 ) {\r
+ while ( last && inline[ last.toLowerCase() ] === 1 ) {\r
+ parseEndTag( stack, handler, last );\r
+ last = stack[ stack.length - 1 ];\r
+ };\r
+ };\r
+ X.Dom.Parser.closeSelf[ tagLower ] === 1 && ( last === tagName || ( sisters[ tagLower ] && sisters[ tagLower ][ last.toLowerCase() ] === 1 ) ) && parseEndTag( stack, handler, last );\r
+ unary = unary || X.Dom.Parser.empty[ tagName.toUpperCase() ];\r
+ !unary && ( stack[ stack.length ] = tagName );\r
+ \r
+ return handler.start( tagName, attrs, unary, index );\r
+ },\r
+\r
+ parseEndTag : function( stack, handler, tagName ) {\r
+ var pos = 0, i = stack.length;\r
+ // If no tag name is provided, clean shop\r
+ \r
+ // Find the closest opened tag of the same type\r
+ if ( tagName )\r
+ for ( pos = i; 0 <= pos; )\r
+ if ( stack[ --pos ] === tagName )\r
+ break;\r
+ \r
+ if ( 0 <= pos ) {\r
+ // Close all the open elements, up the stack\r
+ for ( ; pos < i; )\r
+ handler.end( stack[ --i ] );\r
+ \r
+ // Remove the open elements from the stack\r
+ stack.length = pos;\r
+ };\r
+ }\r
+ \r
+};\r
+\r
+X.Dom._htmlStringToXNode = {\r
+ flat : null,\r
+ nest : [],\r
+ err : function( html ){\r
+ X.Dom._htmlStringToXNode.flat.length = 0;\r
+ X.Dom._htmlStringToXNode.ignoreError !== true && X.Notification.warn( 'X.Dom.Parser() error ' + html );\r
+ },\r
+ start : function( tagName, attrs, noChild, length ){\r
+ var xnode,\r
+ nest = X.Dom._htmlStringToXNode.nest,\r
+ flat = X.Dom._htmlStringToXNode.flat,\r
+ l = nest.length,\r
+ attr, name, i, _attrs; //, toIndex;\r
+ if( l ){\r
+ xnode = nest[ l - 1 ].create( tagName );\r
+ } else {\r
+ xnode = flat[ flat.length ] = X.Dom.Node.create( tagName );\r
+ };\r
+ if( !noChild ) nest[ l ] = xnode;\r
+ if( i = attrs.length ){\r
+ _attrs = {};\r
+ for( ; i; ){\r
+ if( attr = attrs[ --i ] ){\r
+ if( typeof attr === 'string' ){\r
+ name = attr;\r
+ _attrs[ name ] = true;\r
+ } else {\r
+ name = attr.name;\r
+ _attrs[ name ] = attr.escaped;\r
+ };\r
+ };\r
+ };\r
+ xnode.attr( _attrs );\r
+ };\r
+ },\r
+ end : function(){\r
+ 0 < X.Dom._htmlStringToXNode.nest.length && ( --X.Dom._htmlStringToXNode.nest.length );\r
+ },\r
+ chars : function( text ){\r
+ if( X.Dom._htmlStringToXNode.nest.length ){\r
+ X.Dom._htmlStringToXNode.nest[ X.Dom._htmlStringToXNode.nest.length - 1 ].createText( text );\r
+ } else {\r
+ X.Dom._htmlStringToXNode.flat[ X.Dom._htmlStringToXNode.flat.length ] = X.Dom.Node.createText( text );\r
+ };\r
+ },\r
+ comment : X.emptyFunction\r
+};\r
+\r
+X.Dom.parse = function( html, ignoreError ){\r
+ var worker = X.Dom._htmlStringToXNode, ret;\r
+ worker.flat = [];\r
+ worker.nest.length = 0;\r
+ worker.ignoreError = ignoreError;\r
+ X.Dom.Parser.exec( html, worker );\r
+ ret = worker.flat;\r
+ delete worker.flat;\r
+ return ret;\r
+};\r
+\r
+X.Dom._asyncHtmlStringToXNode = {\r
+ err : function( html ){\r
+ X.Dom._htmlStringToXNode.err( html );\r
+ this.asyncDispatch( 0, { type : X.Event.ERROR } );\r
+ },\r
+ start : X.Dom._htmlStringToXNode.start,\r
+ end : X.Dom._htmlStringToXNode.end,\r
+ chars : X.Dom._htmlStringToXNode.chars,\r
+ comment : X.emptyFunction,\r
+ \r
+ progress : function( pct ){\r
+ this.asyncDispatch( 0, { type : X.Event.PROGRESS, progress : pct } );\r
+ },\r
+ complete : function(){\r
+ var ret = X.Dom._htmlStringToXNode.flat;\r
+ delete X.Dom._htmlStringToXNode.flat;\r
+ this.asyncDispatch( 0, { type : X.Event.SUCCESS, xnodes : ret } );\r
+ }\r
+};\r
+\r
+X.Dom.asyncParse = function( html, ignoreError ){\r
+ var dispatcher = X.Class._override( new X.EventDispatcher(), X.Dom._asyncHtmlStringToXNode ),\r
+ worker = X.Dom._htmlStringToXNode;\r
+ dispatcher.listenOnce( X.Event.SUCCESS, dispatcher, dispatcher.kill );\r
+ worker.flat = [];\r
+ worker.nest.length = 0;\r
+ worker.ignoreError = ignoreError;\r
+ X.Dom.Parser.exec( html, dispatcher, [ html.length, [] ] );\r
+ return dispatcher;\r
+};\r