Workshop 1: A Floating Panel Utility

' ' ' ' Workshop #1: A Floating Panel Utility"-->

Workshop #1: A Floating Panel Utility

graphics/icon02.gif

It's time to put some of this knowledge to work. Why would you want to create a custom floater ? Floating panels provide a good opportunity to create utility interfaces, to help users perform common tasks without being restricted by the confines of the standard Property inspector. Watch yourself analytically as you use Dreamweaver. Watch your colleagues as they work. Are there any tasks that could be accomplished much more efficiently or intuitively with the aid of a different interface? That's the time to make a custom floating panel.

Sample Floater: Table Helper

I admit itI'd rather create my tables the old-fashioned way than use new-fangled toys such as the Dreamweaver Layout View or Convert Layers to Table. I like knowing exactly what structural elements are going into my tables, so I can better secondguess what's going to happen to them in a browser display. But I find myself limited by not being able to see all the widths, heights, rowspans, and colspans at once. I want a table-editing utility that presents me with all that information in one handy visual interfacesomething like the one shown in Figure 7.16.

Figure 7.16. The proposed Table Helper utility interface. The diagram reports widths, heights, rowspans, and colspans to help diagnose possible table problems.

graphics/07fig16.gif

This is the floater we'll be creating in this workshop. Given a user -selected table in a document, the floater reports table dimensions; diagrams how many rows and columns are in the table; and presents information on width, height, rowspan, and colspan for each cell .

Task 1: Create the basic floater

To get started, you need a floater file and a menu entry to launch it.

  1. In your text editor, create a new HTML document (you can use framework code from the practice session or create a new document). Call it TableHelper.htm, and save it in the Configuration/ Floaters folder. The basic code framework should look like this:

     <html>  <head>  <title>Table Helper</title>  <script language="JavaScript">  function initialTabs() {  window.resizeTo(300,400);  return "";  }  </script>  </head>  <body>  </body>  </html> 

    The initialTabs() function sets up the initial size of the floater window, but doesn't group it with any other floaters.

  2. In menus .xml, find the bottom of the Window menu, and enter or change a line of code to launch the new floater:

     <menuitem name="Table Helper" enabled="true"  command="dw.toggleFloater('TableHelper')"  checked="dw.getFloaterVisibility('TableHelper')"  id="MyStuff_TableHelper_Floater"/> 

    If you're the cautious sort , take a moment to launch Dreamweaver and test the new floater, just to make sure it's been created correctly. (It should launch an empty floater window.)

Task 2: Enable the floater to rewrite its own contents

If you examined the projected floater shown in Figure 7.15, you noticed that its contents are dynamically determined, based on the structure of the user's selected table. The idea behind this floater is to re-create the user's table structure in the floater, stripped of its cell contents and decoration. If you were scripting JavaScript destined for a browser, you would probably use the document.write() method to accomplish this. Unfortunately, the Dreamweaver API doesn't support document.write() . But you can accomplish your goal by using that most handy of functions: dw.getDocumentDOM() .

note

See Tables 4.2 and 4.3 in Chapter 4, "The Dreamweaver DOM," for a list of properties and methods supported by the document object in Dreamweaver. See Table 4.10 for dw.getDocumentDOM() specifications, including optional arguments and their uses.


We've been using dw.getDocumentDOM() without any arguments to refer to the current user document. By supplying a document name as an argument, however, we can gain access to the DOM of any documentincluding the floater document itself. To communicate between floater and user document, we can gain access to two DOMs at once like this:

 //the user's document  var myDOM = dw.getDocumentDOM();  //the floater  var floaterDOM = dw.getDocumentDOM('TableHelper.htm'); 
  1. To avoid the penalties that are associated with documentEdited() and selectionChanged() , you want the floater to appear with a button that activates it. To begin with, that's the only visible element it needs. Create a simple form in the <body> section of the floater file:

     <form name="myForm">  <input type="button" value="Create Diagram" onClick="displayDiagram()">  </form> 
  2. Now create a function to call from it:

      1  function displayDiagram() {  2 //access the floater's DOM  3 var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  4 var floaterBody = floaterDOM.body;  5 //rewrite its contents  6 var contentString = "This is a test.";  7 floaterBody.innerHTML = contentString;  8 } 

    This function tests DOM access by altering the contents of the floater window, replacing the button with the words This is a test .

  3. Try it out! The resulting floater should look and behave like the one shown in Figure 7.17.

    Figure 7.17. The Table Helper floater, scripted to rewrite its own contents when the Create Diagram button is clicked. This is made possible by gaining access to the floater file's DOM.

    graphics/07fig17.gif

  4. One problem with the floater so far is that once you've clicked the button and the contents have changed, the button disappears. Closing and re-opening the floater won't even bring it back. To fix this problem, make sure you re-create the button when you rewrite the floater's contents. Revise your diagramTable() function to look like this:

     1 function displayDiagram() {  2 //access the floater's DOM  3 var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  4 var floaterBody = floaterDOM.body;  5 //rewrite its contents  6 var contentString = "  <p>  This is a test.  <\/p>  ";  7 contentString += '<input type="button" value="Create Diagram" onClick="displayDiagram( graphics/ccc.gif )">';  8 floaterBody.innerHTML = contentString;  9 } 

    Now that's a handy addition! The displayDiagram() function re-creates the form button, complete with a function call to call the displayDiagram() function.

Task 3: Make the floater re-create the code for a selected table in the user's document

If the user has a table selected, the floater should reproduce that table in itself. You use your dual DOM access to make this happen. String access is the easiest way to accomplish this.

  1. Revise the diagramTable() function so it collects a string representing the selected table like this:

     1 function displayDiagram()  {  2 //access user's selection   3 var myDOM = dw.getDocumentDOM();   4 var myObject = myDOM.getSelectedNode();   5 //if selection is a table   6 if (myObject.nodeType == 1 && myObject.tagName == "TABLE") {   7 //collect it as a string for manipulation   8    var myHTML = myDOM.documentElement;   9    var myHTMLstring = myHTML.outerHTML;   10   var myOffsets = myDOM.nodeToOffsets(myObject);   11   var myString = myHTMLstring.substring(myOffsets[0],myOffsets[1]);   12 //otherwise, don't go any further   13   }else{   14   return;   15   }//end if-else  16 //access the floater's DOM  17 var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  18 var floaterBody = floaterDOM.body;   19 //rewrite its contents  20 var contentString =  myString  ;  21 contentString += '<input type="button" value="Create Diagram" onClick="displayDiagram( graphics/ccc.gif )">';  22 floaterBody.innerHTML = contentString;  23 } 

    What's happening here? Lines 34 access the selected object. In line 6, a conditional statement tests to see if the selected object is a <table> tag. If the condition is true, several new variables are declared, gaining access to the selected table as a string ( myString ). If the conditional isn't true, the function stops without doing anything (line 14).

    Why collect the selected table as a string? Remember, the second part of the function uses a string ( contentString ) to rewrite the floater's contents. The table must be collected as a string and fed into contentString .

  2. Launch Dreamweaver, and try out the result. Create a new Dreamweaver document and put a simple table in it. Make sure the table has a border, so its structure is clearly visible. Then open the Table Helper floater and click the Check Table button. Your result should look and behave like the one shown in Figure 7.18.

    Figure 7.18. The Table Helper floating panel, collecting and reproducing a selected table (contents and all) from a user document.

    graphics/07fig18.gif

  3. To make the interface look a little nicer, dress up the code that gets placed in the floater, like this:

     1 function displayDiagram() {  etc  15 //access the floater's DOM  16 var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  17 var floaterBody = floaterDOM.body;  18 //rewrite its contents  19 var floaterIntro = "<p>Current table structure:<\/p>";  20  var floaterReset =  '<input type="button" value="Create Diagram" graphics/ccc.gif onClick="displayDiagram()">';  21 var contentString = floaterIntro+myString+floaterReset;  22 floaterBody.innerHTML = contentString;  23 } 

    You're creating an introductory line of text for the floater ( floaterIntro ). And, because the items to be written into the floater are getting more complex, you've created another variable to hold the form button ( floaterReset ) as well. The resulting interface looks like the one shown in Figure 7.19.

    Figure 7.19. The Table Helper floating panel with a friendlier interface.

    graphics/07fig19.gif

Task 4: Remove contents and decoration from the table that appears in the floater

You don't need the floater to show you the user's table as is. You need to keep the table structure but without its formatting, and you need to replace the contents with a reporting of width, height, and so on. The simplest way to do this is with object access after the table code is inside the floater.

What do you want the table to look like as it appears in the floater? It should have a border, to make it visible. It should resize itself to fit nicely inside the floater window. It doesn't need a background color , cell padding, or other niceties.

  1. Start by gaining access to the table, once it's in the floater, like this (new code is in bold):

     1 function displayDiagram() {  etc  23 floaterBody.innerHTML = contentString;  24 //get access to the first (and only) table in the floater file   25 var tableDiagram = floaterDOM.getElementsByTagName("TABLE").item(0);  26 } 
  2. Now adjust the table's attributes for better display in the floater window:

     1 function displayDiagram() {  etc  23 floaterBody.innerHTML = contentString;  24 //get access to the first (and only) table in the floater file  25 var tableDiagram = floaterDOM.getElementsByTagName("TABLE").item(0);  26 //reset or remove attributes   27 tableDiagram.border = "1";   28 tableDiagram.width = "100%";   29 tableDiagram.height = "75%";   30 tableDiagram.removeAttribute("cellpadding");   31 tableDiagram.removeAttribute("cellspacing");   32 tableDiagram.removeAttribute("bgcolor");   33 tableDiagram.removeAttribute("background");   34 etc  }//end function 

    What are you doing here? In line 27, you're giving the table a border, so it shows up in the floater. In lines 28 and 29 you're setting the table width to 100%, so it adjusts to the panel's width, and the height slightly smaller (75%), to make room for the extra page contents at top and bottom. Finally, in lines 3033, you're removing all other attributes so they don't clog up the floater's display.

  3. Next, you need to access each cell in the table, determine its width and height, and rewrite the cell's outerHTML to display these values, like this:

     1 function displayDiagram() {  etc  23 floaterBody.innerHTML = contentString;  24 //get access to the first (and only) table in the floater file  25 var tableDiagram = floaterDOM.getElementsByTagName("TABLE").item(0);  26 //reset or remove attributes  27 tableDiagram.border = "1";  28 tableDiagram.width = "100%";  29 tableDiagram.height = "75%";  30 tableDiagram.removeAttribute("cellpadding");  31 tableDiagram.removeAttribute("cellspacing");  32 tableDiagram.removeAttribute("bgcolor");  33 tableDiagram.removeAttribute("background");  34 //collect a list of rows (child nodes of table)   35 var myRows=tableDiagram.childNodes;   36 var myCells, openTag, cellContents, closeTag;   37 //for each row:   38 for (var a=0;a<myRows.length;a++) {   39    //collect a list of cells (child nodes of row)   40    myCells=myRows.item(a).childNodes;   41    //for each child:   42    for (var b=0;b<myCells.length;b++) {   43       //create new <td> string   44       openTag='<td align="center" valign="middle" nowrap>';   45       closeTag='<\/td>';   46       cellContents='w: ';   47       cellContents+=(myCells.item(b).width)?myCells.item(b).width:'';   48       cellContents+='<br>';   49       cellContents+='h: ';   50       cellContents+=(myCells.item(b).height)?myCells.item(b).height:'';   51       //replace outerHTML of TD with new <td> string   52       myCells.item(b).outerHTML=openTag+cellContents+closeTag;   53       }//end for each cell   54    }//end for each row  55 }//end function 

    What's happening here? Line 35 collects all of the <tr> tags of the table as a node list ( myRows ). Starting in line 38, a for loop steps through each row. Within each row, line 40 collects all <td> tags in a node list ( myCells ). Starting in line 42, another for loop steps through each cell. For each cell, lines 4445 create text strings containing the code for the opening and closing <td> tags ( openTag and closeTag ). Lines 4647 add a line of text to the cell's contents, indicating the cell's width (if any). Lines 4950 add a line indicating the cell's height (if any). Finally, line 52 puts the opening tag, closing tag, and contents together into a string ( openTag + cellContents + closeTag ) and substitutes that string for the current cell's outerHTML property.

  4. For one more refinement, collect the overall width and height of the table itself, and change the opening line of the panel so it displays those values:

     1  function displayDiagram() {  etc  6  if (myObject.nodeType == 1 && myObject.tagName == "TABLE") {  7  //collect it as a string for manipulation  8     var myHTML = myDOM.documentElement;  9     var myHTMLstring = myHTML.outerHTML;  10    var myOffsets = myDOM.nodeToOffsets(myObject);  11    var myString = myHTMLstring.substring(myOffsets[0],myOffsets[1]);  12    if (myObject.width) {   13       var tableWidth=myObject.width;   14       }else{   15       var tableWidth="";   16       }//end if (width)   17    if (myObject.height) {   18       var tableHeight=myObject.height;   19       }else{   20       var tableHeight="";   21       }//end if (height)  22 //otherwise, don't go any further  23   }else{  24   return;  25   }  26 //access the floater's DOM  27 var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  28 var floaterBody = floaterDOM.body;  29 floaterIntro =  "<p>Wd: "+tableWidth+"; Ht: "+tableHeight+"<\/p>"  ;  etc 

    The new pair of conditional statements (lines 12 and 17) create two new variables, tableWidth and tableHeight , each holding the width/height value or the alternate text string .

  5. Try it out! At this point, the floater should work with any table that doesn't use colspans or rowspans, to create a result like that shown in Figure 7.20.

    Figure 7.20. The Table Helper floating panel, reporting widths and heights in a generic table diagram.

    graphics/07fig20.gif

Task 5: Refine the floater to work with rowspan and colspan in tables

The panel, as it is currently scripted, works just fine with plain vanilla tables. But we can make it more robust in all sorts of ways. First and foremost, if it's going to be useful for layout tables, it needs to be able to handle rowspan and colspan attributes.

  1. Because rowspan and colspan are cell attributes, they must be added to the code string for each cell as it is being created. This means adding a bit of complexity, and a few conditionals, to the portion of your code where you create the openTag variable. Revise your code like this:

     1 function displayDiagram() {  etc  45 //for each row:  46 for (var a=0;a<myRows.length;a++) {  47    //collect a list of cells (child nodes of row)  48    myCells=myRows.item(a).childNodes;  49    //for each child:  50    for (var b=0;b<myCells.length;b++) {  51       //create new <td> string  52       openTag='<td align="center" valign="middle" nowrap';   53       if (myCells.item(b).rowspan) {   54          openTag+=' rowspan="'+myCells.item(b).rowspan+'"';   55          }//end if (rowspan)   56       if (myCells.item(b).colspan) {   57          openTag+=' colspan="'+myCells.item(b).colspan+'"';   58          }//end if (colspan)   59       openTag+=">";  60       closeTag='<\/td>'; 

    Can you see what's going on here? In line 52, the initialization of the openTag variable has changed slightlythe text string fed into this variable no longer ends with a > character. A conditional in lines 5355 determines if the current cell has a rowspan attribute, and if so, adds rowspan=" value " to openTag . A conditional in lines 5658 does the same for colspan . Finally, line 59 finishes the code for the opening tag by adding > to openTag.

  2. Try your Table Helper out again. It should be able to diagram tables with and without colspan and rowspan values, like the ones shown in Figures 7.21 and 7.22.

    Figure 7.21. The Table Helper, analyzing and reporting on a table that uses the rowspan attribute.

    graphics/07fig21.gif

    Figure 7.22. Table Helper reporting on a complex layout table (generated by Fireworks).

    graphics/07fig22.gif

That's it! Your Table Helper is now finished. Listing 7.1 shows the finished code, with all comments in place.

Listing 7.1 Final Code for the Table Helper Floating Panel
 <html>  <head>  <title>Table Helper</title>  <script language="JavaScript">  function initialTabs() {  window.resizeTo(300,400);  return "";   continues       Listing 7.1    Continued  }  function displayDiagram() {  //access user's selection  var myDOM = dw.getDocumentDOM();  var myObject = myDOM.getSelectedNode();  //if selection is a table  if (myObject.nodeType == 1 && myObject.tagName == "TABLE") {  //collect it as a string for manipulation     var myHTML = myDOM.documentElement;     var myHTMLstring = myHTML.outerHTML;     var myOffsets = myDOM.nodeToOffsets(myObject);     var myString = myHTMLstring.substring(myOffsets[0],myOffsets[1]);     if (myObject.width) {        var tableWidth=myObject.width;        }else{        var tableWidth="";        }//end if (width)     if (myObject.height) {        var tableHeight=myObject.height;        }else{        var tableHeight="";        }//end if (height)  //otherwise, don't go any further     }else{     return;     }  //access the floater's DOM  var floaterDOM = dw.getDocumentDOM('TableHelper.htm');  var floaterBody = floaterDOM.body;  floaterIntro = "<p>Wd: "+tableWidth+"; Ht: "+tableHeight+"<\/p>";  var floaterReset = '<input type="button" value="Create Diagram"  onClick="displayDiagram()">';  var contentString = floaterIntro + myString + floaterReset;  floaterBody.innerHTML = contentString;  //get access to the first (and only) table in the floater file  var tableDiagram = floaterDOM.getElementsByTagName("TABLE").item(0);  tableDiagram.border="1";  tableDiagram.width="100%";  tableDiagram.height="75%";  tableDiagram.removeAttribute("cellpadding");  tableDiagram.removeAttribute("cellspacing");  tableDiagram.removeAttribute("bgcolor");  tableDiagram.removeAttribute("background");  //collect a list of rows (child nodes of table)  var myRows=tableDiagram.childNodes;  var myCells, openTag, cellContents, closeTag;  //for each row:  for (var a=0;a<myRows.length;a++) {      //collect a list of cells (child nodes of row)      myCells=myRows.item(a).childNodes;     //for each child:     for (var b=0;b<myCells.length;b++) {         //create new <td> string         openTag='<td align="center" valign="middle" nowrap';         if (myCells.item(b).rowspan) {              openTag+=' rowspan="'+myCells.item(b).rowspan+'"';              }         if (myCells.item(b).colspan) {              openTag+=' colspan="'+myCells.item(b).colspan+'"';              }         openTag+=">";         closeTag='<\/td>';         cellContents='w: ';         cellContents+=(myCells.item(b).width)?myCells.item(b).width:'';         cellContents+='<br>';         cellContents+='h: ';  cellContents+=(myCells.item(b).height)?myCells.item(b).height:'';        //replace outerHTML of TD with new <td> string        myCells.item(b).outerHTML=openTag+cellContents+closeTag;        }//end for each cell     }//end for each row  }  </script>  </head>  <body>  <form name="myForm">  <input type="button" value="Create Diagram" onClick="displayDiagram()">  </form>  </body>  </html> 

Challenge!

The Table Helper is now a handy-dandy diagnostic tool for reporting on table construction. But it's not quite as powerful as it could be. Can you revise the floater to add the following functionality?

  • Tables do not display correctly in browsers if their width, height, rowspans, and colspans don't add up. Can you make Table Helper display a warning if, for instance, all the widths in a row add up to more or less than the table width allows?

  • Because of the way you scripted it, Table Helper can be slow in diagramming complex tables or tables with many images in them. You could increase the speed by using string access to rewrite the table code before it's ever displayed in the floating panel.

  • Can you make Table Helper respond to user clicks in the floater by selecting particular cells in the main document? How about responding to users selecting individual table cells in the main document by highlighting particular cells in the floater diagram?



Dreamweaver MX Extensions
Dreamweaver MX Extensions
ISBN: 0735711828
EAN: 2147483647
Year: 2001
Pages: 141
Authors: Laura Gutman

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net