OSDN Git Service

Version 0.6.47, fix for IE5 & Opera7.x.
[pettanr/clientJs.git] / 0.6.x / js / dom / 19_XDomParser.js
index 010537c..db0c897 100644 (file)
@@ -5,28 +5,24 @@
  *\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
@@ -35,7 +31,7 @@
                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
@@ -308,13 +335,13 @@ X.Dom._htmlStringToXNode = {
                };\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
@@ -325,9 +352,39 @@ X.Dom.parse = function( html, ignoreError ){
        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