home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / editor / EdConvertToTable.js < prev    next >
Encoding:
JavaScript  |  2001-08-31  |  9.8 KB  |  343 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.  */
  22.  
  23. var dialog;
  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 (!InitEditorShell())
  33.     return;
  34.  
  35.   doSetOKCancel(onOK, onCancel);
  36.  
  37.   // Create dialog object to store controls for easy access
  38.   dialog = new Object;
  39.   dialog.sepRadioGroup      = document.getElementById("SepRadioGroup");
  40.   dialog.sepCharacterInput  = document.getElementById("SepCharacterInput");
  41.   dialog.deleteSepCharacter = document.getElementById("DeleteSepCharacter");
  42.   dialog.collapseSpaces     = document.getElementById("CollapseSpaces");
  43.  
  44.   // We persist the user's separator character
  45.   dialog.sepCharacterInput.value = dialog.sepRadioGroup.getAttribute("character");
  46.  
  47.   gIndex = dialog.sepRadioGroup.getAttribute("index");
  48.  
  49.   switch (gIndex)
  50.   {
  51.     case gCommaIndex:
  52.     default:
  53.       document.getElementById("comma").checked = true;
  54.       break;
  55.     case gSpaceIndex:
  56.       document.getElementById("space").checked = true;
  57.       break;
  58.     case gOtherIndex:
  59.       document.getElementById("other").checked = true;
  60.       break;
  61.   }
  62.  
  63.   // Set initial enable state on character input and "collapse" checkbox
  64.   SelectCharacter(gIndex);
  65.  
  66.   SetTextboxFocus(dialog.sepRadioGroup);
  67.  
  68.   SetWindowLocation();
  69. }
  70.  
  71. function InputSepCharacter()
  72. {
  73.   var str = dialog.sepCharacterInput.value;
  74.  
  75.   // Limit input to 1 character
  76.   if (str.length > 1)
  77.     str.slice(0,1);
  78.  
  79.   // We can never allow tag or entity delimeters for separator character
  80.   if (str == "<" || str == ">" || str == "&" || str == ";" || str == " ")
  81.     str = "";
  82.  
  83.   dialog.sepCharacterInput.value = str;
  84. }
  85.  
  86. function SelectCharacter(radioGroupIndex)
  87. {
  88.   gIndex = radioGroupIndex;
  89.   SetElementEnabledById("SepCharacterInput", gIndex == gOtherIndex);
  90.   SetElementEnabledById("CollapseSpaces", gIndex == gSpaceIndex);
  91. }
  92.  
  93. function onOK()
  94. {
  95.   var sepCharacter = "";
  96.   switch ( gIndex )
  97.   {
  98.     case gCommaIndex:
  99.       sepCharacter = ",";
  100.       break;
  101.     case gSpaceIndex:
  102.       sepCharacter = " ";
  103.       break;
  104.     case gOtherIndex:
  105.       sepCharacter = dialog.sepCharacterInput.value.slice(0,1);
  106.       break;
  107.   }
  108.  
  109.   // 1 = OutputSelectionOnly, 1024 = OutputLFLineBreak
  110.   // 256 = OutputEncodeEntities
  111.   var str = editorShell.GetContentsAs("text/html", 1+1024);
  112.  
  113.   // Replace nbsp with spaces:
  114.   str = str.replace(/\u00a0/g, " ");
  115.  
  116.   // Strip out </p> completely
  117.   str = str.replace(/\s*<\/p>\s*/g, "");
  118.  
  119.   // Trim whitespace adjacent to <p> and <br> tags
  120.   //  and replace <p> with <br> 
  121.   //  (which will be replaced with </tr> below)
  122.   str = str.replace(/\s*<p>\s*|\s*<br>\s*/g, "<br>");
  123.  
  124.   // Trim leading <br>s
  125.   str = str.replace(/^(<br>)+/, "");
  126.  
  127.   // Trim trailing <br>s
  128.   str = str.replace(/(<br>)+$/, "");
  129.  
  130.   // Reduce multiple internal <br> to just 1
  131.   // TODO: Maybe add a checkbox to let user decide
  132.   //str = str.replace(/(<br>)+/g, "<br>");
  133.  
  134.   // Trim leading and trailing spaces
  135.   str = str.replace(/^\s+|\s+$/, "");
  136.  
  137.   // Remove all tag contents so we don't replace
  138.   //   separator character within tags
  139.   // Also converts lists to something usefull
  140.   var stack = [];
  141.   var start;
  142.   var end;
  143.   var searchStart = 0;
  144.   var listSeparator = "";
  145.   var listItemSeparator = "";
  146.   var endList = false;
  147.  
  148.   do {
  149.     start = str.indexOf("<", searchStart);
  150.  
  151.     if (start >= 0)
  152.     {
  153.       var end = str.indexOf(">", start+1);
  154.       if (end > start)
  155.       {
  156.         var tagContent = TrimString(str.slice(start+1, end));
  157.  
  158.         if ( tagContent.match(/^ol|^ul|^dl/) )
  159.         {
  160.           //  Replace list tag with <BR> to start new row 
  161.           //   at begining of second or greater list tag
  162.           str = str.slice(0, start) + listSeparator + str.slice(end+1);
  163.           if (listSeparator == "")
  164.             listSeparator = "<br>";
  165.           
  166.           // Reset for list item separation into cells
  167.           listItemSeparator = "";
  168.         }
  169.         else if ( tagContent.match(/^li|^dt|^dd/) )
  170.         {
  171.           // Start a new row if this is first item after the ending the last list
  172.           if (endList)
  173.             listItemSeparator = "<br>";
  174.  
  175.           // Start new cell at begining of second or greater list items
  176.           str = str.slice(0, start) + listItemSeparator + str.slice(end+1);
  177.  
  178.           if (endList || listItemSeparator == "")
  179.             listItemSeparator = sepCharacter;
  180.  
  181.           endList = false;
  182.         }
  183.         else 
  184.         {
  185.           // Find end tags
  186.           endList = tagContent.match(/^\/ol|^\/ul|^\/dl/);
  187.           if ( endList || tagContent.match(/^\/li|^\/dt|^\/dd/) )
  188.           {
  189.             // Strip out tag
  190.             str = str.slice(0, start) + str.slice(end+1);
  191.           }
  192.           else
  193.           {
  194.             // Not a list-related tag: Store tag contents in an array
  195.             stack.push(tagContent);
  196.            
  197.             // Keep the "<" and ">" while removing from source string
  198.             start++;
  199.             str = str.slice(0, start) + str.slice(end);
  200.           }
  201.         }
  202.       }
  203.       searchStart = start + 1;
  204.     }
  205.   } while (start >= 0);
  206.  
  207.   // Replace separator characters with table cells
  208.   var replaceString;
  209.   if (dialog.deleteSepCharacter.checked)
  210.   {
  211.     replaceString = "";
  212.   }  
  213.   else
  214.   {
  215.     // Don't delete separator character,
  216.     //  so include it at start of string to replace
  217.     replaceString = sepCharacter;
  218.   }
  219.  
  220.   replaceString += "<td>"; 
  221.  
  222.   if (sepCharacter.length > 0)
  223.   {
  224.     var tempStr = sepCharacter;
  225.     var regExpChars = ".!@#$%^&*-+[]{}\\\/";
  226.     if (regExpChars.indexOf(sepCharacter) >= 0)
  227.       tempStr = "\\" + sepCharacter;
  228.  
  229.     if (gIndex == gSpaceIndex)
  230.     {
  231.       // If checkbox is checked, 
  232.       //   one or more adjacent spaces are one separator
  233.       if (dialog.collapseSpaces.checked)
  234.           tempStr = "\\s+"
  235.         else
  236.           tempStr = "\\s";
  237.     }
  238.     var pattern = new RegExp(tempStr, "g");
  239.     str = str.replace(pattern, replaceString);
  240.   }
  241.  
  242.   // Put back tag contents that we removed above
  243.   searchStart = 0;
  244.   var stackIndex = 0;
  245.   do {
  246.     start = str.indexOf("<", searchStart);
  247.     end = start + 1;
  248.     if (start >= 0 && str.charAt(end) == ">")
  249.     {
  250.       // We really need a FIFO stack!
  251.       str = str.slice(0, end) + stack[stackIndex++] + str.slice(end);
  252.     }
  253.     searchStart = end;
  254.  
  255.   } while (start >= 0);
  256.  
  257.   // End table row and start another for each br or p
  258.   str = str.replace(/\s*<br>\s*/g, "</tr>\n<tr><td>");
  259.  
  260.   // Add the table tags and the opening and closing tr/td tags
  261.   // Default table attributes should be same as those used in nsHTMLEditor::CreateElementWithDefaults()
  262.   // (Default width="100%" is used in EdInsertTable.js)
  263.   str = "<table border=\"1\" width=\"100%\" cellpadding=\"2\" cellspacing=\"2\">\n<tr><td>" + str + "</tr>\n</table>\n";
  264.  
  265.   editorShell.BeginBatchChanges();
  266.   
  267.   // Delete the selection -- makes it easier to find where table will insert
  268.   editorShell.DeleteSelection(0);
  269.  
  270.   var anchorNodeBeforeInsert = editorShell.editorSelection.anchorNode;
  271.   var offset = editorShell.editorSelection.anchorOffset;
  272.   var nodeBeforeTable = null;
  273.   var nodeAfterTable = null;
  274.   if (anchorNodeBeforeInsert.nodeType == Node.TEXT_NODE)
  275.   {
  276.     // Text was split. Table should be right after the first or before 
  277.     nodeBeforeTable = anchorNodeBeforeInsert.previousSibling;
  278.     nodeAfterTable = anchorNodeBeforeInsert;
  279.   }
  280.   else
  281.   {
  282.     // Table should be inserted right after node pointed to by selection
  283.     if (offset > 0)
  284.       nodeBeforeTable = anchorNodeBeforeInsert.childNodes.item(offset - 1);
  285.  
  286.     nodeAfterTable = anchorNodeBeforeInsert.childNodes.item(offset);
  287.   }
  288.   
  289.   editorShell.InsertSource(str);
  290.  
  291.   var table = null;
  292.   if (nodeAfterTable)
  293.   {
  294.     var previous = nodeAfterTable.previousSibling;
  295.     if (previous && previous.nodeName.toLowerCase() == "table")
  296.       table = previous;
  297.   }
  298.   if (!table && nodeBeforeTable)
  299.   {
  300.     var next = nodeBeforeTable.nextSibling;
  301.     if (next && next.nodeName.toLowerCase() == "table")
  302.       table = next;
  303.   }
  304.  
  305.   if (table)
  306.   {
  307.     // Fixup table only if pref is set
  308.     var prefs = GetPrefs();
  309.     try {
  310.       if (prefs && prefs.GetBoolPref("editor.table.maintain_structure") )
  311.         editorShell.NormalizeTable(table);
  312.     } catch(ex) {
  313.       dump(ex);
  314.     }
  315.  
  316.     // Put caret in first cell
  317.     var firstRow = editorShell.GetFirstRow(table);
  318.     if (firstRow)
  319.     {
  320.       var node2 = firstRow.firstChild;
  321.       do {
  322.         if (node2.nodeName.toLowerCase() == "td" ||
  323.             node2.nodeName.toLowerCase() == "th")
  324.         {
  325.           editorShell.editorSelection.collapse(node2, 0);
  326.           break;
  327.         }
  328.         node2 = node.nextSibling;
  329.       } while (node2);
  330.     }
  331.   }
  332.  
  333.   editorShell.EndBatchChanges();
  334.  
  335.   // Save persisted attributes
  336.   dialog.sepRadioGroup.setAttribute("index", gIndex);
  337.   if (gIndex == gOtherIndex)
  338.     dialog.sepRadioGroup.setAttribute("character", sepCharacter);
  339.  
  340.   SaveWindowLocation();
  341.   return true;
  342. }
  343.