home *** CD-ROM | disk | FTP | other *** search
/ Practical Internet Web Designer 86 / PIWD86.iso / pc / contents / dreamweaver / software / dwmx2004.exe / Disk1 / data1.cab / Configuration_En / Commands / PMScanners.js < prev    next >
Encoding:
JavaScript  |  2003-09-05  |  54.9 KB  |  2,522 lines

  1. //=========================================================================================================
  2. //
  3. // Copyright 2002 Macromedia, Inc. All rights reserved.
  4. //
  5. // Feature: Paste Fix
  6. // Author:  JDH
  7. // Module:  PMScanners.js
  8. // Purpose: HTML Scanning classes.
  9. // Updates:
  10. //    5/31/02 - Started file control
  11. //
  12. //=========================================================================================================
  13.  
  14.  
  15. // This source file contains a number of generic helper classes that parse or alter a stream of HTML using
  16. // the scanSourceString functionality in the Dreamweaver class.  The pattern for the use of all of these 
  17. // classes is:
  18. //
  19. // var scanner = new <scanner_name>( <args> );
  20. // var retVal = scanner.scan( html );
  21. //
  22. // Where the retVal is either the altered HTML (for a scanner that alters HTML), or an array (or associative
  23. // array) for scanners that parse the HTML looking for specific tags.
  24. //
  25. // These classes are essentially unrolled, by which I mean that, while there are more elegant multi-level
  26. // hierachal solutions to the problems solved by these scanners, I took a more lightweight approach and made
  27. // more scanners that had lower levels of functionality, and did not descend from a large hierarchy.  The
  28. // reason was mainly effeciency and simplicity.  Only the StructureScanner class is meant to be derived from
  29. // during use.
  30.  
  31. // Some thoughts on scanSourceString:
  32. //
  33. // 1) Only implement the methods in the class that you need to get your job done.  Don't implement closeTagBegin
  34. // if you don't need it.  scanSourceString looks for the existence of these methods at the beginning of the parse
  35. // and will short-curcuit the call if you haven't defined a method, and that will save you some time.  It also
  36. // makes the intention of your code more clear.
  37. //
  38. // 2) Don't return anything from the scanSourceString methods.  scanSourceString isn't looking for a return value
  39. // so don't give it one.
  40. //
  41. // 3) I've seen a pattern in other code where you create an object with new Object and then add methods in 
  42. // on slots using new Function.  I think the code is hard to read and hard to maintain, without performance benefit.
  43. // I would avoid this pattern and I have not used it here.
  44.  
  45.  
  46. function handleAttributeText( str )
  47. {
  48.     str = str.replace( /\"/g, "" );
  49.     return str;
  50. }
  51.  
  52.  
  53. //---------------------------------------------------------------------------------------------------------
  54. //  GetContentScanner
  55. //---------------------------------------------------------------------------------------------------------
  56.  
  57. // The GetContentScanner class gets the contents of any tags in the array of tags
  58. // specified in the input array. For example, specifying:  [ "p" ] and then scanning
  59. // this:
  60. //
  61. // <html><body><p>This</p><p>is</p><p>a</p><p>test</p></body></html>
  62. //
  63. // Would return an array like, [ "This", "is", "a", "test" ].
  64. //
  65. // Please note that this code was specifically designed to ignore directives and to get the
  66. // contents within directives.
  67. //
  68. // This scanner does not alter the HTML in any way.
  69.  
  70. function GetContentScanner( tagNameArray )
  71. {
  72.     this._tagNameArray = tagNameArray;
  73.     this._findLookup = {};
  74.     for( var index in tagNameArray )
  75.         this._findLookup[ tagNameArray[ index ] ] = 1;
  76. }
  77.  
  78. // External methods
  79.  
  80. GetContentScanner.prototype.scan = GetContentScanner_scan;
  81.  
  82. // scanSourceString specific methods
  83.  
  84. GetContentScanner.prototype.directive = GetContentScanner_directive;
  85. GetContentScanner.prototype.text = GetContentScanner_text;
  86. GetContentScanner.prototype.openTagBegin = GetContentScanner_openTagBegin;
  87. GetContentScanner.prototype.closeTagBegin = GetContentScanner_closeTagBegin;
  88.  
  89. function GetContentScanner_scan( source )
  90. {
  91.     this._found = [];
  92.     this._inTag = false;
  93.     this._directives = [];
  94.     this._scan_error = false;
  95.  
  96.     dw.scanSourceString( source, this );
  97.  
  98.     if ( this._scan_error )
  99.         throw( "GetContentScanner bad scan" );
  100.  
  101.     for( var dir_index in this._directives )
  102.         dw.scanSourceString( this._directives[ dir_index ], this );
  103.  
  104.     return this._found;
  105. }
  106.  
  107. function GetContentScanner_directive( code, offset )
  108. {
  109.     try {
  110.  
  111.         code = code.replace( /^\<([^>]*)>/, "" );
  112.         code = code.replace( /\<([^>]*)>$/, "" );
  113.  
  114.         this._directives.push( code );
  115.  
  116.     } catch(e) {
  117.  
  118.         this._scan_error = false;
  119.         return false;
  120.  
  121.     }
  122.  
  123.     return true;
  124. }
  125.  
  126. function GetContentScanner_text( code, offset )
  127. {
  128.     try {
  129.  
  130.         if ( this._inTag )
  131.             this._found.push( code );
  132.  
  133.     } catch(e) {
  134.  
  135.         this._scan_error = false;
  136.         return false;
  137.  
  138.     }
  139.  
  140.     return true;
  141. }
  142.  
  143. function GetContentScanner_openTagBegin( tag, offset )
  144. {
  145.     try {
  146.  
  147.         if ( this._findLookup[ tag.toLowerCase() ] )
  148.             this._inTag = true;
  149.  
  150.     } catch(e) {
  151.  
  152.         this._scan_error = false;
  153.         return false;
  154.  
  155.     }
  156.  
  157.     return true;
  158. }
  159.  
  160. function GetContentScanner_closeTagBegin( tag, offset )
  161. {
  162.     try {
  163.  
  164.         if ( this._findLookup[ tag.toLowerCase() ] )
  165.             this._inTag = false;
  166.  
  167.     } catch(e) {
  168.  
  169.         this._scan_error = false;
  170.         return false;
  171.  
  172.     }
  173.  
  174.     return true;
  175. }
  176.  
  177.  
  178.  
  179.  
  180. //---------------------------------------------------------------------------------------------------------
  181. //  FindDirectiveScanner
  182. //---------------------------------------------------------------------------------------------------------
  183.  
  184. // The FindDirectiveScanner class gets the contents of any tags in the array of tags
  185. // specified in the input array. For example, specifying:  [ "p" ] and then scanning
  186. // this:
  187. //
  188. // <html><body><p>This</p><p>is</p><p>a</p><p>test</p></body></html>
  189. //
  190. // Would return an array like, [ "This", "is", "a", "test" ].
  191. //
  192. // Please note that this code was specifically designed to ignore directives and to get the
  193. // contents within directives.
  194. //
  195. // This scanner does not alter the HTML in any way.
  196.  
  197. function FindDirectiveScanner( directive )
  198. {
  199.     this._directive = directive;
  200. }
  201.  
  202. // External methods
  203.  
  204. FindDirectiveScanner.prototype.scan = FindDirectiveScanner_scan;
  205.  
  206. // scanSourceString specific methods
  207.  
  208. FindDirectiveScanner.prototype.directive = FindDirectiveScanner_directive;
  209.  
  210. function FindDirectiveScanner_scan( source )
  211. {
  212.     this._found = false;
  213.     this._scan_error = false;
  214.  
  215.     dw.scanSourceString( source, this );
  216.  
  217.     if ( this._scan_error )
  218.         throw( "FindDirectiveScanner bad scan" );
  219.  
  220.     return this._found;
  221. }
  222.  
  223. function FindDirectiveScanner_directive( code, offset )
  224. {
  225.     try {
  226.  
  227.         if ( code == this._directive )
  228.             this._found = true;
  229.  
  230.         return true;
  231.  
  232.     } catch(e) {
  233.  
  234.         this._scan_error = false;
  235.         return false;
  236.  
  237.     }
  238.  
  239.     return true;
  240. }
  241.  
  242.  
  243. //---------------------------------------------------------------------------------------------------------
  244. //  GetMetaTagsScanner
  245. //---------------------------------------------------------------------------------------------------------
  246.  
  247. // Scans the source string for meta tags and returns an associative array
  248. // of name value pairs.  For example, scanning this HTML:
  249. //
  250. // <html><head>
  251. // <meta name="key1" content="value1">
  252. // <meta name="key2" content="value2">
  253. // </head></html>
  254. //
  255. // Will return { key1: "value1", key2: "value2" }
  256. //
  257. // This scanner does not alter the HTML in any way.
  258.  
  259. function GetMetaTagsScanner( ) { }
  260.  
  261. // External methods
  262.  
  263. GetMetaTagsScanner.prototype.scan = GetMetaTagsScanner_scan;
  264.  
  265. // scanSourceString specific methods
  266.  
  267. GetMetaTagsScanner.prototype.openTagBegin = GetMetaTagsScanner_openTagBegin;
  268. GetMetaTagsScanner.prototype.closeTagBegin = GetMetaTagsScanner_closeTagBegin;
  269. GetMetaTagsScanner.prototype.attribute = GetMetaTagsScanner_attribute;
  270.  
  271. function GetMetaTagsScanner_scan( source )
  272. {
  273.     this._found = {};
  274.     this._inMeta = false;
  275.     this._name = null;
  276.     this._content = null;
  277.     this._scan_error = false;
  278.  
  279.     dw.scanSourceString( source, this );
  280.  
  281.     if ( this._scan_error )
  282.         throw( "GetMetaTagsScanner bad scan" );
  283.  
  284.     return this._found;
  285. }
  286.  
  287. function GetMetaTagsScanner_openTagBegin( tag, offset )
  288. {
  289.     try {
  290.  
  291.         if ( tag.toLowerCase() == "meta" )
  292.         {
  293.             this._inMeta = true;
  294.             this._name = null;
  295.             this._content = null;
  296.         }
  297.  
  298.     } catch( e ) {
  299.  
  300.         this._scan_error = true;
  301.         return false;
  302.  
  303.     }
  304. }
  305.  
  306. function GetMetaTagsScanner_closeTagBegin( tag, offset )
  307. {
  308.     try {
  309.  
  310.         if ( this._inMeta )
  311.             this._inMeta = false;
  312.  
  313.     } catch( e ) {
  314.  
  315.         this._scan_error = true;
  316.         return false;
  317.  
  318.     }
  319. }
  320.  
  321. function GetMetaTagsScanner_attribute( name, code )
  322. {
  323.     try {
  324.  
  325.         if ( this._inMeta )
  326.         {
  327.             if ( name.toLowerCase() == "name" )
  328.                 this._name = code;
  329.             if ( name.toLowerCase() == "content" )
  330.                 this._content = code;
  331.  
  332.             if ( this._name != null && this._content != null )
  333.             {
  334.                 this._found[ this._name.toLowerCase() ] = this._content;
  335.                 this._name = null;
  336.                 this._content = null;
  337.             }
  338.         }
  339.  
  340.     } catch( e ) {
  341.  
  342.         this._scan_error = true;
  343.         return false;
  344.  
  345.     }
  346. }
  347.  
  348.  
  349.  
  350. //---------------------------------------------------------------------------------------------------------
  351. //  ParseSupportListsScanner
  352. //---------------------------------------------------------------------------------------------------------
  353.  
  354. // The ParseSupportListsScanner was specifically written with word in mind.  Word has some fairly
  355. // interesting directive laced HTML that sits around hierarchal list items.  This does not apply to single
  356. // level numeric or bulleted lists, which are implemented with <LI> tags.  This only applies to multi-level
  357. // hierarchal lists, like:
  358. //
  359. // 1. First level
  360. //     1.1  Sub level 1
  361. //          1.1.1  Something reminiscent of the military
  362. //     1.2  Sub level 2
  363. //
  364. // The Word format puts in a directive around supporting lists, this parser removes only the
  365. // sections we want from it.  As an example:
  366. // 
  367. // <![if !supportLists]><span style='mso-list:Ignore'>I.<span
  368. // style='font:7.0pt "Times New Roman"'>          &nb
  369. // sp;        
  370. // </span></span><![endif]>
  371. //
  372. // Becomes, just:
  373. //
  374. // I.
  375. //
  376. // The encloding <P> tag has the indent level in the style attribute.
  377.  
  378. function ParseSupportListsScanner( ) { }
  379.  
  380. // Local methods
  381.  
  382. ParseSupportListsScanner.prototype.scan = ParseSupportListsScanner_scan;
  383.  
  384. // scanSourceString specific methods
  385.  
  386. ParseSupportListsScanner.prototype.directive = ParseSupportListsScanner_directive;
  387. ParseSupportListsScanner.prototype.text = ParseSupportListsScanner_text;
  388. ParseSupportListsScanner.prototype.openTagBegin = ParseSupportListsScanner_openTagBegin;
  389. ParseSupportListsScanner.prototype.openTagEnd = ParseSupportListsScanner_openTagEnd;
  390. ParseSupportListsScanner.prototype.closeTagBegin = ParseSupportListsScanner_closeTagBegin;
  391. ParseSupportListsScanner.prototype.attribute = ParseSupportListsScanner_attribute;
  392.  
  393. function ParseSupportListsScanner_scan( source, context )
  394. {
  395.     this._sb = context.createStringBuffer();
  396.     this._inSupportLists = false;
  397.     this._firstItem = false;
  398.     this._scan_error = false;
  399.  
  400.     dw.scanSourceString( source, this );
  401.  
  402.     if ( this._scan_error )
  403.         throw( "ParseSupportListsScanner bad scan" );
  404.  
  405.     return this._sb.get();
  406. }
  407.  
  408. function ParseSupportListsScanner_directive( code, offset )
  409. {
  410.     try {
  411.  
  412.         var testCode = code.toLowerCase();
  413.         if( code.match( /^\<\!\[if \!supportLists\]>/ ) )
  414.         {
  415.             this._inSupportLists = true;
  416.             this._firstItem = true;
  417.         }
  418.         else if ( this._inSupportLists )
  419.         {
  420.             if ( code.match( /^\<\!\[endif\]\>/ ) )
  421.                 this._inSupportLists = false;
  422.         }
  423.         else
  424.         {
  425.             this._sb.append( code );
  426.         }
  427.  
  428.     } catch( e ) {
  429.  
  430.         this._scan_error = true;
  431.         return false;
  432.  
  433.     }
  434.  
  435.     return true;
  436. }
  437.  
  438. function ParseSupportListsScanner_text( code, offset )
  439. {
  440.     try {
  441.  
  442.         if ( this._inSupportLists )
  443.             code = code.replace( /\ /g, "" );
  444.  
  445.         if ( this._firstItem )
  446.         {
  447.             this._firstItem = false;
  448.             this._sb.append( "• " );
  449.         }
  450.         else
  451.         {
  452.             if ( code.length > 0 )
  453.                 this._sb.append( code + " " );
  454.         }
  455.  
  456.     } catch( e ) {
  457.  
  458.         this._scan_error = true;
  459.         return false;
  460.  
  461.     }
  462.  
  463.     return true;
  464. }
  465.  
  466. function ParseSupportListsScanner_openTagBegin( tag, offset )
  467. {
  468.     try {
  469.  
  470.         if ( ! this._inSupportLists )
  471.             this._sb.append( "<" + tag );
  472.  
  473.     } catch( e ) {
  474.  
  475.         this._scan_error = true;
  476.         return false;
  477.  
  478.     }
  479.  
  480.     return true;
  481. }
  482.  
  483. function ParseSupportListsScanner_openTagEnd( tag, trailingFormat )
  484. {
  485.     try {
  486.  
  487.         if ( ! this._inSupportLists )
  488.             this._sb.append( ">" );
  489.  
  490.     } catch( e ) {
  491.  
  492.         this._scan_error = true;
  493.         return false;
  494.  
  495.     }
  496.  
  497.     return true;
  498. }
  499.  
  500. function ParseSupportListsScanner_closeTagBegin( tag, offset )
  501. {
  502.     try {
  503.  
  504.         if ( ! this._inSupportLists )
  505.             this._sb.append( "</" + tag + ">" );
  506.  
  507.     } catch( e ) {
  508.  
  509.         this._scan_error = true;
  510.         return false;
  511.  
  512.     }
  513.  
  514.     return true;
  515. }
  516.  
  517. function ParseSupportListsScanner_attribute( name, code )
  518. {
  519.     try {
  520.  
  521.         if ( ! this._inSupportLists )
  522.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  523.  
  524.     } catch( e ) {
  525.  
  526.         this._scan_error = true;
  527.         return false;
  528.  
  529.     }
  530.  
  531.     return true;
  532. }
  533.  
  534.  
  535.  
  536. //---------------------------------------------------------------------------------------------------------
  537. //  RemoveConditionalsScanner
  538. //---------------------------------------------------------------------------------------------------------
  539.  
  540. // This scanner is specific to MS products.  The MS HTML output format is laced with 
  541. // directives throughout.  What this scanner does is find the directives and remove them.  Additionally, if some
  542. // interesting tags are within the directive then it will keep just that tag and remove the surrounding directive.
  543. // It is important to note that there are often nested directives with MS documents.
  544. //
  545. // An example of the directives you might see is:
  546. //
  547. //  <![if !vml]><span style='mso-ignore:vglayout'><table cellpadding=0 cellspacing=0>
  548. //   <tr><td width=63 height=0></td></tr>
  549. //   <tr><td></td>
  550. //    <td><![endif]><![if !excel]><img width=482 height=247 src="file:some_temp_file.gif">
  551. //    <![endif]><![if !vml]></td>
  552. //    <td width=31></td>
  553. //   </tr>
  554. //   <tr><td height=8></td></tr></table></span><![endif]>
  555. // 
  556. // When all we really want is:
  557. //
  558. // <img width=482 height=247 src="file:some_temp_file.gif">
  559. //
  560. // Passing allowTags = { img: 1 } will do that for you.
  561. //
  562. // One note on RemoveConditionalsScanner. The tags you specify with allowTags should be tags that have opens with
  563. // no closes, like <img> or <br>.  The code is not built generically enough to handle open and close pairs.  If that
  564. // is required then the class will need some redesigning.
  565.  
  566. function RemoveConditionalsScanner( allowTags )
  567. {
  568.     this._allowTags = allowTags;
  569. }
  570.  
  571. // External methods
  572.  
  573. RemoveConditionalsScanner.prototype.scan = RemoveConditionalsScanner_scan;
  574.  
  575. // scanSourceString specific methods
  576.  
  577. RemoveConditionalsScanner.prototype.directive = RemoveConditionalsScanner_directive;
  578. RemoveConditionalsScanner.prototype.text = RemoveConditionalsScanner_text;
  579. RemoveConditionalsScanner.prototype.openTagBegin = RemoveConditionalsScanner_openTagBegin;
  580. RemoveConditionalsScanner.prototype.openTagEnd = RemoveConditionalsScanner_openTagEnd;
  581. RemoveConditionalsScanner.prototype.closeTagBegin = RemoveConditionalsScanner_closeTagBegin;
  582. RemoveConditionalsScanner.prototype.attribute = RemoveConditionalsScanner_attribute;
  583.  
  584. function RemoveConditionalsScanner_scan( source, context )
  585. {
  586.     this._sb = context.createStringBuffer();
  587.     this._inDirective = 0;
  588.     this._exceptionTag = false;
  589.     this._scan_error = false;
  590.  
  591.     dw.scanSourceString( source, this );
  592.  
  593.     if ( this._scan_error )
  594.         throw( "RemoveConditionalsScanner bad scan" );
  595.  
  596.     return this._sb.get();
  597. }
  598.  
  599. function RemoveConditionalsScanner_directive( code, offset )
  600. {
  601.     try {
  602.  
  603.         var testCode = code.toLowerCase();
  604.         if( testCode.match( /^\<\!\[if/ ) )
  605.         {
  606.             this._inDirective++;
  607.         }
  608.         else if ( testCode.match( /^\<\!\-\-\[if/ ) )
  609.         {
  610.             ;
  611.         }
  612.         else if ( this._inDirective )
  613.         {
  614.             if ( testCode.match( /^\<\!\[endif\]/ ) )
  615.                 this._inDirective--;
  616.         }
  617.         else
  618.         {
  619.             if ( code.match( /\<\!\-\-(\s*)startfragment(\s*)\-\->/i ) || code.match( /\<\!\-\-(\s*)endfragment(\s*)\-\->/i ) )
  620.                 this._sb.append( code );
  621.         }
  622.  
  623.     } catch( e ) {
  624.  
  625.         this._scan_error = true;
  626.         return false;
  627.  
  628.     }
  629.  
  630.     return true;
  631. }
  632.  
  633. function RemoveConditionalsScanner_text( code, offset )
  634. {
  635.     try {
  636.  
  637.         if ( this._inDirective == 0 )
  638.             this._sb.append( code + " " );
  639.  
  640.     } catch( e ) {
  641.  
  642.         this._scan_error = true;
  643.         return false;
  644.  
  645.     }
  646.  
  647.     return true;
  648. }
  649.  
  650. function RemoveConditionalsScanner_openTagBegin( tag, offset )
  651. {
  652.     try {
  653.  
  654.         if ( this._allowTags[ tag.toLowerCase() ] )
  655.             this._exceptionTag = true;
  656.  
  657.         if ( this._inDirective == 0 || this._exceptionTag )
  658.             this._sb.append( "<" + tag );
  659.  
  660.     } catch( e ) {
  661.  
  662.         this._scan_error = true;
  663.         return false;
  664.  
  665.     }
  666.  
  667.     return true;
  668. }
  669.  
  670. function RemoveConditionalsScanner_openTagEnd( tag, trailingFormat )
  671. {
  672.     try {
  673.  
  674.         if ( this._inDirective == 0 || this._exceptionTag )
  675.             this._sb.append( ">" );
  676.  
  677.         this._exceptionTag = false;
  678.  
  679.     } catch( e ) {
  680.  
  681.         this._scan_error = true;
  682.         return false;
  683.  
  684.     }
  685.  
  686.     return true;
  687. }
  688.  
  689. function RemoveConditionalsScanner_closeTagBegin( tag, offset )
  690. {
  691.     try {
  692.  
  693.         if ( this._inDirective == 0 || this._exceptionTag )
  694.             this._sb.append( "</" + tag + ">" );
  695.  
  696.     } catch( e ) {
  697.  
  698.         this._scan_error = true;
  699.         return false;
  700.  
  701.     }
  702.  
  703.     return true;
  704. }
  705.  
  706. function RemoveConditionalsScanner_attribute( name, code )
  707. {
  708.     try {
  709.  
  710.         if ( this._inDirective == 0 || this._exceptionTag )
  711.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  712.  
  713.     } catch( e ) {
  714.  
  715.         this._scan_error = true;
  716.         return false;
  717.  
  718.     }
  719.  
  720.     return true;
  721. }
  722.  
  723.  
  724.  
  725.  
  726.  
  727. //---------------------------------------------------------------------------------------------------------
  728. //  FindClippingScanner
  729. //---------------------------------------------------------------------------------------------------------
  730.  
  731. // FindClippingScanner is designed to find the fragment of the clipboard in the HTML and return just that
  732. // fragment with the minimum amount of support HTML around it.  As an example:
  733. //
  734. // <html><head>.... Cruft...</head><body>... More cruft ...
  735. // <!---StartFragment---><p>Some small text</p><!---EndFragment--->... More cruft ...</body></html>
  736. //
  737. // Becomes:
  738. //
  739. // <html><body><!---StartFragment---><p>Some small text</p><!---EndFragment---></body></html>
  740. //
  741. // The idea is that removing all of the header, body pre, and body post information.
  742. //
  743. // In the case where there is no <!--StartFragment--> (where we are importing the contents of a file) then
  744. // we look for the start and end <body> tags.
  745.  
  746. function FindClippingScanner( ) { }
  747.  
  748. // External methods
  749.  
  750. FindClippingScanner.prototype.scan = FindClippingScanner_scan;
  751.  
  752. // scanSourceString specific methods
  753.  
  754. FindClippingScanner.prototype.directive = FindClippingScanner_directive;
  755. FindClippingScanner.prototype.text = FindClippingScanner_text;
  756. FindClippingScanner.prototype.openTagBegin = FindClippingScanner_openTagBegin;
  757. FindClippingScanner.prototype.openTagEnd = FindClippingScanner_openTagEnd;
  758. FindClippingScanner.prototype.closeTagBegin = FindClippingScanner_closeTagBegin;
  759. FindClippingScanner.prototype.attribute = FindClippingScanner_attribute;
  760.  
  761. function FindClippingScanner_scan( source, context )
  762. {
  763.     this._inClipping = false;
  764.     this._firstTagException = false;
  765.     this._findComment = false;
  766.     this._clipTag = "";
  767.     this._frag = "";
  768.     this._scan_error = false;
  769.  
  770.     this._sb = context.createStringBuffer();
  771.  
  772.     if( source.match( /\<\!\-\-(\s*)startfragment(\s*)\-\->/i ) )
  773.     {
  774.         this._findComment = true;
  775.         this._startText = /\<\!\-\-(\s*)startfragment(\s*)\-\->/i;
  776.         this._endText = /\<\!\-\-(\s*)endfragment(\s*)\-\->/i;
  777.     }
  778.     else
  779.         this._clipTag = "body";
  780.  
  781.     dw.scanSourceString( source, this );
  782.  
  783.     if ( this._scan_error )
  784.         throw( "FindClippingScanner bad scan" );
  785.  
  786.     var text = this._sb.get();
  787.  
  788.     return "<html><body>" + text + "</body></html>";
  789. }
  790.  
  791. function FindClippingScanner_directive( code, offset )
  792. {
  793.     try {
  794.  
  795.         var testCode = code.toLowerCase();
  796.  
  797.         if( this._findComment && this._startText.exec( testCode ) )
  798.         {
  799.             code = "<!--StartFragment-->";
  800.             this._inClipping = true;
  801.         }
  802.  
  803.         if( this._findComment && this._endText.exec( testCode ) )
  804.         {
  805.             code = "<!--EndFragment-->";
  806.             this._sb.append( code );
  807.             this._inClipping = false;
  808.         }
  809.         else if ( this._inClipping )
  810.             this._sb.append( code );
  811.  
  812.     } catch( e ) {
  813.  
  814.         this._scan_error = true;
  815.         return false;
  816.  
  817.     }
  818.  
  819.     return true;
  820. }
  821.  
  822. function FindClippingScanner_text( code, offset )
  823. {
  824.     try {
  825.  
  826.         if ( this._inClipping )
  827.             this._sb.append( code + " " );
  828.  
  829.     } catch( e ) {
  830.  
  831.         this._scan_error = true;
  832.         return false;
  833.  
  834.     }
  835.  
  836.     return true;
  837. }
  838.  
  839. function FindClippingScanner_openTagBegin( tag, offset )
  840. {
  841.     try {
  842.  
  843.         if ( this._inClipping )
  844.             this._frag = "<" + tag;
  845.  
  846.         if ( this._clipTag == tag && this._findComment == false )
  847.         {
  848.             this._inClipping = true;
  849.             this._firstTagException = true;
  850.         }
  851.  
  852.     } catch( e ) {
  853.  
  854.         this._scan_error = true;
  855.         return false;
  856.  
  857.     }
  858.  
  859.     return true;
  860. }
  861.  
  862. function FindClippingScanner_openTagEnd( tag, trailingFormat )
  863. {
  864.     try {
  865.  
  866.         if ( this._inClipping && this._firstTagException == false )
  867.         {
  868.             this._frag += ">";
  869.             this._sb.append( this._frag );
  870.         }
  871.  
  872.         this._firstTagException = false;
  873.  
  874.     } catch( e ) {
  875.  
  876.         this._scan_error = true;
  877.         return false;
  878.  
  879.     }
  880.  
  881.     return true;
  882. }
  883.  
  884. function FindClippingScanner_closeTagBegin( tag, offset )
  885. {
  886.     try {
  887.  
  888.         if ( this._clipTag == tag && this._findComment == false )
  889.             this._inClipping = false;
  890.  
  891.         if ( this._inClipping )
  892.             this._sb.append( "</" + tag + ">" );
  893.  
  894.         this._exceptionTag = false;
  895.  
  896.     } catch( e ) {
  897.  
  898.         this._scan_error = true;
  899.         return false;
  900.  
  901.     }
  902.  
  903.     return true;
  904. }
  905.  
  906. function FindClippingScanner_attribute( name, code )
  907. {
  908.     try {
  909.  
  910.         if ( this._inClipping && this._firstTagException == false )
  911.             this._frag += " " + name + "=\"" + handleAttributeText(code) + "\"";
  912.  
  913.     } catch( e ) {
  914.  
  915.         this._scan_error = true;
  916.         return false;
  917.  
  918.     }
  919.  
  920.     return true;
  921. }
  922.  
  923.  
  924.  
  925. //---------------------------------------------------------------------------------------------------------
  926. //  RemoveTagsScanner
  927. //---------------------------------------------------------------------------------------------------------
  928.  
  929. // The RemoveTagScanner removes any tag listed in the associative array passed
  930. // in with the constructor.  For example, to remove every <P> tag from the 
  931. // following HTML:
  932. //
  933. //    <html><body><p>This</p><ul><li>is<li>a<li>test</ul></body><html>
  934. //
  935. // Yould would pass { p: 1 } into the constructor and invoke scan with the HTML.
  936. // The return value would be:
  937. //
  938. //    <html><body><ul><li>is<li>a<li>test</ul></body><html>
  939.  
  940. function RemoveTagsScanner( tagLookup )
  941. {
  942.     this._tagLookup = tagLookup;
  943. }
  944.  
  945. // External methods
  946.  
  947. RemoveTagsScanner.prototype.scan = RemoveTagsScanner_scan;
  948.  
  949. // scanSourceString specific methods
  950.  
  951. RemoveTagsScanner.prototype.directive = RemoveTagsScanner_directive;
  952. RemoveTagsScanner.prototype.text = RemoveTagsScanner_text;
  953. RemoveTagsScanner.prototype.openTagBegin = RemoveTagsScanner_openTagBegin;
  954. RemoveTagsScanner.prototype.openTagEnd = RemoveTagsScanner_openTagEnd;
  955. RemoveTagsScanner.prototype.closeTagBegin = RemoveTagsScanner_closeTagBegin;
  956. RemoveTagsScanner.prototype.attribute = RemoveTagsScanner_attribute;
  957.  
  958. function RemoveTagsScanner_scan( source, context )
  959. {
  960.     this._sb = context.createStringBuffer();
  961.     this._inGoodTag = true;
  962.     this._scan_error = false;
  963.  
  964.     dw.scanSourceString( source, this );
  965.  
  966.     if ( this._scan_error )
  967.         throw( "RemoveTagsScanner bad scan" );
  968.  
  969.     return this._sb.get();
  970. }
  971.  
  972. function RemoveTagsScanner_directive( code, offset )
  973. {
  974.     try {
  975.  
  976.         this._sb.append( code );
  977.  
  978.     } catch( e ) {
  979.  
  980.         this._scan_error = true;
  981.         return false;
  982.  
  983.     }
  984.  
  985.     return true;
  986. }
  987.  
  988. function RemoveTagsScanner_text( code, offset )
  989. {
  990.     try {
  991.  
  992.         this._sb.append( code + " " );
  993.  
  994.     } catch( e ) {
  995.  
  996.         this._scan_error = true;
  997.         return false;
  998.  
  999.     }
  1000.  
  1001.     return true;
  1002. }
  1003.  
  1004. function RemoveTagsScanner_openTagBegin( tag, offset )
  1005. {
  1006.     try {
  1007.  
  1008.         if ( this._tagLookup[ tag.toLowerCase() ] )
  1009.             this._inGoodTag = true;
  1010.         else
  1011.             this._inGoodTag = false;
  1012.  
  1013.         if ( this._inGoodTag )
  1014.             this._sb.append( "<" + tag );
  1015.  
  1016.     } catch( e ) {
  1017.  
  1018.         this._scan_error = true;
  1019.         return false;
  1020.  
  1021.     }
  1022.  
  1023.     return true;
  1024. }
  1025.  
  1026. function RemoveTagsScanner_openTagEnd( tag, trailingFormat )
  1027. {
  1028.     try {
  1029.  
  1030.         if ( this._inGoodTag )
  1031.             this._sb.append( ">" );
  1032.  
  1033.         this._inGoodTag = true;
  1034.  
  1035.     } catch( e ) {
  1036.  
  1037.         this._scan_error = true;
  1038.         return false;
  1039.  
  1040.     }
  1041.  
  1042.     return true;
  1043. }
  1044.  
  1045. function RemoveTagsScanner_closeTagBegin( tag, offset )
  1046. {
  1047.     try {
  1048.  
  1049.         if ( this._tagLookup[ tag.toLowerCase() ] )
  1050.             this._sb.append( "</" + tag + ">" );
  1051.  
  1052.     } catch( e ) {
  1053.  
  1054.         this._scan_error = true;
  1055.         return false;
  1056.  
  1057.     }
  1058.  
  1059.     return true;
  1060. }
  1061.  
  1062. function RemoveTagsScanner_attribute( name, code )
  1063. {
  1064.     try {
  1065.  
  1066.         if ( this._inGoodTag )
  1067.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1068.  
  1069.     } catch( e ) {
  1070.  
  1071.         this._scan_error = true;
  1072.         return false;
  1073.  
  1074.     }
  1075.  
  1076.     return true;
  1077. }
  1078.  
  1079.  
  1080.  
  1081. //---------------------------------------------------------------------------------------------------------
  1082. //  RemoveAttributesScanner
  1083. //---------------------------------------------------------------------------------------------------------
  1084.  
  1085. // The RemoveAttributesScanner removes attributes and styles that are NOT
  1086. // listed in the constructor.  For example with the HTML:
  1087. //
  1088. //    <html><body><p>This</p><ul><li>is<li>a<li>test</ul></body><html>
  1089. //
  1090. // Passing in { html: 1, body: 1, p: 1 } as the attributes would get you:
  1091. //
  1092. //    <html><body><p>This</p> is a test </body><html>
  1093. //
  1094. // The same thing applies to the attributes.  So on this html:
  1095. //
  1096. //     <p style="mso-reject: 1; font-family: Arial">
  1097. //
  1098. // Passing in { "font-family": 1 } as the style filter would get you:
  1099. //
  1100. //     <p style="font-family: Arial;">
  1101. //
  1102.  
  1103. function RemoveAttributesScanner( attributeLookup, styleLookup )
  1104. {
  1105.     this._attributeLookupMaster = attributeLookup;
  1106.     this._styleLookupMaster = styleLookup;
  1107. }
  1108.  
  1109. // External methods
  1110.  
  1111. RemoveAttributesScanner.prototype.scan = RemoveAttributesScanner_scan;
  1112.  
  1113. // scanSourceString specific methods
  1114.  
  1115. RemoveAttributesScanner.prototype.directive = RemoveAttributesScanner_directive;
  1116. RemoveAttributesScanner.prototype.text = RemoveAttributesScanner_text;
  1117. RemoveAttributesScanner.prototype.openTagBegin = RemoveAttributesScanner_openTagBegin;
  1118. RemoveAttributesScanner.prototype.openTagEnd = RemoveAttributesScanner_openTagEnd;
  1119. RemoveAttributesScanner.prototype.closeTagBegin = RemoveAttributesScanner_closeTagBegin;
  1120. RemoveAttributesScanner.prototype.attribute = RemoveAttributesScanner_attribute;
  1121.  
  1122. function RemoveAttributesScanner_scan( source, context )
  1123. {
  1124.     this._sb = context.createStringBuffer();
  1125.     this._tagName = null;
  1126.     this._scan_error = false;
  1127.  
  1128.     dw.scanSourceString( source, this );
  1129.  
  1130.     if ( this._scan_error )
  1131.         throw( "RemoveAttributesScanner bad scan" );
  1132.  
  1133.     return this._sb.get();
  1134. }
  1135.  
  1136. function RemoveAttributesScanner_directive( code, offset )
  1137. {
  1138.     try {
  1139.  
  1140.         this._sb.append( code );
  1141.  
  1142.     } catch( e ) {
  1143.  
  1144.         this._scan_error = true;
  1145.         return false;
  1146.  
  1147.     }
  1148.  
  1149.     return true;
  1150. }
  1151.  
  1152. function RemoveAttributesScanner_text( code, offset )
  1153. {
  1154.     try {
  1155.  
  1156.         this._sb.append( code + " " );
  1157.  
  1158.     } catch( e ) {
  1159.  
  1160.         this._scan_error = true;
  1161.         return false;
  1162.  
  1163.     }
  1164.  
  1165.     return true;
  1166. }
  1167.  
  1168. function RemoveAttributesScanner_openTagBegin( tag, offset )
  1169. {
  1170.     try {
  1171.  
  1172.         this._tagName = tag.toLowerCase();
  1173.  
  1174.         this._attributeLookup = this._attributeLookupMaster[ this._tagName ];
  1175.         this._styleLookup = this._styleLookupMaster[ this._tagName ];
  1176.  
  1177.         if ( this._attributeLookup == null )
  1178.             this._attributeLookup = {};
  1179.         if ( this._styleLookup == null )
  1180.             this._styleLookup = {};
  1181.  
  1182.         this._sb.append( "<" + tag );
  1183.  
  1184.     } catch( e ) {
  1185.  
  1186.         this._scan_error = true;
  1187.         return false;
  1188.  
  1189.     }
  1190.  
  1191.     return true;
  1192. }
  1193.  
  1194. function RemoveAttributesScanner_openTagEnd( tag, trailingFormat )
  1195. {
  1196.     try {
  1197.  
  1198.         this._sb.append( ">" );
  1199.  
  1200.     } catch( e ) {
  1201.  
  1202.         this._scan_error = true;
  1203.         return false;
  1204.  
  1205.     }
  1206.  
  1207.     return true;
  1208. }
  1209.  
  1210. function RemoveAttributesScanner_closeTagBegin( tag, offset )
  1211. {
  1212.     try {
  1213.  
  1214.         this._sb.append( "</" + tag + ">" );
  1215.  
  1216.     } catch( e ) {
  1217.  
  1218.         this._scan_error = true;
  1219.         return false;
  1220.  
  1221.     }
  1222.  
  1223.     return true;
  1224. }
  1225.  
  1226. function RemoveAttributesScanner_attribute( name, code )
  1227. {
  1228.     try {
  1229.  
  1230.         if ( this._attributeLookup[ name.toLowerCase() ] )
  1231.         {
  1232.             if ( name.toLowerCase() == "style" )
  1233.             {
  1234.                 var styles = Utils_ParseStyle( code );
  1235.  
  1236.                 for( var style in styles )
  1237.                 {
  1238.                     if ( this._styleLookup[ style.toLowerCase() ] == null )
  1239.                         styles = Utils_DeleteArrayItem( style, styles );
  1240.                 }
  1241.  
  1242.                 // Rebuild the style text
  1243.  
  1244.                 code = Utils_BuildStyle( styles );
  1245.             }
  1246.  
  1247.             if ( code.length > 0 )
  1248.                 this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1249.         }
  1250.  
  1251.     } catch( e ) {
  1252.  
  1253.         this._scan_error = true;
  1254.         return false;
  1255.  
  1256.     }
  1257.  
  1258.     return true;
  1259. }
  1260.  
  1261.  
  1262. //---------------------------------------------------------------------------------------------------------
  1263. //  RemoveOnlyTheseTagsScanner
  1264. //---------------------------------------------------------------------------------------------------------
  1265.  
  1266. // The RemoveOnlyTheseTagsScanner removes only the specified tags from the given HTML stream.
  1267. // So given this HTML:
  1268. //
  1269. //    <html><body><p>This is <b>bold</b> and <i>italic</i></p></body></html>
  1270. //
  1271. // With a filter of { b: 1, i: 1 }, you would get:
  1272. //
  1273. //    <html><body><p>This is bold  and italic </p></body></html>
  1274.  
  1275. function RemoveOnlyTheseTagsScanner( tagLookup )
  1276. {
  1277.     this._tagLookup = tagLookup;
  1278. }
  1279.  
  1280. // External methods
  1281.  
  1282. RemoveOnlyTheseTagsScanner.prototype.scan = RemoveOnlyTheseTagsScanner_scan;
  1283.  
  1284. // scanSourceString specific methods
  1285.  
  1286. RemoveOnlyTheseTagsScanner.prototype.directive = RemoveOnlyTheseTagsScanner_directive;
  1287. RemoveOnlyTheseTagsScanner.prototype.text = RemoveOnlyTheseTagsScanner_text;
  1288. RemoveOnlyTheseTagsScanner.prototype.openTagBegin = RemoveOnlyTheseTagsScanner_openTagBegin;
  1289. RemoveOnlyTheseTagsScanner.prototype.openTagEnd = RemoveOnlyTheseTagsScanner_openTagEnd;
  1290. RemoveOnlyTheseTagsScanner.prototype.closeTagBegin = RemoveOnlyTheseTagsScanner_closeTagBegin;
  1291. RemoveOnlyTheseTagsScanner.prototype.attribute = RemoveOnlyTheseTagsScanner_attribute;
  1292.  
  1293. function RemoveOnlyTheseTagsScanner_scan( source, context )
  1294. {
  1295.     this._sb = context.createStringBuffer();
  1296.     this._inGoodTag = true;
  1297.     this._scan_error = false;
  1298.  
  1299.     dw.scanSourceString( source, this );
  1300.  
  1301.     if ( this._scan_error )
  1302.         throw( "RemoveOnlyTheseTagsScanner bad scan" );
  1303.  
  1304.     return this._sb.get();
  1305. }
  1306.  
  1307. function RemoveOnlyTheseTagsScanner_directive( code, offset )
  1308. {
  1309.     try {
  1310.  
  1311.         this._sb.append( code );
  1312.  
  1313.     } catch( e ) {
  1314.  
  1315.         this._scan_error = true;
  1316.         return false;
  1317.  
  1318.     }
  1319.  
  1320.     return true;
  1321. }
  1322.  
  1323. function RemoveOnlyTheseTagsScanner_text( code, offset )
  1324. {
  1325.     try {
  1326.  
  1327.         this._sb.append( code + " " );
  1328.  
  1329.     } catch( e ) {
  1330.  
  1331.         this._scan_error = true;
  1332.         return false;
  1333.  
  1334.     }
  1335.  
  1336.     return true;
  1337. }
  1338.  
  1339. function RemoveOnlyTheseTagsScanner_openTagBegin( tag, offset )
  1340. {
  1341.     try {
  1342.  
  1343.         if ( this._tagLookup[ tag.toLowerCase() ] )
  1344.             this._inGoodTag = false;
  1345.         else
  1346.             this._inGoodTag = true;
  1347.  
  1348.         if ( this._inGoodTag )
  1349.             this._sb.append( "<" + tag );
  1350.  
  1351.     } catch( e ) {
  1352.  
  1353.         this._scan_error = true;
  1354.         return false;
  1355.  
  1356.     }
  1357.  
  1358.     return true;
  1359. }
  1360.  
  1361. function RemoveOnlyTheseTagsScanner_openTagEnd( tag, trailingFormat )
  1362. {
  1363.     try {
  1364.  
  1365.         if ( this._inGoodTag )
  1366.             this._sb.append( ">" );
  1367.  
  1368.         this._inGoodTag = true;
  1369.  
  1370.     } catch( e ) {
  1371.  
  1372.         this._scan_error = true;
  1373.         return false;
  1374.  
  1375.     }
  1376.  
  1377.     return true;
  1378. }
  1379.  
  1380. function RemoveOnlyTheseTagsScanner_closeTagBegin( tag, offset )
  1381. {
  1382.     try {
  1383.  
  1384.         if ( this._tagLookup[ tag.toLowerCase() ] == null )
  1385.             this._sb.append( "</" + tag + ">" );
  1386.  
  1387.     } catch( e ) {
  1388.  
  1389.         this._scan_error = true;
  1390.         return false;
  1391.  
  1392.     }
  1393.  
  1394.     return true;
  1395. }
  1396.  
  1397. function RemoveOnlyTheseTagsScanner_attribute( name, code )
  1398. {
  1399.     try {
  1400.  
  1401.         if ( this._inGoodTag )
  1402.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1403.  
  1404.     } catch( e ) {
  1405.  
  1406.         this._scan_error = true;
  1407.         return false;
  1408.  
  1409.     }
  1410.  
  1411.     return true;
  1412. }
  1413.  
  1414.  
  1415.  
  1416. //---------------------------------------------------------------------------------------------------------
  1417. //  RemoveOnlyTheseAttributesScanner
  1418. //---------------------------------------------------------------------------------------------------------
  1419.  
  1420. // The RemoveOnlyTheseAttributesScanner removes just the specified attributes from ANY
  1421. // tag in the provided HTML string.  As an example, this HTML:
  1422. //
  1423. //    <html><body><p class=MsoNormal>Hello</p></body></html>
  1424. //
  1425. // With a filter of { 'class': 1 } would result in this HTML:
  1426. //
  1427. //    <html><body><p>Hello </p></body></html>
  1428.  
  1429. function RemoveOnlyTheseAttributesScanner( attributeLookup )
  1430. {
  1431.     this._attributeLookup = attributeLookup;
  1432. }
  1433.  
  1434. // External methods
  1435.  
  1436. RemoveOnlyTheseAttributesScanner.prototype.scan = RemoveOnlyTheseAttributesScanner_scan;
  1437.  
  1438. // scanSourceString specific methods
  1439.  
  1440. RemoveOnlyTheseAttributesScanner.prototype.directive = RemoveOnlyTheseAttributesScanner_directive;
  1441. RemoveOnlyTheseAttributesScanner.prototype.text = RemoveOnlyTheseAttributesScanner_text;
  1442. RemoveOnlyTheseAttributesScanner.prototype.openTagBegin = RemoveOnlyTheseAttributesScanner_openTagBegin;
  1443. RemoveOnlyTheseAttributesScanner.prototype.openTagEnd = RemoveOnlyTheseAttributesScanner_openTagEnd;
  1444. RemoveOnlyTheseAttributesScanner.prototype.closeTagBegin = RemoveOnlyTheseAttributesScanner_closeTagBegin;
  1445. RemoveOnlyTheseAttributesScanner.prototype.attribute = RemoveOnlyTheseAttributesScanner_attribute;
  1446.  
  1447. function RemoveOnlyTheseAttributesScanner_scan( source, context )
  1448. {
  1449.     this._sb = context.createStringBuffer();
  1450.     this._scan_error = false;
  1451.  
  1452.     dw.scanSourceString( source, this );
  1453.  
  1454.     if ( this._scan_error )
  1455.         throw( "RemoveOnlyTheseAttributesScanner bad scan" );
  1456.  
  1457.     return this._sb.get();
  1458. }
  1459.  
  1460. function RemoveOnlyTheseAttributesScanner_directive( code, offset )
  1461. {
  1462.     try {
  1463.  
  1464.         this._sb.append( code );
  1465.  
  1466.     } catch( e ) {
  1467.  
  1468.         this._scan_error = true;
  1469.         return false;
  1470.  
  1471.     }
  1472.  
  1473.     return true;
  1474. }
  1475.  
  1476. function RemoveOnlyTheseAttributesScanner_text( code, offset )
  1477. {
  1478.     try {
  1479.  
  1480.         this._sb.append( code + " " );
  1481.  
  1482.     } catch( e ) {
  1483.  
  1484.         this._scan_error = true;
  1485.         return false;
  1486.  
  1487.     }
  1488.  
  1489.     return true;
  1490. }
  1491.  
  1492. function RemoveOnlyTheseAttributesScanner_openTagBegin( tag, offset )
  1493. {
  1494.     try {
  1495.  
  1496.         this._sb.append( "<" + tag );
  1497.  
  1498.     } catch( e ) {
  1499.  
  1500.         this._scan_error = true;
  1501.         return false;
  1502.  
  1503.     }
  1504.  
  1505.     return true;
  1506. }
  1507.  
  1508. function RemoveOnlyTheseAttributesScanner_openTagEnd( tag, trailingFormat )
  1509. {
  1510.     try {
  1511.  
  1512.         this._sb.append( ">" );
  1513.  
  1514.     } catch( e ) {
  1515.  
  1516.         this._scan_error = true;
  1517.         return false;
  1518.  
  1519.     }
  1520.  
  1521.     return true;
  1522. }
  1523.  
  1524. function RemoveOnlyTheseAttributesScanner_closeTagBegin( tag, offset )
  1525. {
  1526.     try {
  1527.  
  1528.         this._sb.append( "</" + tag + ">" );
  1529.  
  1530.     } catch( e ) {
  1531.  
  1532.         this._scan_error = true;
  1533.         return false;
  1534.  
  1535.     }
  1536.  
  1537.     return true;
  1538. }
  1539.  
  1540. function RemoveOnlyTheseAttributesScanner_attribute( name, code )
  1541. {
  1542.     try {
  1543.  
  1544.         if ( this._attributeLookup[ name.toLowerCase() ] == null )
  1545.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1546.  
  1547.     } catch( e ) {
  1548.  
  1549.         this._scan_error = true;
  1550.         return false;
  1551.  
  1552.     }
  1553.  
  1554.     return true;
  1555. }
  1556.  
  1557.  
  1558.  
  1559. //---------------------------------------------------------------------------------------------------------
  1560. //  MapTagNamesScanner
  1561. //---------------------------------------------------------------------------------------------------------
  1562.  
  1563. // The MapTagNamesScanner is a very specialized scanner.  It takes a regular expression
  1564. // and maps any tag name that matches that expression to the given name.  For example,
  1565. // given this HTML:
  1566. //
  1567. // <html><body><h1>Level One</h1><h2>Level Two</h2></body></html>
  1568. //
  1569. // With matchCriteria = new Regexp( /h[12]/ ) and outName = "p", you would get:
  1570. //
  1571. // <html><body><p>Level One </p><p>Level Two </p></body></html>
  1572. //
  1573.  
  1574. function MapTagNamesScanner( matchCriteria, outName )
  1575. {
  1576.     this._matchCriteria = matchCriteria;
  1577.     this._outName = outName;
  1578. }
  1579.  
  1580. // External methods
  1581.  
  1582. MapTagNamesScanner.prototype.scan = MapTagNamesScanner_scan;
  1583.  
  1584. // scanSourceString specific methods
  1585.  
  1586. MapTagNamesScanner.prototype.directive = MapTagNamesScanner_directive;
  1587. MapTagNamesScanner.prototype.text = MapTagNamesScanner_text;
  1588. MapTagNamesScanner.prototype.openTagBegin = MapTagNamesScanner_openTagBegin;
  1589. MapTagNamesScanner.prototype.openTagEnd = MapTagNamesScanner_openTagEnd;
  1590. MapTagNamesScanner.prototype.closeTagBegin = MapTagNamesScanner_closeTagBegin;
  1591. MapTagNamesScanner.prototype.attribute = MapTagNamesScanner_attribute;
  1592.  
  1593. function MapTagNamesScanner_scan( source, context )
  1594. {
  1595.     this._sb = context.createStringBuffer();
  1596.     this._scan_error = false;
  1597.  
  1598.     dw.scanSourceString( source, this );
  1599.  
  1600.     if ( this._scan_error )
  1601.         throw( "MapTagNamesScanner bad scan" );
  1602.  
  1603.     return this._sb.get();
  1604. }
  1605.  
  1606. function MapTagNamesScanner_directive( code, offset )
  1607. {
  1608.     try {
  1609.  
  1610.         this._sb.append( code );
  1611.  
  1612.     } catch( e ) {
  1613.  
  1614.         this._scan_error = true;
  1615.         return false;
  1616.  
  1617.     }
  1618.  
  1619.     return true;
  1620. }
  1621.  
  1622. function MapTagNamesScanner_text( code, offset )
  1623. {
  1624.     try {
  1625.  
  1626.         this._sb.append( code + " " );
  1627.  
  1628.     } catch( e ) {
  1629.  
  1630.         this._scan_error = true;
  1631.         return false;
  1632.  
  1633.     }
  1634.  
  1635.     return true;
  1636. }
  1637.  
  1638. function MapTagNamesScanner_openTagBegin( tag, offset )
  1639. {
  1640.     try {
  1641.  
  1642.         if ( this._matchCriteria.exec( tag ) )
  1643.             tag = this._outName;
  1644.         this._sb.append( "<" + tag );
  1645.  
  1646.     } catch( e ) {
  1647.  
  1648.         this._scan_error = true;
  1649.         return false;
  1650.  
  1651.     }
  1652.  
  1653.     return true;
  1654. }
  1655.  
  1656. function MapTagNamesScanner_openTagEnd( tag, trailingFormat )
  1657. {
  1658.     try {
  1659.  
  1660.         this._sb.append( ">" );
  1661.  
  1662.     } catch( e ) {
  1663.  
  1664.         this._scan_error = true;
  1665.         return false;
  1666.  
  1667.     }
  1668.  
  1669.     return true;
  1670. }
  1671.  
  1672. function MapTagNamesScanner_closeTagBegin( tag, offset )
  1673. {
  1674.     try {
  1675.  
  1676.         if ( this._matchCriteria.exec( tag ) )
  1677.             tag = this._outName;
  1678.         this._sb.append( "</" + tag + ">" );
  1679.  
  1680.     } catch( e ) {
  1681.  
  1682.         this._scan_error = true;
  1683.         return false;
  1684.  
  1685.     }
  1686.  
  1687.     return true;
  1688. }
  1689.  
  1690. function MapTagNamesScanner_attribute( name, code )
  1691. {
  1692.     try {
  1693.  
  1694.         this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1695.  
  1696.     } catch( e ) {
  1697.  
  1698.         this._scan_error = true;
  1699.         return false;
  1700.  
  1701.     }
  1702.  
  1703.     return true;
  1704. }
  1705.  
  1706.  
  1707. //---------------------------------------------------------------------------------------------------------
  1708. //  AddStylesScanner
  1709. //---------------------------------------------------------------------------------------------------------
  1710.  
  1711. // The AddStylesScanner is meant to do just that, add the specified styles to the tags
  1712. // of the type specified.  For example, with the following HTML:
  1713. //
  1714. // <html><body><p>Level One</p></body></html>
  1715. //
  1716. // Passing tagName = "p" and styles = { 'margin-top':0, 'margin-bottom':0 } you would get:
  1717. //
  1718. // <html><body><p style="margin-top:0;margin-bottom:0">Level One </p></body></html>
  1719. //
  1720.  
  1721. function AddStylesScanner( tagName, styles )
  1722. {
  1723.     this._tagName = tagName.toLowerCase();
  1724.     this._styles = styles;
  1725. }
  1726.  
  1727. // External methods
  1728.  
  1729. AddStylesScanner.prototype.scan = AddStylesScanner_scan;
  1730.  
  1731. // scanSourceString specific methods
  1732.  
  1733. AddStylesScanner.prototype.directive = AddStylesScanner_directive;
  1734. AddStylesScanner.prototype.text = AddStylesScanner_text;
  1735. AddStylesScanner.prototype.openTagBegin = AddStylesScanner_openTagBegin;
  1736. AddStylesScanner.prototype.openTagEnd = AddStylesScanner_openTagEnd;
  1737. AddStylesScanner.prototype.closeTagBegin = AddStylesScanner_closeTagBegin;
  1738. AddStylesScanner.prototype.attribute = AddStylesScanner_attribute;
  1739.  
  1740. function AddStylesScanner_scan( source, context )
  1741. {
  1742.     this._sb = context.createStringBuffer();
  1743.     this._fixup = false;
  1744.     this._foundStyle = false;
  1745.     this._scan_error = false;
  1746.  
  1747.     dw.scanSourceString( source, this );
  1748.  
  1749.     if ( this._scan_error )
  1750.         throw( "AddStylesScanner bad scan" );
  1751.  
  1752.     return this._sb.get();
  1753. }
  1754.  
  1755. function AddStylesScanner_directive( code, offset )
  1756. {
  1757.     try {
  1758.  
  1759.         this._sb.append( code );
  1760.  
  1761.     } catch( e ) {
  1762.  
  1763.         this._scan_error = true;
  1764.         return false;
  1765.  
  1766.     }
  1767.  
  1768.     return true;
  1769. }
  1770.  
  1771. function AddStylesScanner_text( code, offset )
  1772. {
  1773.     try {
  1774.  
  1775.         this._sb.append( code + " " );
  1776.  
  1777.     } catch( e ) {
  1778.  
  1779.         this._scan_error = true;
  1780.         return false;
  1781.  
  1782.     }
  1783.  
  1784.     return true;
  1785. }
  1786.  
  1787. function AddStylesScanner_openTagBegin( tag, offset )
  1788. {
  1789.     try {
  1790.  
  1791.         if ( this._tagName == tag.toLowerCase() )
  1792.             this._fixup = true;
  1793.  
  1794.         this._foundStyle = false;
  1795.  
  1796.         this._sb.append( "<" + tag );
  1797.  
  1798.     } catch( e ) {
  1799.  
  1800.         this._scan_error = true;
  1801.         return false;
  1802.  
  1803.     }
  1804.  
  1805.     return true;
  1806. }
  1807.  
  1808. function AddStylesScanner_openTagEnd( tag, trailingFormat )
  1809. {
  1810.     try {
  1811.  
  1812.         if ( this._fixup == true && this._foundStyle == false )
  1813.         {
  1814.             var code = Utils_BuildStyle( this._styles );
  1815.  
  1816.             this._sb.append( " style=\"" + code + "\"" );
  1817.         }
  1818.  
  1819.         this._sb.append( ">" );
  1820.  
  1821.         this._fixup = false;
  1822.  
  1823.     } catch( e ) {
  1824.  
  1825.         this._scan_error = true;
  1826.         return false;
  1827.  
  1828.     }
  1829.  
  1830.     return true;
  1831. }
  1832.  
  1833. function AddStylesScanner_closeTagBegin( tag, offset )
  1834. {
  1835.     try {
  1836.  
  1837.         this._sb.append( "</" + tag + ">" );
  1838.  
  1839.     } catch( e ) {
  1840.  
  1841.         this._scan_error = true;
  1842.         return false;
  1843.  
  1844.     }
  1845.  
  1846.     return true;
  1847. }
  1848.  
  1849. function AddStylesScanner_attribute( name, code )
  1850. {
  1851.     try {
  1852.  
  1853.         if ( this._fixup && name.toLowerCase() == "style" )
  1854.         {
  1855.             var styles = Utils_ParseStyle( code );
  1856.  
  1857.             for( var style in this._styles )
  1858.                 styles[ style ] = this._styles[ style ];
  1859.  
  1860.             code = Utils_BuildStyle( styles );
  1861.  
  1862.             this._foundStyle = true;
  1863.         }
  1864.  
  1865.         if ( code.length > 0 )
  1866.             this._sb.append( " " + name + "=\"" + handleAttributeText(code) + "\"" );
  1867.  
  1868.     } catch( e ) {
  1869.  
  1870.         this._scan_error = true;
  1871.         return false;
  1872.  
  1873.     }
  1874.  
  1875.     return true;
  1876. }
  1877.  
  1878.  
  1879.  
  1880.  
  1881. //---------------------------------------------------------------------------------------------------------
  1882. //  StructureScanner
  1883. //---------------------------------------------------------------------------------------------------------
  1884.  
  1885. // The StructureScanner is the most complex of all of the scanners.  Given proper HTML it will create an
  1886. // internal representation of the HTML using associative arrays and arrays, and then reconstruct the HTML
  1887. // while calling member functions (which can be overidden) at key points.
  1888. //
  1889. // Given this HTML:
  1890. //
  1891. // <html><body><p>This is a test</p></body></html>
  1892. //
  1893. // The internal representation would be:
  1894. //
  1895. // { type: 'root',
  1896. //   children: [
  1897. //     { type: 'tag',
  1898. //       tag: 'html',
  1899. //       attributes: {},
  1900. //       children: [
  1901. //         { type: 'tag',
  1902. //           tag: 'body',
  1903. //           attributes: {},
  1904. //           children: [
  1905. //             { type: 'tag',
  1906. //               tag: 'p',
  1907. //               attributes: {},
  1908. //               children: [
  1909. //                 { type: 'text',
  1910. //                   text: 'This is a test'
  1911. //                 }
  1912. //             }
  1913. //         }
  1914. //     }
  1915. // }
  1916.  
  1917. // The overide methods descibed below are called after the structure has been created, during
  1918. // the phase where the new HTML text is created.
  1919.  
  1920. // -- StructureScanner.prototype.inspectTag( tag )
  1921. //
  1922. //    tag - The root of this tag structure
  1923. //
  1924. // This is called first time the tag is seen during the creation phase.  Here you can alter
  1925. // the tag before it is sent to the output.  You can change the tag name, remove or add attributes,
  1926. // and alter the children from here on down.
  1927.  
  1928. // -- StructureScanner.prototype.startTag( tag )
  1929. //
  1930. //    tag - The root of this tag structure
  1931. //
  1932. // For tags (not text) start tag is created before the child nodes are turned into HTML.
  1933.  
  1934. // -- StructureScanner.prototype.createTag( tag, attributes, closed )
  1935. //
  1936. //    tag - The tag name
  1937. //    attributes - The associative array of attributes
  1938. //    closed - true if the tag was both opened and closed officially (e.g. <p> and </p>)
  1939. //
  1940. // This is called to create the HTML for the tag.  This method does not need to handle the child
  1941. // nodes, those are handled by the structure parser (if you want to alter those see inspectTag.)
  1942. // The output from this should either be null (which means that StructureScanner should handle
  1943. // the tag) or an associative array with postfix and prefix attributes.  The postfix is how the
  1944. // tag should end and prefix is how the tag should start.
  1945.  
  1946. // -- StructureScanner.prototype.endTag( tag )
  1947. //
  1948. //    tag - The root of this tag structure
  1949. //
  1950. // The opposite number of start tag.
  1951.  
  1952. // -- StructureScanner.prototype.finalizeTag( tag, attributes, closed, childHTML )
  1953. //
  1954. //    tag - The tag name
  1955. //    attributes - The associative array of attributes
  1956. //    closed - true if the tag was both opened and closed officially (e.g. <p> and </p>)
  1957. //    childHTML - The finalized HTML of all of the children
  1958. //
  1959. // This is called as a final approval of the tag.  If false is returned then the tag (and all of
  1960. // it's children) are not added into the HTML stream.
  1961.  
  1962. function StructureScanner( ) { }
  1963.  
  1964. // External methods
  1965.  
  1966. StructureScanner.prototype.scan = StructureScanner_scan;
  1967.  
  1968. // scanSourceString methods
  1969.  
  1970. StructureScanner.prototype.directive = StructureScanner_directive;
  1971. StructureScanner.prototype.text = StructureScanner_text;
  1972. StructureScanner.prototype.openTagBegin = StructureScanner_openTagBegin;
  1973. StructureScanner.prototype.closeTagBegin = StructureScanner_closeTagBegin;
  1974. StructureScanner.prototype.attribute = StructureScanner_attribute;
  1975.  
  1976. // Internal methods to build the structure
  1977.  
  1978. StructureScanner.prototype.addTextChild = StructureScanner_addTextChild;
  1979. StructureScanner.prototype.addTagChild = StructureScanner_addTagChild;
  1980. StructureScanner.prototype.addAttribute = StructureScanner_addAttribute;
  1981. StructureScanner.prototype.finishTag = StructureScanner_finishTag;
  1982. StructureScanner.prototype.buildHTML = StructureScanner_buildHTML;
  1983.  
  1984. // Methods to overide
  1985.  
  1986. StructureScanner.prototype.inspectTag = StructureScanner_inspectTag;
  1987. StructureScanner.prototype.startTag = StructureScanner_startTag;
  1988. StructureScanner.prototype.createTag = StructureScanner_createTag;
  1989. StructureScanner.prototype.finalizeTag = StructureScanner_finalizeTag;
  1990. StructureScanner.prototype.endTag = StructureScanner_endTag;
  1991.  
  1992. function StructureScanner_addTextChild( text )
  1993. {
  1994.     this._curTag.children.push( { type: "text", text: text } );
  1995. }
  1996.  
  1997. function StructureScanner_addTagChild( tag )
  1998. {
  1999.     tag = tag.toLowerCase();
  2000.  
  2001.     var node = { type: "tag", tag: tag, attributes: {}, children: [], closed: false };
  2002.     this._curTag.children.push( node );
  2003.     this._curTag = node;
  2004.     this._opStack.push( node );
  2005. }
  2006.  
  2007. function StructureScanner_addAttribute( name, value )
  2008. {
  2009.     name = name.toLowerCase();
  2010.  
  2011.     this._curTag.attributes[ name ] = value;
  2012. }
  2013.  
  2014. function StructureScanner_finishTag( tag )
  2015. {
  2016.     tag = tag.toLowerCase();
  2017.  
  2018.     var aTag = this._opStack.pop();
  2019.  
  2020.     while( aTag != null )
  2021.     {
  2022.         if ( aTag.tag == tag )
  2023.         {
  2024.             aTag.closed = true;
  2025.             break;
  2026.         }
  2027.         aTag = this._opStack.pop();
  2028.     }
  2029.  
  2030.     this._curTag = this._opStack[ this._opStack.length - 1 ];
  2031. }
  2032.  
  2033. function StructureScanner_buildHTML( tag )
  2034. {
  2035.     this.inspectTag( tag );
  2036.  
  2037.     var prefix = "";
  2038.     var postfix = "";
  2039.     var chldHTML = "";
  2040.  
  2041.     if ( tag.type == "text" )
  2042.     {
  2043.         prefix = tag.text;
  2044.     }
  2045.     else
  2046.     {
  2047.         this.startTag( tag );
  2048.  
  2049.         if ( tag.type == "tag" )
  2050.         {
  2051.             var retVal = this.createTag( tag.tag, tag.attributes, tag.closed );
  2052.  
  2053.             if ( retVal == null )
  2054.                 retVal = StructureScanner_createTag( tag.tag, tag.attributes, tag.closed );
  2055.  
  2056.             prefix = retVal.prefix;
  2057.             postfix = retVal.postfix;
  2058.         }
  2059.  
  2060.         for( var index in tag.children )
  2061.             chldHTML += this.buildHTML( tag.children[ index ] );
  2062.             
  2063.         this.endTag( tag );
  2064.  
  2065.         if ( this.finalizeTag( tag.tag, tag.attributes, tag.closed, chldHTML ) == false )
  2066.         {
  2067.             prefix = "";
  2068.             childHTML = "";
  2069.             postfix = "";
  2070.         }
  2071.     }
  2072.  
  2073.     return prefix + chldHTML + postfix;
  2074. }
  2075.  
  2076. function StructureScanner_finalizeTag( tag ) { return true; }
  2077.  
  2078. function StructureScanner_startTag( tag ) { }
  2079.  
  2080. function StructureScanner_endTag( tag ) { }
  2081.  
  2082. function StructureScanner_inspectTag( tag ) { return tag; }
  2083.  
  2084. function StructureScanner_createTag( tag, attributes, closed )
  2085. {
  2086.     var prefix = "";
  2087.     var postfix = "";
  2088.  
  2089.     prefix = "<" + tag;
  2090.     for( var key in attributes )
  2091.     {
  2092.         if ( attributes[ key ] != null )
  2093.             prefix += " " + key + "=\"" + handleAttributeText(attributes[ key ]) + "\"";
  2094.     }
  2095.     prefix += ">";
  2096.  
  2097.     if ( closed )
  2098.         postfix = "</" + tag + ">";
  2099.  
  2100.     return { prefix: prefix, postfix: postfix };
  2101. }
  2102.  
  2103.  
  2104. function StructureScanner_scan( source )
  2105. {
  2106.     var rootTag = { type: "root", children: [] };
  2107.     this._curTag = rootTag;
  2108.     this._opStack = [ this._curTag ];
  2109.     this._scan_error = false;
  2110.  
  2111.     dw.scanSourceString( source, this );
  2112.  
  2113.     if ( this._scan_error )
  2114.         throw( "StructureScanner bad scan" );
  2115.  
  2116.     var html = "";
  2117.  
  2118.     html = this.buildHTML( rootTag );
  2119.  
  2120.     return html;
  2121. }
  2122.  
  2123. function StructureScanner_directive( code, offset )
  2124. {
  2125.     try {
  2126.  
  2127.         this.addTextChild( code );
  2128.  
  2129.     } catch( e ) {
  2130.  
  2131.         this._scan_error = true;
  2132.         return false;
  2133.  
  2134.     }
  2135.  
  2136.     return true;
  2137. }
  2138.  
  2139. function StructureScanner_text( code, offset )
  2140. {
  2141.     try {
  2142.  
  2143.         this.addTextChild( code );
  2144.  
  2145.     } catch( e ) {
  2146.  
  2147.         this._scan_error = true;
  2148.         return false;
  2149.  
  2150.     }
  2151.  
  2152.     return true;
  2153. }
  2154.  
  2155. function StructureScanner_openTagBegin( tag, offset )
  2156. {
  2157.     try {
  2158.  
  2159.         this.addTagChild( tag );
  2160.  
  2161.     } catch( e ) {
  2162.  
  2163.         this._scan_error = true;
  2164.         return false;
  2165.  
  2166.     }
  2167.  
  2168.     return true;
  2169. }
  2170.  
  2171. function StructureScanner_closeTagBegin( tag, offset )
  2172. {
  2173.     try {
  2174.  
  2175.         this.finishTag( tag );
  2176.  
  2177.     } catch( e ) {
  2178.  
  2179.         this._scan_error = true;
  2180.         return false;
  2181.  
  2182.     }
  2183.  
  2184.     return true;
  2185. }
  2186.  
  2187. function StructureScanner_attribute( name, code )
  2188. {
  2189.     try {
  2190.  
  2191.         this.addAttribute( name, code );
  2192.  
  2193.     } catch( e ) {
  2194.  
  2195.         this._scan_error = true;
  2196.         return false;
  2197.  
  2198.     }
  2199.  
  2200.     return true;
  2201. }
  2202.  
  2203.  
  2204.  
  2205.  
  2206. //---------------------------------------------------------------------------------------------------------
  2207. //  RemoveHiddenSpansScanner
  2208. //---------------------------------------------------------------------------------------------------------
  2209.  
  2210. // This scanner is specific to MS products.  This removes any DIV tags within the document.
  2211.  
  2212. function RemoveHiddenSpansScanner( )
  2213. {
  2214. }
  2215.  
  2216. // External methods
  2217.  
  2218. RemoveHiddenSpansScanner.prototype.scan = RemoveHiddenSpansScanner_scan;
  2219.  
  2220. // scanSourceString specific methods
  2221.  
  2222. RemoveHiddenSpansScanner.prototype.directive = RemoveHiddenSpansScanner_directive;
  2223. RemoveHiddenSpansScanner.prototype.text = RemoveHiddenSpansScanner_text;
  2224. RemoveHiddenSpansScanner.prototype.openTagBegin = RemoveHiddenSpansScanner_openTagBegin;
  2225. RemoveHiddenSpansScanner.prototype.openTagEnd = RemoveHiddenSpansScanner_openTagEnd;
  2226. RemoveHiddenSpansScanner.prototype.closeTagBegin = RemoveHiddenSpansScanner_closeTagBegin;
  2227. RemoveHiddenSpansScanner.prototype.attribute = RemoveHiddenSpansScanner_attribute;
  2228.  
  2229. function RemoveHiddenSpansScanner_scan( source, context )
  2230. {
  2231.     this._sb = context.createStringBuffer();
  2232.     this._attributes = [];
  2233.     this._hiddenSpanDepth = 0;
  2234.     this._tag = "";
  2235.     this._scan_error = false;
  2236.  
  2237.     dw.scanSourceString( source, this );
  2238.  
  2239.     if ( this._scan_error )
  2240.         throw( "RemoveHiddenSpansScanner bad scan" );
  2241.  
  2242.     return this._sb.get();
  2243. }
  2244.  
  2245. function RemoveHiddenSpansScanner_directive( code, offset )
  2246. {
  2247.     try {
  2248.  
  2249.         if ( this._hiddenSpanDepth == 0 )
  2250.             this._sb.append( code + " " );
  2251.  
  2252.     } catch( e ) {
  2253.  
  2254.         this._scan_error = true;
  2255.         return false;
  2256.  
  2257.     }
  2258.  
  2259.     return true;
  2260. }
  2261.  
  2262. function RemoveHiddenSpansScanner_text( code, offset )
  2263. {
  2264.     try {
  2265.  
  2266.         if ( this._hiddenSpanDepth == 0 )
  2267.             this._sb.append( code + " " );
  2268.  
  2269.     } catch( e ) {
  2270.  
  2271.         this._scan_error = true;
  2272.         return false;
  2273.  
  2274.     }
  2275.  
  2276.     return true;
  2277. }
  2278.  
  2279. function RemoveHiddenSpansScanner_openTagBegin( tag, offset )
  2280. {
  2281.     try {
  2282.  
  2283.         this._tag = tag;
  2284.         this._attributes = [];
  2285.  
  2286.     } catch( e ) {
  2287.  
  2288.         this._scan_error = true;
  2289.         return false;
  2290.  
  2291.     }
  2292.  
  2293.     return true;
  2294. }
  2295.  
  2296. function RemoveHiddenSpansScanner_openTagEnd( tag, trailingFormat )
  2297. {
  2298.     try {
  2299.  
  2300.         if ( this._hiddenSpanDepth == 0 )
  2301.         {
  2302.             if ( ( this._tag == "span" && this._attributes[ "style" ] ) )
  2303.             {
  2304.                 if ( this._attributes[ "style" ].match( /display:none/ ) )
  2305.                 {
  2306.                     this._hiddenSpanDepth = 1;
  2307.                 }
  2308.             }
  2309.  
  2310.             if ( ( this._tag == "p" && this._attributes[ "class" ] ) )
  2311.             {
  2312.                 if ( this._attributes[ "class" ].match( /MsoCommentText/ ) )
  2313.                 {
  2314.                     this._hiddenSpanDepth = 1;
  2315.                 }
  2316.             }
  2317.             
  2318.             if ( ( this._tag == "span" && this._attributes[ "class" ] ) )
  2319.             {
  2320.                 if ( this._attributes[ "class" ].match( /MsoCommentReference/ ) )
  2321.                 {
  2322.                     this._hiddenSpanDepth = 1;
  2323.                 }
  2324.             }
  2325.  
  2326.             if ( this._hiddenSpanDepth == 0 )
  2327.             {
  2328.                 this._sb.append( "<" + this._tag );
  2329.                 for( key in this._attributes )
  2330.                 {
  2331.                     this._sb.append( " " + key + "=\"" + handleAttributeText(this._attributes[ key ]) + "\"" );
  2332.                 }
  2333.                 this._sb.append( ">" );
  2334.             }
  2335.         }
  2336.         else
  2337.             this._hiddenSpanDepth++;
  2338.  
  2339.  
  2340.     } catch( e ) {
  2341.  
  2342.         this._scan_error = true;
  2343.         return false;
  2344.  
  2345.     }
  2346.  
  2347.     return true;
  2348. }
  2349.  
  2350. function RemoveHiddenSpansScanner_attribute( name, code )
  2351. {
  2352.     try {
  2353.  
  2354.         if ( this._hiddenSpanDepth == 0 )
  2355.             this._attributes[ name ] = code;
  2356.  
  2357.     } catch( e ) {
  2358.  
  2359.         this._scan_error = true;
  2360.         return false;
  2361.  
  2362.     }
  2363.  
  2364.     return true;
  2365. }
  2366.  
  2367. function RemoveHiddenSpansScanner_closeTagBegin( tag, offset )
  2368. {
  2369.     try {
  2370.  
  2371.         if ( this._hiddenSpanDepth == 0 )
  2372.         {
  2373.             this._sb.append( "</" + tag + ">" );
  2374.         }
  2375.         else
  2376.         {
  2377.             this._hiddenSpanDepth--;
  2378.         }
  2379.  
  2380.     } catch( e ) {
  2381.  
  2382.         this._scan_error = true;
  2383.         return false;
  2384.  
  2385.     }
  2386.  
  2387.     return true;
  2388. }
  2389.  
  2390.  
  2391.  
  2392.  
  2393.  
  2394. //---------------------------------------------------------------------------------------------------------
  2395. //  DebugScanner
  2396. //---------------------------------------------------------------------------------------------------------
  2397.  
  2398. function DebugScanner( )
  2399. {
  2400. }
  2401.  
  2402. // External methods
  2403.  
  2404. DebugScanner.prototype.scan = DebugScanner_scan;
  2405.  
  2406. // scanSourceString specific methods
  2407.  
  2408. DebugScanner.prototype.directive = DebugScanner_directive;
  2409. DebugScanner.prototype.text = DebugScanner_text;
  2410. DebugScanner.prototype.openTagBegin = DebugScanner_openTagBegin;
  2411. DebugScanner.prototype.openTagEnd = DebugScanner_openTagEnd;
  2412. DebugScanner.prototype.closeTagBegin = DebugScanner_closeTagBegin;
  2413. DebugScanner.prototype.attribute = DebugScanner_attribute;
  2414.  
  2415. function DebugScanner_scan( source )
  2416. {
  2417.     this._exceptionTag = false;
  2418.     this._scan_error = false;
  2419.  
  2420.     dw.scanSourceString( source, this );
  2421.  
  2422.     if ( this._scan_error )
  2423.         throw( "DebugScanner bad scan" );
  2424. }
  2425.  
  2426. function DebugScanner_directive( code, offset )
  2427. {
  2428.     try {
  2429.  
  2430.         alert( "directive( " + code + ", " + offset + " )" );
  2431.  
  2432.     } catch( e ) {
  2433.  
  2434.         this._scan_error = true;
  2435.         return false;
  2436.  
  2437.     }
  2438.  
  2439.     return true;
  2440. }
  2441.  
  2442. function DebugScanner_text( code, offset )
  2443. {
  2444.     try {
  2445.  
  2446.         alert( "text( " + code + ", " + offset + " )" );
  2447.  
  2448.     } catch( e ) {
  2449.  
  2450.         this._scan_error = true;
  2451.         return false;
  2452.  
  2453.     }
  2454.  
  2455.     return true;
  2456. }
  2457.  
  2458. function DebugScanner_openTagBegin( tag, offset )
  2459. {
  2460.     try {
  2461.  
  2462.         alert( "openTagBegin( " + tag + ", " + offset + " )" );
  2463.  
  2464.     } catch( e ) {
  2465.  
  2466.         this._scan_error = true;
  2467.         return false;
  2468.  
  2469.     }
  2470.  
  2471.     return true;
  2472. }
  2473.  
  2474. function DebugScanner_openTagEnd( tag, trailingFormat )
  2475. {
  2476.     try {
  2477.  
  2478.         alert( "openTagEnd( " + tag + ", " + trailingFormat + " )" );
  2479.  
  2480.     } catch( e ) {
  2481.  
  2482.         this._scan_error = true;
  2483.         return false;
  2484.  
  2485.     }
  2486.  
  2487.     return true;
  2488. }
  2489.  
  2490. function DebugScanner_closeTagBegin( tag, offset )
  2491. {
  2492.     try {
  2493.  
  2494.         alert( "closeTagBegin( " + tag + ", " + offset + " )" );
  2495.  
  2496.     } catch( e ) {
  2497.  
  2498.         this._scan_error = true;
  2499.         return false;
  2500.  
  2501.     }
  2502.  
  2503.     return true;
  2504. }
  2505.  
  2506. function DebugScanner_attribute( name, code )
  2507. {
  2508.     try {
  2509.     
  2510.         alert( "attribute( " + name + ", " + handleAttributeText(code) + " )" );
  2511.  
  2512.     } catch( e ) {
  2513.  
  2514.         this._scan_error = true;
  2515.         return false;
  2516.  
  2517.     }
  2518.  
  2519.     return true;
  2520. }
  2521.  
  2522.