/[suikacvs]/markup/html/scripting-parser/parser.html
Suika

Diff of /markup/html/scripting-parser/parser.html

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by wakaba, Sun Apr 20 07:48:00 2008 UTC revision 1.18 by wakaba, Sun Aug 31 09:46:14 2008 UTC
# Line 1  Line 1 
1  <!DOCTYPE HTML>  <!DOCTYPE HTML>
2  <html lang=en>  <html lang=en>
3  <head>  <head>
4  <title>Demo of HTML5 Parsing Algorithm with Scripting Enabled</title>  <title>Live Scripting HTML Parser</title>
5    <link rel=author href="http://suika.fam.cx/~wakaba/who?">
6    <link rel=license href="http://suika.fam.cx/c/gnu/gpl"
7        title="GNU GPL2 or later">
8  <style>  <style>
9      h1 {
10        margin: 0;
11        font-size: 150%;
12      }
13      h2 {
14        margin: 0;
15        font-size: 100%;
16      }
17      p {
18        margin: 0 1em;
19      }
20    textarea {    textarea {
21       display: block;      width: 100%;
22       width: 80%;      -width: 99%;
23       margin-left: auto;      height: 10em;
      margin-right: auto;  
      min-height: 20em;  
24    }    }
25    output {    output {
26      display: block;      display: block;
27      font-family: monospace;      font-family: monospace;
28      white-space: pre;      white-space: -moz-pre-wrap;
29        white-space: pre-wrap;
30    }    }
31  </style>  </style>
32  <script>  <script>
33      var delayedUpdater = 0;
34    
35    function update () {    function update () {
36      document.logElement.textContent = '';      if (delayedUpdater) {
37      var p = new Parser (new InputStream (document.sourceElement.value));        clearTimeout (delayedUpdater);
38      p.parse ();        delayedUpdater = 0;
39      log (dumpTree (p.doc, ''));      }
40        delayedUpdater = setTimeout (update2, 100);
41    } // update    } // update
42    
43      function update2 () {
44        var v = document.sourceElement.value;
45        if (v != document.previousSourceText) {
46          document.previousSourceText = v;
47          document.links['permalink'].href
48              = location.pathname + '?s=' + encodeURIComponent (v);
49          document.links['ldvlink'].href
50              = 'http://software.hixie.ch/utilities/js/live-dom-viewer/?'
51              + encodeURIComponent (v);
52    
53          document.logElement.textContent = '';
54          var p = new Parser (new InputStream (v));
55          var doc = p.doc;
56          p.parse ();
57          
58          log (dumpTree (doc, ''));
59          
60          if (p.hasAsyncScript) {
61            log ('Some script codes are executed asynchronously; it means that the document might be rendered in different ways depending on the network condition and other factors');
62          }
63        }
64      } // update2
65    
66      var logIndentLevel = 0;
67    function log (s) {    function log (s) {
68        var indent = '';
69        for (var i = 0; i < logIndentLevel; i++) {
70          indent += '  ';
71        }
72        s = indent + s.replace (/\n/g, "\n" + indent);
73      document.logElement.appendChild (document.createTextNode (s + "\n"));      document.logElement.appendChild (document.createTextNode (s + "\n"));
74    } // log    } // log
75    
# Line 32  Line 77 
77      this.s = s;      this.s = s;
78    } // InputStream    } // InputStream
79    
80    function Parser (i) {    function Parser (i, doc) {
81      this.parseMode = 'pcdata';      this.parseMode = 'pcdata';
82      this.doc = new JSDocument (this);      if (!doc) {
83      this.openElements = [this.doc];        doc = new JSDocument (this);
84      this.in = i;        doc.manakaiIsHTML = true;
85        }
86        this.nextToken = [];
87        this.doc = doc;
88        this.openElements = [doc];
89        this.input = i;
90        this.scriptsExecutedAfterParsing = [];
91        this.scriptsExecutedSoon = [];
92        this.scriptsExecutedAsynchronously = [];
93    } // Parser    } // Parser
94    
95    Parser.prototype.getNextToken = function () {    Parser.prototype.getNextToken = function () {
96      var i = this.in;      if (this.nextToken.length) {
97      if (this.parseMode == 'script') {        return this.nextToken.shift ();
98        }
99    
100        var p = this;
101        var i = this.input;
102        if (this.parseMode == 'cdata') {
103          var tagName = this.endTagName;
104        var token;        var token;
105        i.s = i.s.replace (/^([\s\S]+?)<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/,        if (p.insertionPoint <= 0) {
106            return {type: 'abort'};
107          }
108          i.s = i.s.replace (/^([^<]+)/,
109        function (s, t) {        function (s, t) {
110            if (0 < p.insertionPoint && p.insertionPoint < t.length) {
111              token = {type: 'char', value: t.substring (0, p.insertionPoint)};
112              var ip = p.insertionPoint;
113              p.insertionPoint = 0;
114              return t.substring (ip, t.length);
115            }
116          token = {type: 'char', value: t};          token = {type: 'char', value: t};
117          return '<' + '/script>';          p.insertionPoint -= t.length;
118            return '';
119        });        });
120        if (token) return token;        if (token) return token;
121        i.s = i.s.replace (/^<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/, function () {        var pattern = new RegExp ('^</' + tagName + '>', 'i');
122          token = {type: 'end-tag', value: 'script'};        i.s = i.s.replace (pattern, function (s) {
123            if (p.insertionPoint < s.length) {
124              token = {type: 'abort'};
125              return s;
126            }
127            token = {type: 'end-tag', value: tagName};
128            p.insertionPoint -= s.length;
129            return '';
130          });
131          if (token) return token;
132          var m;
133          if ((p.insertionPoint < ('</' + tagName).length) &&
134              (m = i.s.match (/^<\/([A-Za-z]+)/))) {
135            var v = m[1].substring (0, p.insertionPoint).toLowerCase ();
136            if (v == tagName.substring (0, p.insertionPoint - '</'.length)) {
137              return {type: 'abort'};
138            }
139          }
140          i.s = i.s.replace (/^</,
141          function (s) {
142            token = {type: 'char', value: s};
143            p.insertionPoint -= s.length;
144          return '';          return '';
145        });        });
146        if (token) return token;        if (token) return token;
# Line 58  Line 148 
148      }      }
149    
150      var token;      var token;
151      i.s = i.s.replace (/^<\/([^>]+)>/, function (s, e) {      i.s = i.s.replace (/^<\/([^>]+)(?:>|$)/, function (s, e) {
152          if (p.insertionPoint < s.length ||