home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 2000 July / macformat-092.iso / Dreamweaver 3 / Configuration / Shared / MM / Scripts / CMN / DOM.js < prev    next >
Encoding:
Text File  |  1999-12-01  |  11.6 KB  |  349 lines

  1. //
  2. // Copyright 1999 Macromedia, Inc.  All rights reserved.
  3. // -----------------------------------------------------
  4. //
  5. // DOM.js
  6. //
  7. // This file contains some general helper functions for working with
  8. // the Dreamweaver DOM.
  9. //
  10.  
  11.  
  12. /////////////////////////////////////////////////////////////////////////////
  13. // Function
  14. //    getRootNode
  15. //
  16. // Purpose
  17. //    Quickie function for getting the root node of the active document.
  18. //
  19. function getRootNode()
  20. {
  21.    return dreamweaver.getDocumentDOM("document").documentElement;
  22. }
  23.  
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Function
  27. //    findTag
  28. //
  29. // Purpose
  30. //    Find a tag with the given name.  The search starts at startNode and
  31. //    searches its children.
  32. //
  33. // Entry
  34. //    tagName - a string that contains the name of the tag to find.
  35. //    startNode - the node in the dom to start from.  If this is not
  36. //       given, the root node will be used by default.
  37. //
  38. function findTag(tagName) // optional:  startNode
  39. {
  40.    var startNode = (findTag.arguments.length >= 2 ? findTag.arguments[1] : null);
  41.    var i, result;
  42.  
  43.    if(startNode == null)
  44.       startNode = getRootNode();
  45.  
  46.    if(startNode.tagName != null &&
  47.       startNode.tagName.toUpperCase() == tagName.toUpperCase())
  48.       return startNode;
  49.  
  50.    for(i = 0; i < startNode.childNodes.length; i++)
  51.    {
  52.       result = findTag(tagName, startNode.childNodes[i]);
  53.  
  54.       if(result != null)
  55.          return result;  // found it.
  56.    }
  57.  
  58.    return null;  // didn't find it here.
  59. }
  60.  
  61.  
  62. //////////////////////////////////////////////////////////////////////////////
  63. // Function
  64. //    traverse
  65. //
  66. // Purpose
  67. //    Given a node, this will traverse the entire DOM structure, calling
  68. //    a handler (callback) function for each node type that it encounters.
  69. //
  70. function traverse( node, fElementHandler ) // optional: fTextHandler, fCommentHandler, userData )
  71. {
  72.    if(node == null)
  73.       node = getRootNode();
  74.  
  75.    var fTextHandler  = traverse.arguments.length >= 3 ? traverse.arguments[2] : null;
  76.    var fCommentHandler  = traverse.arguments.length >= 4 ? traverse.arguments[3] : null;
  77.    var userData      = traverse.arguments.length >= 5 ? traverse.arguments[4] : null;
  78.    var children      = node.childNodes;
  79.    var nChildren     = children.length;
  80.    var bContinue     = true;
  81.    var current       = null;
  82.  
  83.    if(fElementHandler == null && fTextHandler == null && fCommentHandler == null)        return;  // No callbacks.  Nothing to do.
  84.  
  85.    for( var i = 0; bContinue && (i < nChildren); i++ )
  86.    {
  87.       current = children.item( i );
  88.  
  89.       // descend to any children first
  90.       if ( current.hasChildNodes() )
  91.          traverse( current, fElementHandler, fTextHandler, fCommentHandler, userData );
  92.  
  93.       // process current node
  94.       switch( current.nodeType )
  95.       {
  96.          case Node.ELEMENT_NODE:
  97.             if(fElementHandler != null)
  98.                if ( userData != null )
  99.                   bContinue = fElementHandler( current, userData );
  100.                else
  101.                   bContinue = fElementHandler( current );
  102.             break;
  103.  
  104.          case Node.COMMENT_NODE:
  105.             if ( fCommentHandler != null )
  106.                if ( userData != null )
  107.                   bContinue = fCommentHandler( current, userData );
  108.                else
  109.                   bContinue = fCommentHandler( current );
  110.             break;
  111.  
  112.          case Node.TEXT_NODE:
  113.             if ( fTextHandler != null )
  114.                if ( userData != null )
  115.                   bContinue = fTextHandler( current, userData )
  116.                else
  117.                   bContinue = fTextHandler( current )
  118.             break;
  119.  
  120.          case Node.DOCUMENT_NODE:
  121.          default:
  122.              MM_error( MSG_UnknownNodeType, current.nodeType );
  123.       }
  124.    }
  125. }
  126.  
  127.  
  128. //////////////////////////////////////////////////////////////////////////////
  129. // Function
  130. //    isInsideTag
  131. //
  132. // Purpose
  133. //    Check to see if a given tag is contained within another tag.
  134. //
  135. // Parameters
  136. //    tag - the tag in the DOM for which to check
  137. //    tagNames - a comma delimited list of tags to search for.
  138. //       (ie "p,h1,h2,h3,h4,h5,h6").  No spaces.
  139. //
  140. // Returns
  141. //    true if the tag is contained within one of the given tags.
  142. //
  143. function isInsideTag(tag, tagNames)
  144. {
  145.    var tagList = tagNames.split(",");
  146.    var regx = new RegExp();
  147.    var parent, result;
  148.  
  149.    for(i = 0; i < tagList.length; i++)
  150.    {
  151.       parent = tag.parentNode;
  152.       regx.compile(tagList[i], "i");
  153.  
  154.       while(parent != null)
  155.       {
  156.          result = regx.exec(parent.tagName);
  157.  
  158.          if(result != null)
  159.             return true;
  160.  
  161.          parent = parent.parentNode;
  162.       }
  163.    }
  164.  
  165.    return false;
  166. }
  167.  
  168.  
  169. //Popups up a command. Before popping it up, updates globals. Command can then
  170. //use these globals to get and receive arguments from the caller.
  171.  
  172. function callCommand(cmdName,argObject) {
  173.   MM.commandArgument = argObject;
  174.   MM.commandReturnValue = null;
  175.   dw.popupCommand(cmdName);
  176.   return MM.commandReturnValue;
  177. }
  178.  
  179.  
  180.  
  181. //************** FUNCTIONS FOR UPDATING BEHAVIOR CODE ****************8
  182.  
  183. var DW_VERSION = 3.0;
  184.  
  185. //Checks if function is latest, and maybe updates it. If out of date (and first caller),
  186. //refresh all behaviors on page. Returns true if behavior was out of date.
  187.  
  188. function updateBehaviorFns() {
  189.   var behNames = updateBehaviorFns.arguments;
  190.   var retVal = false;
  191.   var fnVerOnPage, fnVersion;
  192.  
  193.   for (i=0; i<behNames.length; i++) { //with each name passed in...
  194.     fnVersion = document["VERSION_"+behNames[i]];   //if fn has defined document.VERSION_MM_fnName, get it
  195.     if (!fnVersion) fnVersion = DW_VERSION;         //if not defined, use general Dreamweaver version
  196.     fnVerOnPage = getFunctionVersion(behNames[i]);  //get version of the function in user's page
  197.     if (fnVerOnPage > -1 && fnVerOnPage < fnVersion) { //if fn out of date
  198.       deleteFunction(behNames[i]);                     //delete older fn
  199.       retVal = true;
  200.   } }
  201.   if (retVal) { //if any function was updated, refresh all the behavior calls on the page
  202.     var DOM = dw.getDocumentDOM();
  203.     if (DOM) {
  204.         DOM.reapplyBehaviors();
  205.   } }
  206.   return retVal;
  207. }
  208.  
  209. //Used by behaviors to see if behavior function already exists on the page, and
  210. //if so, what version it is. Given a function name, returns the version (if
  211. //it exists on the first line as //v3.123) or 0 if no version. Returns -1 if
  212. //the function is not found on the page. For example, given function
  213. //       function myFunction() { //v2.0
  214. //Calling getFunctionVersion("myFunction") returns 2. Given function
  215. //       function myFunction() {
  216. //Calling getFunctionVersion("myFunction") returns 0.
  217. //Searches dom if passed, else searches active document.
  218. //Does not search included src files (use dom to do this).
  219. //
  220. //Arguments: fnName, dom (optional). If no dom, searches current page
  221. //Returns -1 if function not found, 0 if found without version number.
  222.  
  223. function getFunctionVersion(fnName, dom) {
  224.   if (!dom) dom = dreamweaver.getDocumentDOM("document");
  225.   var i, aScript, result, version=-1;
  226.   var allScripts = dom.getElementsByTagName("SCRIPT");
  227.   var fnPatt = new RegExp("function\\s+" + fnName + "\\s*\\(.+$"); //find function fnName(...);  ...\n
  228.   var verPatt = new RegExp("\\/\\/v(\\d+\\.?\\d*)","i");           //find //v3.123
  229.  
  230.   for (i=0; i<allScripts.length; i++) if (allScripts[i].hasChildNodes()) {
  231.     aScript = allScripts[i].childNodes[0].data; //read script tag
  232.     RegExp.multiline = true;        //required so that $ stops at the end of the line
  233.     result = aScript.match(fnPatt);
  234.     RegExp.multiline = false;       //reset the value
  235.     if (result) {
  236.       version = 0;
  237.       aScript = result[0];
  238.       result = aScript.match(verPatt);    //find //v3.123
  239.       if (result) version = parseFloat(result[1]);
  240.       break;
  241.   } }
  242.   return version;
  243. }
  244.  
  245.  
  246. //Used by behaviors to remove older versions of behavior functions.
  247. //Deletes a function with a given name from the document.
  248. //IMPORTANT! Will not work if function contains braces {} within quotes.
  249. //Does not search included src files (use dom to do this).
  250. //
  251. //Arguments: fnName, dom (optional). If no dom, searches current page
  252. //Returns: empty string if function not found, otherwise returns deleted function
  253.  
  254. function deleteFunction(fnName, dom) {
  255.   if (!dom) dom = dreamweaver.getDocumentDOM("document");
  256.   var i, j, aScript, startPos, curChar, braceCount, retVal=false;
  257.   var allScripts = dom.getElementsByTagName("SCRIPT");
  258.   var fnPatt = new RegExp("function\\s+" + fnName + "\\s*\\(");  //find function fnName(...{
  259.  
  260.   for (i=0; i<allScripts.length; i++) if (allScripts[i].hasChildNodes()) {
  261.     aScript = allScripts[i].childNodes[0].data;
  262.     startPos = aScript.search(fnPatt);
  263.     if (startPos != -1) { //found function, start traversing
  264.       for (j=startPos; aScript.charAt(j) != "{"; j++);  //find first brace
  265.       j++;
  266.       braceCount=1;
  267.       while (braceCount>0 && j<aScript.length) {        //count braces until 0
  268.         curChar = aScript.charAt(j++);
  269.         if (curChar=="{") braceCount++;
  270.         if (curChar=="}") braceCount--;
  271.       }
  272.       if (braceCount == 0) {
  273.         while (aScript.charAt(j).search(/\s/) != -1) j++; //remove trailing whitespace
  274.         retVal = (aScript.substring(startPos,j));         //return the chunk to delete
  275.         allScripts[i].childNodes[0].data = aScript.substring(0,startPos) + aScript.substring(j); //delete it!
  276.       }
  277.       break;
  278.   } }
  279.   return retVal;
  280. }
  281.  
  282.  
  283.  
  284.  
  285. //Used by behaviors to remove old function call.
  286. //Deletes a function call with a given name from the document.
  287. //Does not search included src files (use dom to do this).
  288. //Requires function to have closing semicolon.
  289. //
  290. //Arguments: fnName, dom (optional). If no dom, searches current page
  291. //Returns: false if function call not found, otherwise returns script node in which it was deleted.
  292.  
  293. function deleteFunctionCall(fnName, dom) {
  294.   if (!dom) dom = dreamweaver.getDocumentDOM("document");
  295.   var i, j, aScript, startPos, retVal=false;
  296.   var allScripts = dom.getElementsByTagName("SCRIPT");
  297.   var fnPatt = new RegExp("\\s+" + fnName + "\\s*\\(");  //find function fnName(...{
  298.  
  299.   for (i=0; i<allScripts.length; i++) if (allScripts[i].hasChildNodes()) {
  300.     aScript = allScripts[i].childNodes[0].data;
  301.     startPos = aScript.search(fnPatt);
  302.     if (startPos != -1) { //found function, start traversing
  303.       for (j=startPos; j<aScript.length-1 && aScript.charAt(j) != ";"; j++);  //find closing semicolon
  304.       if (aScript.charAt(j) == ";") {  //if semicolon found
  305.         retVal = aScript.substring(startPos,j);      //return the deleted string.
  306.         aScript = aScript.substring(0,startPos) + aScript.substring(j+1);
  307.         if (scriptIsEmpty(aScript)) {  // Remove the entire script if it is empty.
  308.           allScripts[i].outerHTML = '';
  309.         } else {
  310.           allScripts[i].childNodes[0].data = aScript; //delete it!
  311.         }
  312.       }
  313.       break;
  314.   } }
  315.   return retVal;
  316. }
  317.  
  318. //Tests for the exisitence of a function call.
  319. //Does not search included src files (use dom to do this).
  320. //
  321. //Arguments: fnName, dom (optional). If no dom, searches current page
  322. //Returns: false if function call not found, otherwise true.
  323.  
  324. function hasFunctionCall(fnName, dom) {
  325.   if (!dom) dom = dreamweaver.getDocumentDOM("document");
  326.   var retVal=false;
  327.   var allScripts = dom.getElementsByTagName("SCRIPT");
  328.   var fnPatt = new RegExp("\\s+" + fnName + "\\s*\\(");  //find function fnName(...{
  329.  
  330.   for (var i=0; i<allScripts.length; i++) {
  331.     if (fnPatt.test(allScripts[i].innerHTML)) {
  332.       retVal = true;
  333.       break;
  334.     }
  335.   }
  336.   return retVal;
  337. }
  338.  
  339.  
  340.  
  341. // Determine if script is empty. Check for just white space
  342. //  and a standard javascript comment tag.
  343. //Arguments: String (which should be the contents of a script tag.
  344. //Returns: true if the script contains only empty commments, otherwise false.
  345.  
  346. function scriptIsEmpty(aScript) {
  347.   var re = /^\s*(<!--+)*\s*(\/\/+\s*--+>)*\s*$/;
  348.   return re.test(aScript);
  349. }