home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / comm.jar / content / editor / EdAEHTMLAttributes.js < prev    next >
Encoding:
JavaScript  |  2001-09-01  |  12.8 KB  |  396 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.  *   Ben "Count XULula" Goodger
  22.  */
  23.  
  24. function BuildHTMLAttributeNameList()
  25. {
  26.   ClearMenulist(dialog.AddHTMLAttributeNameInput);
  27.   
  28.   var elementName = gElement.localName.toLowerCase();
  29.   var attNames = gHTMLAttr[elementName];
  30.  
  31.   if (attNames && attNames.length)
  32.   {
  33.     var menuitem;
  34.  
  35.     for (var i = 0; i < attNames.length; i++)
  36.     {
  37.       var name = attNames[i];
  38.       var limitFirstChar;
  39.  
  40.       if (name == "_core")
  41.       {
  42.         // Signal to append the common 'core' attributes.
  43.         for (var j = 0; j < gCoreHTMLAttr.length; j++)
  44.         {
  45.           name = gCoreHTMLAttr[j];
  46.  
  47.           // "limitFirstChar" is the only filtering rule used for core attributes as of 8-20-01
  48.           // Add more rules if necessary          
  49.           limitFirstChar = name.indexOf("^") >= 0;
  50.           if (limitFirstChar)
  51.           {
  52.             menuitem = AppendStringToMenulist(dialog.AddHTMLAttributeNameInput, name.replace(/\^/g, ""));
  53.             menuitem.setAttribute("limitFirstChar", "true");
  54.           }
  55.           else
  56.             AppendStringToMenulist(dialog.AddHTMLAttributeNameInput, name);
  57.         }
  58.       }
  59.       else if (name == "-")
  60.       {
  61.         // Signal for separator
  62.         var popup = dialog.AddHTMLAttributeNameInput.firstChild;
  63.         if (popup)
  64.         {
  65.           var sep = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuseparator");
  66.           if (sep)
  67.             popup.appendChild(sep);
  68.         }        
  69.       }
  70.       else
  71.       {
  72.         // Get information about value filtering
  73.         var forceOneChar = name.indexOf("!") >= 0;
  74.         var forceInteger = name.indexOf("#") >= 0;
  75.         var forceSignedInteger = name.indexOf("+") >= 0;
  76.         var forceIntOrPercent = name.indexOf("%") >= 0;
  77.         limitFirstChar = name.indexOf("\^") >= 0;
  78.         //var required = name.indexOf("$") >= 0;
  79.  
  80.         // Strip flag characters ("_" is used when attribute name is reserved JS word)
  81.         name = name.replace(/[!^#%$_+]/g, "");
  82.  
  83.         menuitem = AppendStringToMenulist(dialog.AddHTMLAttributeNameInput, name);
  84.         if (menuitem)
  85.         {
  86.           // Signify "required" attributes by special style
  87.           //TODO: Don't do this until next version, when we add
  88.           //      explanatory text and an 'Autofill Required Attributes' button
  89.           //if (required)
  90.           //  menuitem.setAttribute("class", "menuitem-highlight-1");
  91.  
  92.           // Set flags to filter value input
  93.           menuitem.setAttribute("forceOneChar", forceOneChar ? "true" : "");
  94.           menuitem.setAttribute("limitFirstChar", limitFirstChar ? "true" : "");
  95.           menuitem.setAttribute("forceInteger", forceInteger ? "true" : "");
  96.           menuitem.setAttribute("forceSignedInteger", forceSignedInteger ? "true" : "");
  97.           menuitem.setAttribute("forceIntOrPercent", forceIntOrPercent ? "true" : "");
  98.         }
  99.       }
  100.     }
  101.   }
  102.  
  103.   // Always start with empty input fields
  104.   ClearHTMLInputWidgets();
  105. }
  106.  
  107. // build attribute list in tree form from element attributes
  108. function BuildHTMLAttributeTable()
  109. {
  110.   var nodeMap = gElement.attributes;
  111.   var i;
  112.   if (nodeMap.length > 0) 
  113.   {
  114.     var added = false;
  115.     for(i = 0; i < nodeMap.length; i++)
  116.     {
  117.       if ( CheckAttributeNameSimilarity( nodeMap[i].nodeName, HTMLAttrs ) ||
  118.           IsEventHandler( nodeMap[i].nodeName ) ||
  119.           TrimString( nodeMap[i].nodeName.toLowerCase() ) == "style" ) {
  120.         continue;   // repeated or non-HTML attribute, ignore this one and go to next
  121.       }
  122.       var name  = nodeMap[i].nodeName.toLowerCase();
  123.       var value = gElement.getAttribute ( nodeMap[i].nodeName );
  124.       if ( name.indexOf("_moz") != 0 &&
  125.            AddTreeItem(name, value, "HTMLAList", HTMLAttrs) )
  126.         added = true;
  127.     }
  128.  
  129.     if (added)
  130.       SelectHTMLTree(0);
  131.   }
  132. }
  133.  
  134. // add or select an attribute in the tree widget
  135. function onChangeHTMLAttribute()
  136. {
  137.   var name  = TrimString(dialog.AddHTMLAttributeNameInput.value);
  138.   if (!name)
  139.     return;
  140.  
  141.   var value = TrimString(dialog.AddHTMLAttributeValueInput.value);
  142.  
  143.   // First try to update existing attribute
  144.   // If not found, add new attribute
  145.   if ( !UpdateExistingAttribute( name, value, "HTMLAList" ) )
  146.     AddTreeItem ( name, value, "HTMLAList", HTMLAttrs );
  147. }
  148.  
  149. function ClearHTMLInputWidgets()
  150. {
  151.   dialog.AddHTMLAttributeTree.clearItemSelection();
  152.   dialog.AddHTMLAttributeNameInput.value ="";
  153.   dialog.AddHTMLAttributeValueInput.value = "";
  154.   dialog.AddHTMLAttributeNameInput.inputField.focus();
  155. }
  156.  
  157. function onSelectHTMLTreeItem()
  158. {
  159.   if (!gDoOnSelectTree)
  160.     return;
  161.  
  162.   var tree = dialog.AddHTMLAttributeTree;
  163.   if (tree && tree.selectedItems && tree.selectedItems.length)
  164.   {
  165.     var inputName = TrimString(dialog.AddHTMLAttributeNameInput.value).toLowerCase();
  166.     var selectedName = tree.selectedItems[0].firstChild.firstChild.getAttribute("label");
  167.  
  168.     if (inputName == selectedName)
  169.     {
  170.       // Already editing selected name - just update the value input
  171.       dialog.AddHTMLAttributeValueInput.value =  GetTreeItemValueStr(tree.selectedItems[0]);
  172.     }
  173.     else
  174.     {
  175.       dialog.AddHTMLAttributeNameInput.value =  selectedName;
  176.  
  177.       // Change value input based on new selected name
  178.       onInputHTMLAttributeName();
  179.     }
  180.   }
  181. }
  182.  
  183. function onInputHTMLAttributeName()
  184. {
  185.   var attName = TrimString(dialog.AddHTMLAttributeNameInput.value).toLowerCase();
  186.  
  187.   // Clear value widget, but prevent triggering update in tree
  188.   gUpdateTreeValue = false;
  189.   dialog.AddHTMLAttributeValueInput.value = "";
  190.   gUpdateTreeValue = true; 
  191.  
  192.   if (attName)
  193.   {
  194.     // Get value list for current attribute name
  195.     var valueListName;
  196.  
  197.     // Most elements have the "dir" attribute,
  198.     //   so we have just one array for the allowed values instead
  199.     //   requiring duplicate entries for each element in EdAEAttributes.js
  200.     if (attName == "dir")
  201.       valueListName = "all_dir";
  202.     else
  203.       valueListName = gElement.localName.toLowerCase() + "_" + attName;
  204.  
  205.     // Strip off leading "_" we sometimes use (when element name is reserved word)
  206.     if (valueListName[0] == "_")
  207.       valueListName = valueListName.slice(1);
  208.  
  209.     var newValue = "";
  210.     var listLen = 0;
  211.     var deckIndex = 0;
  212.  
  213.     if (valueListName in gHTMLAttr)
  214.     {
  215.       var valueList = gHTMLAttr[valueListName];
  216.  
  217.       // Index to which widget we were using to edit the value
  218.       deckIndex = dialog.AddHTMLAttributeValueDeck.getAttribute("index");
  219.  
  220.       listLen = valueList.length;
  221.       if (listLen > 0)
  222.         newValue = valueList[0];
  223.  
  224.       // Note: For case where "value list" is actually just 
  225.       // one (default) item, don't use menulist for that
  226.       if (listLen > 1)
  227.       {
  228.         ClearMenulist(dialog.AddHTMLAttributeValueMenulist);
  229.  
  230.         if (deckIndex != "1")
  231.         {
  232.           // Switch to using editable menulist
  233.           dialog.AddHTMLAttributeValueInput = dialog.AddHTMLAttributeValueMenulist;
  234.           dialog.AddHTMLAttributeValueDeck.setAttribute("index", "1");
  235.         }
  236.         // Rebuild the list
  237.         for (var i = 0; i < listLen; i++)
  238.         {
  239.           if (valueList[i] == "-")
  240.           {
  241.             // Signal for separator
  242.             var popup = dialog.AddHTMLAttributeValueInput.firstChild;
  243.             if (popup)
  244.             {
  245.               var sep = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuseparator");
  246.               if (sep)
  247.                 popup.appendChild(sep);
  248.             }        
  249.           } else {
  250.             AppendStringToMenulist(dialog.AddHTMLAttributeValueMenulist, valueList[i]);
  251.           }
  252.         }
  253.       }
  254.     }
  255.     
  256.     if (listLen <= 1 && deckIndex != "0")
  257.     {
  258.       // No list: Use textbox for input instead
  259.       dialog.AddHTMLAttributeValueInput = dialog.AddHTMLAttributeValueTextbox;
  260.       dialog.AddHTMLAttributeValueDeck.setAttribute("index", "0");
  261.     }
  262.  
  263.     // If attribute already exists in tree, use associated value,
  264.     //  else use default found above
  265.     var existingValue = GetAndSelectExistingAttributeValue(attName, "HTMLAList");
  266.     if (existingValue)
  267.       newValue = existingValue;
  268.       
  269.     dialog.AddHTMLAttributeValueInput.value = newValue;
  270.   }
  271. }
  272.  
  273. function onInputHTMLAttributeValue()
  274. {
  275.   if (!gUpdateTreeValue)
  276.     return;
  277.  
  278.   // Trim spaces only from left since we must allow spaces within the string
  279.   //  (we always reset the input field's value below)
  280.   var value = TrimStringLeft(dialog.AddHTMLAttributeValueInput.value);
  281.   if (value)
  282.   {
  283.     // Do value filtering based on type of attribute
  284.     // (Do not use "LimitStringLength()" and "forceInteger()"
  285.     //  to avoid multiple reseting of input's value and flickering)
  286.     var selectedItem = dialog.AddHTMLAttributeNameInput.selectedItem;
  287.     if (selectedItem)
  288.     {
  289.       if ( selectedItem.getAttribute("forceOneChar") == "true" &&
  290.            value.length > 1 )
  291.         value = value.slice(0, 1);
  292.  
  293.       if ( selectedItem.getAttribute("forceIntOrPercent") == "true" )
  294.       {
  295.         // Allow integer with optional "%" as last character
  296.         var percent = TrimStringRight(value).slice(-1);
  297.         value = value.replace(/\D+/g,"");
  298.         if (percent == "%")
  299.           value += percent;
  300.       }
  301.       else if ( selectedItem.getAttribute("forceInteger") == "true" )
  302.       {
  303.         value = value.replace(/\D+/g,"");
  304.       }
  305.       else if ( selectedItem.getAttribute("forceSignedInteger") == "true" )
  306.       {
  307.         // Allow integer with optional "+" or "-" as first character
  308.         var sign = value[0];
  309.         value = value.replace(/\D+/g,"");
  310.         if (sign == "+" || sign == "-")
  311.           value = sign + value;
  312.       }
  313.       
  314.       // Special case attributes 
  315.       if (selectedItem.getAttribute("limitFirstChar") == "true")
  316.       {
  317.         // Limit first character to letter, and all others to 
  318.         //  letters, numbers, and a few others
  319.         value = value.replace(/^[^a-zA-Z\u0080-\uFFFF]/, "").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
  320.       }
  321.  
  322.       // Update once only if it changed
  323.       if ( value != dialog.AddHTMLAttributeValueInput.value )
  324.         dialog.AddHTMLAttributeValueInput.value = value;
  325.     }
  326.   }
  327.  
  328.   // Always update value in the tree list
  329.   UpdateExistingAttribute( dialog.AddHTMLAttributeNameInput.value, value, "HTMLAList" );
  330. }
  331.  
  332. function editHTMLAttributeValue(targetCell)
  333. {
  334.   if (IsNotTreeHeader(targetCell))
  335.     dialog.AddHTMLAttributeValueInput.inputField.select();
  336. }
  337.  
  338.  
  339. // update the object with added and removed attributes
  340. function UpdateHTMLAttributes()
  341. {
  342.   var HTMLAList = document.getElementById("HTMLAList");
  343.   var i;
  344.  
  345.   // remove removed attributes
  346.   for( i = 0; i < HTMLRAttrs.length; i++ )
  347.   {
  348.     var name = HTMLRAttrs[i];
  349.  
  350.     // We can't use getAttribute to figure out if attribute already
  351.     //  exists for attributes that don't require a value
  352.     // This gets the attribute NODE from the attributes NamedNodeMap
  353.     if (gElement.attributes.getNamedItem(name))
  354.       gElement.removeAttribute(name);
  355.   }
  356.  
  357.   // Set added or changed attributes
  358.   for( i = 0; i < HTMLAList.childNodes.length; i++)
  359.   {
  360.     var item = HTMLAList.childNodes[i];
  361.     gElement.setAttribute( GetTreeItemAttributeStr(item), GetTreeItemValueStr(item) );
  362.   }
  363. }
  364.  
  365. function RemoveHTMLAttribute()
  366. {
  367.   var treechildren = dialog.AddHTMLAttributeTree.lastChild;
  368.  
  369.   // We only allow 1 selected item
  370.   if (dialog.AddHTMLAttributeTree.selectedItems.length)
  371.   {
  372.     var item = dialog.AddHTMLAttributeTree.selectedItems[0];
  373.     var attr = GetTreeItemAttributeStr(item);
  374.  
  375.     // remove the item from the attribute array
  376.     HTMLRAttrs[HTMLRAttrs.length] = attr;
  377.     RemoveNameFromAttArray(attr, HTMLAttrs);
  378.  
  379.     // Remove the item from the tree
  380.     treechildren.removeChild(item);
  381.  
  382.     // Clear inputs and selected item in tree
  383.     ClearHTMLInputWidgets();
  384.   }
  385. }
  386.  
  387. function SelectHTMLTree( index )
  388. {
  389.  
  390.   gDoOnSelectTree = false;
  391.   try {
  392.     dialog.AddHTMLAttributeTree.selectedIndex = index;
  393.   } catch (e) {}
  394.   gDoOnSelectTree = true;
  395. }
  396.