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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations) (download) (as text)
Sun Apr 27 11:27:04 2008 UTC (18 years, 4 months ago) by wakaba
Branch: MAIN
Changes since 1.12: +31 -6 lines
File MIME type: text/html
license and styling refinement

1 wakaba 1.1 <!DOCTYPE HTML>
2     <html lang=en>
3     <head>
4 wakaba 1.8 <title>Live Scripting HTML Parser</title>
5 wakaba 1.13 <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 wakaba 1.1 <style>
9 wakaba 1.13 h1 {
10     margin: 0;
11     font-size: 150%;
12     }
13     h2 {
14 wakaba 1.7 margin: 0;
15     font-size: 100%;
16     }
17 wakaba 1.13 p {
18     margin: 0 1em;
19 wakaba 1.7 }
20 wakaba 1.1 textarea {
21 wakaba 1.7 width: 100%;
22     -width: 99%;
23     height: 10em;
24 wakaba 1.1 }
25     output {
26     display: block;
27     font-family: monospace;
28 wakaba 1.4 white-space: -moz-pre-wrap;
29     white-space: pre-wrap;
30 wakaba 1.1 }
31     </style>
32     <script>
33 wakaba 1.7 var delayedUpdater = 0;
34    
35 wakaba 1.1 function update () {
36 wakaba 1.7 if (delayedUpdater) {
37     clearTimeout (delayedUpdater);
38     delayedUpdater = 0;
39     }
40     delayedUpdater = setTimeout (update2, 100);
41     } // update
42    
43     function update2 () {
44     var v = document.sourceElement.value;
45 wakaba 1.8 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 wakaba 1.10
58 wakaba 1.8 log (dumpTree (doc, ''));
59 wakaba 1.10
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 wakaba 1.8 }
64 wakaba 1.7 } // update2
65 wakaba 1.1
66 wakaba 1.6 var logIndentLevel = 0;
67 wakaba 1.1 function log (s) {
68 wakaba 1.6 for (var i = 0; i < logIndentLevel; i++) {
69     s = ' ' + s;
70     }
71 wakaba 1.1 document.logElement.appendChild (document.createTextNode (s + "\n"));
72     } // log
73    
74     function InputStream (s) {
75     this.s = s;
76     } // InputStream
77    
78 wakaba 1.4 function Parser (i, doc) {
79 wakaba 1.1 this.parseMode = 'pcdata';
80 wakaba 1.4 if (!doc) {
81     doc = new JSDocument (this);
82     doc.manakaiIsHTML = true;
83     }
84     this.doc = doc;
85     this.openElements = [doc];
86 wakaba 1.8 this.input = i;
87 wakaba 1.4 this.scriptsExecutedAfterParsing = [];
88 wakaba 1.10 this.scriptsExecutedSoon = [];
89 wakaba 1.12 this.scriptsExecutedAsynchronously = [];
90 wakaba 1.1 } // Parser
91    
92 wakaba 1.2 Parser.prototype.getNextToken = function () {
93 wakaba 1.3 var p = this;
94 wakaba 1.8 var i = this.input;
95 wakaba 1.1 if (this.parseMode == 'script') {
96     var token;
97 wakaba 1.3 if (p.insertionPoint <= 0) {
98     return {type: 'abort'};
99     }
100 wakaba 1.4 i.s = i.s.replace (/^([^<]+)/,
101 wakaba 1.1 function (s, t) {
102 wakaba 1.3 if (0 < p.insertionPoint && p.insertionPoint < t.length) {
103     token = {type: 'char', value: t.substring (0, p.insertionPoint)};
104     var ip = p.insertionPoint;
105     p.insertionPoint = 0;
106 wakaba 1.4 return t.substring (ip, t.length);
107 wakaba 1.3 }
108 wakaba 1.1 token = {type: 'char', value: t};
109 wakaba 1.4 p.insertionPoint -= t.length;
110     return '';
111 wakaba 1.1 });
112     if (token) return token;
113 wakaba 1.3 i.s = i.s.replace (/^<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/, function (s) {
114 wakaba 1.4 if (p.insertionPoint < s.length) {
115 wakaba 1.3 token = {type: 'abort'};
116     return s;
117     }
118 wakaba 1.1 token = {type: 'end-tag', value: 'script'};
119 wakaba 1.3 p.insertionPoint -= s.length;
120 wakaba 1.1 return '';
121     });
122     if (token) return token;
123 wakaba 1.5 var m;
124     if ((p.insertionPoint < '</script'.length) &&
125     (m = i.s.match (/^<\/([SCRIPTscript]+)/))) {
126     var v = m[1].substring (0, p.insertionPoint).toLowerCase ();
127     if (v == 'script'.substring (0, p.insertionPoint - '</'.length)) {
128     return {type: 'abort'};
129     }
130     }
131 wakaba 1.4 i.s = i.s.replace (/^</,
132     function (s) {
133     token = {type: 'char', value: s};
134     p.insertionPoint -= s.length;
135     return '';
136     });
137     if (token) return token;
138 wakaba 1.1 return {type: 'eof'};
139     }
140    
141     var token;
142 wakaba 1.5 i.s = i.s.replace (/^<\/([^>]+)(?:>|$)/, function (s, e) {
143     if (p.insertionPoint < s.length ||
144     (p.insertionPoint <= s.length &&
145     s.substring (s.length - 1, 1) != '>')) {
146 wakaba 1.3 token = {type: 'abort'};
147     return s;
148     }
149 wakaba 1.1 token = {type: 'end-tag', value: e.toLowerCase ()};
150 wakaba 1.3 p.insertionPoint -= s.length;
151 wakaba 1.1 return '';
152     });
153     if (token) return token;
154 wakaba 1.5 i.s = i.s.replace (/^<([^>]+)(?:>|$)/, function (s, e) {
155     if (p.insertionPoint < s.length ||
156     (p.insertionPoint <= s.length &&
157     s.substring (s.length - 1, 1) != '>')) {
158 wakaba 1.3 token = {type: 'abort'};
159     return s;
160     }
161 wakaba 1.4 var tagName;
162     var attrs = {};
163     e = e.replace (/^[\S]+/, function (v) {
164     tagName = v.toLowerCase ();
165     return '';
166     });
167 wakaba 1.9 while (true) {
168     var m = false;
169     e = e.replace (/^\s*([^\s=]+)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^"'\s]*)))?/,
170     function (x, attrName, attrValue1, attrValue2, attrValue3) {
171     v = attrValue1 || attrValue2 || attrValue3;