Dreamweaver MX Extensions

Workshop #1: A Command That Uses Object Access

Working with commands is all about working with the Document Object Model (DOM). If you have read Chapter 4, "The Dreamweaver DOM," and gone through the Practice Session in that chapter, you already know a little bit about navigating and manipulating user documents with DOM- related functions, and about the basics of working with very simple command files. This workshop builds on that, giving you more experience with the DOM and also with the optional elements of commands. We'll start nice and simple, and add complexity and features as we go.

Sample Command: Automatically Adding the alt Parameter to All Images in a Document

It's good manners to give all the images on your Web pages alternate text labels for visitors who don't have access to images. (Actually, if you work on government-related web sites, it's more than good mannersit's required by Section 508 of the Federal Rehabilitation Act.) For maximum site usability, nothing beats manually going through your pages and adding the most appropriate labels. But when quick-and-dirty is all there's time for, a command that automatically generates the alt parameter is just the thing.

In this exercise, we'll create a command that creates alt labels for all images in a document. For images that are not also links, the alt text will be constructed from the image filename (minus its extension) for the label text. For images that are links, alt text will be generated based on the link address. Images that already have alt text will be excluded from the command, on the assumption that the user won't want this text overwritten. Figure 5.6 shows what we want this command to accomplish in a typical document.

Figure 5.6. A sample user document, showing an image's filename being used to generate an alt parameter.

note

If you haven't gone through the Practice Session in Chapter 4, do so now! All projects in this chapter assume that you have a basic familiarity with the DOM as it operates in the Dreamweaver API.

Task 1: Create the command file document

In your text editor, create a standard command file document with framework elements in place. The code should look like this:

<html> <head> <title>Automatic Alt Text</title> <script language="JavaScript"> function addAlt() { //statements will go here } </script> </head> <body onLoad="addAlt()"> </body> </html>

Save the command file in the Dreamweaver Configuration/Commands folder. The filename appears in the Commands menu, remember, so give the file a descriptive name such as Automatic Alt Text.htm.

Task 2: Create the basic code for the addAlt() function

This command involves navigating the DOM to access each image object and add an alt property. The command's main function addAlt() is responsible for doing this. In this task, you'll fill in this function.

  1. In terms of the DOM, adding alt text means accessing each image object and setting an alt attribute. Breaking that down to its simplest level, start by adding code to your main function that will access one image, and set its alt attribute to a preset value. Revise the addAlt() function to look like this (new code is in bold):

    function addAlt() { var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); myImages[0].alt = "Sample Alt Text"; }

    Can you see what the code is doing? Using the dom.getElementsByTagName() method, it gains access to a node list containing all images in the document. It then selects the first image in the node list and assigns it an alt property.

    Before proceeding, try out the command to make sure it works so far. Reload extensions in Dreamweaver and open a document that contains at least one image (the command looks for the first image on the page). Then choose Commands > Automatic Alt Text. Figure 5.7 shows what should happen to your document when you do this.

    Figure 5.7. Setting the alt attribute for one image in a document to a preset value.

    note

    What's the difference between a node list and an array? For scripting purposes, node lists use slightly different syntax. To access the first item in an array, the correct syntax is myArray[0] . To access the first item in a node list, the syntax is myNodeList.item(0) . For specifications of node lists, see Table 4.1 in Chapter 4.

  2. If you can set alt text for one image in the document's node list of image objects, you can add a for loop to step through the entire node list and add alt attributes to all of them. Revise your function to look like this (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); for (var a=0;a<myImages.length;a++) { myImages.item( a ).alt = "Sample Alt Text"; } }

    To test the code, save the file, reload extensions in Dreamweaver, and try it out on a Dreamweaver document that contains more than one image.

  3. The next step is to revise the function so that it uses each image's filename as its alt text. The filename is included as part of every image's src attributethe attribute that specifies the relative or absolute path to the image file. Because the src attribute is a text string, extracting the desired filename is a simple matter of using the JavaScript substring method to get results like this:

    src attribute

    desired alt text

    scheherezade.gif

    scheherezade

    Images/blinky.gif

    blinky

    ../../../images/housepix/diningroom.jpg

    diningroom

    http://www.domain.com/images/home.gif

    home

    You need to extract everything after the final / and before the final period ( . ). To accomplish this, revise your function to look like this (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); var mySrc = ""; var myName = ""; for (var a=0;a<myImages.length;a++) { mySrc = myImages.item(a).src; myName = mySrc.substring(mySrc.lastIndexOf("/")+1,mySrc.lastIndexOf(".")); myImages.item(a).alt = myName ; } }

    The new code declares two variables ( mySrc and myName ) that are then used in the for loop. The first variable holds the complete src attribute; the second is passed a substring of the src attribute that contains only the filename.

    To test the command's thoroughness, try it on a variety of files with different paths listed in the src parameter. Try to stump the command by giving it a filename or path that it won't report correctly. If you find a problem path, see if you can rewrite the code so that the command deals with it correctly.

note

If you're unclear on how to use the substring() method, read all about it in the Dreamweaver Reference panel. Set the panel to display the O'Reilly JavaScript Reference, and look up the String object and its methods . See the section on "Assembling Reference Materials" in the Introduction for more about the Reference panel.

Task 3: Refine the addAlt() function

The command is fine, as far as it goes. Now it's time to ask yourself how it might be more flexible and useful.

  1. It would be nice, for one thing, if the command didn't overwrite any existing alt text. To accommodate this, rewrite the function to include a conditional statement so that it looks for existing alt tags and adds the alt property only if one doesn't already exist (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); var mySrc = ""; var myName = ""; for (var a=0;a<myImages.length;a++) { if (!myImages.item(a).alt) { mySrc = myImages.item(a).src; myName = mySrc.substring(mySrc.lastIndexOf("/")+1,mySrc.lastIndexOf(".")); myImages.item(a).alt = myName; } } }

    Try this version of your command in Dreamweaver. Be sure to test it out on a Dreamweaver document that has several images, some with and some without existing alt text. It should ignore the images that already have an alt attribute and add alt text only to those without.

  2. Another refinement you can make is to improve how it handles images that are being used as links. If an image is functioning on the page as a button, information about the link provides a more useful alt label than information about the image.

    How will you identify which images in the user's document are linked? The HTML code for a linked image has the a tag wrapped around the img tag, like this:

    <a href="index.html"><img src="dog.jpg"></a>

    Therefore, for each image in the array you can check to see whether it's a link by checking its parent element to see whether it's an a tag.

    What will you do with linked images? Instead of using the image's own src attribute to generate the alt text, you'll use the parent link's href attribute (this property specifies the destination of the link).

    To add this new criteria to your function, you'll need to add another conditional statement. Revise your code like this (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); var mySrc = ""; var myName = ""; for (var a=0;a<myImages.length;a++) { if (!myImages.item(a).alt) { if (myImages.item(a).parentNode.tagName == 'A') { myName = "Visit "+myImages.item(a).parentNode.href; }else{ mySrc = myImages.item(a).src; myName = mySrc.substring(mySrc.lastIndexOf("/")+1,mySrc.lastIndexOf(".")); } myImages.item(a).alt = myName; } } }

    What's happening here? Line 8 of the code adds a conditional statement that checks for an <a> tag wrapped around the image. If that condition is true, line 9 sets the myName variable to reflect the <a> tag's href attribute. The code that was already in place for creating alt text based on the image's src attribute has been moved into the else portion of the conditional, to be executed only if there isn't a link.

  3. But wait! What about images that are linked only for scripting purposes? You don't want # or javascript:myFunction() to show up as part of your alt text, yet both of these are often used in HTML construction. If an image is linked to one of these pseudo-destinations, you want its alt text to display the standard src information that non-linked images display.

    To accomplish this, you need to refine the conditional statement in line 8 so that it will return true only if three conditions are met: an image's parent element must be an <a> tag, and that <a> tag must not have # for its href value, and that <a> tag also must not have an href that begins with javascript: . This all adds up to a pretty packed conditional statement, requiring three parts . Revise line 9 of your function to look like this:

    if (myImages.item(a).parentNode.tagName == 'A' && myImages.item(a).parentNode.href != "#" && myImages.item(a).parentNode.href.substring(0,10) != "javascript") {

    Try this outthe Automatic Alt Text command is now cognizant of links, pseudolinks, and filenames.

note

How fancy do you want to get? Before you spend a lot of time and effort making the biggest, baddest extension on the block, ask yourself what you're going to use it for. If you'll be the only person using a command, and you know the limited circumstances you'll be working in, you don't have to accommodate all possible permutations of circumstance that might break your code. If you're planning to share your extension with others, however, it's a good idea to be as comprehensive as you can be.

Task 4: Add the canAcceptCommand() function

As noted earlier in this chapter, the canAcceptCommand() function determines whether a command is available or grayed out in the menu. If the function returns true (or if it isn't present), the command is available. If it returns false , the command is grayed out.

When would you want the Automatic Alt Text command to be unavailable? Well, it's a pretty useless command if the document doesn't contain any imagesalthough running the command under those circumstances wouldn't cause any problems. It's also uselessand will generate errorsif there's no open document at all.

To make the Automatic Alt Text command unavailable under these circumstances, add the canAcceptCommand() function to your command file, coded so that it returns false if there's no DOM or if the array of <img> tags in the document is empty:

function canAcceptCommand() { var myDOM = dw.getDocumentDOM(); if (!myDOM) return false; var myImages = myDOM.getElementsByTagName('IMG'); if (myImages.item(0)) { return true; } else { return false; } }

Can you see how the command works? If there is no DOM it returns false ; otherwise , it gains access to a node list of all images in the document using the dom.getElementsByTagName() function. Then it tries to find the first item in the node list, item(0) . If it can't find that item, then there are no images, and it returns false .

Try the command out now. In Dreamweaver, reload extensions and open a file that doesn't contain any images. Then try to choose the Automatic Alt Text command. It should be grayed out in the Commands menu (see Figure 5.8). Open a file that does contain images and try again. The command should be available (not grayed out) in the menu.

Figure 5.8. The Automatic Alt Text command, available for use.

note

What if it doesn't work? There's not much that can go wrong with this simple canAcceptCommand() function, except typos. Compare your code to the code printed here, and make sure there are no misspellings or mistypings.

Task 5: Add a dialog box and the commandButtons() function

It's a common technique in web page layout to use small, invisible shim images to stabilize tables and add white space to a page. These images don't need alt text; in fact, having alt text for every shim can be a distraction for visitors. This is especially true if the visitor's browser is set to show little popup ToolTips based on alt text. The standard way to avoid an overload of alt text when shim images are used is to assign empty alt labels ( alt = " " ) to those images.

Expanding on the preceding techniques for accessing DOM objects, it should be easy enough to alter the function to identify and deal with shim images. But we'll need a way to ask the user which images in the current document are shims. This requires that our command have a dialog box. The dialog box requires some extra coding; equally importantly, it requires some strategizing.

  1. Start by designing the form for the dialog box. It needs one input field to collect the source ( src ) information for shim files. There are several ways to collect this information. You could ask the user to type in the filename or path; allow the user to browse to the file and derive the path from that; present the user with a list of images already in the document and ask him to select one (or more) to be treated as shims; or present a checkbox list of common filenames and allow the user to check all that apply. The solution we'll use here is to present a text field and a browse button, as this follows the approach used elsewhere in Dreamweaver.

    In your command file, create the form, remembering not to include any OK or Cancel buttons (Dreamweaver supplies those). Figure 5.9 shows the proposed dialog box design. The code for the form should look like this:

    <form name="myForm"> <table border="0"> <tr valign="baseline"> <td align="right" nowrap>Shim image:</td> <td align="left" nowrap> <input type="text" name="shimfile"> <input type="button" value="Browse"> </td> </tr> </table> </form>

    Figure 5.9. The desired layout for the Automatic Alt Text command's dialog box.

  2. Unlike the API for behaviors and objects, the commands don't automatically add OK and Cancel buttons to dialog boxes. Now that the form code is in place, you need to add the commandButtons() function to the file to tell Dreamweaver what buttons to include and what actions to associate with each button. This function must return an array consisting of a pair of items for each button. The first item in each pair is the name of the button, and the second item is the action to take if the button is clicked.

    For the Automatic Alt Text command, you want an OK button, which causes the addAlt() function to execute and close the dialog box window; and a Cancel button that just closes the window. To create these buttons, add the following code to the command file:

    function commandButtons() { return new Array("OK","addAlt();window.close();","Cancel","window.close()"); }

    To remind yourself how this function creates its buttons, refer back to Figure 5.3.

  3. Now that you have an OK button to execute the main function, remove the onLoad event handler from the <body> . (If you don't remove it, the command will execute before the dialog box even opens.

    To check the button functionality, try out the revised command. The dialog box should look like the one in Figure 5.9. Note that the command file's <title> becomes the title of the dialog box.

  4. Now you want the dialog box to actually do something. Whenever the addAlt() function encounters an image whose src attribute matches whatever file path the user has entered in the dialog box, it should assign that image an alt label consisting of an empty space.

    Adjusting the addAlt() function so that it does this involves collecting the form data and then adding yet another conditional statement, this one checking the src attribute of each image. Because the src is first examined in line 11 of the function (in the else portion of the conditional that tests for links), this seems like a logical place to add the new code. Revise your addAlt() function like this (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); var mySrc = ""; var shimfile=document.myForm.shimfile.value; var myName = ""; for (var a=0;a<myImages.length;a++) { if (!myImages.item(a).alt) { if (myImages.item(a).parentNode.tagName == 'A' && myImages.item(a).parentNode.href != "#" && myImages.item(a).parentNode.href.substring(0,10) != "javascript") { myName = "Visit "+myImages.item(a).parentNode.href; }else{ mySrc = myImages.item(a).src; if (mySrc==shimfile) { myName=" "; }else{ myName = mySrc.substring(mySrc.lastIndexOf("/")+1, mySrc. lastIndexOf(".")); } } myImages.item(a).alt = myName; } } }

    With this code, line 6 collects the dialog box input into a variable called shimfile . In line 14, the src is compared to shimrfile . If the condition is met, an empty space is used for the alt text; if not, the original code using a truncated version of src for the alt text is executed instead.

    Try this out and see how it works! Open a Dreamweaver file that contains regular images and at least one or two spacer images. Note that because the Browse button is not functional yet, you'll need to type the relative address of the shim image into the text field.

note

What if it doesn't work? Aside from typos, the most common problem when dealing with this many nested conditionals is balancing the curly braces. Make sure you have an opening brace for every closing brace, and that they're in the right places. One trick is to comment lines that contain closing braces, indicating which opening brace is being closed, like this:

if (a==b) { alert("Hello"); }//end if (a==b)

Task 6: Add browsing capability to the dialog box

Making users type in filenames and paths isn't very good interface design. That's why you created the Automatic Alt Text dialog box with a Browse button. Following Macromedia's UI practices, you want the user to be able to manually enter information in the text field, but you also want the user to be able to click the Browse button, choose a file, and have that information automatically fill in the text field. In scripting terms, this means adding an onClick event handler to the button that triggers a new browse-for-file function, and having that function return a filename and path into the shimfile text field. Sounds simple, eh? Guess what? It is simple!

  1. Start by adding the framework code for a new function to the <script> tag in the <head> section of your command file. For now, don't add any statements within the code, but you can remind yourself what the function will eventually do by adding comment lines:

    function browseForShim() { //open Browse dialog box and allow user to choose file //store the chosen file address in the text field }

  2. Because the browseForShim() function needs to be called when the Browse button is clicked, also add a function call to the button in your form:

    <input type="button" value="Browse" onClick="browseForShim()" >

  3. In case you're wondering how on earth you're going to write the code that will let users browse for a file, you can relax! The Dreamweaver API has a method for just that dw.browseForFileURL() . Calling this method opens a standard Dreamweaver Select File dialog box, allows the user to select a file, and returns the file path for the chosen file. Table 5.1 lists the specifications of this method.

    Table 5.1. Specifications of the dw.browseForFileURL() Function

    Function

    dw.browseForFileURL()

    Description

    Opens a browse dialog box to allow users to choose files of varying types.

    Syntax

    variableName = dw.browseForFileURL(openSelectOrSave, [titleBarLabel], [bShowPreviewPane], [bSuppressSiteRootWarnings], [arrayOfExtensions] )

    Arguments

    openSelectOrSave : Indicates which type of browse dialog box to bring up. Accepted values: open , select , save .

    [titleBarLabel] : The label that should appear at the top of the dialog box. If this parameter is not defined, the operating system default is used. Accepted value: a string.

    [bShowPreviewPane ]: A Boolean value that indicates whether to display the image preview pane as part of the dialog box. If this parameter is not defined, it defaults to true if browsing for image files, and false if not.

    [bSuppressSiteRootWarnings] : A Boolean value indicating whether to suppress warnings about selected files being outside the site root. If this parameter is not defined, it defaults to false .

    [arrayOfExtensions] : An array of strings for specifying the Files of Type popup menu that appears at the bottom of the dialog box. Accepted syntax for each entry in the array:

    menuEntryText. xxx [;. yyy ;. zzz ] CCCC . The name specified in place of menuEntryText appears in the popup list. The extensions can be specified as . xxx [;. yyy ;. zzz ] or CCCC ; where . xxx specifies the file extension for the file type ( optionally , . yyy and . zzz specify multiple file extensions), and CCCC is the four-character file type constant for use on the Macintosh.

    Returns

    A string containing the file path (for example, ../../images/myfile.gif )

    Examples

    myVar = browseForFileURL("select", "Find an image", true, false) opens a "select" dialog box, with a custom title at the top, the preview pane turned on regardless of file type, and site root warnings turned off.

    myVar = browseForFileURL("open", "", false) opens an "open" dialog box, with the default title at the top, and the preview pane turned off regardless of file type.

    myVar = browseForFileURL("save") opens a "save" dialog box, with all other options at their defaults.

    Add the following code to your browseForShim() function (new code is in bold):

    function browseForShim() { //open Browse dialog box and allow user to choose file var myFile = dw.browseForFileURL(); //store the chosen file address in the text field document.myForm.shimfile.value = myFile; }

    This code is still incomplete, lacking the parameters that you'll need to pass the dw.browseForFileURL() method. But you should be able to see how it uses the method to collect a file path into a variable, and then puts that variable into the shimfile text field in the form.

  4. Look at the syntax requirements in Table 5.1. The dw.browseForFileURL() method takes one required and four optional parameters. For the required parameter, the purpose of this Browse button is to let the user select a file, not open or save a file, so the function should call up a select dialog box. Rewrite line 3 of your browseForShim() function to look like this (new code is in bold):

    var myFile = dw.browseForFileURL( "select" );

  5. At this point, all required parameters are present, and the code is technically complete. But do you want to add any optional parameters? How about determining what title appears in the title bar of the dialog box? That would be a nice touch. Rewrite the code to look like this:

    var myFile = dw.browseForFileURL("select", "Select Shim File" );

    Try it out! When you choose the Automatic Alt Text command and its dialog box appears, you should now be able to click the Browse button to open a Select Shim File dialog box. Choosing a file in that dialog box, and clicking OK to close that dialog box, should put the file path of the chosen image in your dialog box's text field. Figure 5.10 shows the functional browsing interface at work.

    Figure 5.10. Using the Browse feature in the Automatic Alt Text command.

Task 7: Create a fancier dialog box

Instead of asking the user to choose a shim file from among all the files on his system, wouldn't it be helpful to let him choose from just the images that are actually in the document? That's what we'll tackle next. To accomplish this, we must replace the Browse button and text field with a popup menu that displays the filenames for all images in the document. Because the contents of the popup menu must be determined when the command is called and the dialog box opens, we must also add a new local function to the command file, to be executed onLoad , which will collect the filenames of all images in the document and use those names to fill the menu.

  1. Start by redesigning the form so that it uses a popup menu instead of a Browse button. For now, give the popup menu only one choice **no images found** . Your redesigned form should look like the one shown in Figure 5.11. The revised form code looks like this (new code is in bold):

    <form name="myForm"> <table border="0"> <tr valign="baseline"> <td align="right" nowrap>Shim image:</td> <td align="left" nowrap> <select name="shimfile"> <option>**no images found**</option> </select> </td> </tr> </table> </form>

    Figure 5.11. The Automatic Alt dialog box, showing a popup menu with default option.

  2. While you're at it, you no longer need the browseForShim() function that you created in the previous task. Delete that code from the command file's <head> section.

  3. Next, start building the function that will initialize the dialog box by filling in the popup menu entries. Start by adding the framework code for the function, like this:

    function initializeUI(){ //gain access to the document's images //put each image's src into a new menu item }

  4. Because this is a non-API function that must be executed when the dialog box loads, revise your <body> tag to include a function call (new code is in bold):

    <body onLoad="initializeUI()" >

  5. Now start filling in the code framework for the function. As the first comment line says, the function must start by accessing the document's images. Revise the initializeUI() function like this (new code is in bold):

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item }

  6. After the images can be accessed, you need to create a popup menu item (or <option> element, in HTML terms) for each one. Menu items require two pieces of information: a label, to be displayed in the menu; and a value, to be used if that menu, item is chosen. For the current project, the value should be the image's file path. The file path could also be used for the label, but for a more readable menu, you'll use the image's filename only (minus any other path information). Both of these pieces of information can be obtained from each image's src attribute.

    Add the following code to your function:

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; imageValue=myImages.item(0).src; imageLabel=imageValue.substring(imageValue.lastIndexOf('/')+1, imageValue.length); }

    The added code creates two variables ( imageLabel and imageValue ) to store the label and value information for the popup menu entry. Then, for the first image in the document, it collects the src into one variable and creates a truncated version of the src for the other. (The substring method used here is very similar to that used in Task 2 of this workshop to generate alt labels from src properties.)

  7. Now use JavaScript's Option() constructor to create a new <option> (new menu item) using the information collected (new code is in bold):

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; imageValue=myImages.item(0).src; imageLabel=imageValue.substring(imageValue.lastIndexOf('/')+1, imageValue.length); document.myForm.shimfile.options[0]=new Option(imageLabel,imageValue); }

    Because all menu items in the popup menu are part of an options array, by referring to options[0] this code creates a new menu item replacing the single menu item ( **no images found**) that has been coded into the HTML.

    note

    To learn more about the Option() constructor, look up the Option object in the Dreamweaver JavaScript Reference panel.

  8. Before proceeding any further, test the command to make sure it works so far. When the command is called and the Automatic Alt Text dialog box opens, it should display a popup menu containing one itemnot the default item but the name of the first image in the document (see Figure 5.12).

    Figure 5.12. The Automatic Alt Text dialog box, showing one dynamically generated menu item.

  9. Why does the popup menu contain only one item? Because the initializeUI() function collects information from only the first image in the document's node list. Revise the function by adding a for loop to step through every image in the list, creating a menu item for each, like this:

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; for (var a=0;a<myImages.length;a++) { imageValue=myImages.item( a ).src; imageLabel = imageValue.substring (imageValue.lastIndexOf('/')+1,imageValue.length); document.myForm.shimfile.options[ a ]=new Option(imageLabel,imageValue); } }

    The for loop surrounds all the code for collecting image information and creating menu items. Within the loop, the references to the image node list (line 8) and the options array (line 10) have been revised to reference the counter variable, a , instead of . This allows the function to add popup menu items for all images in the document.

  10. Try the command again. When the dialog box appears, the popup menu should contain a full list of all images in the document (see Figure 5.13).

    Figure 5.13. The Automatic Alt Text dialog box, with dynamically generated popup menu displaying the filenames of all document images.

  11. Now that the dialog box is working properly, another problem remains. The addAlt() function has been written to collect a value from a text field, ike this:

    shimfile = document.myForm.shimfile.value;

    It must be revised to collect information from a popup menu. Revise the opening portion of the addAlt() function to look like this (new code is in bold):

    function addAlt() { var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); var mySrc = ""; var myName = ""; var choice = document.myForm.shimfile.selectedIndex; var shimfile = document.myForm.shimfile.options[choice].value; [etc]

    Line 6 of the function determines which option the user has chosen from the menu; line 7 collects the value of that selected option. As long as the rest of your function refers to the variable shimfile , as the sample code here does, no other changes need to be made.

    note

    For a refresher on how to collect input from different kinds of form element, see the section on "Working with Form Elements" in Appendix A, "JavaScript Primer."

  12. Try your command out and see how it works. Choosing the command should generate a dialog box that looks like the one shown in Figure 5.14. Choosing an image from the popup menu should identify that image as the shim for the document, exactly as if you had browsed to it using the dialog box you defined earlier. When you click OK, alt labels should be added to all images in the document except your chosen shim images, which should have empty alt labels.

    Figure 5.14. The Automatic Alt Text dialog box, showing the populated popup menu. Repeated images in the document appear multiple times in the list.

  13. One interface problem you could complain about in this dialog box is that any image that appears more than once in the document also appears more than once in the popup list. (If the test document used to try out your command didn't have multiple instances of images, you may not have noticed this problem.) A better solution is for the popup menu to list each image only once, even if it appears in the document multiple times. This requires some revision of the initializeUI() function.

    How can you make this happen? Instead of using the document's node list of images to create your popup menu (the node list may have repeated occurrences of images in it), you need to create a special array of unique images in the document and build the popup menu from that. You need to create this special array by stepping through the node list and adding images to it only if they haven't already been added. This requires some complex for loops and if-statements.

    Start by changing your code so that it puts all images into an array called uniqueImages and creates the popup menu from that array (new code is in bold):

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; var uniqueImages = new Array(); var ctr=0; //feed node list of images into uniqueImages array for (var b=0;b<myImages.length;b++) { uniqueImages[ctr]=myImages.item(b); ctr++; } // end for loop b //construct popup menu from uniqueImages array for (var a=0;a< uniqueImages .length;a++) { imageValue= uniqueImages[a].src ; imageLabel=imageValue.substring(imageValue.lastIndexOf('/')+1, imageValue.length); document.myForm.shimfile.options[a]=new Option(imageLabel,imageValue); } //end for loop a }

    You've defined a new array in line 7, with its own counter variable ( ctr , defined in line 8). Then you added a second for loop (this one using the variable b as a counter), which steps through the document's images node list and moves every image into the uniqueImages array.

    Note that you also added comments to the end of each of your two for loops, in lines 14 and 21. This is simply to help you keep track of the closing curly braces so that you can tell at a glance where each loop starts and ends.

  14. After you have this new code in place, reload extensions in Dreamweaver and try your command again. The resulting dialog box and popup menu should be identical to the ones created earlier, because you haven't changed any functionality here. All you did was add an intermediate step so that the script now uses an intermediate uniqueImages array.

  15. You've created the intermediate array because you don't necessarily want to put all of the images in the node list into your popup menu. Weeding out the unwanted images requires a conditional statement, so only certain images get fed into the uniqueImages array. To prepare the ground for that, add the following new code (shown in bold):

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; var uniqueImages = new Array(); var ctr=0; var found=0; //feed node list of images into uniqueImages array for (var b=0;b<myImages.length;b++) { if (found==0) { uniqueImages[ctr]=myImages.item(b); ctr++; }//end if (found==0) }//end for loop b [etc]

    What did you do here? You created a variable called found and used it as part of a conditional statement that determines whether or not each image will be fed into the uniqueImages array. Only if found is set to will the image in question be added. Of course, this is a very simple setup, in which found will always be set to because that's how you initialized it, and your script never changes that. This bit of code is just an easy way of getting the if-statement syntax in place without disturbing the functionality of your script.

  16. Can you tell how the new conditional will change what appears in your popup menu? Try it out and see. Because found is always equal to , the condition will always be true , and the image will always be added to the uniqueImages array. So your resulting popup menu should still display all images, just as it did before. (If you test the script, and it doesn't work, make sure the syntax of your conditional is correct.)

  17. Now that the conditional is in place, see how it works. Change line 9 of your code by initializing found to 1 instead of , like this:

    var found = 1 ;

    Now when you try your command, what will show in the popup menu? Nothing except the default entry, because no images are moved into the uniqueImages array.

  18. Finally, make your conditional do something useful. Each image in the myImages node list should be added to the uniqueImages array only if an entry with that src doesn't already exist there. This means adding yet another for loop and conditional, to set found before moving the images. To do this, don't initialize the found variable right away. Instead, add the following the lines to your code (shown in bold):

    function initializeUI(){ //gain access to the document's images var myDOM=dw.getDocumentDOM(); var myImages=myDOM.getElementsByTagName('IMG'); //put each image's src into a new menu item var imageLabel, imageValue; var uniqueImages = new Array(); var ctr=0; var found; //feed node list of images into uniqueImages array for (var b=0;b<myImages.length;b++) { //test to see if this image is in the uniqueImages array found=0; //step through the uniqueImages array, comparing each entry to this image for (var c=0;c<uniqueImages.length;c++) { //if a match is found, set found to 1 and stop looking if (myImages.item(b).src==uniqueImages[c].src) { found=1; break; }//end if }//end for loop c if (found==0) { uniqueImages[ctr]=myImages.item(b); ctr++; }//end if (found==0) }//end for loop b [etc]

    What's happening here? Within for loop b , before adding an image to the uniqueImages array, the image's src value must be compared to all src values already in the uniqueImages array. The process starts by setting found to (because at the beginning of the process, no match has been found in the uniqueImages array). Then another for loop (indicated by the c counter variable) steps through the entries already in the uniqueImages array. Within that loop, another conditional compares the src value of the image to each entry in the uniqueImages array. If a match is found, found is set to 1 , and a break statement stops the loop from continuing. Can you see why it helps to comment the closing curly braces for each loop and conditional?

  19. After you have this latest code revision in place, try the command out in Dreamweaver. You should get a dialog box with a much tidier popup list, like the one shown in Figure 5.15.

    Figure 5.15. The Automatic Alt Text dialog box, with non-redundant popup list.

  20. Are you done yet? Not quite! Here's one last problem you may run into: If, when you're testing your command, you don't choose anything from the popup menu and then click OK, you'll generate a JavaScript error. This is because the addAlt() function tries to pull a value from the selected popup menu option, but there isn't one.

    To eliminate this error, add the following code to your function (new code is in bold):

    function addAlt() { //gain access to the images in the document var myDOM = dw.getDocumentDOM(); var myImages = myDOM.getElementsByTagName('IMG'); //variables to store info for new menu options to be created var mySrc = ""; var myName = ""; //collect name of selected image in popup menu (shim) var choice = document.myForm.shimfile.selectedIndex; if (choice>=0) {//if user has made a choice var shimfile = document.myForm.shimfile.options[choice].value; }

    If the user doesn't make any choice from the popup menu, the selectedIndex property fed into the choice variable will be 1 . So, by adding a conditional that only tries to collect a shimfile value only if the choice is or larger, you eliminate this error.

Task 8: Adding online help

Adding online help to commands is basically the same as adding help to any extension type: The help can be in the form of a short paragraph in the dialog box itself, a link to a web page, or a link to an HTML page stored within the Configuration folder. Just as you must explicitly add OK and Cancel buttons to command dialog boxes, however, you must also explicitly add Help buttons. In this step, you create an HTML document containing help information, and create a Help button that links to it.

  1. Macromedia requests that help documents, along with any other support files your extensions may need, be stored in subfolders in the Configuration/Shared folder. So, start by navigating to the Configuration/Shared folder and creating a new folder. Call the folder MyShared . Figure 5.16 shows the new MyShared folder in place.

    Figure 5.16. The Configuration/Shared folder, with the MyShared folder added.

    note

    If you're going to share your extensions, especially if you may want to submit them to the Dreamweaver Exchange, it's a good idea to name your shared folder something that reflects you or your company. A generic name is used in the exercises here, but for your own use you'll want something more descriptive.

  2. Next, create the HTML help document for your command. Call it AutomaticAltHelp.htm and store it in the MyShared folder.

    You can do this in Dreamweaver or in your text editor. You can make the document as simple or as extensive as you like. Macromedia recommends that the document include information about where the item can be found in the interface and how it works. Figure 5.17 shows a sample of a simple help file for Automatic Alt Text.

    Figure 5.17. The Help document for Automatic Alt Text.

    Now you create the Help button in the command's dialog box. This is a two-step process: first, you write a function that launches the help document; second, you use the commandButtons() function to create a new button to call that function.

  3. In your text editor, open the command document, and add the following function (new code is in bold):

    function launchHelp() { var myURL = dw.getConfigurationPath(); myURL += "/Shared/MyShared/AutomaticAltHelp.htm"; dw.browseDocument(myURL); }

    What's happening here? To open the help document, you need its absolute address on the user's computer. The dw.getConfigurationPath() function gets the absolute address of the Configuration folder. Then you concatenate that information with the path from the Configuration root to the file itself. Finally, you use the dw.browseDocument() function, feeding it the absolute address, to open the file.

    Table 5.2 shows the specifications for these two functions. Note that because both functions are methods of the dreamweaver object, you don't need to get DOM access before calling them.

    Table 5.2. Specifications and Examples for the Functions Used in Calling Help Documents

    Function

    dw.getConfigurationPath()

    Description

    Gets the absolute address of the Configuration folder on a user's computer.

    Syntax

    variableName = dw.getConfigurationPath()

    Arguments

    None

    Returns

    A string containing the file path (for example, file://MyComputer/ProgramFiles/ Macromedia/Dreamweaver/Configuration )

    Function

    dw.browseDocument()

    Description

    Launches the default browser and opens a specified file.

    Syntax

    dw.browseDocument( absoluteURL )

    Arguments

    absoluteURL: a string representing an absolute path to an HTML document

    Returns

    Nothing

    Examples

    //launches the default browser, connects to the Internet, and opens the Macromedia home page dw.browseDocument("http://www.macromedia.com") //launches the default browser and opens a locally stored file var myURL="file://MyComputer/WebFiles/index. html" dw.browseDocument(myURL); //launches a file in the Configuration folder var myURL=dw.getConfigurationPath(); myURL += "/Shared/MyShared/myfile.html"; sdw.browseDocument(myURL);

  4. Now you need to add the Help button that calls this function. In your command document, find the commandButtons() function and add the following code (new code is in bold):

    function commandButtons() { return new Array("OK","addAlt();window.close();","Cancel","window.close()" ,"Help"," launchHelp()" ); }

Note that the instructions for the Help button do not include closing the dialog box. Normally, when a user asks for help while in a dialog box, he wants to come back to the same dialog box after reading the help document.

With all of this new code in place, try your command out again. If you entered the correct code in the commandButtons() function, the dialog box will include a Help button, like that shown in Figure 5.18. If you created your help document and entered the correct path for it in the launchHelp() function, clicking the Help button will open it in the browser. When you return to Dreamweaver from the help page, the dialog box will still be open.

Figure 5.18. The Automatic Alt Text dialog box, with the Help button in place.

Wrapping Up the Automatic Alt Command

There has been a lot to learn in this one command. You learned how to use the commands API. In the course of building the main addAlt() function, you got some good experience working with the DOM to access images and their properties. You learned how to make some sophisticated interface elements, and how to add more substantial online help to an extension. And you learned a whole selection of useful API methods along the way, including dw.browseForFile() and dw.getConfigurationPath() . As a bonus, you ended up with a potentially useful command for future Dreamweaver projects.

Категории