/[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.2 - (hide annotations) (download) (as text)
Sun Oct 18 08:12:05 2009 UTC (15 years, 9 months ago) by wakaba
Branch: MAIN
Changes since 1.1: +7 -7 lines
File MIME type: text/html
oops, s/progress/meter/

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24