home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 October / Chip Ekim 2003.iso / prog / code / contr / setup.exe / Disk1 / data1.cab / Configuration_En / Commands / PMScanners.js < prev    next >
Encoding:
JavaScript  |  2003-07-18  |  64.6 KB  |  3,029 lines

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