/[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.4 by wakaba, Sun Apr 20 12:19:13 2008 UTC revision 1.8 by wakaba, Sun Apr 27 08:56:34 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  <style>  <style>
6      h1, h2 {
7        margin: 0;
8        font-size: 100%;
9      }
10      p, pre {
11        margin: 0;
12      }
13    textarea {    textarea {
14       display: block;      width: 100%;
15       width: 80%;      -width: 99%;
16       margin-left: auto;      height: 10em;
      margin-right: auto;  
      min-height: 20em;  
17    }    }
18    output {    output {
19      display: block;      display: block;
# Line 18  Line 23 
23    }    }
24  </style>  </style>
25  <script>  <script>
26      var delayedUpdater = 0;
27    
28    function update () {    function update () {
29      document.logElement.textContent = '';      if (delayedUpdater) {
30      var p = new Parser (new InputStream (document.sourceElement.value));        clearTimeout (delayedUpdater);
31      var doc = p.doc;        delayedUpdater = 0;
32      p.parse ();      }
33      log (dumpTree (doc, ''));      delayedUpdater = setTimeout (update2, 100);
34    } // update    } // update
35    
36      function update2 () {
37        var v = document.sourceElement.value;
38        if (v != document.previousSourceText) {
39          document.previousSourceText = v;
40          document.links['permalink'].href
41              = location.pathname + '?s=' + encodeURIComponent (v);
42          document.links['ldvlink'].href
43              = 'http://software.hixie.ch/utilities/js/live-dom-viewer/?'
44              + encodeURIComponent (v);
45    
46          document.logElement.textContent = '';
47          var p = new Parser (new InputStream (v));
48          var doc = p.doc;
49          p.parse ();
50          log (dumpTree (doc, ''));
51        }
52      } // update2
53    
54      var logIndentLevel = 0;
55    function log (s) {    function log (s) {
56        for (var i = 0; i < logIndentLevel; i++) {
57          s = '  ' + s;
58        }
59      document.logElement.appendChild (document.createTextNode (s + "\n"));      document.logElement.appendChild (document.createTextNode (s + "\n"));
60    } // log    } // log
61    
# Line 42  Line 71 
71      }      }
72      this.doc = doc;      this.doc = doc;
73      this.openElements = [doc];      this.openElements = [doc];
74      this.in = i;      this.input = i;
75      this.scriptsExecutedAfterParsing = [];      this.scriptsExecutedAfterParsing = [];
76    } // Parser    } // Parser
77    
78    Parser.prototype.getNextToken = function () {    Parser.prototype.getNextToken = function () {
79      var p = this;      var p = this;
80      var i = this.in;      var i = this.input;
81      if (this.parseMode == 'script') {      if (this.parseMode == 'script') {
82        var token;        var token;
83        if (p.insertionPoint <= 0) {        if (p.insertionPoint <= 0) {
# Line 77  Line 106 
106          return '';          return '';
107        });        });
108        if (token) return token;        if (token) return token;
109          var m;
110          if ((p.insertionPoint < '</script'.length) &&
111              (m = i.s.match (/^<\/([SCRIPTscript]+)/))) {
112            var v = m[1].substring (0, p.insertionPoint).toLowerCase ();
113            if (v == 'script'.substring (0, p.insertionPoint - '</'.length)) {
114              return {type: 'abort'};
115            }
116          }
117        i.s = i.s.replace (/^</,        i.s = i.s.replace (/^</,
118        function (s) {        function (s) {
119          token = {type: 'char', value: s};          token = {type: 'char', value: s};
# Line 88  Line 125 
125      }      }
126    
127      var token;      var token;
128      i.s = i.s.replace (/^<\/([^>]+)>/, function (s, e) {      i.s = i.s.replace (/^<\/([^>]+)(?:>|$)/, function (s, e) {
129        if (p.insertionPoint < s.length) {        if (p.insertionPoint < s.length ||
130              (p.insertionPoint <= s.length &&
131               s.substring (s.length - 1, 1) != '>')) {
132          token = {type: 'abort'};          token = {type: 'abort'};
133          return s;          return s;
134        }        }
# Line 98  Line 137 
137        return '';        return '';
138      });      });
139      if (token) return token;      if (token) return token;
140      i.s = i.s.replace (/^<([^>]+)>/, function (s, e) {      i.s = i.s.replace (/^<([^>]+)(?:>|$)/, function (s, e) {
141        if (p.insertionPoint < s.length) {        if (p.insertionPoint < s.length ||
142              (p.insertionPoint <= s.length &&
143               s.substring (s.length - 1, 1) != '>')) {
144          token = {type: 'abort'};          token = {type: 'abort'};
145          return s;          return s;
146        }        }
# Line 109  Line 150 
150          tagName = v.toLowerCase ();          tagName = v.toLowerCase ();
151          return '';          return '';
152        });        });
153        e = e.replace (/^\s*(\S+)\s*(?:=\s*"([^"]*)"|'([^']*)'|([^"']+))?/,        e = e.replace (/^\s*([^\s=]+)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^"']+)))?/,
154        function (x, attrName, attrValue1, attrValue2, attrValue3) {        function (x, attrName, attrValue1, attrValue2, attrValue3) {
155          attrs[attrName] = attrValue1 || attrValue2 || attrValue3;          v = attrValue1 || attrValue2 || attrValue3;
156            v = v.replace (/&quot;/g, '"').replace (/&apos;/g, "'")
157                .replace (/&amp;/g, '&');
158            attrs[attrName.toLowerCase ()] = v;
159          return '';          return '';
160        });        });
161          if (e.length) {
162            log ('Broken start tag: "' + e + '"');
163          }
164        token = {type: 'start-tag', value: tagName, attrs: attrs};        token = {type: 'start-tag', value: tagName, attrs: attrs};
165        p.insertionPoint -= s.length;        p.insertionPoint -= s.length;
166        return '';        return '';
# Line 144  Line 191 
191    } // getNextToken    } // getNextToken
192    
193    Parser.prototype.parse = function () {    Parser.prototype.parse = function () {
194      log ('start parsing');      logIndentLevel++;
195        log ('parse: start');
196    
197      while (true) {      while (true) {
198        var token = this.getNextToken ();        var token = this.getNextToken ();
# Line 212  Line 260 
260            this.openElements[this.openElements.length - 1].appendChild (el);            this.openElements[this.openElements.length - 1].appendChild (el);
261    
262            // 11. Let the insertion point have the value of the old ...            // 11. Let the insertion point have the value of the old ...
263    
264              oldInsertionPoint += this.insertionPoint;
265            this.setInsertionPoint (oldInsertionPoint);            this.setInsertionPoint (oldInsertionPoint);
266    
267            // 12. If there is a script that will execute as soon as ...            // 12. If there is a script that will execute as soon as ...
268                        while (this.scriptExecutedWhenParserResumes) {