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 / Clean Up Word HTML.js < prev    next >
Encoding:
JavaScript  |  2003-07-18  |  61.1 KB  |  2,255 lines

  1. // Copyright 2000, 2001, 2002, 2003 Macromedia, Inc. All rights reserved.
  2. // --------------------------------------------------------------------------
  3. //
  4. // Import Word HTML.js
  5. //
  6. // This command is similar to the "Clean Up HTML.js" command, except that it
  7. // is specifically designed to work with HTML documents generated by
  8. // Microsoft Word.
  9. //
  10. // 09/15/2001 ksunder: To run this without a UI, include the same JS files,
  11. //                     and call remoteImportWordHTML(). Optional arg: file dom ptr.
  12. //                     Will use the settings for DEFAULT_WORD_VERSION.
  13. //
  14. // --------------------------------------------------------------------------
  15.  
  16. var canceledImport = false;
  17.  
  18. var DEFAULT_WORD_VERSION = "2000";
  19. var DOM;
  20.  
  21.  
  22. function receiveArguments()
  23. {
  24.     canceledImport = false;
  25.  
  26.     if (arguments[0] == "import")
  27.     {
  28.       var curDOM, newDOM;
  29.       // Select the word file to be imported, don't show images, supress not in root warnings.
  30.       var HTMLfileTypes = new Array("Word HTML Files (*.htm; *.html)|*.htm;*.html|TEXT|");
  31.       var fileName = browseForFileURL("open", MSG_Word_Import, false, true, HTMLfileTypes);  //returns a local filename
  32.       if (fileName) {
  33.         // Check for name may not exist.
  34.         curDOM = dw.getDocumentDOM(fileName);
  35.         if (curDOM) {
  36.           newDOM = dw.createDocument();
  37.           if (newDOM) {
  38.             newDOM.documentElement.outerHTML = curDOM.documentElement.outerHTML;
  39.           }
  40.         }
  41.       }
  42.       else
  43.       {
  44.         canceledImport = true;
  45.       }
  46.     }
  47. }
  48.  
  49. //******************* Commands API *******************
  50.  
  51. function commandButtons()
  52. {
  53.    return new Array( MM.BTN_OK,     "importWordHTML()",  // main entry point
  54.                      MM.BTN_Cancel, "window.close()",
  55.                      MM.BTN_Help,   "displayHelp()");
  56. }
  57.  
  58. function canAcceptCommand()
  59. {
  60.   var retVal = false;
  61.   if (dw.getDocumentDOM() && dw.getDocumentDOM().getParseMode() == 'html' && (dw.getFocus() == 'document' || dw.getFocus(true) == 'html' || dw.getFocus() == 'textView')){
  62.     retVal = true;
  63.   }
  64.   return retVal;
  65. }
  66.  
  67.  
  68. //******************* Global Variables *******************
  69.  
  70. var helpDoc = MM.HELP_cmdCleanUpWordHTML;
  71.  
  72. var gWordVersion;
  73. var CB;               // The checkbox group
  74. var CBTags;           // The Checkboxes in the dialog
  75.  
  76. // Logging vars
  77. var gRemoveMetaTags = 0;
  78. var gRemoveWordXML = 0;
  79. var gRemoveConditionals = 0;
  80. var gRemoveEmptyParas = 0;
  81. var gRemoveMargins = 0;
  82. var gRemoveInlineCSS = 0;
  83. var gRemovemsoStyle = 0;
  84. var gRemoveNonCSS = 0;
  85. var gRemoveTableCSS = 0;
  86. var gRemoveUnusedCSS = 0;
  87.  
  88. var gFontsConverted = 0;
  89.  
  90. var gNestingFixed = 0;
  91. var gBackgroundSet = "";
  92. var gSourceFormatted = 0;
  93.  
  94.  
  95. //************** Main functions *********************
  96.  
  97. /////////////////////////////////////////////////////////////////////////////
  98. // Function
  99. //    importWordHTML
  100. //
  101. // Purpose
  102. //    This is the "main" function that the dialog calls when the user
  103. //    clicks OK.
  104. //
  105. function importWordHTML()
  106. {
  107.    T.finish(); //ensure Tabs are through getting input
  108.  
  109.    // Lets save the settings first.  That way if something crashes or
  110.    // goes wrong during the processing, the user doesn't need to reset
  111.    // all of the options again.
  112.    if(doSaveSettings())
  113.       saveSettings();
  114.  
  115.    // Set up logging particulars
  116.    if ( doShowLog() )
  117.    {
  118.       MM_enableLogging();
  119.       MM_clearLog();
  120.    }
  121.    else
  122.    {
  123.       MM_disableLogging();
  124.    }
  125.  
  126.    version = getVersion();
  127.  
  128.    MM.setBusyCursor();
  129.  
  130.    switch(version)
  131.    {
  132.       case "2000":
  133.          ProcessWord2000();
  134.          break;
  135.  
  136.       case "97":
  137.          ProcessWord97();
  138.          break;
  139.    }
  140.  
  141.    // Do some processing that needs to be done no matter the version.
  142.    GeneralProcessing();
  143.  
  144.    // Cleanup
  145.    PostProcess();
  146.  
  147.    MM.clearBusyCursor();
  148.  
  149.    // Show the log, if they said to.
  150.    finish();
  151. }
  152.  
  153.  
  154. //These functions provide a way to run Clean Up Word remotely without
  155. //the UI. You can include this file (plus Source Formatting.js and DOM.js)
  156. //and call this function with a dom for any document. By default it
  157. //runs the Word2000 cleanup.
  158.  
  159. function remoteImportWordHTML(dom) {
  160.   DOM = dom;
  161.   CB = new HeadlessUI();
  162.   ProcessWord2000();  //if no UI, default is Word2000
  163.   GeneralProcessing();
  164.   PostProcess();
  165. }
  166. function HeadlessUI() {
  167.   this.isChecked = HeadlessUI_isChecked;
  168. }
  169. function HeadlessUI_isChecked() {
  170.   return true;
  171. }
  172.  
  173.  
  174. /////////////////////////////////////////////////////////////////////////////
  175. function GeneralProcessing()
  176. {
  177.    if(doRemoveMetaLink())
  178.       removeMetaLink();
  179.  
  180.    if(doSetBgColor())
  181.       setBgColor();
  182. }
  183.  
  184.  
  185. /////////////////////////////////////////////////////////////////////////////
  186. // Function
  187. //    PostProcess
  188. //
  189. // Purpose
  190. //    Anything that needs to be done after we have done all of the cleaning
  191. //    should be done in here.  This gets run no matter what options are
  192. //    turned on.
  193. //
  194. function PostProcess()
  195. {
  196.    var root = DOM.documentElement;
  197.    var html;
  198.  
  199.    // Remove the blank style="" attributes.
  200.    html = root.outerHTML;
  201.    html = html.replace(/\s*style=(""|'')/g, "");
  202.    root.outerHTML = html;
  203.  
  204.    RemoveEmptyTags();
  205.  
  206.    if(doApplySourceFormatting())
  207.    {
  208.       // Included from "Source Formatting.js".
  209.       formatSource(DOM);
  210.  
  211.       gSourceFormatted = 1;
  212.    }
  213. }
  214.  
  215.  
  216. /////////////////////////////////////////////////////////////////////////////
  217. // Function
  218. //    initialize
  219. //
  220. // Purpose
  221. //    This is called from body onLoad to initialize the dialog.
  222. //
  223. function initialize()
  224. {
  225.  
  226.   DOM = dw.getDocumentDOM('document');
  227.  
  228.     if (canceledImport)
  229.     {
  230.         window.close();
  231.         return;
  232.     }
  233.  
  234.    getCheckboxes();
  235.  
  236.    // Initialize the checkboxes.
  237.    initCheckboxes();
  238.  
  239.    // Ok, we have hooked up all of the checkboxes.  Now we need to set
  240.    // them to initial values of some kind.
  241.    setCheckboxStates();
  242.  
  243.   var tab0 = dwscripts.findDOMObject("Tab0");
  244.   var tab1 = dwscripts.findDOMObject("Tab1");
  245.  
  246.   //Use appropriate background & tabs for Mac OS X.
  247.   if (dw.isOSX()) {
  248.     dwscripts.findDOMObject("tabBgWin").src = "../Shared/MM/Images/tabBgOSX335x290.gif";
  249.     var oldMulti = RegExp.multiline;
  250.     RegExp.multiline = true;
  251.     var pat1 = /tabBg\.gif/;
  252.     tab0.innerHTML = tab0.innerHTML.replace(pat1, "tabBgOSX.gif");
  253.       tab1.innerHTML = tab1.innerHTML.replace(pat1, "tabBgOSX.gif");
  254.     var pat2 = /tabBgSel\.gif/;
  255.     tab0.innerHTML = tab0.innerHTML.replace(pat2, "tabBgSelOSX.gif");
  256.     tab1.innerHTML = tab1.innerHTML.replace(pat2, "tabBgSelOSX.gif");
  257.     RegExp.multiline = oldMulti;
  258.        var bgImage = findObject("tabBgWin");
  259.       bgImage.width = LABEL_OSX_BG_WIDTH;
  260.     window.resizeToContents();
  261.   // Use appropriate background & tabs for WinXP with themes  
  262.   } else if (dw.isXPThemed()) {
  263.     dwscripts.findDOMObject("tabBgWin").src = "../Shared/MM/Images/tabBgWinXP335x290.gif";
  264.     var oldMulti = RegExp.multiline;
  265.     RegExp.multiline = true;
  266.     var pat1 = /tabBg\.gif/;
  267.     tab0.innerHTML = tab0.innerHTML.replace(pat1, "tabBgXP.gif");
  268.       tab1.innerHTML = tab1.innerHTML.replace(pat1, "tabBgXP.gif");
  269.     var pat2 = /tabBgSel\.gif/;
  270.     tab0.innerHTML = tab0.innerHTML.replace(pat2, "tabBgSelXP.gif");
  271.     tab1.innerHTML = tab1.innerHTML.replace(pat2, "tabBgSelXP.gif");
  272.     RegExp.multiline = oldMulti;
  273.   // Use standard background  
  274.   } else {    
  275.     findObject("tabBgWin").src = "../Shared/MM/Images/tabBgWin335x290.gif";
  276.   }
  277.  
  278.    //Initialize the TabControl.  (Pass in the prefix used for the tab layers)
  279.    T = new TabControl('Tab');
  280.  
  281.    //Add tab pages.   (Pass the layer name, and the page object)
  282.    T.addPage('basic', new Pg1(LABEL_Basic));
  283.    T.addPage('detailWord2000', new Pg2(LABEL_Detailed));
  284.    T.addPage('detailWord97', new Pg3(LABEL_Detailed));
  285.  
  286.    T.addGroup("group2000", new Array("basic","detailWord2000"));
  287.    T.addGroup("group97", new Array("basic","detailWord97"));
  288.  
  289.    //Show default group
  290.    T.showGroup("group97");
  291.  
  292.    //Initialize and display the tabs.  (Could pass the name of a page to start on)
  293.    T.start();
  294.  
  295.    // Determine what version of Word this thing came from.
  296.    detectWordVersion();
  297.  
  298.    setWordVersion();
  299. }
  300.  
  301.  
  302. /////////////////////////////////////////////////////////////////////////////
  303. // Function
  304. //    setDropDownStates
  305. //
  306. // Purpose
  307. //    Retrieve the settings for the font drop downs from the MetaFile.
  308. //
  309. function setDropDownStates()
  310. {
  311.    var path = document.URL;
  312.    var name, font, value, valueStr;
  313.    var metaFile;
  314.  
  315.    metaFile = MMNotes.open(path, false);
  316.  
  317.    if(metaFile != 0)
  318.    {
  319.       // We have some stored settings.  Set the checkboxes based on them.
  320.       for(i = 1; i <= 7; i++)
  321.       {
  322.          name = "menuSize" + i;
  323.          font = dwscripts.findDOMObject(name);
  324.          valueStr = MMNotes.get(metaFile, name);
  325.  
  326.          if (font != null && valueStr) {
  327.            value = parseInt(valueStr);
  328.  
  329.            if((valueStr == value.toString) && (value >= 0) && (value < fontValues.length))
  330.               font.selectedIndex = value;
  331.          }
  332.       }
  333.  
  334.       // We are done with the file, close it.
  335.       MMNotes.close(metaFile);
  336.       metaFile = 0;
  337.    }
  338.  
  339.    // Note that the dropdowns are initialized to some default settings
  340.    // in initDropDowns().  So if there are no keys in the metafile,
  341.    // the dropdowns will be set to something appropriate.
  342. }
  343.  
  344.  
  345. /////////////////////////////////////////////////////////////////////////////
  346. // Function
  347. //    initDropDowns
  348. //
  349. // Purpose
  350. //    Initialize the convert font sizes drop downs with the array that
  351. //    is defined in the .htm file.
  352. //
  353. function initDropDowns()
  354. {
  355.    var i, j;
  356.    var font;
  357.    var select;
  358.  
  359.    for(i = 1; i <= 7; i++)
  360.    {
  361.       font = dwscripts.findDOMObject("menuSize"+i);
  362.  
  363.       // Select something appropriate as a default.
  364.       switch(i)
  365.       {
  366.          case 1:
  367.             select = 6;
  368.             break;
  369.  
  370.          case 2:
  371.             select = 7;
  372.             break;
  373.  
  374.          case 3:
  375.             select = 3;
  376.             break;
  377.  
  378.          case 4:
  379.                     select = 2;
  380.             break;
  381.  
  382.          case 5:
  383.                     select = 1;
  384.             break;
  385.  
  386.          case 6:
  387.          case 7:
  388.             select = 0;
  389.             break;
  390.       }
  391.  
  392.       if(font != null)
  393.         loadSelectList(font, fontValues, true, select);
  394.    }
  395. }
  396.  
  397.  
  398. /////////////////////////////////////////////////////////////////////////////
  399. // Function
  400. //    getCheckboxes
  401. //
  402. // Purpose
  403. //    Search through our dialog and find all of our "checkboxes"
  404. //    This way, if we add or delete them, we don't have to
  405. //    do as much maintainence.
  406. //
  407. function getCheckboxes()
  408. {
  409.    CBTags = new Array();
  410.    var tag;
  411.    var inputArr = document.getElementsByTagName("INPUT");
  412.  
  413.    while (inputArr.length > 0) {
  414.       tag = inputArr.pop();
  415.       click = tag.getAttribute("onClick");
  416.  
  417.       if(click != null && click.match(/CB\.clicked/))
  418.       {
  419.          // This is a checkbox add its name to the list.
  420.          CBTags.push(tag);
  421.       }
  422.    }
  423.    return true;
  424. }
  425.  
  426.  
  427. /////////////////////////////////////////////////////////////////////////////
  428. // Function
  429. //    initCheckboxes
  430. //
  431. // Purpose
  432. //    Create and hookup the hierarchical checkboxes.  Note, the hierarchy is
  433. //    stored in the "parents" attribute on the checkbox in the HTML.  This
  434. //    way, the HTML file sepecifies the relationship and the javascript
  435. //    doesn't care.  Saves us maintainence time when changing the checkboxes.
  436. //
  437. function initCheckboxes()
  438. {
  439.    CB = new CheckboxSet();
  440.  
  441.    // Add the "parent" checkboxes first because they need to exist
  442.    // for the child checkboxes to name them as a parent.  Parent
  443.    // checkboxes have no "parents" attribute.
  444.    for(i = 0; i < CBTags.length; i++)
  445.    {
  446.       parents = CBTags[i].getAttribute("parents");
  447.  
  448.       if(parents == null || parents == "")
  449.          CB.addCheckbox(CBTags[i].getAttribute("name"));
  450.    }
  451.  
  452.    // Now that all of the parent checkboxes have been registered,
  453.    // we can now register the child checkboxes.
  454.    for(i = 0; i < CBTags.length; i++)
  455.    {
  456.       parents = CBTags[i].getAttribute("parents");
  457.  
  458.       if(parents != null && parents != "")
  459.       {
  460.          CB.addCheckbox(CBTags[i].getAttribute("name"),
  461.             CBTags[i].getAttribute("parents"));
  462.       }
  463.    }
  464.  
  465. }
  466.  
  467.  
  468. /////////////////////////////////////////////////////////////////////////////
  469. // Function
  470. //    setCheckboxStates
  471. //
  472. // Purpose
  473. //    Set the checkbox states based on the saved defaults, or if we don't
  474. //    have any saved defaults, set the checkboxes to our hard coded
  475. //    defaults.
  476. //
  477. function setCheckboxStates()
  478. {
  479.    if(setCheckboxStatesFromSavedDefaults())
  480.       return;
  481.  
  482.    // Default settings.  Turn all options on by default.
  483.    for(i = 0; i < CBTags.length; i++)
  484.       CB.check(CBTags[i].getAttribute("name"), true);
  485.  
  486. }
  487.  
  488.  
  489. /////////////////////////////////////////////////////////////////////////////
  490. // Function
  491. //    setCheckboxStatesFromSavedDefaults
  492. //
  493. // Purpose
  494. //    Set the checkboxes based on the defaults that we have saved.
  495. //
  496. // Returns
  497. //    true if we were able to read info from the metafile. false if we
  498. //    could not read the metafile (didn't exist, etc) and we should set
  499. //    some defaults ourselves.
  500. //
  501. function setCheckboxStatesFromSavedDefaults()
  502. {
  503.    var path = document.URL;
  504.    var metaFile = MMNotes.open(path, false);
  505.  
  506.    if(metaFile != 0)
  507.    {
  508.       // We have some stored settings.  Set the checkboxes based on them.
  509.       var keys = MMNotes.getKeys(metaFile);
  510.       var i, j;
  511.  
  512.       for(i = 0; i < keys.length; i++)
  513.       {
  514.          for(j = 0; j < CBTags.length; j++)
  515.          {
  516.             if(keys[i] == CBTags[j].getAttribute("name"))
  517.             {
  518.                CB.check(CBTags[j].getAttribute("name"), true);
  519.                break;
  520.             }
  521.          }
  522.       }
  523.  
  524.  
  525.       // We are done with the file, close it.
  526.       MMNotes.close(metaFile);
  527.       metaFile = 0;
  528.  
  529.       return true;
  530.    }
  531.    else
  532.    {
  533.       // No settings to read.
  534.       return false;
  535.    }
  536.  
  537.    return false;
  538. }
  539.  
  540.  
  541. /////////////////////////////////////////////////////////////////////////////
  542. // Function
  543. //    finish
  544. //
  545. // Purpose
  546. //    We are done.  Do any last minute stuff and show any log information
  547. //    that user may have requested.
  548. //
  549. function finish()
  550. {
  551.    // Show what we did if show log is enabled
  552.    if ( doShowLog() )
  553.    {
  554.       var bDidSomething = (
  555.                         (gRemoveMetaTags > 0)      ||
  556.                         (gRemoveWordXML > 0)       ||
  557.                         (gRemoveConditionals > 0)  ||
  558.                         (gRemoveEmptyParas > 0)    ||
  559.                         (gRemoveMargins > 0)       ||
  560.                         (gRemoveInlineCSS > 0)     ||
  561.                         (gRemovemsoStyle > 0)      ||
  562.                         (gRemoveNonCSS > 0)        ||
  563.                         (gRemoveTableCSS > 0)      ||
  564.                         (gRemoveUnusedCSS > 0)     ||
  565.                         (gFontsConverted > 0)      ||
  566.                         (gNestingFixed > 0)        ||
  567.                         (gBackgroundSet != "")     ||
  568.                         (gSourceFormatted > 0)       );
  569.  
  570.       MM_note(MSG_TrcSummaryHeader);
  571.  
  572.       if(bDidSomething)
  573.       {
  574.          if(gRemoveMetaTags > 0)
  575.             MM_note(MSG_TrcRemoveMetaTags, gRemoveMetaTags);
  576.  
  577.          if(gRemoveWordXML > 0)
  578.             MM_note(MSG_TrcRemoveWordXML, gRemoveWordXML);
  579.  
  580.          if(gRemoveConditionals > 0)
  581.             MM_note(MSG_TrcRemoveConditionals, gRemoveConditionals);
  582.  
  583.          if(gRemoveEmptyParas > 0)
  584.             MM_note(MSG_TrcRemoveEmptyParas, gRemoveEmptyParas);
  585.  
  586.          if(gRemoveMargins > 0)
  587.             MM_note(MSG_TrcRemoveMargins, gRemoveMargins);
  588.  
  589.          if(gRemoveInlineCSS > 0)
  590.             MM_note(MSG_TrcRemoveInlineCSS, gRemoveInlineCSS);
  591.  
  592.          if(gRemovemsoStyle > 0)
  593.             MM_note(MSG_TrcRemovemsoStyle, gRemovemsoStyle);
  594.  
  595.          if(gRemoveNonCSS > 0)
  596.             MM_note(MSG_TrcRemoveNonCSS, gRemoveNonCSS);
  597.  
  598.          if(gRemoveTableCSS > 0)
  599.             MM_note(MSG_TrcRemoveTableCSS, gRemoveTableCSS);
  600.  
  601.          if(gRemoveUnusedCSS > 0)
  602.             MM_note(MSG_TrcRemoveUnusedCSS, gRemoveUnusedCSS);
  603.  
  604.          if(gFontsConverted > 0)
  605.             MM_note(MSG_TrcFontsConverted, gFontsConverted);
  606.  
  607.          if(gNestingFixed > 0)
  608.             MM_note(MSG_TrcNestingFixed, gNestingFixed);
  609.  
  610.          if(gBackgroundSet != "")
  611.             MM_note(MSG_TrcBackgroundSet, gBackgroundSet);
  612.  
  613.          if(gSourceFormatted > 0)
  614.             MM_note(MSG_TrcSourceFormatted);
  615.       }
  616.       else
  617.       {
  618.          MM_note( MSG_TrcDidNothing );
  619.       }
  620.  
  621.       MM_showLog();
  622.    }
  623.  
  624.    window.close();
  625. }
  626.  
  627.  
  628. /////////////////////////////////////////////////////////////////////////////
  629. // Function
  630. //    saveSettings
  631. //
  632. // Purpose
  633. //    Save the options that the user has selected so that the next time
  634. //    they use this dialog, it will have their last settings.
  635. //
  636. function saveSettings()
  637. {
  638.    var path = document.URL;
  639.    var metaFile = MMNotes.open(path, true);
  640.    var name;
  641.  
  642.    if(metaFile == 0)
  643.    {
  644.       alert(wrapTextForAlert(MSG_metaFileError, 80));
  645.       return;
  646.    }
  647.  
  648.    // Make sure the meta file does not contain stale information.
  649.    clearMetaFile(metaFile);
  650.  
  651.    // Now set a key for each option that is on.
  652.    for(i = 0; i < CBTags.length; i++)
  653.    {
  654.       name = CBTags[i].getAttribute("name");
  655.       if(CB.isChecked(name))
  656.          MMNotes.set(metaFile, name, "1");
  657.    }
  658.  
  659.    // Now, save the state of the "convert fonts" things.
  660.    for(i = 1; i <= 7; i++)
  661.    {
  662.       name = "menuSize" + i;
  663.       font = dwscripts.findDOMObject(name);
  664.  
  665.       if(font != null)
  666.          MMNotes.set(metaFile, name, font.selectedIndex+"");
  667.    }
  668.  
  669.    MMNotes.close(metaFile);
  670.    metaFile = 0;
  671. }
  672.  
  673.  
  674. /////////////////////////////////////////////////////////////////////////////
  675. // Function
  676. //    clearMetaFile
  677. //
  678. // Purpose
  679. //    Clear the metafile so that we don't have stale info in there.
  680. //
  681. function clearMetaFile(metaFile)
  682. {
  683.    if(metaFile == 0)
  684.       return;
  685.  
  686.    var keys = MMNotes.getKeys(metaFile);
  687.  
  688.    for(i = 0; i < keys.length; i++)
  689.       MMNotes.remove(metaFile, keys[i]);
  690. }
  691.  
  692. // ----------- Autodetection routines ----------------
  693.  
  694. /////////////////////////////////////////////////////////////////////////////
  695. // Function
  696. //    detectWordVersion
  697. //
  698. // Purpose
  699. //    Find out what version of Word the document was generated by.  We do
  700. //    this so that the user doesn't need to worry about it.
  701. //
  702. function detectWordVersion()
  703. {
  704.    var bFoundVersion = true;
  705.  
  706.    // Init gWordVersion
  707.    gWordVersion = -1;
  708.  
  709.    // This will set 'gWordVersion' if it finds anything
  710.    findVersionInMetaTag();
  711.  
  712.    if(gWordVersion == -1)
  713.    {
  714.       // We could not determine the version of Word used to generate this
  715.       // document.  Default to Word 2000.
  716.       gWordVersion = 2000;
  717.       bFoundVersion = false;
  718.    }
  719.  
  720.    // Set the dropdown to have what we have detected.
  721.    dwscripts.findDOMObject("detecting").visibility = 'hidden';
  722.    dwscripts.findDOMObject("wordVersion").visibility = 'visible';
  723.    with(dwscripts.findDOMObject("selectWordVersion"))
  724.    {
  725.       for(i = 0; i < options.length; i++)
  726.       {
  727.          if(options[i].value == gWordVersion)
  728.          {
  729.             selectedIndex = i;
  730.             break;
  731.          }
  732.       }
  733.    }
  734.  
  735.    if(!bFoundVersion)
  736.    {
  737.       // Notify the user that we were unable to determine the version of Word.
  738.       alert(wrapTextForAlert(MSG_UnknownVersion, 80));
  739.    }
  740.    return gWordVersion;
  741. }
  742.  
  743.  
  744. /////////////////////////////////////////////////////////////////////////////
  745. // Function
  746. //    findVersionInMetaTag
  747. //
  748. // Purpose
  749. //    This function is the meat of finding the version of Word used to
  750. //    generate the HTML.  We look at the meta tags and find the one that
  751. //    gives the version of Word.
  752. //
  753. function findVersionInMetaTag()
  754. {
  755.  
  756.    var metaArr = DOM.getElementsByTagName("META");
  757.    var tag;
  758.  
  759.    for (var i = 0; i < metaArr.length; i++)
  760.    {
  761.       tag = metaArr[i];
  762.  
  763.       name = tag.getAttribute("NAME");
  764.       if(name && name != undefined && (name.toUpperCase() == "GENERATOR" || name.toUpperCase() == "ORIGINATOR"))
  765.       {
  766.          content = tag.getAttribute("CONTENT");
  767.          if(content != null && content.search(/word/i) != -1)
  768.          {         
  769.             if(content.search(/word 97/i) >= 0)
  770.             {
  771.                gWordVersion = 97;
  772.                return false;
  773.             }
  774.             else if(content.search(/word 81/i) >= 0)
  775.             {
  776.                gWordVersion = 97;
  777.                return false;
  778.             }
  779.             else if(content.search(/word 98/i) >= 0)
  780.             {
  781.                gWordVersion = 97;
  782.                return false;
  783.             }
  784.             else if(content.search(/word 9/i) >= 0)
  785.             {
  786.                gWordVersion = 2000;
  787.                return false;
  788.             }
  789.             else if(content.search(/word 10/i) >= 0)
  790.             {
  791.                gWordVersion = 2000;
  792.                return false;
  793.             }
  794.          }
  795.       }
  796.    }
  797.    return true;
  798. }
  799.  
  800.  
  801. /////////////////////////////////////////////////////////////////////////////
  802. // Function
  803. //    setWordVersion
  804. //
  805. // Purpose
  806. //    This gets called when the user selects a different version of Word
  807. //    from the drop down list.  This grabs the selected value from the
  808. //    drop down and shows the appropriate options by hiding or showing
  809. //    the different layers.
  810. //
  811. function setWordVersion()
  812. {
  813.    version = getVersion();
  814.  
  815.    if(version != gWordVersion)
  816.    {
  817.       // The user is trying to select the options for a version of
  818.       // word that does not match what we think it is.  Allow them
  819.       // to to do this, but warn them that in doing so the import
  820.       // may not work since the algorithms for the different versions
  821.       // are different.
  822.  
  823.       alert(wrapTextForAlert(MSG_DiffWordVersion, 80));
  824.    }
  825.  
  826.    switch(version)
  827.    {
  828.       case "2000":
  829.          T.showGroup("group2000");
  830.          break;
  831.  
  832.       case "97":
  833.          T.showGroup("group97");
  834.          break;
  835.  
  836.       default:
  837.          alert(wrapTextForAlert(MSG_Error, 80));
  838.          break;
  839.    }
  840.    T.refresh();
  841. }
  842.  
  843.  
  844. /////////////////////////////////////////////////////////////////////////////
  845. // Function
  846. //    getVersion
  847. //
  848. // Purpose
  849. //    Quickie function to get the version from the selected version
  850. //
  851. function getVersion()
  852. {
  853.   var retVal = DEFAULT_WORD_VERSION;
  854.   var menu = dwscripts.findDOMObject("selectWordVersion");
  855.  
  856.   if (menu)
  857.   {
  858.     retVal = menu.options[menu.selectedIndex].value;
  859.   }
  860.  
  861.   return retVal;
  862. }
  863.  
  864.  
  865.  
  866. // ----- Check functions ----------------------------------------------------
  867.  
  868. /////////////////////////////////////////////////////////////////////////////
  869. function doRemoveMetaLink()
  870. {
  871.    switch(getVersion())
  872.    {
  873.       case "2000":
  874.          return CB.isChecked("removeMetaLink2000_detail");
  875.          break;
  876.  
  877.       case "97":
  878.          return CB.isChecked("removeMetaLink97_detail");
  879.          break;
  880.    }
  881.  
  882.    return false;
  883. }
  884.  
  885.  
  886. /////////////////////////////////////////////////////////////////////////////
  887. function doConvertSize(size)
  888. {
  889.    switch(size)
  890.    {
  891.       case "7":
  892.          return CB.isChecked("convertSize7_detail");
  893.       case "6":
  894.          return CB.isChecked("convertSize6_detail");
  895.       case "5":
  896.          return CB.isChecked("convertSize5_detail");
  897.       case "4":
  898.          return CB.isChecked("convertSize4_detail");
  899.       case "3":
  900.          return CB.isChecked("convertSize3_detail");
  901.       case "2":
  902.          return CB.isChecked("convertSize2_detail");
  903.       case "1":
  904.          return CB.isChecked("convertSize1_detail");
  905.    }
  906.  
  907.    return false;
  908. }
  909.  
  910.  
  911. /////////////////////////////////////////////////////////////////////////////
  912. // Function
  913. //    getDesiredFontSize
  914. //
  915. // Purpose
  916. //    Given a size, find out what the user has specified to change that
  917. //    size to.  This queries the dropdown box associated with the given
  918. //    size.
  919. //
  920. function getDesiredFontSize(size)
  921. {
  922.    var option;
  923.  
  924.    if(size.length != 1)
  925.       return "-1";
  926.  
  927.    if(size[0] < '1' || size[0] > '7')
  928.       return "-1";
  929.  
  930.    option = dwscripts.findDOMObject("menuSize"+size);
  931.  
  932.    if(option != null && option != '')
  933.       return option.options[option.selectedIndex].value;
  934.  
  935.    return "-1";
  936. }
  937.  
  938.  
  939. /////////////////////////////////////////////////////////////////////////////
  940. function doRemoveXMLFromHTML()
  941. {
  942.    return CB.isChecked("removeXMLHTML2000_detail");
  943. }
  944.  
  945. /////////////////////////////////////////////////////////////////////////////
  946. function doRemoveXMLMarkup()
  947. {
  948.    return CB.isChecked("removeXMLmarkup2000_detail");
  949. }
  950.  
  951. /////////////////////////////////////////////////////////////////////////////
  952. function doRemoveIfs()
  953. {
  954.    return CB.isChecked("removeIf2000_detail");
  955. }
  956.  
  957. /////////////////////////////////////////////////////////////////////////////
  958. function doRemoveEmptyParas()
  959. {
  960.    return CB.isChecked("removeEmptyPara2000_detail");
  961. }
  962.  
  963. /////////////////////////////////////////////////////////////////////////////
  964. function doRemoveInlineCSS()
  965. {
  966.    return CB.isChecked("removeInlineCSS2000_detail");
  967. }
  968.  
  969. /////////////////////////////////////////////////////////////////////////////
  970. function doRemoveMSOStyleAttr()
  971. {
  972.    return CB.isChecked("removeInlineCSS2000_detail");
  973. }
  974.  
  975. /////////////////////////////////////////////////////////////////////////////
  976. function doRemoveNonCSSDeclaration()
  977. {
  978.    return CB.isChecked("removeNonCSS2000_detail");
  979. }
  980.  
  981. /////////////////////////////////////////////////////////////////////////////
  982. function doRemoveCSSFromTables()
  983. {
  984.    return CB.isChecked("removeCSSTable2000_detail");
  985. }
  986.  
  987. /////////////////////////////////////////////////////////////////////////////
  988. function doRemoveUnusedStyles()
  989. {
  990.    return CB.isChecked("removeUnusedCSS2000_detail");
  991. }
  992.  
  993. /////////////////////////////////////////////////////////////////////////////
  994. function doFixInvalidNesting()
  995. {
  996.    return CB.isChecked("removeInlineCSS2000_detail");
  997. }
  998.  
  999. /////////////////////////////////////////////////////////////////////////////
  1000. function doSetBgColor()
  1001. {
  1002.    return CB.isChecked("setBgColor_basic");
  1003. }
  1004.  
  1005. /////////////////////////////////////////////////////////////////////////////
  1006. function doApplySourceFormatting()
  1007. {
  1008.    return CB.isChecked("applyFormatting_basic");
  1009. }
  1010.  
  1011. /////////////////////////////////////////////////////////////////////////////
  1012. function doShowLog()
  1013. {
  1014.    return CB.isChecked("showLog_basic");
  1015. }
  1016.  
  1017. /////////////////////////////////////////////////////////////////////////////
  1018. function doSaveSettings()
  1019. {
  1020.    return true;
  1021. }
  1022.  
  1023.  
  1024. /////////////////////////////////////////////////////////////////////////////
  1025. // Function
  1026. //    ProcessWord2000
  1027. //
  1028. // Purpose
  1029. //    This is the main function for doing Word 2000 processing on the
  1030. //    document.
  1031. //
  1032. function ProcessWord2000()
  1033. {
  1034.    if(doRemoveXMLFromHTML())
  1035.       removeXMLFromHTML();
  1036.    
  1037.    if(doRemoveXMLMarkup())
  1038.       removeXMLMarkup();
  1039.  
  1040.    if(doRemoveIfs())
  1041.      removeIfs();
  1042.  
  1043.    if(doRemoveMSOStyleAttr())
  1044.       removeMSOStyleAttr();
  1045.  
  1046.    if(doRemoveEmptyParas())
  1047.       removeEmptyParas();
  1048.  
  1049.    if(doRemoveCSSFromTables())
  1050.       removeCSSFromTables();
  1051.  
  1052.    if(doRemoveNonCSSDeclaration())
  1053.       removeNonCSSDeclaration();
  1054.  
  1055.    if(doRemoveInlineCSS())
  1056.       removeInlineCSS();
  1057.  
  1058.    if(doRemoveUnusedStyles())
  1059.       removeUnusedStyles();
  1060.  
  1061.    // We are done.  Do some general cleanup
  1062.    formatCSS();
  1063.    
  1064. }
  1065.  
  1066.  
  1067. /////////////////////////////////////////////////////////////////////////////
  1068. function RemoveEmptyTags()
  1069. {
  1070.    var body = DOM.body;
  1071.    var emptyTags = new Array();
  1072.    var tag;
  1073.  
  1074.    // First find all of the tags that are empty inside the body.
  1075.    traverse(body, findEmptyTags, null, null, emptyTags);
  1076.   
  1077.    // Now remove them.
  1078.    while((tag = emptyTags.pop()) != null)
  1079.    {
  1080.       if (dw.nodeExists(tag)){
  1081.          tag.outerHTML = tag.innerHTML;
  1082.       }
  1083.    }
  1084.    
  1085.    // Now deal with tags that might have attributes but no
  1086.    // contents, or that are wrapped around nothing something stupid, 
  1087.    // like a <br>.
  1088.    
  1089.    // Find all <br> tags, and check if each one's parent is a SPAN.
  1090.    // If that SPAN has no other children, it's safe to remove it.
  1091.    var brTags = DOM.getElementsByTagName('br');
  1092.    for (var i=brTags.length-1; i >=0; i--){
  1093.      if (brTags[i].parentNode.tagName == 'SPAN' && brTags[i].parentNode.childNodes.length == 1){
  1094.        brTags[i].parentNode.outerHTML = brTags[i].parentNode.innerHTML;
  1095.      }
  1096.    }
  1097.    
  1098.    // Find all <br> tags, and check if each one's parent is a B.
  1099.    // If that B has no other children, it's safe to remove it.
  1100.    var brTags = DOM.getElementsByTagName('br');
  1101.    for (var i=brTags.length-1; i >=0; i--){
  1102.      if (brTags[i].parentNode.tagName == 'B' && brTags[i].parentNode.childNodes.length == 1){
  1103.        brTags[i].parentNode.outerHTML = brTags[i].parentNode.innerHTML;
  1104.      }
  1105.    }
  1106.    
  1107.    // Find all the SPAN tags that may have style attributes but 
  1108.    // no content, and remove them.
  1109.    var spans = DOM.getElementsByTagName('span');
  1110.    for (var i=spans.length-1; i >= 0; i--){
  1111.      if (spans[i].innerHTML == ""){
  1112.        spans[i].outerHTML = spans[i].innerHTML;
  1113.      }else{
  1114.        var match = spans[i].innerHTML.match(/[^<][\w]*/);
  1115.        if (!match){
  1116.          spans[i].outerHTML == "";
  1117.        }
  1118.      }
  1119.    }
  1120.    
  1121.    // Find all the SPAN tags that may have style attributes but 
  1122.    // no content, and remove them.
  1123.    var spans = DOM.getElementsByTagName('span');
  1124.    for (var i=spans.length-1; i >= 0; i--){
  1125.      if (spans[i].innerHTML == ""){
  1126.        spans[i].outerHTML = spans[i].innerHTML;
  1127.      }else{
  1128.        var match = spans[i].innerHTML.match(/[^<][\w]*/);
  1129.        if (!match){
  1130.          spans[i].outerHTML == "";
  1131.        }
  1132.      }
  1133.    }
  1134.  
  1135.    // Word usually nests SPAN tags inside B tags, so once
  1136.    // all the empty SPAN tags are removed, the B tags may
  1137.    // also have no content. Remove those.
  1138.    var btags = DOM.getElementsByTagName('b');
  1139.    for (var i=btags.length-1; i >= 0; i--){
  1140.      if (btags[i].innerHTML == ""){
  1141.        btags[i].outerHTML = btags[i].innerHTML;
  1142.      }
  1143.    }
  1144.    
  1145. }
  1146.  
  1147. /////////////////////////////////////////////////////////////////////////////
  1148. function findEmptyTags(tag, emptyTags)
  1149. {
  1150.    var tagName = tag.tagName;
  1151.    var html;
  1152.    var regx;
  1153.    var result;
  1154.  
  1155.    switch(tagName.toUpperCase())
  1156.    {
  1157.       // Add new empty tags to be removed here.
  1158.       case "DIV":
  1159.       case "SPAN":
  1160.       case "FONT":
  1161.  
  1162.          // Do a match to see if the tag is empty (no attributes)
  1163.          // If it is add it to the list of empty tags that we
  1164.          // will remove from the doc.
  1165.          html = tag.outerHTML;
  1166.          regx = new RegExp("<"+tagName+">", "i");
  1167.          result = regx.exec(html);
  1168.  
  1169.          // LMH: Fixed logic error where empty tags within a
  1170.          // non-empty tag were being matched by accident.
  1171.          // if(result != null && result.index != -1)
  1172.          if(result != null && result.index == 0)
  1173.             emptyTags.push(tag);
  1174.  
  1175.          break;
  1176.    }
  1177.    
  1178.    switch(tagName.toUpperCase())  // fix for bug 24752
  1179.    {
  1180.      case "FONT":{
  1181.        if (!tag.innerHTML || tag.innerHTML==" "){
  1182.          emptyTags.push(tag);
  1183.          if (tag.parentNode.tagName == "P"){
  1184.            tag.parentNode.innerHTML = tag.outerHTML
  1185.            tag.parentNode.setAttribute("cleanup","dwDelete");
  1186.          }
  1187.        }
  1188.        break;
  1189.      }
  1190.      case "P":
  1191.        if (tag.getAttribute("CLEANUP") == "dwDelete")
  1192.          emptyTags.push(tag);
  1193.        break;
  1194.    }
  1195.  
  1196.    return true;
  1197. }
  1198.  
  1199.  
  1200. /////////////////////////////////////////////////////////////////////////////
  1201. // Function
  1202. //    ProcessWord97
  1203. //
  1204. // Purpose
  1205. //    This is the main function for doing Word 97 processing on the
  1206. //    document.
  1207. //
  1208. function ProcessWord97()
  1209. {
  1210.    if(doRemoveMetaLink())
  1211.       removeMetaLink();
  1212.  
  1213.    convertFontSizes();
  1214.  
  1215.    if(doFixInvalidNesting())
  1216.       fixInvalidNesting();
  1217. }
  1218.  
  1219.  
  1220. function convertFontSizes()
  1221. {
  1222.    traverse(DOM.documentElement, convertFontSizeHandler);
  1223.  
  1224.    // post processing will strip the empty <font> tags.
  1225. }
  1226.  
  1227.  
  1228. //////////////////////////////////////////////////////////////////////////////
  1229. // Function
  1230. //    convertFontSizeHandler
  1231. //
  1232. // Purpose
  1233. //    Callback that searches for font tags to convert.
  1234. //
  1235. function convertFontSizeHandler(tag)
  1236. {
  1237.    if(tag.tagName.toUpperCase() == "FONT")
  1238.    {
  1239.       var size = tag.getAttribute("size");
  1240.       var desiredSize;
  1241.  
  1242.       if(size != null && doConvertSize(size))
  1243.       {
  1244.          desiredSize = getDesiredFontSize(size);
  1245.          switch(desiredSize)
  1246.          {
  1247.             case "-1":  // don't change anything
  1248.                break;
  1249.  
  1250.             case "0":  // use default size
  1251.                tag.removeAttribute("size");
  1252.                gFontsConverted++;
  1253.                break;
  1254.  
  1255.             case "1":
  1256.             case "2":
  1257.             case "3":
  1258.             case "4":
  1259.             case "5":
  1260.             case "6":
  1261.             case "7":
  1262.                tag.setAttribute("size", desiredSize);
  1263.                gFontsConverted++;
  1264.                break;
  1265.  
  1266.             case "h1":
  1267.             case "h2":
  1268.             case "h3":
  1269.             case "h4":
  1270.             case "h5":
  1271.             case "h6":
  1272.                // If this font tag is not contained within another block tag,
  1273.                // we can convert it to a header.  If the font is contained
  1274.                // within a block tag, it is an inline font size change.  We
  1275.                // don't want to convert those to headers since headers create
  1276.                // vertical white space.
  1277.                if(!isInsideTag(tag, "p,h1,h2,h3,h4,h5,h6"))
  1278.                {
  1279.                   // We remove the size attribute from the <font> tag
  1280.                   // and wrap the font tag and all its content with
  1281.                   // the appropriate heading.
  1282.                   tag.removeAttribute("size");
  1283.  
  1284.                   html = tag.outerHTML;
  1285.  
  1286.                   // Strip any internal <p>'s that we might have.  We don't
  1287.                   // need them since we are converting this to a header.
  1288.                   html = html.replace(/<\/?P[^>]*>/ig, "");
  1289.  
  1290.                   html = "<"+desiredSize+">" + html + "</"+desiredSize+">";
  1291.                   tag.outerHTML = html;
  1292.  
  1293.                   gFontsConverted++;
  1294.  
  1295.                   // Note, we could be leaving behind an empty <font> tag.
  1296.                   // But, this is OK.  The general post processing will
  1297.                   // clean these up.
  1298.                }
  1299.                break;
  1300.          }
  1301.       }
  1302.    }
  1303.  
  1304.    // Keep traversing...
  1305.    return true;
  1306. }
  1307.  
  1308.  
  1309. /////////////////////////////////////////////////////////////////////////////
  1310. // Function
  1311. //    fixInvalidNesting
  1312. //
  1313. // Purpose
  1314. //    Word 97 has no clue about HTML structure.  Most HTML documents that
  1315. //    it generates have overlapped tags, and invalid nesting structures.
  1316. //    This function aims to clean up that mess.
  1317. //
  1318. //    Note!  This is a very specialized case for Word 97.  This will
  1319. //    not fix all general cases of invalid nesting.
  1320. //
  1321. function fixInvalidNesting()
  1322. {
  1323.    traverse(DOM.documentElement, fixHandler);
  1324.    traverse(DOM.documentElement, removeMarkedTags);
  1325. }
  1326.  
  1327.  
  1328. /////////////////////////////////////////////////////////////////////////////
  1329. // Function
  1330. //    fixHandler
  1331. //
  1332. // Purpose
  1333. //    Callback for fixing up invalidly nested tags.  This is very specific
  1334. //    to how Word 97 generates its HTML.  This will NOT fix any general
  1335. //    case of invalid HTML (that problem is actually quite difficult).
  1336. //
  1337. function fixHandler(tag, nestingFixes)
  1338. {
  1339.    var html;
  1340.    var tagName = tag.tagName.toUpperCase();
  1341.  
  1342.    // If this is a <p> or a header, we need to do some work.
  1343.    if(tagName == "P" || tagName == "LI" || (tagName.match(/h[1-6]/i) != null))
  1344.    {
  1345.       // Fix up them tags
  1346.  
  1347.       var pCase = tag.tagName;  // maintain upper/lower case
  1348.       var parent = tag.parentNode;
  1349.       var innerMostHTML = tag.innerHTML;
  1350.  
  1351.       while(parent != null)
  1352.       {
  1353.          if(parent.tagName)
  1354.          {
  1355.             switch(parent.tagName.toUpperCase())
  1356.             {
  1357.                case "FONT":
  1358.                case "B":
  1359.                case "I":
  1360.                   parent.removeAttribute("TO_BE_DELETED");
  1361.                   html = parent.outerHTML;
  1362.                   parent.setAttribute("TO_BE_DELETED",true);
  1363.  
  1364.                   // We use match here to make sure we maintain any tag attributes.
  1365.                   startTag = html.match(/<[^>]*>/);
  1366.  
  1367.                   if(startTag != null)
  1368.                   {
  1369.                      innerMostHTML = startTag[0] + innerMostHTML +
  1370.                         "</" + parent.tagName + ">";
  1371.                   }
  1372.                   break;
  1373.             }
  1374.  
  1375.          }
  1376.  
  1377.          parent = parent.parentNode;
  1378.       }
  1379.       tag.innerHTML = innerMostHTML;  //actually change the internal tag
  1380.    }
  1381.  
  1382.    return true;
  1383. }
  1384.  
  1385.  
  1386. function removeMarkedTags(tag) {
  1387.   if (tag.getAttribute("TO_BE_DELETED")) {
  1388.     tag.outerHTML = tag.innerHTML;         //blow away outer tag
  1389.   }
  1390.   return true;
  1391. }
  1392.  
  1393.  
  1394. /////////////////////////////////////////////////////////////////////////////
  1395. // Function
  1396. //    removeXMLFromHTML
  1397. //
  1398. // Purpose
  1399. //    Word puts some useless XML markup in the start <html> tag, nuke it.
  1400. //
  1401. function removeXMLFromHTML()
  1402. {
  1403.    var root = DOM.documentElement;
  1404.    var html = root.outerHTML;
  1405.  
  1406.    // We have 2 submatches, "<html", everything after "<html" to the ending
  1407.    // ">".  We want to throw out everything between "<html" and the end.
  1408.    // So, we will just keep $1. Search is case-insensitive to match both
  1409.    // <HTML and <html.
  1410.    html = html.replace(/(<html)([^>]*)/i, "$1");
  1411.  
  1412.    root.outerHTML = html;
  1413. }
  1414.  
  1415.  
  1416. /////////////////////////////////////////////////////////////////////////////
  1417. // Function
  1418. //    removeXMLMarkup
  1419. //
  1420. // Purpose
  1421. //    Word puts some random, useless XML markup in the body.  Strip it.
  1422. //
  1423. function removeXMLMarkup()
  1424. {
  1425.    var root = DOM.documentElement;
  1426.    var html = root.outerHTML;
  1427.  
  1428.    if(doShowLog())
  1429.    {
  1430.       var match;
  1431.  
  1432.       match = html.match(/<o:p>/g);
  1433.       gRemoveWordXML += (match != null ? match.length : 0);
  1434.  
  1435. /* LMH: I don't think we should be including end tags in the count.
  1436.       match = html.match(/<\/o:p>/g);
  1437.       gRemoveWordXML += (match != null ? match.length : 0);
  1438. */
  1439.       match = html.match(/<o:SmartTagType[^>]*>/g);
  1440.       gRemoveWordXML += (match != null ? match.length : 0);
  1441.       
  1442.       match = html.match(/<st1:[\w\s"=]*>/gi);
  1443.       gRemoveWordXML += (match != null ? match.length : 0);
  1444.    }
  1445.  
  1446.    // Paragraphs that have <st1:address> in them are addresses, so
  1447.    // the line after the address shouldn't be in a new paragraph. Attempt
  1448.    // to substitute a <br> for the paragraph break before stripping
  1449.    // out all remaining <st1:> tags.
  1450.    html = html.replace(/<\/st1:address>(<\/st1:\w*>)?<\/p>[\n\r\s]*<p[\s\w="']*>/gi, "<br>");
  1451.    
  1452.    // Remove all instances of <o:p></o:p>
  1453.    html = html.replace(/<o:p>/g, "");
  1454.    html = html.replace(/<\/o:p>/g, "");
  1455.    html = html.replace(/<o:SmartTagType[^>]*>/g, "");
  1456.  
  1457.    // Remove all instances of <st1:whatever></st1:whatever>
  1458.    html = html.replace(/<st1:[\w\s"=]*>/gi, "");
  1459.    html = html.replace(/<\/st1:\w*>/gi, "");
  1460.  
  1461.    // If we find any other instances of XML markup, we can add it here.
  1462.  
  1463.    root.outerHTML = html;
  1464. }
  1465.  
  1466.  
  1467. /////////////////////////////////////////////////////////////////////////////
  1468. // Function
  1469. //    removeIfs
  1470. //
  1471. // Purpose
  1472. //    Word uses many <![if...]> style comments for its own internal
  1473. //    purposes, which are useless in HTML.  This function strips those.
  1474. //
  1475. function removeIfs()
  1476. {
  1477.    traverse(DOM.documentElement, null, null, ifHandler);
  1478.  
  1479.    var root = DOM.documentElement;
  1480.    var html = root.outerHTML;
  1481.  
  1482.    // clean up those empty comments!
  1483.    html = html.replace(/<!-*>/g, "");
  1484.    root.outerHTML = html;
  1485. }
  1486.  
  1487.  
  1488. /////////////////////////////////////////////////////////////////////////////
  1489. // Function
  1490. //    ifHandler
  1491. //
  1492. // Purpose
  1493. //    Find those pesky "if" conditionals that Word 2000 puts in the HTML
  1494. //    and nuke'em.
  1495. //
  1496. function ifHandler(comment)
  1497. {
  1498.    var html = comment.data;
  1499.    var matchif = html.match(/\[if /);
  1500.    var matchendif = html.match(/\[endif/);
  1501.  
  1502.    if(matchif != null || matchendif != null)
  1503.    {
  1504.       gRemoveConditionals++;
  1505.       comment.data = "";
  1506.    }
  1507.  
  1508.    return true;
  1509. }
  1510.  
  1511.  
  1512. /////////////////////////////////////////////////////////////////////////////
  1513. // Function
  1514. //    removeMSOStyleAttr
  1515. //
  1516. // Purpose
  1517. //    Microsoft Word uses many custom CSS attributes.  This function hunts
  1518. //    them down and removes them.
  1519. //
  1520. function removeMSOStyleAttr()
  1521. {
  1522.    var root = DOM.documentElement;
  1523.    var html = root.outerHTML;
  1524.  
  1525.    RegExp.multiline = true;
  1526.  
  1527.    if(doShowLog())
  1528.    {
  1529.       // NOTE!  This is highly ineffiecient since we are doing the regexp
  1530.       // searches twice (once to count, once to do the actual replaces).
  1531.       // If there is a better way to know how many times a replace()
  1532.       // does its thing, we should do that.     
  1533.       var match;
  1534.  
  1535.       match = html.match(/mso-[^:]*:"[^"]*";/g, "");
  1536.       if (match) gRemovemsoStyle += match.length;
  1537.       match = html.match(/mso-[^;'"]*;*(\n|\r)*/g, "");
  1538.       if (match) gRemovemsoStyle += match.length;
  1539.       match = html.match(/page-break-after[^;]*;/g, "");
  1540.       if (match) gRemovemsoStyle += match.length;
  1541.       match = html.match(/ style=['"]tab-interval:[^'"]*['"]/g, "");
  1542.       if (match) gRemovemsoStyle += match.length;
  1543.    }
  1544.  
  1545.    // This finds the mso-*:"SomeStuff"; style attributes and sets them to be nothing.
  1546.    html = html.replace(/mso-[^:]*:"[^"]*";/g, "");
  1547.  
  1548.    // This finds the other mso-* style attibutes.
  1549.    html = html.replace(/mso-[^;'"]*;*(\n|\r)*/g, "");
  1550.  
  1551.    // Remove some other Word-only css style attributes.
  1552.    html = html.replace(/page-break-after[^;]*;/g, "");
  1553.    html = html.replace(/ style=['"]tab-interval:[^'"]*['"]/g, "");
  1554.  
  1555.    root.outerHTML = html;
  1556. }
  1557.  
  1558.  
  1559. /////////////////////////////////////////////////////////////////////////////
  1560. // Function
  1561. //    removeEmptyParas
  1562. //
  1563. // Purpose
  1564. //    Word sets paragraph bottom margins to zero, then inserts empty
  1565. //    (containing  ) paragraphs to maintain the vertical spacing
  1566. //    expected.  This is soley for its own purpose and is redundant
  1567. //    for HTML.  This function removes margin definitions and removes
  1568. //    those pesky empty paragraphs.
  1569. //
  1570. function removeEmptyParas()
  1571. {
  1572.    var root = DOM.documentElement;
  1573.    var style = findTag("style",DOM.documentElement);
  1574.    var html = null;
  1575.  
  1576.    if(style != null)
  1577.    {
  1578.       // Clean out the nonsense zero margin definitions from the
  1579.       // style block.
  1580.       html = style.innerHTML;
  1581.  
  1582.       // Just strip all of those wacky margins that Word puts in there.
  1583.       html = html.replace(/margin[^:]*:[^\n\r]*/g, "");
  1584.  
  1585.       style.innerHTML = html;
  1586.    }
  1587.  
  1588.    // Next, go through the document and strip out those inline margins too.
  1589.    traverse(root, stripMargins);
  1590.  
  1591.    // Now go find those empty paragraphs and remove them.
  1592.    traverse(root, paraHandler);
  1593. }
  1594.  
  1595.  
  1596. /////////////////////////////////////////////////////////////////////////////
  1597. // Function
  1598. //    stripMargins
  1599. //
  1600. // Purpose
  1601. //    Word uses a lot of CSS margin settings in attempt to make the HTML
  1602. //    version look exactly like the native Word version.  In general, this
  1603. //    is unwanted, so lets remove all this stuff.
  1604. //
  1605. function stripMargins(tag)
  1606. {
  1607.    var style = tag.getAttribute("style");
  1608.  
  1609.    if(style != null)
  1610.    {
  1611.       if(doShowLog())
  1612.       {
  1613.          // Note, if there is a better way to count (if replace can be forced
  1614.          // to report how many replaces it did), we should do that.  Because
  1615.          // this takes extra processing effort to count this stuff using
  1616.          // "match".
  1617.  
  1618.          var match;
  1619.  
  1620.          match = style.match(/margin[^"';]*;?/g);
  1621.          gRemoveMargins += (match != null ? match.length : 0);
  1622.          match = style.match(/text-indent[^"';]*;?/g);
  1623.          gRemoveMargins += (match != null ? match.length : 0);
  1624.          match = style.match(/tab-stops:[^'";]*;?/g);
  1625.          gRemoveMargins += (match != null ? match.length : 0);
  1626.       }
  1627.  
  1628.       style = style.replace(/margin[^"';]*;?/g, "");
  1629.       style = style.replace(/text-indent[^"';]*;?/g, "");
  1630.       style = style.replace(/tab-stops:[^'";]*;?/g, "");
  1631.  
  1632.       if(style == null || style == "" || style.search (/[^\s]/) == -1)
  1633.          tag.removeAttribute("style");
  1634.       else
  1635.          tag.setAttribute("style", style);
  1636.    }
  1637.  
  1638.    return true;
  1639. }
  1640.  
  1641.  
  1642. /////////////////////////////////////////////////////////////////////////////
  1643. // Function
  1644. //    paraHandler
  1645. //
  1646. // Purpose
  1647. //    Callback that looks for empty <p>'s and deletes them.  After
  1648. //    doing some processing removing stuff, we can easily end up
  1649. //    with empty paragraphs.  This just cleans up after ourselves.
  1650. //
  1651. function paraHandler(tag)
  1652. {
  1653.    tagName = tag.tagName;
  1654.    if(tagName.toUpperCase() == "P")
  1655.    {
  1656.       text = tag.innerHTML;
  1657.  
  1658.       // Make sure there are not any content generating HTML tags, this
  1659.       // prevents us from removing say, <img> in the next step.
  1660.       if(containsContentTags(text))
  1661.          return true; // Keep searching in the traverse
  1662.  
  1663.       // Ok, we don't have any content tags.  We are save to strip any
  1664.       // other tags (font, b, etc).
  1665.       text = text.replace(/<[^>]*>/g, "");
  1666.  
  1667.       // Strip whitespace
  1668.       text = text.replace(/\s/g, "");
  1669.  
  1670.       // Strip  s
  1671.       text = text.replace(/ /g, "");
  1672.  
  1673.       // After doing all that, if there is nothing left, this paragraph is empty.
  1674.       if(text == "" || text == null)
  1675.       {
  1676.          gRemoveEmptyParas++;
  1677.          tag.outerHTML = "";
  1678.       }
  1679.    }
  1680.  
  1681.    return true;
  1682. }
  1683.  
  1684.  
  1685. /////////////////////////////////////////////////////////////////////////////
  1686. // Function
  1687. //    containsContentTags
  1688. //
  1689. // Purpose
  1690. //    Given a string that contains some HTML, check to see if we have
  1691. //    any tags that generate visible content.
  1692. //
  1693. // Returns
  1694. //    zero (false) if no content generating tags are found.  Non-zero
  1695. //    value if anything is found.
  1696. //
  1697. function containsContentTags(text)
  1698. {
  1699.    var index = 0;
  1700.  
  1701.    // text.search returns -1 if it does not find anything.  So by adding
  1702.    // 1 and bitwise or-ing the result, we maintain zero if no match.
  1703.    index |= text.search(/<hr/i) + 1;
  1704.    index |= text.search(/<img/i) + 1;
  1705.    index |= text.search(/<input/i) + 1;
  1706.    index |= text.search(/<object/i) + 1;
  1707.    index |= text.search(/<table/i) + 1;
  1708.    index |= text.search(/<textarea/i) + 1;
  1709.    index |= text.search(/<embed/i) + 1;
  1710.  
  1711.    // if index is still zero after all that, we don't have any content tags.
  1712.  
  1713.    return index;
  1714. }
  1715.  
  1716.  
  1717. /////////////////////////////////////////////////////////////////////////////
  1718. // Function
  1719. //    formatCSS
  1720. //
  1721. // Purpose
  1722. //    When we modify or remove stuff from the <style> block we leave it in
  1723. //    a not so pretty state.  This will clean it up so it looks nice.
  1724. //
  1725. function formatCSS()
  1726. {
  1727.    var style = findTag("style",DOM.documentElement);
  1728.  
  1729.    if(style != null)
  1730.    {
  1731.       var html = style.innerHTML;
  1732.  
  1733.       // We need multiline turned on for this.
  1734.       var multiline = RegExp.multiline;
  1735.       RegExp.multiline = true;
  1736.  
  1737.       // Lets just get rid of those comments that Word puts in there
  1738.       html = html.replace(/\/\*.*\*\//g, "");
  1739.  
  1740.       // Clean up the whitespace between the start and end brackets.
  1741.       html = html.replace(/\s*\}/g, "}");
  1742.       html = html.replace(/\{\s*/g, "{");
  1743.  
  1744.       // Make sure anything that is indented is indented only one tab.
  1745.       html = html.replace(/^\t+/g, "\t");
  1746.  
  1747.       // Make sure the style names are on their own line.
  1748.       html = html.replace(/\}/g, "}\n");
  1749.  
  1750.       // This will delete blank lines in the style declaration
  1751.       html = html.replace(/^[ \t]*(\r|\n)+/g, "");
  1752.  
  1753.       // Set it back
  1754.       RegExp.multiline = multiline;
  1755.  
  1756.       style.innerHTML = html;
  1757.    }
  1758. }
  1759.  
  1760.  
  1761.  
  1762. /////////////////////////////////////////////////////////////////////////////
  1763. // Function
  1764. //    removeCSSFromTables
  1765. //
  1766. // Purpose
  1767. //    Word tends to go overboard with CSS with tables.  Almost all of it
  1768. //    is used to maintain the "Word appearance" and is generally undesirable
  1769. //    for use with HTML.  So, this function just strips it all.
  1770. //
  1771. function removeCSSFromTables()
  1772. {
  1773.   // Find each table tag and do some processing on it.
  1774.   var tables = DOM.getElementsByTagName('table');
  1775.   for (var i=0; i < tables.length; i++){
  1776.     traverse(tables[i], convertCSSInTables);
  1777.   }
  1778. }
  1779.  
  1780.  
  1781. /////////////////////////////////////////////////////////////////////////////
  1782. // Function
  1783. //    convertCSSInTables
  1784. //
  1785. // Purpose
  1786. //    We want to strip the CSS applied to tables and their cells.
  1787. //    However, some of these styles can be converted into HTML
  1788. //    attributes.  This function converts any styles we can to
  1789. //    HTML attributes and then removes the style attribute.
  1790. //
  1791. function convertCSSInTables(tag)
  1792. {
  1793.    var tagName = tag.tagName.toUpperCase();
  1794.    var style;
  1795.    var match;
  1796.  
  1797.    if(tagName == "TABLE")
  1798.    {
  1799.       style = tag.getAttribute("style");
  1800.  
  1801.       if(style != null && style != "")
  1802.       {
  1803.          match = style.match(/border-color: *([^;'"]*)/);
  1804.  
  1805.          if(match != null)
  1806.             tag.setAttribute("bordercolor", match[1]);
  1807.  
  1808.          tag.removeAttribute("style");
  1809.  
  1810.          gRemoveTableCSS++;
  1811.       }
  1812.    }
  1813.    else if(tagName == "TR")
  1814.    {
  1815.       // TRs do not have any styles that we want to keep.
  1816.       if (tag.getAttribute("style")){
  1817.         tag.removeAttribute("style");
  1818.         gRemoveTableCSS++;
  1819.       }
  1820.    }
  1821.    else if(tagName == "TD")
  1822.    {
  1823.       style = tag.getAttribute("style");
  1824.  
  1825.       if(style != null && style != "")
  1826.       {
  1827.          match = style.match(/background: *([^;'"]*)/);
  1828.  
  1829.          if(match != null)
  1830.             tag.setAttribute("bgcolor", match[1]);
  1831.  
  1832.          // Remove the style attribute from the TD.
  1833.          tag.removeAttribute("style");
  1834.  
  1835.          gRemoveTableCSS++;
  1836.       }
  1837.    }
  1838.  
  1839.    return true;
  1840. }
  1841.  
  1842.  
  1843.  
  1844. /////////////////////////////////////////////////////////////////////////////
  1845. // Function
  1846. //    removeNonCSSDeclaration
  1847. //
  1848. // Purpose
  1849. //    Word puts a number of non-standard CSS style declarations in the
  1850. //    style block.  This will strip them, and remove any references to
  1851. //    them.
  1852. //    
  1853. //    While we're here, we're also going to remove any empty style 
  1854. //    declarations, and the references to them.
  1855. //
  1856. function removeNonCSSDeclaration()
  1857. {
  1858.    var root = DOM.documentElement;
  1859.    var data = new Array();
  1860.    var invalidList;
  1861.    var style;
  1862.  
  1863.    style = findTag("style",DOM.documentElement);
  1864.    if(style != null)
  1865.    {
  1866.       var html = style.innerHTML;
  1867.       var htmlLeft, htmlRight;
  1868.  
  1869.       // First, we need to get a list of all the invalid style names.  This
  1870.       // way, we can go through the file and remove the references to them.
  1871.       // An invalid style looks like this: @foo bar
  1872.       invalidList = html.match(/^@[^\s]*\s\w*/g);
  1873.  
  1874.       if(invalidList != null)
  1875.       {
  1876.          // Log the number of invalid CSS styles we find.
  1877.          gRemoveNonCSS += invalidList.length;
  1878.  
  1879.          for(var i = 0; i < invalidList.length; i++)
  1880.          {
  1881.             invalidList[i] = invalidList[i].replace(/@\w* /g, "");
  1882.             invalidList[i] = invalidList[i].replace(/(\r|\n)*/g, "");
  1883.          }
  1884.       }
  1885.  
  1886.       // This removes the invalid "@" CSS declarations
  1887.       html = html.replace(/^@[^\}]*\}/g, "");
  1888.  
  1889.       // Now we need to go and clean out everything that referenced the
  1890.       // invalid styles.  First lets finish cleaning the style block.
  1891.       if(invalidList != null)
  1892.       {
  1893.          var regx = new RegExp();
  1894.          var htmlLeft, htmlRight;
  1895.          var result;
  1896.  
  1897.          for(var j = 0; j < invalidList.length; j++)
  1898.          {
  1899.             // Find stuff of the form "div.Section1 ... { ... }"
  1900.             regx.compile("^.*\\."+invalidList[j]+"[^\\}]*\\}", "g");
  1901.  
  1902.             while((result = regx.exec(html)) != null)
  1903.             {
  1904.                htmlLeft = html.substring(0, result.index);
  1905.                htmlRight = html.substring(result.index + result[0].length);
  1906.  
  1907.                // Remove the match
  1908.                html = htmlLeft + htmlRight;
  1909.             }
  1910.          }
  1911.  
  1912.          style.innerHTML = html;
  1913.          
  1914.          // Now remove any empty style blocks
  1915.          var multiline = RegExp.multiline;
  1916.          html = DOM.getElementsByTagName('style')[0].innerHTML;
  1917.          RegExp.multiline = true;
  1918.  
  1919.          regx.compile("\\.?\\w*\\.([^\\{]*)\\{([^\\}]*)\\}", "g");
  1920.  
  1921.          while((result = regx.exec(html)) != null){
  1922.            result[1] = result[1].replace(/[\r\n\s]*/g,"");
  1923.            result[2] = result[2].replace(/[\r\n\s]*/g,"");
  1924.            if (result[2] == ""){
  1925.              htmlLeft = html.substring(0, result.index);
  1926.              htmlRight = html.substring(result.index + result[0].length);
  1927.              invalidList.push(result[1]);           
  1928.            }
  1929.            html = htmlLeft + htmlRight;
  1930.          }
  1931.          RegExp.multiline = multiline;
  1932.          style.innerHTML = html;
  1933.          
  1934.       }
  1935. /*
  1936.       else
  1937.       {
  1938.          style.innerHTML = html;
  1939.       }
  1940. */      
  1941.    }
  1942.  
  1943.    // OK, we cleaned up the style block, now we just need to go
  1944.    // through the rest of the document and remove any references
  1945.    // to the invalid CSS classes.
  1946.    if(invalidList != null)
  1947.    {
  1948.       root = DOM.documentElement;
  1949.       var html = root.outerHTML;
  1950.       var regx = new RegExp();
  1951.  
  1952.       for(var k = 0; k < invalidList.length; k++)
  1953.       {
  1954.          regx.compile(' ?class=((")?)'+invalidList[k]+'\\1', 'g');
  1955.          while((result = regx.exec(html)) != null)
  1956.          {
  1957.             htmlLeft = html.substring(0, result.index);
  1958.             htmlRight = html.substring(result.index + result[0].length);
  1959.  
  1960.             html = htmlLeft + htmlRight;
  1961.          }
  1962.       }
  1963.  
  1964.       root.outerHTML = html;
  1965.    }
  1966. }
  1967.  
  1968.  
  1969.  
  1970. /////////////////////////////////////////////////////////////////////////////
  1971. // Function
  1972. //    removeMetaLink
  1973. //
  1974. // Purpose
  1975. //    Removes those nasty Microsoft-only Meta tags.
  1976. //
  1977. function removeMetaLink()
  1978. {
  1979.    var tag, html, rel, tagArr;
  1980.  
  1981.    // Clean up the META tags.
  1982.    tagArr = DOM.getElementsByTagName("META");
  1983.    while (tagArr.length > 0)
  1984.    {
  1985.       tag = tagArr.pop(); // Order is important here. Removing last first.
  1986.  
  1987.       if(tag.outerHTML.match(/(word|microsoft|mshtml)/i))
  1988.       {
  1989.          // This tag contains some Word junk, nuke it.
  1990.          tag.outerHTML="";
  1991.          gRemoveMetaTags++;
  1992.       }
  1993.    }
  1994.  
  1995.    // Clean up the LINK tags.
  1996.    tagArr = DOM.getElementsByTagName("LINK");
  1997.    while (tagArr.length > 0)
  1998.    {
  1999.       tag = tagArr.pop(); // Order is important here. Removing last first.
  2000.       rel = tag.getAttribute("rel");
  2001.  
  2002.       if(rel == "File-List")
  2003.       {
  2004.          tag.outerHTML = "";
  2005.          gRemoveMetaTags++;
  2006.       }
  2007.    }
  2008.  
  2009.    return true;
  2010. }
  2011.  
  2012.  
  2013. /////////////////////////////////////////////////////////////////////////////
  2014. function setBgColor()
  2015. {
  2016.    var body = findTag("body",DOM.documentElement);
  2017.  
  2018.    if(body != null)
  2019.    {
  2020.       var colorObj = dwscripts.findDOMObject("bgcolor_basic");
  2021.       var color = (colorObj == null ? null : colorObj.value);
  2022.  
  2023.       if(color != null)
  2024.       {
  2025.          if (!body.bgcolor || (body.bgcolor.toLowerCase() != color.toLowerCase())){
  2026.            body.setAttribute("bgcolor", color);
  2027.            gBackgroundSet = color;
  2028.          }
  2029.       }
  2030.    }
  2031. }
  2032.  
  2033.  
  2034.  
  2035. /////////////////////////////////////////////////////////////////////////////
  2036. // Function
  2037. //    removeInlineCSS
  2038. //
  2039. // Purpose
  2040. //    Word 2000 loves to declare "normal" styles and then apply them to
  2041. //    every block in the document.  Let's just set it on the body and
  2042. //    remove it from everything else.
  2043. //
  2044. function removeInlineCSS()
  2045. {
  2046.  
  2047.    var style = findTag("style",DOM.documentElement);
  2048.  
  2049.    if(style != null)
  2050.    {
  2051.       var index;
  2052.  
  2053.       html = style.innerHTML;
  2054.  
  2055.       index = html.search(/\.(MsoNormal)/i);
  2056.       if(index != -1)
  2057.       {
  2058.          // Lets strip out the "normal" styles and make only one.  Word
  2059.          // tends to have stuff like p.MsoNormal, li.MsoNormal, etc.
  2060.          html = html.replace(/^\s*\w*\.MsoNormal([A-Za-z]+)?/ig, ".TempNormal");
  2061.  
  2062.          // Change the first one we find to "FirstNormal"
  2063.          html = html.replace(/\.TempNormal/, ".FirstNormal");
  2064.  
  2065.          // Remove the rest.
  2066.          html = html.replace(/\.TempNormal/g, "");
  2067.  
  2068.          // Change the first normal to just "Normal". 
  2069.          // LMH: Make sure *not* to replace the opening curly brace if it
  2070.          // happens to be on the name line as the class name, or we'll end
  2071.          // up with an invalid style declaration.
  2072.          html = html.replace(/^.*\.FirstNormal[^\r\n\s\{]*/, ".Normal");
  2073.  
  2074.          style.innerHTML = html;
  2075.  
  2076.          // Now we need to go and remove all references to the old class.
  2077.          html = DOM.body.innerHTML;
  2078.  
  2079.          if(doShowLog())
  2080.          {
  2081.             var match = html.match(/ class=MsoNormal/g);
  2082.             gRemoveInlineCSS += (match != null ? match.length : 0);
  2083.          }
  2084.  
  2085.          html = html.replace(/ class=MsoNormal([A-Za-z]+)?/g, "");
  2086.          DOM.body.innerHTML = html;
  2087.  
  2088.          DOM.body.setAttribute("class", "Normal");
  2089.  
  2090.          // Since body styles do not filter down into table cells,
  2091.          // we need to set the styles on the table cells too.
  2092.          traverse(DOM.documentElement, setTDStyles);
  2093.       }
  2094.    }
  2095. }
  2096.  
  2097.  
  2098. /////////////////////////////////////////////////////////////////////////////
  2099. // Function
  2100. //    setTDStyles
  2101. //
  2102. // Purpose
  2103. //    We have removed the styles from individual paragraphs and the body
  2104. //    style does not filter down into the table cells, so we need to set
  2105. //    the style on the table cells too.
  2106. //
  2107. function setTDStyles(tag)
  2108. {
  2109.    if(tag.tagName.toUpperCase() == "TD")
  2110.    {
  2111.       tag.setAttribute("class", "Normal");
  2112.    }
  2113.  
  2114.    return true;
  2115. }
  2116.  
  2117.  
  2118. /////////////////////////////////////////////////////////////////////////////
  2119. // Function
  2120. //    removeUnusedStyles
  2121. //
  2122. // Purpose
  2123. //    After we have done all of our house cleaning, some styles defined
  2124. //    in the head may no longer be used anywhere.  If they are no longer
  2125. //    used, we will blow them away.
  2126. //
  2127. function removeUnusedStyles()
  2128. {
  2129.    var style = findTag("style",DOM.documentElement);
  2130.    var html;
  2131.    var classes;
  2132.  
  2133.    if(style != null)
  2134.    {
  2135.       html = style.innerHTML;
  2136.  
  2137.       // Put each style class in an array.
  2138.       // LMH: Removed ? after \. to prevent us from considering
  2139.       // redefined HTML tags as classes (redefined HTML tags
  2140.       // aren't called from anywhere, but they're still used).
  2141.       classes = html.match(/\.\w*\s*\{[^\}]*\}/g);
  2142.  
  2143.       if(classes != null)
  2144.       {
  2145.          var classNames = new Array(classes.length);
  2146.          var regx = new RegExp();
  2147.  
  2148.          // Clean up the matches so we only have the class name.
  2149.          for(i = 0; i < classes.length; i++)
  2150.             classNames[i] = classes[i].replace(/^\s*\.?(\w*)\s*\{[^\}]*\}/g, "$1");
  2151.  
  2152.          body = findTag("body",DOM.documentElement);
  2153.          bodyhtml = body.outerHTML;
  2154.  
  2155.          // Now search in the body to see if we use them anywhere.
  2156.          for(i = 0; i < classes.length; i++)
  2157.          {
  2158.             regx.compile("class=['\"]?" + classNames[i], "g");
  2159.  
  2160.             result = regx.exec(bodyhtml);
  2161.  
  2162.             if(result == null)
  2163.             {
  2164.                // this style is not used.  Nuke it.
  2165.                classes[i] = "";
  2166.  
  2167.                gRemoveUnusedCSS++;
  2168.             }
  2169.          }
  2170.  
  2171.          // Now reconstruct the style block
  2172.          html = "\n<!--\n";
  2173.  
  2174.          for(i = 0; i < classes.length; i++)
  2175.             html += classes[i];
  2176.  
  2177.          html += "\n-->\n";
  2178.  
  2179.          style.innerHTML = html;
  2180.          
  2181.       }
  2182.    }
  2183. }
  2184.  
  2185. //*************** Pg1 Class *****************
  2186.  
  2187. //This is an example of a page class to be used with the TabControl.
  2188. //Uncomment the alert() calls to display the various events as they occur.
  2189.  
  2190. function Pg1(theTabLabel) {
  2191.   this.tabLabel = theTabLabel;
  2192. }
  2193. Pg1.prototype.getTabLabel = Pg1_getTabLabel;
  2194.  
  2195.  
  2196. function Pg1_getTabLabel() {
  2197.   return this.tabLabel;
  2198. }
  2199.  
  2200. //***************** End of Pg1 Class ******************
  2201. //*************** Pg2 Class *****************
  2202.  
  2203. //This is an example of a page class to be used with the TabControl.
  2204. //Uncomment the alert() calls to display the various events as they occur.
  2205.  
  2206. function Pg2(theTabLabel) {
  2207.   this.tabLabel = theTabLabel;
  2208. }
  2209. Pg2.prototype.getTabLabel = Pg2_getTabLabel;
  2210.  
  2211.  
  2212. function Pg2_getTabLabel() {
  2213.   return this.tabLabel;
  2214. }
  2215.  
  2216. //***************** End of Pg2 Class ******************
  2217. //*************** Pg3 Class *****************
  2218.  
  2219. //This is an example of a page class to be used with the TabControl.
  2220. //Uncomment the alert() calls to display the various events as they occur.
  2221.  
  2222. function Pg3(theTabLabel) {
  2223.   this.tabLabel = theTabLabel;
  2224.   this.loaded = false;
  2225. }
  2226. Pg3.prototype.getTabLabel = Pg3_getTabLabel;
  2227. Pg3.prototype.canLoad = Pg3_canLoad;
  2228. Pg3.prototype.unload = Pg3_unload;
  2229. Pg3.prototype.lastUnload = Pg3_lastUnload;
  2230.  
  2231.  
  2232. function Pg3_getTabLabel() {
  2233.   return this.tabLabel;
  2234. }
  2235.  
  2236. function Pg3_canLoad() {
  2237.   if (!this.loaded) {
  2238.     initDropDowns();
  2239.     setDropDownStates();
  2240.     this.loaded = true;
  2241.   }
  2242.   return true;
  2243. }
  2244.  
  2245. function Pg3_unload() {
  2246.   T.obj.visibility = "hidden";
  2247.   T.obj.visibility = "visible";
  2248.   return true;
  2249. }
  2250.  
  2251. function Pg3_lastUnload() {
  2252.   return this.canLoad();     //ensure dropdowns are initted before we do our work
  2253. }
  2254. //***************** End of Pg3 Class ******************
  2255.