1 |
<!DOCTYPE HTML> |
2 |
<title>JavaScript object properties</title> |
3 |
<link rel=stylesheet href="/www/style/html/xhtml"> |
4 |
<link rel=license href="http://suika.fam.cx/c/pd" title="Public Domain. (This document and |prop-list| file.)"> |
5 |
|
6 |
<style> |
7 |
[name=result_ta] { |
8 |
height: 40em; |
9 |
} |
10 |
[hidden] { |
11 |
display: none; |
12 |
} |
13 |
</style> |
14 |
|
15 |
<body onload=" |
16 |
var xhr = new XMLHttpRequest (); |
17 |
xhr.open ('GET', 'prop-list.txt?' + Math.random (), false); |
18 |
xhr.send (null); |
19 |
var value = xhr.responseText; |
20 |
if (navigator.userAgent.match (/DSi/)) value = value.substring (1,9999); |
21 |
document.getElementsByName ('known_props_ta')[0].value = value; |
22 |
"> |
23 |
|
24 |
<h1>JavaScript object properties</h1> |
25 |
|
26 |
<form> |
27 |
<p><label>Code to be <code>eval</code>ed:<br> |
28 |
<textarea name=code_ta></textarea></label> |
29 |
|
30 |
<p><label>List of known properties:<br> |
31 |
<textarea name=known_props_ta> |
32 |
</textarea></label><br> |
33 |
(<a href=prop-list>source</a>; ask <a |
34 |
href="/~wakaba/who?">Wakaba</a> to add more properties) |
35 |
|
36 |
<p><button type=submit>Start</button> |
37 |
|
38 |
<h2>Result</h2> |
39 |
|
40 |
<p><textarea name=result_ta> |
41 |
</textarea> |
42 |
|
43 |
</form> |
44 |
|
45 |
<form id=submission hidden method=post accept-charset=utf-8> |
46 |
<div style="display: none"></div> |
47 |
<p><label>User-Agent: <input name=env-name></label> |
48 |
<p><button type=submit>Submit result</button> (<a>Results</a>) |
49 |
</form> |
50 |
|
51 |
<script> |
52 |
document.forms[0].onsubmit = function (event) { |
53 |
if (window.event) window.event.returnValue = false; |
54 |
if (event && event.preventDefault) event.preventDefault (); |
55 |
|
56 |
var objCode = this.code_ta.value; |
57 |
var obj = eval (objCode); |
58 |
|
59 |
if (typeof (obj) === "undefined" || obj === null) { |
60 |
obj = {}; |
61 |
objCode = '{}'; |
62 |
} |
63 |
|
64 |
var knownProps = this.known_props_ta.value.split (/[\r\n]+/); |
65 |
|
66 |
var newKnownProps = []; |
67 |
var newKnownPropNames = {}; |
68 |
|
69 |
var props = {}; |
70 |
var noProps = {}; |
71 |
|
72 |
for (var i = 0; i < knownProps.length; i++) { |
73 |
var propName = knownProps[i]; |
74 |
if (propName == '') continue; |
75 |
if (propName.match (/^\s/)) continue; |
76 |
if (propName.match (/\S\s+\S/)) continue; |
77 |
propName = propName.replace (/\s+$/, ''); |
78 |
|
79 |
try { |
80 |
if (typeof (obj[propName]) !== 'undefined') { |
81 |
if (!newKnownPropNames["name=" + propName]) newKnownProps.push (propName); |
82 |
newKnownPropNames["name=" + propName] = true; |
83 |
props["name="+propName] = {dontEnum: true}; |
84 |
} else { |
85 |
if (!newKnownPropNames["name=" + propName]) newKnownProps.push (propName); |
86 |
newKnownPropNames["name=" + propName] = true; |
87 |
noProps["name="+propName] = {}; |
88 |
} |
89 |
} catch (e) { |
90 |
if (!newKnownPropNames["name=" + propName]) newKnownProps.push (propName); |
91 |
newKnownPropNames["name=" + propName] = true; |
92 |
props["name="+propName] = {error: '' + e}; |
93 |
} |
94 |
} |
95 |
|
96 |
for (var propName in obj) { |
97 |
if (!props["name="+propName]) { |
98 |
props["name="+propName] = {notInList: true}; |
99 |
newKnownProps.push (propName); |
100 |
} |
101 |
props["name="+propName].dontEnum = false; |
102 |
} |
103 |
|
104 |
var n = function (s) { |
105 |
s = s || ''; |
106 |
s = s.toLowerCase () |
107 |
.replace (/_/g, ''); |
108 |
return s; |
109 |
}; |
110 |
|
111 |
var sort = function (l) { |
112 |
var m; |
113 |
try { |
114 |
m = l.sort (function (_a, _b) { |
115 |
var a = n (_a); |
116 |
var b = n (_b); |
117 |
return a < b ? -1 : a > b ? 1 : _a < _b ? -1 : _a > _b ? 1 : 0; |
118 |
}); |
119 |
} catch (e) { } // IE sometimes fails. Why? |
120 |
return m || l; |
121 |
}; |
122 |
|
123 |
var propNames = []; |
124 |
for (var propName in props) { |
125 |
propNames.push (propName); |
126 |
} |
127 |
propNames = sort (propNames); |
128 |
|
129 |
var noPropNames = []; |
130 |
for (var propName in noProps) { |
131 |
noPropNames.push (propName); |
132 |
} |
133 |
noPropNames = sort (noPropNames); |
134 |
|
135 |
var ri = []; |
136 |
|
137 |
var result = 'UA: ' + navigator.userAgent + "\n"; |
138 |
result += 'Object: ' + objCode + "\n"; |
139 |
result += "\n"; |
140 |
result += 'Properties:\n'; |
141 |
for (var i = 0; i < propNames.length; i++) { |
142 |
result += propNames[i].replace (/^name=/, ''); |
143 |
if (props[propNames[i]].dontEnum) result += '\tDontEnum'; |
144 |
if (props[propNames[i]].notInList) result += '\t_not_in_list_'; |
145 |
if (props[propNames[i]].error) result += '\t_error(' + props[propNames[i]].error + ')_'; |
146 |
result += '\n'; |
147 |
|
148 |
ri.push ({name: propNames[i].replace (/^name=/, ''), |
149 |
label: '', |
150 |
className: 'has', |
151 |
result: (props[propNames[i]].dontEnum ? 'DontEnum' : '') |
152 |
+ (props[propNames[i]].error ? '_error(' + props[propNames[i]].error + ')' : '')}); |
153 |
} |
154 |
result += "\n"; |
155 |
result += "Not found:\n" |
156 |
for (var i = 0; i < noPropNames.length; i++) { |
157 |
result += noPropNames[i].replace (/^name=/, '') + '\n'; |
158 |
|
159 |
/* |
160 |
ri.push ({name: noPropNames[i].replace (/^name=/, ''), |
161 |
label: '', |
162 |
className: 'not-have', |
163 |
result: ''}); |
164 |
*/ |
165 |
} |
166 |
this.result_ta.value = result; |
167 |
|
168 |
this.known_props_ta.value = sort (newKnownProps).join ("\n"); |
169 |
|
170 |
var trId = encodeURIComponent (objCode) |
171 |
.replace (/%/g, '') |
172 |
.replace (/[A-Z]+/g, function (s) { return s.toLowerCase () }) |
173 |
.replace (/[_.!~*'()]/g, function (s) { return s.charCodeAt (0).toString (16) }); |
174 |
var submission = document.forms.submission; |
175 |
|
176 |
submission.action = '/gate/test-results/list/enum-' + trId; |
177 |
submission.getElementsByTagName ('a')[0].href = submission.action + '/all'; |
178 |
|
179 |
submission['env-name'].value = navigator.userAgent; |
180 |
var c = submission.getElementsByTagName ('div')[0]; |
181 |
c.innerHTML = ''; |
182 |
for (var i = 0; i < ri.length; i++) { |
183 |
var p = document.createElement ('input'); |
184 |
p.name = 'test-name'; |
185 |
p.value = ri[i].name; |
186 |
c.appendChild (p); |
187 |
|
188 |
var p = document.createElement ('input'); |
189 |
p.name = 'test-label'; |
190 |
p.value = ri[i].label; |
191 |
c.appendChild (p); |
192 |
|
193 |
var p = document.createElement ('input'); |
194 |
p.name = 'test-class'; |
195 |
p.value = ri[i].className; |
196 |
c.appendChild (p); |
197 |
|
198 |
var p = document.createElement ('input'); |
199 |
p.name = 'test-result'; |
200 |
p.value = ri[i].result; |
201 |
c.appendChild (p); |
202 |
} |
203 |
submission.removeAttribute ('hidden'); |
204 |
|
205 |
return false; |
206 |
}; |
207 |
</script> |
208 |
|
209 |
<form action=dummy><input type=submit value=Dummy1></form> |
210 |
<form action=/gate/test-results/list/_dummy_ method=post><input type=submit value=Dummy2></form> |