Dreamweaver MX Extensions

Workshop #3: Creating a More Complex Object

By now, you should be feeling at least a little bit comfortable with the API for creating Dreamweaver objects. So, it's time to get into some serious object scripting. This last workshop builds the most complex object yetone that requires a variety of form elements in its dialog box and requires a more complex return statement. You also add some short online help.

note

Warning

This object includes some fairly advanced concepts. If you're new to scripting, you might want to skip this workshop for now and come back to it when you've had some more JavaScript practice.

Sample Object: Inserting a Custom Horizontal Rule

This is a case in which Dreamweaver already provides an object to insert certain code, but you may not like the options the program gives you. Again, I start from my own workflow needs. The Dreamweaver Horizontal Rule object calls up no dialog box, although I can always use the Property inspector to set its properties. More important for me, though, the Property inspector won't let me set a color property for the tag. This wasn't an oversight on Macromedia's part; it was good, sound practice because only Internet Explorer supports this property, and, as noted previously, Dreamweaver encourages you to stick with cross-platform, cross-browser coding.

But when I design web pages for intranets in which all the site visitors are using Internet Explorer, I want to be able to use colored rules. If I use the regular Horizontal Rule object, I have to use Code view or the Edit Tag command to enter the color property every time. It's definitely time for a custom object!

Creating the Custom HR Object

Creating this object follows the same basic procedure as the first two object workshops, but with the added complexity that the code inserted must be much more customizable and the dialog box interface will use more than just text fields for input.

Task 1: Decide on the code to insert and how customizable it should be

Where there's user input, there are lots of possibilities that have more to do with strategy than scripting. The <hr> tag can take several parameters in addition to color ( width , height , align , noshade , id ). Do we want to include all of them in our dialog box, or only some? If we include them all, and the user specifies only one or two, do we let the others revert to a default value, or do we eliminate them entirely? (Note that the <hr> tag has no required properties.)

In keeping with good clean coding practice, thoroughness and a dose of probability, for the sample code here we'll include all the properties in the dialog box except id , which can be added later from the Property inspector if desired. All dialog box fields start out empty or at their default values. Unless the user enters a value for a property, the inserted code won't include that property. Thus, our custom object needs to be flexible enough to insert any code from <hr> to <hr width="50%" height="3" noshade align="center" color="#FF0000"> .

Task 2: Design the form that collects the user input

As well as determining what code should be inserted, it's always a good idea to know approximately what user interface (the dialog box) an object will have. For the new <hr> object, each possible property that users can add to the <hr> tag should be represented in the dialog box by a descriptive statement or label and an appropriate form input element to collect it: width (text field), height (text field), align (popup menu), noshade (checkbox), and color . If this were a regular HTML form, we'd probably use a text field for collecting color information. But the Dreamweaver API includes a custom form element: the color button. We'll follow the Dreamweaver program's own interface example in this, and use the color button along with a text field to allow users to enter the information however they choose. The desired layout for the dialog box is shown in Figure 2.13.

Figure 2.13. The desired layout for the Custom HR object's dialog box.

Task 3: Create the basic object file

As with the Block Spacer, creating this object is easiest if you start simple and add complexity as you go. Follow these steps:

  1. In your text editor, open My Object.htm and save it in your Development folder as Custom HR.htm .

  2. Change the title to Custom Horizontal Rule . Revise the objectTag() function so it returns a simple <hr> tag. The code for your object file's <head> section should now look like this (new code in bold):

    <head> <title> Custom Horizontal Rule </title> <script language="JavaScript"> function objectTag() { return '<hr>' ; } </script> </head>

    (Note that single quotes have been substituted for double quotes around the return statement. That's because eventually the <hr> tag will include some attributes, with their values specified using double quotes.)

  3. For the form, build a table-based layout that re-creates the dialog box design shown in Figure 2.13. Name the form elements width , height , align , noshade , and color . For those of you creating your form in Dreamweaver Design view, Figure 2.14 shows an annotated diagram (note that the color button form element is recognized by the Dreamweaver Property inspector). The code for the revised <body> section of the object file should look like this (pay particular attention to the way the color button form element is coded):

    Figure 2.14. The Custom Horizontal Rule form being created in Dreamweaver Design view.

<body> <form name="myForm"> <table border="0"> <tr valign="baseline"> <td align="right" nowrap >&nbsp;Width:</td> <td align="left" nowrap> <input type="text" name="width" size="8"> &nbsp; </td> <td align="right" nowrap>Height::</td> <td align="left" nowrap> <input type="text" name="height" size="8"> </td> <td nowrap align="right">&nbsp;Align:</td> <td nowrap> <select name="align"> <option selected value="default">Default</option> <option value="left">Left</option> <option value="right">Right</option> <option value="center">Center</option> </select> </td> </tr> <tr valign="baseline"> <td align="right">&nbsp;</td> <td align="left">&nbsp; </td> <td nowrap align="right">No Shade:</td> <td align="left"> <input type="checkbox" name="noshade" value="noshade"> </td> <td align="right"> <input type="mmcolorbutton" name="colorswatch"> </td> <td > <input type="text" name="colorfield" size="10"> </td> </tr> </table> </form> </body>

Task 4: Add an entry for the object to insertbar.xml

So that the new Custom Horizontal Rule object displays properly in the Insert bar, open insertbar.xml in your text editor and add the following <button/> tag to your Development category:

<button id="DW_Development_CustomHR" image="" enabled="" showIf="" file="Development\Custom HR.htm" />

Before proceeding to the next step, test the object out in Dreamweaver to make sure the dialog box displays properly. Of course, the dialog box is not functional yet. But it should display correctlyand clicking on the color button should even bring up the Dreamweaver color palette (see Figure 2.15).

Figure 2.15. The dialog box for the Custom Horizontal Rule object, with working color button.

Task 5: Revise the objectTag() function to collect user input

The tricky part about the Custom Horizontal Rule object is that, unlike the Block Spacer object, it contains conditional codeattributes for the <hr> tag that shouldn't be included unless the user enters values into the dialog box. This makes the task of constructing the objectTag() function's return statement a little bit different than it was in the previous workshop. This task is a challenge! Don't be frustrated if it takes you several tries to get it right.

  1. Open the Custom HR.htm file in your text editor.

  2. As you did with the Block Spacer object, you need to start by creating variables to collect user input from the form. Start by collecting values from the two text fields ( width and height ). Add the following code to your objectTag() function (new code is in bold):

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; return '<hr>'; }

    Don't worry about the color button form element just yet; you'll be adding that into the mix later.

  3. The checkbox form element ( noshade ) returns true or false, depending on whether it's checked or not. To collect this value, add the following line to your code (new code is in bold):

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; return '<hr>'; }

  4. The popup menu ( align ) takes slightly more work to collect a value from. First, you need to determine which of its items, or options, have been selected; then you need to collect the value from that option. Add the following code to your function:

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; return '<hr>'; }

    (If you're not sure what's happening in these two lines of code, remember that the items in a popup menu create an options array. Each option in the array has an index number, by which it can be identified and accessed.)

  5. Finally, collect the value from the color button. This is easy. Although the color button may have an unusual interface, for scripting purposes it behaves just like a text field. So, you can collect its value just like you collected the width and height fields, like this:

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; var colorValue = document.myForm.colorswatch.value; return '<hr>'; }

Task 6: Use collected input to build the objectTag() function's return statement

Now for the fun part: turning all this collected input into a complete <hr> tag for the return statement. The trick of creating an object like this, where the attributes are all optional and the user may or may not provide values for them, is that you don't want the code to include any properties not specified in the dialog box. After all, you don't want your <hr> tag to look like this:

<hr width="" height="" color="" align="">

To ensure that only properties with values appear in the code, think of the code you're going to insert as a bunch of building blocks, like the illustration in Figure 2.16. Each attribute/value combination is a block; the opening and closing parts of the tag itself are blocks. The opening and closing blocks must always be present, but the interior blocks can be included or excluded based on which attributes you want to use. You're going to revise the objectTag() function so that it builds the <hr> tag one block at a time. You'll start with the opening block. Then, for each attribute, you'll determine whether the user has entered a value for that attribute and if he has, you'll add that block. When you're done, you'll tack on the closing block.

Figure 2.16. The <hr> tag and its attributes, seen as individual building blocks of code.

  1. Start by creating the opening and closing blocks. Define two variables, openingTag and closingTag , and revise your return statement so that it concatenates the two (puts them together), like this (new code is in bold):

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; var colorValue = document.myForm.colorswatch.value; var openingTag="<hr"; var closingTag=">"; return openingTag+closingTag; }

    At its most basic, then, the function will return <hr> . (You can try it out with just this much code in place to check this out. You still aren't processing any form input, but the objectTag() function should successfully insert a plain vanilla <hr> tag.)

  2. Next, for each additional building block (attribute), you need to determine whether the user has entered a value for that attribute; and if he has, you need to construct that block and add it to the code. You do it with a conditional statement and bit of concatenation. To add the width building block, add the following lines of code:

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; var colorValue = document.myForm.colorswatch.value; var openingTag="<hr"; var closingTag=">"; if (widthValue) { openingTag += ' width="' + widthValue + '"'; } return openingTag+closingTag; }

    Can you see how this works? If the width form element contains any value, the conditional statement changes the openingTag variable from <hr to <hr width=" value " . If it doesn't contain a value (if the user hasn't entered any value), the conditional statement doesn't execute and the property is not added. The form elements that don't use text fields will require slightly different syntaxbut the principle remains the same. If you're confused by the quotes in the concatenation part of the statement, refer back to the diagram in Figure 2.8. Note that the first quoted segment starts with a space. If that space isn't present, the opening turns into <hrwidth , which is not good HTML.

  3. Go ahead and add the remaining conditional statements and building blocks to your code. When you're done, your revised objectTag() function will look like this (new code is in bold):

    function objectTag() { var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; var colorValue = document.myForm.colorswatch.value; var openingTag="<hr"; var closingTag=">"; if (widthValue) { openingTag += ' width="' + widthValue + '"'; } if (heightValue) { openingTag += ' size="' + heightValue + '"'; } if (alignValue != "default") { openingTag += ' align="' + alignValue + '"'; } if (colorValue) { openingTag += ' color="' + colorValue + '"'; } if (noshadeValue) { openingTag += ' noshade '; } return openingTag+closingTag; }

    Can you see how this works? Assuming the user assigns a value for every attribute, by the end of the function the openingTag variable will look something like this:

    <hr width="100" size="2" align="center" color="red" noshade

    All it will need is the closing > to finish it off.

  4. Try it out! In Dreamweaver, reload extensions and see how many different kinds of horizontal rules you can insert. If you choose the object and then click OK to close the dialog box without entering any values, it should insert a plain <hr> element. If you enter values in all fields, it should insert a fully packed tag. If you enter only some values, it should add only those attributes. (Note that the color text field has not been accounted for yet, so you will only be able to choose colors using the color button.)

Now all you need is some refining.

Task 7: Refine the color input

To follow the Dreamweaver interface standard for choosing colors, we should let our users choose whether to use the color button or the color text field to choose the color for the horizontal rule. We do this by linking the two fields so that no matter which entry method is used, both input elements will register the user's choice. (If the user types in a color name, the color button should display a swatch of that color; if he chooses a color from the button, the text field should display the name or hex number of that color. No matter which he chooses, the objectTag() function should collect the information.)

To do this, we create two new functions and function calls for our object: a function that copies the value of the color text field into the color button, to be executed when the user has entered text in the text field; and a function that copies the value of the color button into the color text field, to be executed when the user chooses a color using the button.

  1. Start by adding the functions. Inside the <script> tag in your document's <head> section, after the closing curly brace of the objectTag() function, add the following code:

    function setColorField() { document.myForm.colorfield.value = document.myForm.colorswatch.value; } function setColorButton() { document.myForm.colorswatch.value = document.myForm.colorfield.value; }

    Pretty simple code, eh? It just copies the value from one form element to another.

    note

    The setColorField() and setColorButton() are both local functionsthat is, they're not part of the Dreamweaver API. Unlike the objectTag() function, they must be called or they will not execute.

  2. Now these functions need to be triggered by function calls attached to the appropriate form elements. You want to set the color field when the user has changed the color of the color button; so add an onChange event handler to the color button calling the setColorText() function, like this (new code is in bold):

    <input type="mmcolorbutton" name="colorswatch" onChange="setColorField()" >

    Now do the same thing, going the other way. You want to set the color of the color button when the user has finished typing a color name or hexadecimal number into the text field; so add an onBlur event handler to the color text field calling the setColorButton() function (new code is in bold):

    <input type="text" name="colorfield" size="10" onBlur="setColorButton()" >

    In case you were wondering, the onBlur event happens when the user's cursor has been in the text field and then the user clicks somewhere elsewhich is presumably what he will do after he has finished typing.

  3. Try it out. In Dreamweaver, reload extensions and try inserting a Custom Horizontal Rule. When the dialog box appears, see what happens when you use either of the color controls. If you choose from the color button, the text field automatically fills in; if you enter a name or hexadecimal number in the text field, the color button changes color automatically.

    And that's not all! If you think back to how you coded the objectTag() function, you'll remember that the script collects the value of the color button to use in constructing the <hr> tag. But what happens if you type color information into the text field instead? The setColorButton() function updates the value of the color button. So, no matter which entry method you use, the objectTag() function still processes your input and adds your color choice to the code it inserts .

Task 8: Refine the dialog box, and add some online help The Custom Horizontal Rule object is now fully functional and something to be proud of. It just needs a few extra touches on its interface to make it presentable to the world. Like the Block Spacer object in the previous workshop, this new object's dialog box should open with its focus in the first text fieldit needs initializing, in other words. And it could also use a sentence or two of online help, which can be added at the bottom of the dialog box.

  1. To properly initialize the dialog box, add an initializeUI() function to the <script> tag in your document head, after the closing curly brace of the last

    function you defined:

    function initializeUI() { document.myForm.width.focus(); document.myForm.width.select(); }

    This puts the focus in the width text field, which is normally where the user will want to start typing.

  2. Because initializeUI() is a local function, not called as part of the API process, you must also include a function call for it. Add the following code to your <body> tag:

    <body onLoad="initializeUI()" >

  3. Now for the online help. According to the Macromedia UI guidelines, any short online help messages should be added in a new table cell at the bottom of the dialog box, and that table cell should have a light gray (#D3D3D3) background coloras shown in Figure 2.17. To create the Custom Horizontal Rule help message, add the following code to the bottom of your <table> tag (new code shown in bold):

    <tr valign="baseline"> <td align="right">&nbsp;</td> <td align="left" colspan="5" bgcolor="#D3D3D3"> <p>To set width as percent, enter a percent sign in the width field; to set width as pixels, enter a number only. </p> <p>Note that the color property is recognized by MSIE only.</p> </td> </tr> </table>

    Figure 2.17. Dialog box for the Custom Horizontal Rule object, showing added Help text.

    Listing 2.6 shows the completed code for the Custom Horizontal Rule object, with all refinements in place.

Listing 2.6 Code for the Custom Horizontal Rule Object, Commented for Reference

<html> <head> <! title shows in dialog box title bar > <title>Custom Horizontal Rule</title> <script language="JavaScript"> function objectTag() { //collect information from form/dialog box var widthValue = document.myForm.width.value; var heightValue = document.myForm.height.value; var noshadeValue = document.myForm.noshade.checked; var selected = document.myForm.align.selectedIndex; var alignValue = document.myForm.align.options[selected].value; var colorValue = document.myForm.colorswatch.value; //start with two building blocks var openingTag="<hr"; var closingTag=">"; //if user has entered a width, add the code for this attribute if (widthValue) { openingTag += ' width="' + widthValue + '"'; } //if user has entered a height, add the code for this attribute if (heightValue) { openingTag += ' size="' + heightValue + '"'; } //if user has chosen an alignment other than default, add the code for this attribute if (alignValue != "default") { openingTag += ' align="' + alignValue + '"'; } //if user has entered a color, add the code for this attribute if (colorValue) { openingTag += ' color="' + colorValue + '"'; } //if user has selected the noshade checkbox, add the code for this attribute if (noshadeValue) { openingTag += ' noshade '; } //assemble the building blocks return openingTag+closingTag; } //copy input from color text field to color button function setColorField() { document.myForm.colorfield.value = document.myForm.colorswatch.value; } //copy input from color button to color text field function setColorButton() { document.myForm.colorswatch.value = document.myForm.colorfield.value; } //put cursor in first text field when dialog box opens function initializeUI() { document.myForm.width.focus(); document.myForm.width.select(); } </script> </head> <body onLoad="initializeUI()"> <form name="myForm"> <table border="0"> <tr valign="baseline"> <td align="right" nowrap >&nbsp;Width:</td> <td align="left" nowrap> <input type="text" name="width" size="8"> &nbsp; </td> <td align="right" nowrap>Height:</td> <td align="left" nowrap> <input type="text" name="height" size="8"> </td> <td nowrap align="right">&nbsp;Align:</td> <td nowrap> <select name="align"> <option selected value="default">Default</option> <option value="left">Left</option> <option value="right">Right</option> <option value="center">Center</option> </select> </td> </tr> <tr valign="baseline"> <td align="right">&nbsp;</td> <td align="left">&nbsp; </td> <td nowrap align="right">No Shade:</td> <td align="left"> <input type="checkbox" name="noshade" value="noshade"> </td> <td align="right"> <! if user chooses a new color, calls a function to copy color to text field > <input type="mmcolorbutton" name="colorswatch" onChange="setColorField()"> </td> <td > <! if user types in a new color name, calls a function to copy value to color button > <input type="text" name="colorfield" size="10" onBlur="setColorButton()"> </td> </tr> <tr valign="baseline"> <td align="right">&nbsp;</td> <td align="left" colspan="5" bgcolor="#D3D3D3"> <p>To set width as percent, enter a percent sign in the width field; to set width as pixels, enter a number only. </p> <p>Note that the &lt;color property is recognized by MSIE only.</p> </td> </tr> </table> </form> </body> </html>

Task 9: Split the code into separate HTML and JS files

Your Custom Horizontal Rule is finished! And what a lot of JavaScript code went into that object. If you want to follow the Macromedia example, for all but the simplest objects you'll separate your code into an HTML file and a linked JS file. In this task, you'll do that, so you can see how the HTML/JS file linking setup works.

  1. . In the <head> section of the object file, select and cut all the code between the <script> tags (but not the tags themselves ). This should include the objectTag() , setColorField() , setColorButton() , and initializeUI() functions.

  2. Create a new text document, paste the code into it, and save it in your Configuration/Objects/Development folder as Custom HR.js .

  3. Now link the HTML file to the JS file. In the HTML document (Custom HR.htm), change the <script> tag to read like this:

    <script src="Custom HR.js"></script>

  4. Save the HTML file and close it.

  5. Reload extensions in Dreamweaver and try it out. If you moved your code and added the link correctly, the Custom Horizontal Rule objects will behave exactly as they did before you separated the code.

note

Troubleshooting

What could go wrong? If you didn't link the two files correctly, Dreamweaver will report an error as soon as you try to choose the object, because it won't be able to find initializeUI() to initialize the dialog box. If you didn't quite copy and paste all the JavaScript code, Dreamweaver will report a JavaScript syntax error as soon as a function that wasn't moved successfully tries to execute. What can you do if this happens? Double-check the filename you entered as the src for the <script> tag. In the new JS file, double-check every function to make sure each ends with its very own curly brace.

Категории