home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Complet / thunderbird / chrome / mail.jar / content / editor / EdConvertToTable.js < prev    next >
Encoding:
JavaScript  |  2003-03-11  |  9.9 KB  |  352 lines

  1. /* 
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *  
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *  
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation. Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s): 
  21.  *    Charles Manske (cmanske@netscape.com)
  22.  */
  23.  
  24. var gIndex;
  25. var gCommaIndex = "0";
  26. var gSpaceIndex = "1";
  27. var gOtherIndex = "2";
  28.  
  29. // dialog initialization code
  30. function Startup()
  31. {
  32.   if (!GetCurrentEditor())
  33.   {
  34.     window.close();
  35.     return;
  36.   }
  37.  
  38.   gDialog.sepRadioGroup      = document.getElementById("SepRadioGroup");
  39.   gDialog.sepCharacterInput  = document.getElementById("SepCharacterInput");
  40.   gDialog.deleteSepCharacter = document.getElementById("DeleteSepCharacter");
  41.   gDialog.collapseSpaces     = document.getElementById("CollapseSpaces");
  42.  
  43.   // We persist the user's separator character
  44.   gDialog.sepCharacterInput.value = gDialog.sepRadioGroup.getAttribute("character");
  45.  
  46.   gIndex = gDialog.sepRadioGroup.getAttribute("index");
  47.  
  48.   switch (gIndex)
  49.   {
  50.     case gCommaIndex:
  51.     default:
  52.       gDialog.sepRadioGroup.selectedItem = document.getElementById("comma");
  53.       break;
  54.     case gSpaceIndex:
  55.       gDialog.sepRadioGroup.selectedItem = document.getElementById("space");
  56.       break;
  57.     case gOtherIndex:
  58.       gDialog.sepRadioGroup.selectedItem = document.getElementById("other");
  59.       break;
  60.   }
  61.  
  62.   // Set initial enable state on character input and "collapse" checkbox
  63.   SelectCharacter(gIndex);
  64.  
  65.   SetWindowLocation();
  66. }
  67.  
  68. function InputSepCharacter()
  69. {
  70.   var str = gDialog.sepCharacterInput.value;
  71.  
  72.   // Limit input to 1 character
  73.   if (str.length > 1)
  74.     str = str.slice(0,1);
  75.  
  76.   // We can never allow tag or entity delimiters for separator character
  77.   if (str == "<" || str == ">" || str == "&" || str == ";" || str == " ")
  78.     str = "";
  79.  
  80.   gDialog.sepCharacterInput.value = str;
  81. }
  82.  
  83. function SelectCharacter(radioGroupIndex)
  84. {
  85.   gIndex = radioGroupIndex;
  86.   SetElementEnabledById("SepCharacterInput", gIndex == gOtherIndex);
  87.   SetElementEnabledById("CollapseSpaces", gIndex == gSpaceIndex);
  88. }
  89.  
  90. function onAccept()
  91. {
  92.   var sepCharacter = "";
  93.   switch ( gIndex )
  94.   {
  95.     case gCommaIndex:
  96.       sepCharacter = ",";
  97.       break;
  98.     case gSpaceIndex:
  99.       sepCharacter = " ";
  100.       break;
  101.     case gOtherIndex:
  102.       sepCharacter = gDialog.sepCharacterInput.value.slice(0,1);
  103.       break;
  104.   }
  105.  
  106.   var editor = GetCurrentEditor();
  107.   var str;
  108.   try {
  109.     // 1 = OutputSelectionOnly, 1024 = OutputLFLineBreak
  110.     str = editor.outputToString("text/html", 1+1024);
  111.   } catch (e) {}
  112.   if (!str)
  113.   {
  114.     SaveWindowLocation();
  115.     return true;
  116.   }
  117.  
  118.   // Replace nbsp with spaces:
  119.   str = str.replace(/\u00a0/g, " ");
  120.  
  121.   // Strip out </p> completely
  122.   str = str.replace(/\s*<\/p>\s*/g, "");
  123.  
  124.   // Trim whitespace adjacent to <p> and <br> tags
  125.   //  and replace <p> with <br> 
  126.   //  (which will be replaced with </tr> below)
  127.   str = str.replace(/\s*<p>\s*|\s*<br>\s*/g, "<br>");
  128.  
  129.   // Trim leading <br>s
  130.   str = str.replace(/^(<br>)+/, "");
  131.  
  132.   // Trim trailing <br>s
  133.   str = str.replace(/(<br>)+$/, "");
  134.  
  135.   // Reduce multiple internal <br> to just 1
  136.   // TODO: Maybe add a checkbox to let user decide
  137.   //str = str.replace(/(<br>)+/g, "<br>");
  138.  
  139.   // Trim leading and trailing spaces
  140.   str = str.replace(/^\s+|\s+$/, "");
  141.  
  142.   // Remove all tag contents so we don't replace
  143.   //   separator character within tags
  144.   // Also converts lists to something usefull
  145.   var stack = [];
  146.   var start;
  147.   var end;
  148.   var searchStart = 0;
  149.   var listSeparator = "";
  150.   var listItemSeparator = "";
  151.   var endList = false;
  152.  
  153.   do {
  154.     start = str.indexOf("<", searchStart);
  155.  
  156.     if (start >= 0)
  157.     {
  158.       end = str.indexOf(">", start+1);
  159.       if (end > start)
  160.       {
  161.         var tagContent = TrimString(str.slice(start+1, end));
  162.  
  163.         if ( /^ol|^ul|^dl/.test(tagContent) )
  164.         {
  165.           //  Replace list tag with <BR> to start new row 
  166.           //   at begining of second or greater list tag
  167.           str = str.slice(0, start) + listSeparator + str.slice(end+1);
  168.           if (listSeparator == "")
  169.             listSeparator = "<br>";
  170.           
  171.           // Reset for list item separation into cells
  172.           listItemSeparator = "";
  173.         }
  174.         else if ( /^li|^dt|^dd/.test(tagContent) )
  175.         {
  176.           // Start a new row if this is first item after the ending the last list
  177.           if (endList)
  178.             listItemSeparator = "<br>";
  179.  
  180.           // Start new cell at begining of second or greater list items
  181.           str = str.slice(0, start) + listItemSeparator + str.slice(end+1);
  182.  
  183.           if (endList || listItemSeparator == "")
  184.             listItemSeparator = sepCharacter;
  185.  
  186.           endList = false;
  187.         }
  188.         else 
  189.         {
  190.           // Find end tags
  191.           endList = /^\/ol|^\/ul|^\/dl/.test(tagContent);
  192.           if ( endList || /^\/li|^\/dt|^\/dd/.test(tagContent) )
  193.           {
  194.             // Strip out tag
  195.             str = str.slice(0, start) + str.slice(end+1);
  196.           }
  197.           else
  198.           {
  199.             // Not a list-related tag: Store tag contents in an array
  200.             stack.push(tagContent);
  201.            
  202.             // Keep the "<" and ">" while removing from source string
  203.             start++;
  204.             str = str.slice(0, start) + str.slice(end);
  205.           }
  206.         }
  207.       }
  208.       searchStart = start + 1;
  209.     }
  210.   } while (start >= 0);
  211.  
  212.   // Replace separator characters with table cells
  213.   var replaceString;
  214.   if (gDialog.deleteSepCharacter.checked)
  215.   {
  216.     replaceString = "";
  217.   }  
  218.   else
  219.   {
  220.     // Don't delete separator character,
  221.     //  so include it at start of string to replace
  222.     replaceString = sepCharacter;
  223.   }
  224.  
  225.   replaceString += "<td>"; 
  226.  
  227.   if (sepCharacter.length > 0)
  228.   {
  229.     var tempStr = sepCharacter;
  230.     var regExpChars = ".!@#$%^&*-+[]{}()\|\\\/";
  231.     if (regExpChars.indexOf(sepCharacter) >= 0)
  232.       tempStr = "\\" + sepCharacter;
  233.  
  234.     if (gIndex == gSpaceIndex)
  235.     {
  236.       // If checkbox is checked, 
  237.       //   one or more adjacent spaces are one separator
  238.       if (gDialog.collapseSpaces.checked)
  239.           tempStr = "\\s+"
  240.         else
  241.           tempStr = "\\s";
  242.     }
  243.     var pattern = new RegExp(tempStr, "g");
  244.     str = str.replace(pattern, replaceString);
  245.   }
  246.  
  247.   // Put back tag contents that we removed above
  248.   searchStart = 0;
  249.   var stackIndex = 0;
  250.   do {
  251.     start = str.indexOf("<", searchStart);
  252.     end = start + 1;
  253.     if (start >= 0 && str.charAt(end) == ">")
  254.     {
  255.       // We really need a FIFO stack!
  256.       str = str.slice(0, end) + stack[stackIndex++] + str.slice(end);
  257.     }
  258.     searchStart = end;
  259.  
  260.   } while (start >= 0);
  261.  
  262.   // End table row and start another for each br or p
  263.   str = str.replace(/\s*<br>\s*/g, "</tr>\n<tr><td>");
  264.  
  265.   // Add the table tags and the opening and closing tr/td tags
  266.   // Default table attributes should be same as those used in nsHTMLEditor::CreateElementWithDefaults()
  267.   // (Default width="100%" is used in EdInsertTable.js)
  268.   str = "<table border=\"1\" width=\"100%\" cellpadding=\"2\" cellspacing=\"2\">\n<tr><td>" + str + "</tr>\n</table>\n";
  269.  
  270.   editor.beginTransaction();
  271.   
  272.   // Delete the selection -- makes it easier to find where table will insert
  273.   var nodeBeforeTable = null;
  274.   var nodeAfterTable = null;
  275.   try {
  276.     editor.deleteSelection(0);
  277.  
  278.     var anchorNodeBeforeInsert = editor.selection.anchorNode;
  279.     var offset = editor.selection.anchorOffset;
  280.     if (anchorNodeBeforeInsert.nodeType == Node.TEXT_NODE)
  281.     {
  282.       // Text was split. Table should be right after the first or before 
  283.       nodeBeforeTable = anchorNodeBeforeInsert.previousSibling;
  284.       nodeAfterTable = anchorNodeBeforeInsert;
  285.     }
  286.     else
  287.     {
  288.       // Table should be inserted right after node pointed to by selection
  289.       if (offset > 0)
  290.         nodeBeforeTable = anchorNodeBeforeInsert.childNodes.item(offset - 1);
  291.  
  292.       nodeAfterTable = anchorNodeBeforeInsert.childNodes.item(offset);
  293.     }
  294.   
  295.     editor.insertHTML(str);
  296.   } catch (e) {}
  297.  
  298.   var table = null;
  299.   if (nodeAfterTable)
  300.   {
  301.     var previous = nodeAfterTable.previousSibling;
  302.     if (previous && previous.nodeName.toLowerCase() == "table")
  303.       table = previous;
  304.   }
  305.   if (!table && nodeBeforeTable)
  306.   {
  307.     var next = nodeBeforeTable.nextSibling;
  308.     if (next && next.nodeName.toLowerCase() == "table")
  309.       table = next;
  310.   }
  311.  
  312.   if (table)
  313.   {
  314.     // Fixup table only if pref is set
  315.     var prefs = GetPrefs();
  316.     var firstRow;
  317.     try {
  318.       if (prefs && prefs.getBoolPref("editor.table.maintain_structure") )
  319.         editor.normalizeTable(table);
  320.  
  321.       firstRow = editor.getFirstRow(table);
  322.     } catch(e) {}
  323.  
  324.     // Put caret in first cell
  325.     if (firstRow)
  326.     {
  327.       var node2 = firstRow.firstChild;
  328.       do {
  329.         if (node2.nodeName.toLowerCase() == "td" ||
  330.             node2.nodeName.toLowerCase() == "th")
  331.         {
  332.           try { 
  333.             editor.selection.collapse(node2, 0);
  334.           } catch(e) {}
  335.           break;
  336.         }
  337.         node2 = node.nextSibling;
  338.       } while (node2);
  339.     }
  340.   }
  341.  
  342.   editor.endTransaction();
  343.  
  344.   // Save persisted attributes
  345.   gDialog.sepRadioGroup.setAttribute("index", gIndex);
  346.   if (gIndex == gOtherIndex)
  347.     gDialog.sepRadioGroup.setAttribute("character", sepCharacter);
  348.  
  349.   SaveWindowLocation();
  350.   return true;
  351. }
  352.