OLD | NEW |
---|---|
1 #import ("dart:html"); | 1 #import ("dart:html"); |
2 #import ("dart:htmlimpl"); | 2 #import ("dart:htmlimpl"); |
3 #import ("dart:dom", prefix:"dom"); | 3 #import ("dart:dom", prefix:"dom"); |
4 #import ("dart:json"); | 4 #import ("dart:json"); |
5 | 5 |
6 // Workaround for HTML lib missing feature. | 6 // Workaround for HTML lib missing feature. |
7 Range newRange() { | 7 Range newRange() { |
8 return LevelDom.wrapRange(dom.document.createRange()); | 8 return LevelDom.wrapRange(dom.document.createRange()); |
9 } | 9 } |
10 | 10 |
11 // Temporary range object to optimize performance computing client rects | 11 // Temporary range object to optimize performance computing client rects |
12 // from text nodes. | 12 // from text nodes. |
13 Range _tempRange; | 13 Range _tempRange; |
14 // Hacks because ASYNC measurement is annoying when just writing a script. | 14 // Hacks because ASYNC measurement is annoying when just writing a script. |
15 ClientRect getClientRect(Node n) { | 15 ClientRect getClientRect(Node n) { |
16 if (n is Element) { | 16 if (n is Element) { |
17 Element e = n; | 17 dom.Element raw = unwrapDomObject(n.dynamic); |
18 dom.Element raw = unwrapDomObject(e.dynamic); | |
19 return LevelDom.wrapClientRect(raw.getBoundingClientRect()); | 18 return LevelDom.wrapClientRect(raw.getBoundingClientRect()); |
20 } else { | 19 } else { |
21 // Crazy hacks that works for nodes.... create a range and measure it. | 20 // Crazy hacks that works for nodes.... create a range and measure it. |
22 if (_tempRange == null) { | 21 if (_tempRange == null) { |
23 _tempRange = newRange(); | 22 _tempRange = newRange(); |
24 } | 23 } |
25 _tempRange.setStartBefore(n); | 24 _tempRange.setStartBefore(n); |
26 _tempRange.setEndAfter(n); | 25 _tempRange.setEndAfter(n); |
27 return _tempRange.getBoundingClientRect(); | 26 return _tempRange.getBoundingClientRect(); |
28 } | 27 } |
29 } | 28 } |
30 | 29 |
31 final DART_REMOVED = "dart_removed"; | 30 /** |
31 * CSS class that is added to elements in the DOM to indicate that they should | |
32 * be removed when extracting blocks of documentation. This is helpful when | |
33 * running this script in a web browser as it is easy to visually see what | |
34 * blocks of information were extracted when using CSS such as DEBUG_CSS | |
35 * which highlights elements that should be removed. | |
36 */ | |
37 final DART_REMOVED = "dart-removed"; | |
32 | 38 |
33 final DEBUG_CSS = """ | 39 final DEBUG_CSS = """ |
34 <style type="text/css"> | 40 <style type="text/css"> |
35 .dart_removed { | 41 .dart-removed { |
36 background-color: rgba(255, 0, 0, 0.5); | 42 background-color: rgba(255, 0, 0, 0.5); |
37 } | 43 } |
38 </style>"""; | 44 </style>"""; |
39 | 45 |
40 final MIN_PIXELS_DIFFERENT_LINES = 10; | 46 final MIN_PIXELS_DIFFERENT_LINES = 10; |
41 | 47 |
42 final IDL_SELECTOR = "pre.eval, pre.idl"; | 48 final IDL_SELECTOR = "pre.eval, pre.idl"; |
43 | 49 |
44 Map data; | 50 Map data; |
45 | 51 |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
274 if (path.startsWith('/')) { | 280 if (path.startsWith('/')) { |
275 return "$pageDomain$path"; | 281 return "$pageDomain$path"; |
276 } else if (path.startsWith("#")) { | 282 } else if (path.startsWith("#")) { |
277 return "$pageUrl$path"; | 283 return "$pageUrl$path"; |
278 } else { | 284 } else { |
279 return "$pageDir$path"; | 285 return "$pageDir$path"; |
280 } | 286 } |
281 } | 287 } |
282 | 288 |
283 bool inTable(Node n) { | 289 bool inTable(Node n) { |
284 while(n != null) { | 290 while (n != null) { |
285 if (n is TableElement) return true; | 291 if (n is TableElement) return true; |
286 n = n.parent; | 292 n = n.parent; |
287 } | 293 } |
288 return false; | 294 return false; |
289 } | 295 } |
290 | 296 |
291 String escapeHTML(str) { | 297 String escapeHTML(str) { |
292 Element e = new Element.tag("div"); | 298 Element e = new Element.tag("div"); |
293 e.text = str; | 299 e.text = str; |
294 return e.innerHTML; | 300 return e.innerHTML; |
295 } | 301 } |
296 | 302 |
297 List<Text> getAllTextNodes(Element elem) { | 303 List<Text> getAllTextNodes(Element elem) { |
298 List<Text> nodes = <Text>[]; | 304 final nodes = <Text>[]; |
Bob Nystrom
2012/02/01 18:41:13
:D
Jacob
2012/02/01 21:12:02
Done.
| |
299 helper(Node n) { | 305 helper(Node n) { |
300 if (n is Text) { | 306 if (n is Text) { |
301 nodes.add(n); | 307 nodes.add(n); |
302 } else { | 308 } else { |
303 for (Node child in n.nodes) { | 309 for (Node child in n.nodes) { |
304 helper(child); | 310 helper(child); |
305 } | 311 } |
306 } | 312 } |
307 }; | 313 }; |
308 | 314 |
309 helper(elem); | 315 helper(elem); |
310 return nodes; | 316 return nodes; |
311 } | 317 } |
312 | 318 |
313 /** | 319 /** |
314 * Whether a node and its children are all types that are safe to skip if the | 320 * Whether a node and its children are all types that are safe to skip if the |
315 * nodes have no text content. | 321 * nodes have no text content. |
316 */ | 322 */ |
317 bool isSkippableType(Node n) { | 323 bool isSkippableType(Node n) { |
318 // TODO(jacobr): are there any types we don't want to skip even if they | 324 // TODO(jacobr): are there any types we don't want to skip even if they |
319 // have no text content? | 325 // have no text content? |
320 if (n is ImageElement || n is CanvasElement || n is InputElement | 326 if (n is ImageElement || n is CanvasElement || n is InputElement |
321 || n is ObjectElement) { | 327 || n is ObjectElement) { |
322 return false; | 328 return false; |
323 } | 329 } |
324 if (n is Text) return true; | 330 if (n is Text) return true; |
325 | 331 |
326 for (Node child in n.nodes) { | 332 for (final child in n.nodes) { |
327 if (isSkippableType(child) == false) { | 333 if (!isSkippableType(child)) { |
328 return false; | 334 return false; |
329 } | 335 } |
330 } | 336 } |
331 return true; | 337 return true; |
332 } | 338 } |
333 | 339 |
334 bool isSkippable(Node n) { | 340 bool isSkippable(Node n) { |
335 if (!isSkippableType(n)) return false; | 341 if (!isSkippableType(n)) return false; |
336 return n.text.trim().length == 0; | 342 return n.text.trim().length == 0; |
337 } | 343 } |
338 | 344 |
339 void onEnd() { | 345 void onEnd() { |
340 // Hideous hack to send JSON back to JS. | 346 // Hideous hack to send JSON back to JS. |
341 String dbJson = JSON.stringify(dbEntry); | 347 String dbJson = JSON.stringify(dbEntry); |
342 // workaround bug in JSON parser. | 348 // workaround bug in JSON parser. |
343 dbJson = dbJson.replaceAll("ZDARTIUMDOESNTESCAPESLASHNJXXXX", "\\n"); | 349 dbJson = dbJson.replaceAll("ZDARTIUMDOESNTESCAPESLASHNJXXXX", "\\n"); |
344 | 350 |
345 window.postMessage("START_DART_MESSAGE_UNIQUE_IDENTIFIER$dbJson", "*"); | 351 window.postMessage("START_DART_MESSAGE_UNIQUE_IDENTIFIER$dbJson", "*"); |
346 } | 352 } |
347 | 353 |
348 class SectionParseResult { | 354 class SectionParseResult { |
349 final String html; | 355 final String html; |
350 final String url; | 356 final String url; |
351 final String idl; | 357 final String idl; |
352 SectionParseResult(this.html, this.url, this.idl); | 358 SectionParseResult(this.html, this.url, this.idl); |
353 } | 359 } |
354 | 360 |
355 String genCleanHtml(Element root) { | 361 String genCleanHtml(Element root) { |
356 for (Element e in root.queryAll(".$DART_REMOVED")) { | 362 for (final e in root.queryAll(".$DART_REMOVED")) { |
357 e.classes.remove(DART_REMOVED); | 363 e.classes.remove(DART_REMOVED); |
358 } | 364 } |
359 | 365 |
360 // Ditch inline styles. | 366 // Ditch inline styles. |
361 for (Element e in root.queryAll('[style]')) { | 367 for (final e in root.queryAll('[style]')) { |
362 e.attributes.remove('style'); | 368 e.attributes.remove('style'); |
363 } | 369 } |
364 | 370 |
365 // These elements are just tags that we should suppress. | 371 // These elements are just tags that we should suppress. |
366 for (Element e in root.queryAll(".lang.lang-en")) { | 372 for (final e in root.queryAll(".lang.lang-en")) { |
367 e.remove(); | 373 e.remove(); |
368 } | 374 } |
369 | 375 |
376 Element parametersList; | |
377 Element returnValue; | |
378 for (final e in root.queryAll("h6")) { | |
379 if (e.text == 'Parameters') { | |
380 parametersList = e; | |
381 } else if (e.text == 'Return value') { | |
382 returnValue = e; | |
383 } | |
384 } | |
385 | |
386 if (parametersList != null) { | |
387 int numEmptyParameters = 0; | |
388 final parameterDescriptions = root.queryAll("dd"); | |
389 for (Element parameterDescription in parameterDescriptions) { | |
390 if (parameterDescription.text.trim().length == 0) { | |
391 numEmptyParameters++; | |
392 } | |
393 } | |
394 if (numEmptyParameters > 0 && | |
395 numEmptyParameters == parameterDescriptions.length) { | |
396 // Remove the parameter list as it adds zero value as all descriptions | |
397 // are empty. | |
398 parametersList.remove(); | |
399 for (final e in root.queryAll("dl")) { | |
400 e.remove(); | |
401 } | |
402 } else if (parameterDescriptions.length == 0 && | |
403 parametersList.nextElementSibling != null && | |
404 parametersList.nextElementSibling.text.trim() == 'None.') { | |
405 // No need to display that the function takes 0 parameters. | |
406 parametersList.nextElementSibling.remove(); | |
407 parametersList.remove(); | |
408 } | |
409 } | |
410 | |
411 // Heuristic: if the return value is a single word it is a type name not a | |
412 // useful text description so suppress it. | |
Bob Nystrom
2012/02/01 18:41:13
Comments like this are very helpful.
Jacob
2012/02/01 21:12:02
Done.
| |
413 if (returnValue != null && | |
414 returnValue.nextElementSibling != null && | |
415 returnValue.nextElementSibling.text.trim().split(' ').length <= 1) { | |
416 returnValue.nextElementSibling.remove(); | |
417 returnValue.remove(); | |
418 } | |
419 | |
370 bool changed = true; | 420 bool changed = true; |
371 while (changed) { | 421 while (changed) { |
372 changed = false; | 422 changed = false; |
373 while (root.nodes.length == 1) { | 423 while (root.nodes.length == 1 && root.nodes.first is Element) { |
374 Node child = root.nodes.first; | 424 root = root.nodes.first; |
375 if (child is Element) { | 425 changed = true; |
376 root = child; | |
377 changed = true; | |
378 } else { | |
379 // Just calling innerHTML on the parent will be sufficient... | |
380 // and insures the output is properly escaped. | |
381 break; | |
382 } | |
383 } | 426 } |
384 | 427 |
385 // Trim useless nodes from the front. | 428 // Trim useless nodes from the front. |
386 while(root.nodes.length > 0 && | 429 while (root.nodes.length > 0 && |
387 isSkippable(root.nodes.first)) { | 430 isSkippable(root.nodes.first)) { |
388 root.nodes.first.remove(); | 431 root.nodes.first.remove(); |
389 changed = true; | 432 changed = true; |
390 } | 433 } |
391 | 434 |
392 // Trim useless nodes from the back. | 435 // Trim useless nodes from the back. |
393 while(root.nodes.length > 0 && | 436 while (root.nodes.length > 0 && |
394 isSkippable(root.nodes.last())) { | 437 isSkippable(root.nodes.last())) { |
395 root.nodes.last().remove(); | 438 root.nodes.last().remove(); |
396 changed = true; | 439 changed = true; |
397 } | 440 } |
398 } | 441 } |
399 return JSONFIXUPHACK(root.innerHTML); | 442 return JSONFIXUPHACK(root.innerHTML); |
400 } | 443 } |
401 | 444 |
402 String genPrettyHtml(DocumentFragment fragment) { | |
403 return genCleanHtml(fragment); | |
404 } | |
405 | |
406 String genPrettyHtmlFromElement(Element e) { | 445 String genPrettyHtmlFromElement(Element e) { |
407 e = e.clone(true); | 446 e = e.clone(true); |
408 return genCleanHtml(e); | 447 return genCleanHtml(e); |
409 } | 448 } |
410 | 449 |
411 class PostOrderTraversalIterator implements Iterator<Node> { | 450 class PostOrderTraversalIterator implements Iterator<Node> { |
412 | 451 |
413 Node _next; | 452 Node _next; |
414 | 453 |
415 PostOrderTraversalIterator(Node start) { | 454 PostOrderTraversalIterator(Node start) { |
416 _next = _leftMostDescendent(start); | 455 _next = _leftMostDescendent(start); |
417 } | 456 } |
418 | 457 |
419 bool hasNext() => _next != null; | 458 bool hasNext() => _next != null; |
420 | 459 |
421 Node next() { | 460 Node next() { |
422 if (_next == null) return null; | 461 if (_next == null) return null; |
423 Node ret = _next; | 462 final ret = _next; |
424 if (_next.nextNode != null) { | 463 if (_next.nextNode != null) { |
425 _next = _leftMostDescendent(_next.nextNode); | 464 _next = _leftMostDescendent(_next.nextNode); |
426 } else { | 465 } else { |
427 _next = _next.parent; | 466 _next = _next.parent; |
428 } | 467 } |
429 return ret; | 468 return ret; |
430 } | 469 } |
431 | 470 |
432 static Node _leftMostDescendent(Node n) { | 471 static Node _leftMostDescendent(Node n) { |
433 while (n.nodes.length > 0) { | 472 while (n.nodes.length > 0) { |
434 n = n.nodes.first; | 473 n = n.nodes.first; |
435 } | 474 } |
436 return n; | 475 return n; |
437 } | 476 } |
438 } | 477 } |
439 | 478 |
440 class PostOrderTraversal implements Iterable<Node> { | 479 class PostOrderTraversal implements Iterable<Node> { |
441 final Node _node; | 480 final Node _node; |
442 PostOrderTraversal(this._node); | 481 PostOrderTraversal(this._node); |
443 | 482 |
444 Iterator<Node> iterator() => new PostOrderTraversalIterator(_node); | 483 Iterator<Node> iterator() => new PostOrderTraversalIterator(_node); |
445 } | 484 } |
446 | 485 |
447 Range findFirstLine(Range section, String prop) { | 486 Range findFirstLine(Range section, String prop) { |
448 Range firstLine = newRange(); | 487 final firstLine = newRange(); |
449 firstLine.setStart(section.startContainer, section.startOffset); | 488 firstLine.setStart(section.startContainer, section.startOffset); |
450 | 489 |
451 num maxBottom = null; | 490 num maxBottom = null; |
452 for (Node n in new PostOrderTraversal(section.startContainer)) { | 491 for (final n in new PostOrderTraversal(section.startContainer)) { |
453 int compareResult = section.comparePoint(n, 0); | 492 int compareResult = section.comparePoint(n, 0); |
454 if (compareResult == -1) { | 493 if (compareResult == -1) { |
455 // before range so skip. | 494 // before range so skip. |
456 continue; | 495 continue; |
457 } else if (compareResult > 0) { | 496 } else if (compareResult > 0) { |
458 // After range so exit. | 497 // After range so exit. |
459 break; | 498 break; |
460 } | 499 } |
461 | 500 |
462 final rect = getClientRect(n); | 501 final rect = getClientRect(n); |
463 num bottom = rect.bottom; | 502 num bottom = rect.bottom; |
464 if (rect.height > 0 && rect.width > 0) { | 503 if (rect.height > 0 && rect.width > 0) { |
465 if (maxBottom != null && ( | 504 if (maxBottom != null && |
466 maxBottom + MIN_PIXELS_DIFFERENT_LINES < bottom | 505 maxBottom + MIN_PIXELS_DIFFERENT_LINES < bottom) { |
467 )) { | |
468 break; | 506 break; |
469 } else if (maxBottom == null || maxBottom > bottom) { | 507 } else if (maxBottom == null || maxBottom > bottom) { |
470 maxBottom = bottom; | 508 maxBottom = bottom; |
471 } | 509 } |
472 } | 510 } |
473 | 511 |
474 firstLine.setEndAfter(n); | 512 firstLine.setEndAfter(n); |
475 } | 513 } |
476 | 514 |
477 if (firstLine.toString().indexOf(stripWebkit(prop)) == -1) { | 515 // If the first line of text in the section does not contain the property |
516 // name then we're not confident we are able to extract a high accuracy match | |
517 // so we should not return anything. | |
518 if (!firstLine.toString().contains(stripWebkit(prop))) { | |
478 return null; | 519 return null; |
479 } | 520 } |
480 return firstLine; | 521 return firstLine; |
481 } | 522 } |
482 | 523 |
483 AnchorElement findAnchorElement(Element root, String prop) { | 524 AnchorElement findAnchorElement(Element root, String prop) { |
484 for (AnchorElement a in root.queryAll("a")) { | 525 for (AnchorElement a in root.queryAll("a")) { |
485 if (a.text.indexOf(prop) != -1) { | 526 if (a.text.contains(prop)) { |
486 return a; | 527 return a; |
487 } | 528 } |
488 } | 529 } |
489 return null; | 530 return null; |
490 } | 531 } |
491 | 532 |
492 // First surrounding element with an ID is safe enough. | 533 // First surrounding element with an ID is safe enough. |
493 Element findTigherRoot(Element elem, Element root) { | 534 Element findTighterRoot(Element elem, Element root) { |
494 Element candidate = elem; | 535 Element candidate = elem; |
495 while(root != candidate) { | 536 while (root != candidate) { |
496 candidate = candidate.parent; | 537 candidate = candidate.parent; |
497 if (candidate.id.length > 0 && candidate.id.indexOf("section_") != 0) { | 538 if (candidate.id.length > 0 && candidate.id.indexOf("section_") != 0) { |
498 break; | 539 break; |
499 } | 540 } |
500 } | 541 } |
501 return candidate; | 542 return candidate; |
502 } | 543 } |
503 | 544 |
504 // this is very slow and ugly.. consider rewriting. | 545 // TODO(jacobr): this is very slow and ugly.. consider rewriting or at least |
546 // commenting carefully. | |
505 SectionParseResult filteredHtml(Element elem, Element root, String prop, | 547 SectionParseResult filteredHtml(Element elem, Element root, String prop, |
506 Function fragmentGeneratedCallback) { | 548 Function fragmentGeneratedCallback) { |
507 // Using a tighter root avoids false positives at the risk of trimming | 549 // Using a tighter root avoids false positives at the risk of trimming |
508 // text we shouldn't. | 550 // text we shouldn't. |
509 root = findTigherRoot(elem, root); | 551 root = findTighterRoot(elem, root); |
510 Range range = newRange(); | 552 final range = newRange(); |
511 range.setStartBefore(elem); | 553 range.setStartBefore(elem); |
512 | 554 |
513 Element current = elem; | 555 Element current = elem; |
514 while (current != null) { | 556 while (current != null) { |
515 range.setEndBefore(current); | 557 range.setEndBefore(current); |
516 if (current.classes.contains(DART_REMOVED)) { | 558 if (current.classes.contains(DART_REMOVED) && |
517 if (range.toString().trim().length > 0) { | 559 range.toString().trim().length > 0) { |
518 break; | 560 break; |
519 } | |
520 } | 561 } |
521 if (current.firstElementChild != null) { | 562 if (current.firstElementChild != null) { |
522 current = current.firstElementChild; | 563 current = current.firstElementChild; |
523 } else { | 564 } else { |
524 while (current != null) { | 565 while (current != null) { |
525 range.setEndAfter(current); | 566 range.setEndAfter(current); |
526 if (current == root) { | 567 if (current == root) { |
527 current = null; | 568 current = null; |
528 break; | 569 break; |
529 } | 570 } |
(...skipping 10 matching lines...) Expand all Loading... | |
540 Range firstLine = findFirstLine(range, prop); | 581 Range firstLine = findFirstLine(range, prop); |
541 if (firstLine != null) { | 582 if (firstLine != null) { |
542 range.setStart(firstLine.endContainer, firstLine.endOffset); | 583 range.setStart(firstLine.endContainer, firstLine.endOffset); |
543 DocumentFragment firstLineClone = firstLine.cloneContents(); | 584 DocumentFragment firstLineClone = firstLine.cloneContents(); |
544 AnchorElement anchor = findAnchorElement(firstLineClone, prop); | 585 AnchorElement anchor = findAnchorElement(firstLineClone, prop); |
545 if (anchor != null) { | 586 if (anchor != null) { |
546 url = getAbsoluteUrl(anchor); | 587 url = getAbsoluteUrl(anchor); |
547 } | 588 } |
548 } | 589 } |
549 } | 590 } |
550 DocumentFragment fragment = range.cloneContents(); | 591 final fragment = range.cloneContents(); |
551 if (fragmentGeneratedCallback != null) { | 592 if (fragmentGeneratedCallback != null) { |
552 fragmentGeneratedCallback(fragment); | 593 fragmentGeneratedCallback(fragment); |
553 } | 594 } |
554 // Strip tags we don't want | 595 // Strip tags we don't want |
555 for (Element e in fragment.queryAll("script, object, style")) { | 596 for (Element e in fragment.queryAll("script, object, style")) { |
556 e.remove(); | 597 e.remove(); |
557 } | 598 } |
558 | 599 |
559 // Extract idl | 600 // Extract idl |
560 StringBuffer idl = new StringBuffer(); | 601 final idl = new StringBuffer(); |
561 if (prop != null && prop.length > 0) { | 602 if (prop != null && prop.length > 0) { |
562 // Only expect properties to have HTML. | 603 // Only expect properties to have HTML. |
563 for(Element e in fragment.queryAll(IDL_SELECTOR)) { | 604 for(Element e in fragment.queryAll(IDL_SELECTOR)) { |
564 idl.add(e.outerHTML); | 605 idl.add(e.outerHTML); |
565 e.remove(); | 606 e.remove(); |
566 } | 607 } |
567 // TODO(jacobr) this is a very basic regex to see if text looks like IDL | 608 // TODO(jacobr) this is a very basic regex to see if text looks like IDL |
568 RegExp likelyIdl = new RegExp(" $prop\\w*\\("); | 609 RegExp likelyIdl = new RegExp(" $prop\\w*\\("); |
569 | 610 |
570 for (Element e in fragment.queryAll("pre")) { | 611 for (Element e in fragment.queryAll("pre")) { |
571 // Check if it looks like idl... | 612 // Check if it looks like idl... |
572 String txt = e.text.trim(); | 613 String txt = e.text.trim(); |
573 if (likelyIdl.hasMatch(txt) && txt.indexOf("\n") != -1 | 614 if (likelyIdl.hasMatch(txt) && txt.contains("\n") |
574 && txt.indexOf(")") != -1) { | 615 && txt.contains(")")) { |
Bob Nystrom
2012/02/01 18:41:13
This will probably fit on one line now.
Jacob
2012/02/01 21:12:02
Done.
| |
575 idl.add(e.outerHTML); | 616 idl.add(e.outerHTML); |
576 e.remove(); | 617 e.remove(); |
577 } | 618 } |
578 } | 619 } |
579 } | 620 } |
580 return new SectionParseResult(genPrettyHtml(fragment), url, idl.toString()); | 621 return new SectionParseResult(genCleanHtml(fragment), url, idl.toString()); |
581 } | 622 } |
582 | 623 |
583 Element findBest(Element root, List<Text> allText, String prop, String propType) { | 624 Element findBest(Element root, List<Text> allText, String prop, |
625 String propType) { | |
584 // Best bet: match an id | 626 // Best bet: match an id |
585 Element cand; | 627 Element cand; |
586 cand = root.query("#" + prop); | 628 cand = root.query("#$prop"); |
587 | 629 |
588 if (cand == null && propType == "methods") { | 630 if (cand == null && propType == "methods") { |
589 cand = root.query("[id=" + prop + "\\(\\)]"); | 631 cand = root.query("[id=$prop\\(\\)]"); |
632 } | |
633 while (cand != null && cand.text.trim().length == 0) { | |
634 // We found the bookmark for the element but sadly it is just an empty | |
635 // placeholder. Find the first real element. | |
636 cand = cand.nextElementSibling; | |
590 } | 637 } |
591 if (cand != null) { | 638 if (cand != null) { |
592 while (cand != null && cand.text.trim().length == 0) { | 639 return cand; |
593 // We found the bookmark for the element but sadly it is just an empty | |
594 // placeholder. Find the first real element. | |
595 cand = cand.nextElementSibling; | |
596 } | |
597 if (cand != null) { | |
598 return cand; | |
599 } | |
600 } | 640 } |
601 | 641 |
602 // If you are at least 70 pixels from the left, something is definitely fishy and we shouldn't even consider this candidate. | 642 // If you are at least 70 pixels from the left, something is definitely |
643 // fishy and we shouldn't even consider this candidate. | |
603 num candLeft = 70; | 644 num candLeft = 70; |
604 | 645 |
605 for (Text text in allText) { | 646 for (Text text in allText) { |
606 Element proposed = null; | 647 Element proposed = null; |
607 | 648 |
608 // var t = safeNameCleanup(text.text); | 649 // TODO(jacobr): does it hurt precision to use the full cleanup? |
609 // TODO(jacobr): does it hurt precision to use the full cleanup? | |
610 String t = fullNameCleanup(text.text); | 650 String t = fullNameCleanup(text.text); |
611 if (t == prop) { | 651 if (t == prop) { |
612 proposed = text.parent; | 652 proposed = text.parent; |
613 ClientRect candRect = getClientRect(proposed); | 653 ClientRect candRect = getClientRect(proposed); |
614 | 654 |
615 // TODO(jacobr): this is a good heuristic | 655 // TODO(jacobr): this is a good heuristic |
616 // if (selObj.selector.indexOf(" > DD ") == -1 | 656 // if (selObj.selector.indexOf(" > DD ") == -1 |
617 if (candRect.left < candLeft) { | 657 if (candRect.left < candLeft) { |
618 cand = proposed; | 658 cand = proposed; |
619 candLeft = candRect.left; | 659 candLeft = candRect.left; |
620 } | 660 } |
621 } | 661 } |
622 } | 662 } |
623 return cand; | 663 return cand; |
624 } | 664 } |
625 | 665 |
626 bool isObsolete(Element e) { | 666 bool isObsolete(Element e) { |
627 RegExp obsoleteRegExp = new RegExp(@"(^|\s)obsolete(?=\s|$)"); | 667 RegExp obsoleteRegExp = new RegExp(@"(^|\s)obsolete(?=\s|$)"); |
628 RegExp deprecatedRegExp = new RegExp(@"(^|\s)deprecated(?=\s|$)"); | 668 RegExp deprecatedRegExp = new RegExp(@"(^|\s)deprecated(?=\s|$)"); |
629 for (Element child in e.queryAll("span")) { | 669 for (Element child in e.queryAll("span")) { |
630 String t = child.text.toLowerCase(); | 670 String t = child.text.toLowerCase(); |
631 if (t.startsWith("obsolete") || t.startsWith("deprecated")) return true; | 671 if (t.startsWith("obsolete") || t.startsWith("deprecated")) return true; |
632 } | 672 } |
633 | 673 |
634 String text = e.text.toLowerCase(); | 674 String text = e.text.toLowerCase(); |
635 return obsoleteRegExp.hasMatch(text) || deprecatedRegExp.hasMatch(text); | 675 return obsoleteRegExp.hasMatch(text) || deprecatedRegExp.hasMatch(text); |
636 } | 676 } |
637 | 677 |
638 bool isFirstCharLowerCase(String str) { | 678 bool isFirstCharLowerCase(String str) { |
639 RegExp firstLower = new RegExp("^[a-z]"); | 679 return const RegExp("^[a-z]").hasMatch(str); |
640 return firstLower.hasMatch(str); | |
641 } | 680 } |
642 | 681 |
643 void scrapeSection(Element root, String sectionSelector, | 682 // TODO(jacobr): document this method. |
644 String currentType, | 683 void scrapeSection(Element root, String sectionSelector, String currentType, |
645 List members, | 684 List members, String propType) { |
646 String propType) { | |
647 Map expectedProps = dartIdl[propType]; | 685 Map expectedProps = dartIdl[propType]; |
648 | 686 |
649 Set<String> alreadyMatchedProperties = new Set<String>(); | 687 Set<String> alreadyMatchedProperties = new Set<String>(); |
650 bool onlyConsiderTables = false; | 688 bool onlyConsiderTables = false; |
651 ElementList allMatches = root.queryAll(sectionSelector); | 689 ElementList allMatches = root.queryAll(sectionSelector); |
652 if (allMatches.length == 0) { | 690 if (allMatches.length == 0) { |
653 allMatches = root.queryAll(".fullwidth-table"); | 691 allMatches = root.queryAll(".fullwidth-table"); |
654 onlyConsiderTables = true; | 692 onlyConsiderTables = true; |
655 } | 693 } |
656 for (Element matchElement in allMatches) { | 694 for (Element matchElement in allMatches) { |
657 DivElement match = matchElement.parent; | 695 DivElement match = matchElement.parent; |
658 if (!match.id.startsWith("section") && !(match.id == "pageText")) { | 696 if (!match.id.startsWith("section") && match.id != "pageText") { |
659 throw "Enexpected element $match"; | 697 throw "Unexpected element $match"; |
660 } | 698 } |
661 match.classes.add(DART_REMOVED); | 699 match.classes.add(DART_REMOVED); |
662 | 700 |
663 bool foundProps = false; | 701 bool foundProps = false; |
664 | 702 |
665 // TODO(jacobr): we should really look for the table tag instead | 703 // TODO(jacobr): we should really look for the table tag instead |
666 // add an assert if we are missing something that is a table... | 704 // add an assert if we are missing something that is a table... |
667 // TODO(jacobr) ignore tables in tables.... | 705 // TODO(jacobr) ignore tables in tables.... |
668 for (Element t in match.queryAll('.standard-table, .fullwidth-table')) { | 706 for (Element t in match.queryAll('.standard-table, .fullwidth-table')) { |
669 int helpIndex = -1; | 707 int helpIndex = -1; |
670 num i = 0; | 708 num i = 0; |
671 for (Element r in t.queryAll("th, td.header")) { | 709 for (Element r in t.queryAll("th, td.header")) { |
672 var txt = r.text.trim().split(" ")[0].toLowerCase(); | 710 final txt = r.text.trim().split(" ")[0].toLowerCase(); |
673 if (txt == "description") { | 711 if (txt == "description") { |
674 helpIndex = i; | 712 helpIndex = i; |
675 break; | 713 break; |
676 } | 714 } |
677 i++; | 715 i++; |
678 } | 716 } |
679 | 717 |
680 List<int> numMatches = new List<int>(i); | 718 List<int> numMatches = new List<int>(i); |
681 for (int j = 0; j < i; j++) { | 719 for (int j = 0; j < i; j++) { |
682 numMatches[j] = 0; | 720 numMatches[j] = 0; |
683 } | 721 } |
684 | 722 |
685 // Find the row that seems to have the most names that look like | 723 // Find the row that seems to have the most names that look like |
686 // expected properties. | 724 // expected properties. |
687 for (Element r in t.queryAll("tbody tr")) { | 725 for (Element r in t.queryAll("tbody tr")) { |
688 ElementList $row = r.elements; | 726 ElementList row = r.elements; |
689 if ($row.length == 0 || $row.first.classes.contains(".header")) { | 727 if (row.length == 0 || row.first.classes.contains(".header")) { |
690 continue; | 728 continue; |
691 } | 729 } |
692 | 730 |
693 for (int k = 0; k < numMatches.length && k < $row.length; k++) { | 731 for (int k = 0; k < numMatches.length && k < row.length; k++) { |
694 Element e = $row[k]; | 732 if (expectedProps.containsKey(fullNameCleanup(row[k].text))) { |
695 if (expectedProps.containsKey(fullNameCleanup(e.text))) { | |
696 numMatches[k]++; | 733 numMatches[k]++; |
697 break; | 734 break; |
698 } | 735 } |
699 } | 736 } |
700 } | 737 } |
701 | 738 |
702 int propNameIndex = 0; | 739 int propNameIndex = 0; |
703 { | 740 { |
704 int bestCount = numMatches[0]; | 741 int bestCount = numMatches[0]; |
705 for (int k = 1; k < numMatches.length; k++) { | 742 for (int k = 1; k < numMatches.length; k++) { |
706 if (numMatches[k] > bestCount) { | 743 if (numMatches[k] > bestCount) { |
707 bestCount = numMatches[k]; | 744 bestCount = numMatches[k]; |
708 propNameIndex = k; | 745 propNameIndex = k; |
709 } | 746 } |
710 } | 747 } |
711 } | 748 } |
712 | 749 |
713 for (Element r in t.queryAll("tbody tr")) { | 750 for (Element r in t.queryAll("tbody tr")) { |
714 ElementList $row = r.elements; | 751 ElementList row = r.elements; |
715 if ($row.length > propNameIndex && $row.length > helpIndex ) { | 752 if (row.length > propNameIndex && row.length > helpIndex) { |
716 if ($row.first.classes.contains(".header")) { | 753 if (row.first.classes.contains(".header")) { |
717 continue; | 754 continue; |
718 } | 755 } |
719 // TODO(jacobr): this code for determining the namestr is needlessly | 756 // TODO(jacobr): this code for determining the namestr is needlessly |
720 // messy. | 757 // messy. |
721 Element nameRow = $row[propNameIndex]; | 758 Element nameRow = row[propNameIndex]; |
722 AnchorElement a = nameRow.query("a"); | 759 AnchorElement a = nameRow.query("a"); |
723 String goodName = ''; | 760 String goodName = ''; |
724 if (a != null) { | 761 if (a != null) { |
725 goodName = a.text.trim(); | 762 goodName = a.text.trim(); |
726 } | 763 } |
727 String nameStr = nameRow.text; | 764 String nameStr = nameRow.text; |
728 | 765 |
729 Map entry = new Map<String, String>(); | 766 Map entry = new Map<String, String>(); |
730 | 767 |
731 // "currentType": $($row[1]).text().trim(), // find("code") ? | 768 entry["name"] = fullNameCleanup(nameStr.length > 0 ? |
732 entry["name"] = fullNameCleanup(nameStr.length > 0 ? nameStr : goodNam e); | 769 nameStr : goodName); |
733 | 770 |
734 final parse = filteredHtml(nameRow, nameRow, entry["name"], null); | 771 final parse = filteredHtml(nameRow, nameRow, entry["name"], null); |
735 String altHelp = parse.html; | 772 String altHelp = parse.html; |
736 | 773 |
737 // "jsSignature": nameStr, | 774 entry["help"] = (helpIndex == -1 || row[helpIndex] == null) ? |
738 entry["help"] = (helpIndex == -1 || $row[helpIndex] == null) ? altHelp : genPrettyHtmlFromElement($row[helpIndex]); | 775 altHelp : genPrettyHtmlFromElement(row[helpIndex]); |
739 // "altHelp" : altHelp, | |
740 if (parse.url != null) { | 776 if (parse.url != null) { |
741 entry["url"] = parse.url; | 777 entry["url"] = parse.url; |
742 } | 778 } |
743 | 779 |
744 if (parse.idl.length > 0) { | 780 if (parse.idl.length > 0) { |
745 entry["idl"] = parse.idl; | 781 entry["idl"] = parse.idl; |
746 } | 782 } |
747 | 783 |
748 entry["obsolete"] = isObsolete(r); | 784 entry["obsolete"] = isObsolete(r); |
749 | 785 |
(...skipping 20 matching lines...) Expand all Loading... | |
770 if (alreadyMatchedProperties.contains(prop)) { | 806 if (alreadyMatchedProperties.contains(prop)) { |
771 continue; | 807 continue; |
772 } | 808 } |
773 Element e = findBest(match, allText, prop, propType); | 809 Element e = findBest(match, allText, prop, propType); |
774 if (e != null && !inTable(e)) { | 810 if (e != null && !inTable(e)) { |
775 pmap[prop] = e; | 811 pmap[prop] = e; |
776 } | 812 } |
777 } | 813 } |
778 | 814 |
779 for (String prop in pmap.getKeys()) { | 815 for (String prop in pmap.getKeys()) { |
780 Element e = pmap[prop]; | 816 pmap[prop].classes.add(DART_REMOVED); |
781 e.classes.add(DART_REMOVED); | |
782 } | 817 } |
783 | 818 |
784 for (String prop in pmap.getKeys()) { | 819 for (String prop in pmap.getKeys()) { |
785 Element e = pmap[prop]; | 820 Element e = pmap[prop]; |
786 ClientRect r = getClientRect(e); | 821 ClientRect r = getClientRect(e); |
787 // TODO(jacobr): a lot of these queries are identical. | 822 // TODO(jacobr): a lot of these queries are identical. |
788 for (Element cand in match.queryAll(e.tagName)) { | 823 for (Element cand in match.queryAll(e.tagName)) { |
789 if (!cand.classes.contains(DART_REMOVED) && !inTable(cand) ) { // XXX us e a neg selector. | 824 // TODO(jacobr): use a negative selector instead. |
825 if (!cand.classes.contains(DART_REMOVED) && !inTable(cand)) { | |
790 ClientRect candRect = getClientRect(cand); | 826 ClientRect candRect = getClientRect(cand); |
791 // TODO(jacobr): this is somewhat loose. | 827 // TODO(jacobr): this is somewhat loose. |
792 if (candRect.left == r.left && | 828 if (candRect.left == r.left && |
793 (candRect.height - r.height).abs() < 5) { | 829 (candRect.height - r.height).abs() < 5) { |
794 String propName = fullNameCleanup(cand.text); | 830 String propName = fullNameCleanup(cand.text); |
795 if (isFirstCharLowerCase(propName) && pmap.containsKey(propName) == false && alreadyMatchedProperties.contains(propName) == false) { | 831 if (isFirstCharLowerCase(propName) && !pmap.containsKey(propName) |
796 // Don't set here to avoid layouts... cand.classes.add(DART_REMOVE D); | 832 && !alreadyMatchedProperties.contains(propName)) { |
797 pmap[propName] = cand; | 833 pmap[propName] = cand; |
798 } | 834 } |
799 } | 835 } |
800 } | 836 } |
801 } | 837 } |
802 } | 838 } |
803 | 839 |
804 for (String prop in pmap.getKeys()) { | 840 for (String prop in pmap.getKeys()) { |
805 Element e = pmap[prop]; | 841 Element e = pmap[prop]; |
806 e.classes.add(DART_REMOVED); | 842 e.classes.add(DART_REMOVED); |
807 } | 843 } |
808 | 844 |
809 // Find likely "subsections" of the main section and mark them with | 845 // Find likely "subsections" of the main section and mark them with |
810 // DART_REMOVED so we don't include them in member descriptions... which | 846 // DART_REMOVED so we don't include them in member descriptions... which |
811 // would suck. | 847 // would suck. |
812 for (Element e in match.queryAll("[id]")) { | 848 for (Element e in match.queryAll("[id]")) { |
813 if (e.id.indexOf(matchElement.id) != -1) { | 849 if (e.id.contains(matchElement.id)) { |
814 e.classes.add(DART_REMOVED); | 850 e.classes.add(DART_REMOVED); |
815 } | 851 } |
816 } | 852 } |
817 | 853 |
818 for (String prop in pmap.getKeys()) { | 854 for (String prop in pmap.getKeys()) { |
819 Element elem = pmap[prop]; | 855 Element elem = pmap[prop]; |
820 bool obsolete = false; | 856 bool obsolete = false; |
821 final parse = filteredHtml( | 857 final parse = filteredHtml( |
822 elem, match, prop, | 858 elem, match, prop, |
823 (Element e) { | 859 (Element e) { |
824 obsolete = isObsolete(e); | 860 obsolete = isObsolete(e); |
825 }); | 861 }); |
826 Map entry = { | 862 Map entry = { |
827 "url" : parse.url, | 863 "url" : parse.url, |
828 "name" : prop, | 864 "name" : prop, |
829 "help" : parse.html, | 865 "help" : parse.html, |
830 "obsolete" : obsolete | 866 "obsolete" : obsolete |
831 //"jsSignature" : nameStr | |
832 }; | 867 }; |
833 if (parse.idl.length > 0) { | 868 if (parse.idl.length > 0) { |
834 entry["idl"] = parse.idl; | 869 entry["idl"] = parse.idl; |
835 } | 870 } |
836 cleanupEntry(members, entry); | 871 cleanupEntry(members, entry); |
837 } | 872 } |
838 } | 873 } |
839 } | 874 } |
840 | 875 |
841 String trimHtml(String html) { | 876 String trimHtml(String html) { |
842 // TODO(jacobr): impl. | 877 // TODO(jacobr): impl. |
843 return html; | 878 return html; |
844 } | 879 } |
845 | 880 |
846 bool maybeName(String name) { | 881 bool maybeName(String name) { |
Bob Nystrom
2012/02/01 18:41:13
Doesn't seem to be used?
Jacob
2012/02/01 21:12:02
It is used. You must be just searching this diff
| |
847 RegExp nameRegExp = new RegExp("^[a-z][a-z0-9A-Z]+\$"); | 882 return const RegExp("^[a-z][a-z0-9A-Z]+\$").hasMatch(name) || |
848 if (nameRegExp.hasMatch(name)) return true; | 883 const RegExp("^[A-Z][A-Z_]*\$").hasMatch(name); |
849 RegExp constRegExp = new RegExp("^[A-Z][A-Z_]*\$"); | |
850 if (constRegExp.hasMatch(name)) return true; | |
851 } | 884 } |
852 | 885 |
853 void markRemoved(var e) { | 886 void markRemoved(var e) { |
854 if (e != null) { | 887 if (e != null) { |
855 // TODO( remove) | 888 // TODO( remove) |
856 if (e is Element) { | 889 if (e is Element) { |
857 e.classes.add(DART_REMOVED); | 890 e.classes.add(DART_REMOVED); |
858 } else { | 891 } else { |
859 for (Element el in e) { | 892 for (Element el in e) { |
860 el.classes.add(DART_REMOVED); | 893 el.classes.add(DART_REMOVED); |
861 } | 894 } |
862 } | 895 } |
863 } | 896 } |
864 } | 897 } |
865 | 898 |
866 String JSONFIXUPHACK(String value) { | 899 String JSONFIXUPHACK(String value) { |
867 return value.replaceAll("\n", "ZDARTIUMDOESNTESCAPESLASHNJXXXX"); | 900 return value.replaceAll("\n", "ZDARTIUMDOESNTESCAPESLASHNJXXXX"); |
868 } | 901 } |
869 | 902 |
870 String mozToWebkit(String name) { | 903 String mozToWebkit(String name) { |
871 RegExp regExp = new RegExp("^moz"); | 904 return name.replaceFirst(const RegExp("^moz"), "webkit"); |
872 name = name.replaceFirst(regExp, "webkit"); | |
873 return name; | |
874 } | 905 } |
875 | 906 |
876 String stripWebkit(String name) { | 907 String stripWebkit(String name) { |
877 return trimPrefix(name, "webkit"); | 908 return trimPrefix(name, "webkit"); |
878 } | 909 } |
879 | 910 |
880 String fullNameCleanup(String name) { | 911 String fullNameCleanup(String name) { |
881 int parenIndex = name.indexOf('('); | 912 int parenIndex = name.indexOf('('); |
882 if (parenIndex != -1) { | 913 if (parenIndex != -1) { |
883 // TODO(jacobr): workaround bug in: | 914 // TODO(jacobr): workaround bug in: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
943 | 974 |
944 // TODO(jacobr) dup with trim start.... | 975 // TODO(jacobr) dup with trim start.... |
945 String trimPrefix(String str, String prefix) { | 976 String trimPrefix(String str, String prefix) { |
946 if (str.indexOf(prefix) == 0) { | 977 if (str.indexOf(prefix) == 0) { |
947 return str.substring(prefix.length); | 978 return str.substring(prefix.length); |
948 } else { | 979 } else { |
949 return str; | 980 return str; |
950 } | 981 } |
951 } | 982 } |
952 | 983 |
953 void resourceLoaded() { | |
954 if (data != null) run(); | |
955 } | |
956 | |
957 String trimStart(String str, String start) { | 984 String trimStart(String str, String start) { |
958 if (str.startsWith(start) && str.length > start.length) { | 985 if (str.startsWith(start) && str.length > start.length) { |
959 return str.substring(start.length); | 986 return str.substring(start.length); |
960 } | 987 } |
961 return str; | 988 return str; |
962 } | 989 } |
963 | 990 |
964 String trimEnd(String str, String end) { | 991 String trimEnd(String str, String end) { |
965 if (str.endsWith(end) && str.length > end.length) { | 992 if (str.endsWith(end) && str.length > end.length) { |
966 return str.substring(0, str.length - end.length); | 993 return str.substring(0, str.length - end.length); |
(...skipping 13 matching lines...) Expand all Loading... | |
980 dbEntry[key] += html; | 1007 dbEntry[key] += html; |
981 } else { | 1008 } else { |
982 dbEntry[key] = html; | 1009 dbEntry[key] = html; |
983 } | 1010 } |
984 } | 1011 } |
985 e.classes.add(DART_REMOVED); | 1012 e.classes.add(DART_REMOVED); |
986 } | 1013 } |
987 } | 1014 } |
988 | 1015 |
989 void run() { | 1016 void run() { |
990 // Inject CSS to insure lines don't wrap unless it was intentional. | 1017 // Inject CSS to ensure lines don't wrap unless it was intentional. |
991 document.head.nodes.add(new Element.html(""" | 1018 document.head.nodes.add(new Element.html(""" |
992 <style type="text/css"> | 1019 <style type="text/css"> |
993 body { | 1020 body { |
994 width: 10000px; | 1021 width: 10000px; |
995 } | 1022 } |
996 </style>""")); | 1023 </style>""")); |
997 | 1024 |
998 String title = trimEnd(window.document.title.trim(), " - MDN"); | 1025 String title = trimEnd(window.document.title.trim(), " - MDN"); |
999 dbEntry['title'] = title; | 1026 dbEntry['title'] = title; |
1000 | 1027 |
1001 // TODO(rnystrom): Clean up the page a bunch. Not sure if this is the best | 1028 // TODO(rnystrom): Clean up the page a bunch. Not sure if this is the best |
1002 // place to do this... | 1029 // place to do this... |
1003 | 1030 |
1004 // Remove the "Introduced in HTML <version>" boxes. | 1031 // Remove the "Introduced in HTML <version>" boxes. |
1005 for (Element e in document.queryAll('.htmlVersionHeaderTemplate')) { | 1032 for (Element e in document.queryAll('.htmlVersionHeaderTemplate')) { |
1006 e.remove(); | 1033 e.remove(); |
1007 } | 1034 } |
1008 | 1035 |
1009 // Flatten the list of known DOM types into a faster and case-insensitive map. | 1036 // Flatten the list of known DOM types into a faster and case-insensitive |
1037 // map. | |
1010 domTypes = {}; | 1038 domTypes = {}; |
1011 for (final domType in domTypesRaw) { | 1039 for (final domType in domTypesRaw) { |
1012 domTypes[domType.toLowerCase()] = domType; | 1040 domTypes[domType.toLowerCase()] = domType; |
1013 } | 1041 } |
1014 | 1042 |
1015 // Fix up links. | 1043 // Fix up links. |
1016 final SHORT_LINK = const RegExp(@'^[\w/]+$'); | 1044 final SHORT_LINK = const RegExp(@'^[\w/]+$'); |
1017 final INNER_LINK = const RegExp(@'[Ee]n/(?:[\w/]+/|)([\w#.]+)(?:\(\))?$'); | 1045 final INNER_LINK = const RegExp(@'[Ee]n/(?:[\w/]+/|)([\w#.]+)(?:\(\))?$'); |
1018 final MEMBER_LINK = const RegExp(@'(\w+)[.#](\w+)'); | 1046 final MEMBER_LINK = const RegExp(@'(\w+)[.#](\w+)'); |
1019 final RELATIVE_LINK = const RegExp(@'^(?:../)*/?[Ee][Nn]/(.+)'); | 1047 final RELATIVE_LINK = const RegExp(@'^(?:../)*/?[Ee][Nn]/(.+)'); |
1020 | 1048 |
1021 // - Make relative links absolute. | 1049 // - Make relative links absolute. |
1022 // - If we can, take links that point to other MDN pages and retarget them | 1050 // - If we can, take links that point to other MDN pages and retarget them |
1023 // to appropriate pages in our docs. | 1051 // to appropriate pages in our docs. |
1024 // TODO(rnystrom): Add rel external to links we didn't fix. | 1052 // TODO(rnystrom): Add rel external to links we didn't fix. |
1025 for (AnchorElement a in document.queryAll('a')) { | 1053 for (AnchorElement a in document.queryAll('a')) { |
1026 // Get the raw attribute because we *don't* want the browser to fully- | 1054 // Get the raw attribute because we *don't* want the browser to fully- |
1027 // qualify the name for us since it has the wrong base address for the page. | 1055 // qualify the name for us since it has the wrong base address for the |
1056 // page. | |
1028 var href = a.attributes['href']; | 1057 var href = a.attributes['href']; |
1029 | 1058 |
1030 // Ignore busted links. | 1059 // Ignore busted links. |
1031 if (href == null) continue; | 1060 if (href == null) continue; |
1032 | 1061 |
1033 // If we can recognize what it's pointing to, point it to our page instead. | 1062 // If we can recognize what it's pointing to, point it to our page instead. |
1034 tryToLinkToRealType(maybeType) { | 1063 tryToLinkToRealType(maybeType) { |
1035 // See if we know a type with that name. | 1064 // See if we know a type with that name. |
1036 final realType = domTypes[maybeType.toLowerCase()]; | 1065 final realType = domTypes[maybeType.toLowerCase()]; |
1037 if (realType != null) { | 1066 if (realType != null) { |
(...skipping 25 matching lines...) Expand all Loading... | |
1063 tryToLinkToRealType(member[1]); | 1092 tryToLinkToRealType(member[1]); |
1064 } else { | 1093 } else { |
1065 tryToLinkToRealType(match[1]); | 1094 tryToLinkToRealType(match[1]); |
1066 } | 1095 } |
1067 } | 1096 } |
1068 | 1097 |
1069 // Put it back into the element. | 1098 // Put it back into the element. |
1070 a.attributes['href'] = href; | 1099 a.attributes['href'] = href; |
1071 } | 1100 } |
1072 | 1101 |
1073 if (title.toLowerCase().indexOf(currentTypeTiny.toLowerCase()) == -1) { | 1102 if (!title.toLowerCase().contains(currentTypeTiny.toLowerCase())) { |
1074 bool foundMatch = false; | 1103 bool foundMatch = false; |
1075 // Test out if the title is really an HTML tag that matches the | 1104 // Test out if the title is really an HTML tag that matches the |
1076 // current class name. | 1105 // current class name. |
1077 for (String tag in [title.split(" ")[0], title.split(".").last()]) { | 1106 for (String tag in [title.split(" ")[0], title.split(".").last()]) { |
1078 try { | 1107 try { |
1079 dom.Element element = dom.document.createElement(tag); | 1108 dom.Element element = dom.document.createElement(tag); |
1080 if (element.typeName == currentType) { | 1109 if (element.typeName == currentType) { |
1081 foundMatch = true; | 1110 foundMatch = true; |
1082 break; | 1111 break; |
1083 } | 1112 } |
1084 } catch(e) {} | 1113 } catch(e) {} |
1085 } | 1114 } |
1086 if (foundMatch == false) { | 1115 if (!foundMatch ){ |
Bob Nystrom
2012/02/01 18:41:13
Remove space before ")".
Jacob
2012/02/01 21:12:02
rem oved space )
| |
1087 dbEntry['skipped'] = true; | 1116 dbEntry['skipped'] = true; |
1088 dbEntry['cause'] = "Suspect title"; | 1117 dbEntry['cause'] = "Suspect title"; |
1089 onEnd(); | 1118 onEnd(); |
1090 return; | 1119 return; |
1091 } | 1120 } |
1092 } | 1121 } |
1093 | 1122 |
1094 Element root = document.query(".pageText"); | 1123 Element root = document.query(".pageText"); |
1095 if (root == null) { | 1124 if (root == null) { |
1096 dbEntry['cause'] = '.pageText not found'; | 1125 dbEntry['cause'] = '.pageText not found'; |
1097 onEnd(); | 1126 onEnd(); |
1098 return; | 1127 return; |
1099 } | 1128 } |
1100 | 1129 |
1101 markRemoved(root.query("#Notes")); | 1130 markRemoved(root.query("#Notes")); |
1102 List members = dbEntry['members']; | 1131 List members = dbEntry['members']; |
1103 | 1132 |
1104 markRemoved(document.queryAll(".pageToc, footer, header, #nav-toolbar")); | 1133 markRemoved(document.queryAll(".pageToc, footer, header, #nav-toolbar")); |
1105 markRemoved(document.queryAll("#article-nav")); | 1134 markRemoved(document.queryAll("#article-nav")); |
1106 markRemoved(document.queryAll(".hideforedit")); | 1135 markRemoved(document.queryAll(".hideforedit")); |
1107 markRemoved(document.queryAll(".navbox")); | 1136 markRemoved(document.queryAll(".navbox")); |
1108 markRemoved(document.query("#Method_overview")); | 1137 markRemoved(document.query("#Method_overview")); |
1109 markRemoved(document.queryAll("h1, h2")); | 1138 markRemoved(document.queryAll("h1, h2")); |
1110 | 1139 |
1111 scrapeSection(root, "#Methods", currentType, members, 'methods'); | 1140 scrapeSection(root, "#Methods", currentType, members, 'methods'); |
1112 scrapeSection(root, "#Constants, #Error_codes, #State_constants", currentType, members, 'constants'); | 1141 scrapeSection(root, "#Constants, #Error_codes, #State_constants", |
1142 currentType, members, 'constants'); | |
1113 // TODO(jacobr): infer tables based on multiple matches rather than | 1143 // TODO(jacobr): infer tables based on multiple matches rather than |
1114 // using a hard coded list of section ids. | 1144 // using a hard coded list of section ids. |
1115 scrapeSection(root, | 1145 scrapeSection(root, |
1116 "[id^=Properties], #Notes, [id^=Other_properties], #Attributes, #DOM_prope rties, #Event_handlers, #Event_Handlers", | 1146 "[id^=Properties], #Notes, [id^=Other_properties], #Attributes, " + |
1147 "#DOM_properties, #Event_handlers, #Event_Handlers", | |
1117 currentType, members, 'properties'); | 1148 currentType, members, 'properties'); |
1118 | 1149 |
1119 // Avoid doing this till now to avoid messing up the section scrape. | 1150 // Avoid doing this till now to avoid messing up the section scrape. |
1120 markRemoved(document.queryAll("h3")); | 1151 markRemoved(document.queryAll("h3")); |
1121 | 1152 |
1122 ElementList $examples = root.queryAll("span[id^=example], span[id^=Example]"); | 1153 ElementList examples = root.queryAll("span[id^=example], span[id^=Example]"); |
1123 | 1154 |
1124 extractSection("#See_also", 'seeAlso'); | 1155 extractSection("#See_also", 'seeAlso'); |
1125 extractSection("#Specification, #Specifications", "specification"); | 1156 extractSection("#Specification, #Specifications", "specification"); |
1126 // $("#Methods").parent().remove(); // not safe (e.g. Document) | |
1127 | 1157 |
1128 // TODO(jacobr): actually extract the constructor(s) | 1158 // TODO(jacobr): actually extract the constructor(s) |
1129 extractSection("#Constructor, #Constructors", 'constructor'); | 1159 extractSection("#Constructor, #Constructors", 'constructor'); |
1130 extractSection("#Browser_compatibility, #Compatibility", 'compatibility'); | 1160 extractSection("#Browser_compatibility, #Compatibility", 'compatibility'); |
1131 | 1161 |
1132 List<String> exampleHtml = []; | 1162 List<String> exampleHtml = []; |
1133 for (Element e in $examples) { | 1163 for (Element e in examples) { |
1134 e.classes.add(DART_REMOVED); | 1164 e.classes.add(DART_REMOVED); |
1135 } | 1165 } |
1136 for (Element e in $examples) { | 1166 for (Element e in examples) { |
1137 String html = filteredHtml(e, root, null, | 1167 String html = filteredHtml(e, root, null, |
1138 (DocumentFragment fragment) { | 1168 (DocumentFragment fragment) { |
1139 removeHeaders(fragment); | 1169 removeHeaders(fragment); |
1140 if (fragment.text.trim().toLowerCase() == "example") { | 1170 if (fragment.text.trim().toLowerCase() == "example") { |
1141 // Degenerate example. | 1171 // Degenerate example. |
1142 fragment.nodes.clear(); | 1172 fragment.nodes.clear(); |
1143 } | 1173 } |
1144 }).html; | 1174 }).html; |
1145 if (html.length > 0) { | 1175 if (html.length > 0) { |
1146 exampleHtml.add(html); | 1176 exampleHtml.add(html); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1182 } | 1212 } |
1183 | 1213 |
1184 void main() { | 1214 void main() { |
1185 window.on.load.add(documentLoaded); | 1215 window.on.load.add(documentLoaded); |
1186 } | 1216 } |
1187 | 1217 |
1188 void documentLoaded(event) { | 1218 void documentLoaded(event) { |
1189 new XMLHttpRequest.getTEMPNAME('${window.location}.json', (req) { | 1219 new XMLHttpRequest.getTEMPNAME('${window.location}.json', (req) { |
1190 data = JSON.parse(req.responseText); | 1220 data = JSON.parse(req.responseText); |
1191 dbEntry = {'members': [], 'srcUrl': pageUrl}; | 1221 dbEntry = {'members': [], 'srcUrl': pageUrl}; |
1192 resourceLoaded(); | 1222 run(); |
1193 }); | 1223 }); |
1194 } | 1224 } |
OLD | NEW |