/[suikacvs]/www/test/html/progress/reqs/test.html
Suika

Contents of /www/test/html/progress/reqs/test.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download) (as text)
Sun Oct 18 08:14:37 2009 UTC (15 years, 9 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -0 lines
File MIME type: text/html
emphasizes that it is about meter, not progress :)

1 <!DOCTYPE HTML>
2 <title>&lt;meter> processing and authoring requirements</title>
3
4 <h1>&lt;meter></h1>
5
6 <script>
7
8 // Web Applications 1.0 Revision 4116, 12 October 2009
9
10 var whiteSpace = /\s/; // XXX White_Space != \s
11 var denominatorPunctuationCharacter = /[\u0025\u066A\uFE6A\uFF05\u2030\u2031]/;
12
13 function findingOneOrTwoNumbersOfARatioInAString (string) {
14 // 1. If the string is empty, then return nothing and abort these steps.
15 if (string == '') {
16 return {isNothing: true, step: 1};
17 }
18
19 // 2. Find a number in the string according to the algorithm below, starting at the start of the string.
20 var position = 0;
21 var s2 = findANumber (string, position);
22
23 // 3. If the sub-algorithm in step 2 returned nothing or returned an error condition, return nothing and abort these steps.
24 if (s2.isNothing || s2.isError) {
25 return {isNothing: true, step: 3};
26 }
27
28 // 4. Set number1 to the number returned by the sub-algorithm in step 2.
29 var number1 = s2.number;
30
31 // 5. Starting with the character immediately after the last one examined by the sub-algorithm in step 2, skip all White_Space characters in the string (this might match zero characters).
32 position = s2.position;
33 while (position < string.length && string.charAt (position).match (whiteSpace)) {
34 position++;
35 }
36
37 // 6. If there are still further characters in the string, and the next character in the string is a valid denominator punctuation character, set denominator to that character.
38 var denominator = null;
39 if (position < string.length && string.charAt (position).match (denominatorPunctuationCharacter)) {
40 denominator = string.charAt (position);
41 }
42
43 // 7. If the string contains any other characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), but denominator was given a value in the step 6, return nothing and abort these steps.
44 if (string.substring (position).match (/[0-9]/) && denominator != null) {
45 return {isNothing: true, step: 7};
46 }
47
48 // 8. Otherwise, if denominator was given a value in step 6, return number1 and denominator and abort these steps.
49 if (denominator != null) {
50 return {number1: number1, denominator: denominator, step: 8};
51 }
52
53 // 9. Find a number in the string again, starting immediately after the last character that was examined by the sub-algorithm in step 2.
54 var s9 = findANumber (string, position);
55
56 // 10. If the sub-algorithm in step 9 returned nothing or an error condition, return number1 and abort these steps.
57 if (s9.isNothing || s9.isError) {
58 return {number1: number1, step: 10};
59 }
60
61 // 11. Set number2 to the number returned by the sub-algorithm in step 9.
62 var number2 = s9.number;
63
64 // 12. Starting with the character immediately after the last one examined by the sub-algorithm in step 9, skip all White_Space characters in the string (this might match zero characters).
65 position = s9.position;
66 while (position < string.length && string.charAt (position).match (whiteSpace)) {
67 position++;
68 }
69
70 // 13. If there are still further characters in the string, and the next character in the string is a valid denominator punctuation character, return nothing and abort these steps.
71 if (position < string.length && string.charAt (position).match (denominatorPunctuationCharacter)) {
72 return {isNothing: true, step: 13};
73 }
74
75 // 14. If the string contains any other characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), return nothing and abort these steps.
76 if (string.substring (position).match (/[0-9]/)) {
77 return {isNothing: true, step: 14};
78 }
79
80 // 15. Otherwise, return number1 and number2.
81 return {number1: number1, number2: number2, step: 15};
82 } // findingOneOrTwoNumbersOfARatioInAString
83
84 function findANumber (givenString, position) {
85 // 1. Starting at the given starting position, ignore all characters in the given string until the first character that is either a U+002E FULL STOP or one of the ten characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9).
86 while (position < givenString.length && !givenString.charAt (position).match (/[0-9.]/)) {
87 position++;
88 }
89
90 // 2. If there are no such characters, return nothing and abort these steps.
91 if (position < givenString.length && givenString.charAt (position).match (/[0-9.]/)) {
92 //
93 } else {
94 return {isNothing: true, position: position};
95 }
96
97 // 3. Starting with the character matched in step 1, collect all the consecutive characters that are either a U+002E FULL STOP or one of the ten characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), and assign this string of one or more characters to string.
98 var string = '';
99 while (position < givenString.length && givenString.charAt (position).match (/[0-9.]/)) {
100 string += givenString.charAt (position);
101 position++;
102 }
103
104 // 4. If string consists of just a single U+002E FULL STOP character or if it contains more than one U+002E FULL STOP character then return an error condition and abort these steps.
105 if (string == '.' || string.match (/\..*\./)) {
106 return {isError: true, position: position};
107 }
108
109 // 5. Parse string according to the rules for parsing floating point number values, to obtain number. This step cannot fail (string is guaranteed to be a valid floating point number).
110 var s5 = parseFloatingPointNumberValue (string);
111 var number = s5.value;
112
113 // 6. Return number.
114 return {number: number, position: position};
115 } // findANumber
116
117 function parseFloatingPointNumberValue (input) {
118 // 1. Let input be the string being parsed.
119 //
120
121 // 2. Let position be a pointer into input, initially pointing at the start of the string.
122 var position = 0;
123
124 // 3. Let value have the value 1.
125 var value = 1;
126
127 // 4. Let divisor have the value 1.
128 var divisor = 1;
129
130 // 5. Let exponent have the value 1.
131 var exponent = 1;
132
133 // 6. Skip whitespace.
134 var s6 = skipWhitespace (input, position);
135 position = s6.position;
136
137 // 7. If position is past the end of input, return an error.
138 if (position >= input.length) {
139 return {isError: true};
140 }
141
142 // 8. If the character indicated by position is a U+002D HYPHEN-MINUS character (-):
143 if (input.charAt (position) == '-') {
144 // 1. Change value and divisor to −1.
145 value = -1;
146 divisor = -1;
147
148 // 2. Advance position to the next character.
149 position++;
150
151 // 3. If position is past the end of input, return an error.
152 if (position >= input.length) {
153 return {isError: true};
154 }
155 }
156
157 // 9. If the character indicated by position is not one of U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then return an error.
158 if (!input.charAt (position).match (/[0-9]/)) {
159 return {isError: true};
160 }
161
162 // 10. Collect a sequence of characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), and interpret the resulting sequence as a base-ten integer. Multiply value by that integer.
163 var s10 = collectASequenceOfCharacters (/[0-9]/, input, position);
164 position = s10.position;
165 value *= parseInt (s10.result);
166
167 // 11. If position is past the end of input, return value.
168 if (position >= input.length) {
169 return {value: value};
170 }
171
172 // 12. If the character indicated by position is a U+002E FULL STOP (.), run these substeps:
173 if (input.charAt (position) == '.') {
174 // 1. Advance position to the next character.
175 position++;
176
177 // 2. If position is past the end of input, or if the character indicated by position is not one of U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then return value.
178 if (position >= input.length ||
179 !input.charAt (position).match (/[0-9]/)) {
180 return {value: value};
181 }
182
183 // 3. Fraction loop: Multiply divisor by ten.
184 var fractionLoop = true;
185 while (fractionLoop) {
186 divisor *= 10;
187
188 // 4. Add the value of the current character interpreted as a base-ten digit (0..9) divided by divisor, to value.
189 value += parseInt (input.charAt (position)) / divisor;
190
191 // 5. Advance position to the next character.
192 position++;
193
194 // 6. If position is past the end of input, then return value.
195 if (position >= input.length) {
196 return {value: value};
197 }
198
199 // 7. If the character indicated by position is one of U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), return to the step labeled fraction loop in these substeps.
200 if (input.charAt (position).match (/[0-9]/)) {
201 fractionLoop = true;
202 } else {
203 fractionLoop = false;
204 }
205 }
206 }
207
208 // 13. If the character indicated by position is a U+0065 LATIN SMALL LETTER E character (e) or a U+0045 LATIN CAPITAL LETTER E character (E), run these substeps:
209 if (input.charAt (position).match (/[eE]/)) {
210 // 1. Advance position to the next character.
211 position++;
212
213 // 2. If position is past the end of input, then return value.
214 if (position >= input.length) {
215 return {value: value};
216 }
217
218 // 3. If the character indicated by position is a U+002D HYPHEN-MINUS character (-):
219 if (input.charAt (position) == '-') {
220 // 1. Change exponent to −1.
221 exponent = -1;
222
223 // 2. Advance position to the next character.
224 position++;
225
226 // 3. If position is past the end of input, then return value.
227 if (position >= input.length) {
228 return {value: value};
229 }
230
231 // Otherwise, if the character indicated by position is a U+002B PLUS SIGN character (+):
232 } else if (input.charAt (position) == '+') {
233 // 1. Advance position to the next character.
234 position++;
235
236 // 2. If position is past the end of input, then return value.
237 if (position >= input.length) {
238 return {value: value};
239 }
240 }
241
242 // 4. If the character indicated by position is not one of U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then return value.
243 if (!input.charAt (position).match (/[0-9]/)) {
244 return {value: value};
245 }
246
247 // 5. Collect a sequence of characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), and interpret the resulting sequence as a base-ten integer. Multiply exponent by that integer.
248 var s13_5 = collectASequenceOfCharacters (/[0-9]/, input, position);
249 position = s13_5.position;
250 exponent *= parseInt (s13_5.result);
251
252 // 6. Multiply value by ten raised to the exponentth power.
253 value *= Math.pow (10, exponent);
254 }
255
256 // 14. Return value.
257 return {value: value};
258 } // parseFloatingPointNumberValue
259
260 function skipWhitespace (input, position) {
261 return collectASequenceOfCharacters (/[\u0009\u000A\u000C\u000D\u0020]/, input, position);
262 } // skipWhitespace
263
264 function collectASequenceOfCharacters (characters, input, position) {
265 // 1. Let input and position be the same variables as those of the same name in the algorithm that invoked these steps.
266 //
267
268 // 2. Let result be the empty string.
269 var result = '';
270
271 // 3. While position doesn't point past the end of input and the character at position is one of the characters, append that character to the end of result and advance position to the next character in input.
272 while (position < input.length && input.charAt (position).match (characters)) {
273 result += input.charAt (position);
274 position++;
275 }
276
277 // 4. Return result.
278 return {result: result, position: position};
279 } // collectASequenceOfCharacters
280
281 function tokenizeMeterContent (string) {
282 var position = 0;
283 var tokens = [];
284 var lastToken = {type: 'initial', value: ''};
285 while (position < string.length) {
286 var char = string.charAt (position);
287 var tokenType;
288 if (char.match (/[0-9]/)) {
289 tokenType = 'number';
290 } else if (char.match (/\./)) {
291 if (lastToken.type == 'number' && !lastToken.value.match (/\./)) {
292 tokenType = 'number';
293 } else {
294 tokenType = 'dot';
295 }
296 } else if (char.match (whiteSpace)) {
297 if (lastToken.type == 'number' || lastToken.type == 'whitespace') {
298 tokenType = 'whitespace';
299 } else {
300 tokenType = 'string';
301 }
302 } else if (char.match (denominatorPunctuationCharacter) && (lastToken.type == 'whitespace' || lastToken.type == 'number')) {
303 tokenType = 'denominator';
304 } else {
305 tokenType = 'string';
306 }
307 if (tokenType == lastToken.type) {
308 lastToken.value += char;
309 } else {
310 lastToken = {type: tokenType, value: char};
311 tokens.push (lastToken);
312 }
313 position++;
314 }
315
316 return tokens;
317 } // tokenizeMeterContent
318
319 function extractNumbersFromTokens (tokens) {
320 var number1 = undefined;
321 var number2 = undefined;
322 var denominator = undefined;
323 for (var i = 0; i < tokens.length; i++) {
324 var token = tokens[i];
325 if (token.type == 'number') {
326 if (number1 == undefined) {
327 number1 = parseFloat (token.value);
328 } else if (denominator != undefined) {
329 return {isNothing: true};
330 } else if (number2 == undefined) {
331 number2 = parseFloat (token.value);
332 } else {
333 return {isNothing: true};
334 }
335 } else if (token.type == 'denominator') {
336 if (number2 != undefined) {
337 return {isNothing: true};
338 } else {
339 denominator = token.value;
340 }
341 } else if (token.type == 'dot') {
342 return {isNothing: true};
343 }
344 }
345
346 if (number1 == undefined) {
347 return {isNothing: true};
348 } else {
349 return {number1: number1, number2: number2, denominator: denominator};
350 }
351 } // extractNumbersFromTokens
352
353 function objectToString (object) {
354 return self.JSON ? JSON.stringify (object) : object.toSource ? object.toSource () : object.toString ();
355 } // objectToString
356
357 function processMeterContent (string) {
358 var result = {};
359
360 var ua = findingOneOrTwoNumbersOfARatioInAString (string);
361 for (var i in ua) {
362 result['ua-' + i] = ua[i];
363 }
364
365 var tokens = tokenizeMeterContent (string);
366 result['author-tokens'] = objectToString (tokens);
367 var author = extractNumbersFromTokens (tokens);
368 for (var i in author) {
369 result['author-' + i] = author[i];
370 }
371
372 return result;
373 } // processMeterContent
374
375 function update (form) {
376 var input = form.elements.input.value;
377
378 var result = processMeterContent (input);
379
380 var outputs = form.getElementsByTagName ('output');
381 for (var i = 0; i < outputs.length; i++) {
382 var output = outputs[i];
383 var name = output.getAttribute ('name');
384 var value = result[name];
385 if (value === undefined) {
386 output.textContent = '(undefined)';
387 } else if (value === null) {
388 output.textContent = '(null)';
389 } else if (value === '') {
390 output.textContent = '(empty)';
391 } else {
392 output.textContent = value;
393 }
394 }
395 } // update
396
397 </script>
398
399 <form>
400 <p><input name=input onchange="update (this.form)">
401
402 <fieldset>
403 <legend>From UA parsing rules</legend>
404
405 <p><code>step</code>: <output name=ua-step></output>
406 <p><code>isNothing</code>: <output name=ua-isNothing></output>
407 <p><code>number1</code>: <output name=ua-number1></output>
408 <p><code>number2</code>: <output name=ua-number2></output>
409 <p><code>denominator</code>: <output name=ua-denominator></output>
410 </fieldset>
411
412 <fieldset>
413 <legend>From author requirements</legend>
414
415 <p><code>isNothing</code>: <output name=author-isNothing></output>
416 <p><code>number1</code>: <output name=author-number1></output>
417 <p><code>number2</code>: <output name=author-number2></output>
418 <p><code>denominator</code>: <output name=author-denominator></output>
419 <p>Tokens: <output name=author-tokens></output>
420 </fieldset>
421 </form>
422
423 <script>
424 if (location.href.match (/#/)) {
425 var fragment = decodeURIComponent (location.href.split (/#/, 2)[1]);
426 document.forms[0].elements.input.value = fragment;
427 update (document.forms[0]);
428 }
429 </script>

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24