*\r
*/\r
\r
-(function(){\r
-\r
- var alphabets = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\r
- whiteSpace = '\t\r\n\f\b ';\r
+X.Dom.Parser = {\r
+ alphabets : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\r
+ whiteSpace : '\t\r\n\f\b ',\r
\r
// Empty Elements - HTML 4.01\r
- var empty = X.Dom.DTD.EMPTY;\r
+ empty : X.Dom.DTD.EMPTY,\r
\r
// Block Elements - HTML 4.01\r
- 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};\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
- 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};\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
- 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\r
-\r
- // todo:\r
- var plainText = { plaintext : 1, xmp : 1 };\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
- var sisters = {\r
+ sisters : {\r
th : { td : 1 },\r
td : { th : 1 },\r
dt : { dd : 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
/*\r
* http://www.tohoho-web.com/html/tbody.htm\r
* HTML4.01では、ヘッダとフッタを先読みして表示するために、<tbody> よりも <tfoot> の方を先に記述しなくてはならないと定義されています。\r
*/\r
\r
// Attributes that have their values filled in disabled="disabled"\r
- 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};\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
- var special = {script:1,style:1};\r
-\r
- X.Dom.Parser = function( html, handler ) {\r
- var stack = [],\r
- lastHtml = html,\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
\r
// Make sure we're not in a script or style element\r
if ( last && special[ last.toLowerCase() ] === 1 ) {\r
- if( 0 <= ( index = _parseEndTag( stack, handler, html ) ) ){\r
- //handler.chars( html.substring( 0, index ) );\r
- html = html.substring( index );\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
\r
};\r
\r
- if ( html === lastHtml ){\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
- parseEndTag( stack, handler );\r
- };\r
+ X.Dom.Parser.parseEndTag( stack, handler );\r
+ \r
+ async && handler.complete();\r
+ },\r
\r
- function _parseStartTag( stack, last, handler, html ){\r
- var uri = X.Dom.DTD.ATTR_VAL_IS_URI,\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,\r
+ tagName, empty = false,\r
chr, start, attrName, quot, escape;\r
\r
while( i < l && phase < 9 ){\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.indexOf( attrName ) === -1 && html.substr( i, 2 ) === '\/>' ) && // attr の val が uri で / で終わりかつ、未対応属性の場合\r
- ( empty = true );\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( parseStartTag( stack, last, handler, tagName, attrs, empty, i ) === false ) return false;\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
\r
- function _parseEndTag( stack, handler, html ){\r
- var phase = 0,\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 === '>' ) && ( phase = 9 );\r
( phase !== 2 ) && ( tagName = html.substring( start, i ) );\r
break;\r
- case 3 : // 属性名の開始を待つ\r
+ case 3 : // タグの終了を待つ\r
chr === '>' && ( phase = 9 );\r
break;\r
};\r
++i;\r
};\r
if( phase === 9 ){\r
- parseEndTag( stack, handler, tagName );\r
+ X.Dom.Parser.parseEndTag( stack, handler, tagName );\r
return i;\r
};\r
return 0; // error\r
- };\r
+ },\r
\r
- function saveAttr( attrs, name, value ){\r
+ saveAttr : function( attrs, name, value ){\r
name = name.toLowerCase();\r
- value = fillAttrs[ name ] === 1 ? name : value;\r
+ value = X.Dom.Parser.fillAttrs[ name ] === 1 ? name : value;\r
attrs[ attrs.length ] = {\r
name : name,\r
value : value,\r
value.split( '"' ).join( '\\"' ).split( '\\\\"' ).join( '\\"' ) :\r
value\r
};\r
- };\r
+ },\r
\r
- function parseStartTag( stack, last, handler, tagName, attrs, unary, index ) {\r
- var tagLower = tagName.toLowerCase();\r
- if ( block[ tagLower ] === 1 ) {\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
- closeSelf[ tagLower ] === 1 && ( last === tagName || ( sisters[ tagLower ] && sisters[ tagLower ][ last.toLowerCase() ] === 1 ) ) && parseEndTag( stack, handler, last );\r
- unary = empty[ tagLower ] === 1 || !!unary;\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
\r
- function parseEndTag( stack, handler, tagName ) {\r
+ parseEndTag : function( stack, handler, tagName ) {\r
var pos = 0, i = stack.length;\r
// If no tag name is provided, clean shop\r
\r
// Remove the open elements from the stack\r
stack.length = pos;\r
};\r
- };\r
-\r
-})();\r
+ }\r
+ \r
+};\r
\r
X.Dom._htmlStringToXNode = {\r
flat : null,\r
nest : [],\r
err : function( html ){\r
- this.flat.length = 0;\r
- this.ignoreError !== true && X.Notification.warn( 'X.Dom.Parser() error ' + 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 = this.nest,\r
- flat = this.flat,\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
};\r
},\r
end : function(){\r
- 0 < this.nest.length && ( --this.nest.length );\r
+ 0 < X.Dom._htmlStringToXNode.nest.length && ( --X.Dom._htmlStringToXNode.nest.length );\r
},\r
chars : function( text ){\r
- if( this.nest.length ){\r
- this.nest[ this.nest.length - 1 ].createText( text );\r
+ if( X.Dom._htmlStringToXNode.nest.length ){\r
+ X.Dom._htmlStringToXNode.nest[ X.Dom._htmlStringToXNode.nest.length - 1 ].createText( text );\r
} else {\r
- this.flat[ this.flat.length ] = X.Dom.Node.createText( text );\r
+ X.Dom._htmlStringToXNode.flat[ X.Dom._htmlStringToXNode.flat.length ] = X.Dom.Node.createText( text );\r
};\r
},\r
comment : X.emptyFunction\r
worker.flat = [];\r
worker.nest.length = 0;\r
worker.ignoreError = ignoreError;\r
- X.Dom.Parser( html, worker );\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