1. Trang chủ
  2. » Công Nghệ Thông Tin

JavaScript Bible, Gold Edition part 157 pot

10 79 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 0,99 MB

Nội dung

1408 Part V ✦ Putting JavaScript to Work } evt.cancelBubble = true return false } } When a user drops the currently selected map object, the release() function invokes the onTarget() function to find out if the current location of the map is within range of the desired destination. If it is in range, the background color of the state label object is set to green, and the done property of the selected state’s database entry is set to true. One additional test (the isDone() function call) looks to see if all the done properties are true in the database. If so, the congrats object is shown. But if the object is not in the right place, the label reverts to its original red color. In case the user moves a state that was previously okay, its database entry is also adjusted. No matter what the outcome, however, the user has dropped the map, so key global variables are set to null and the layer order for the item is set to zero (bottom of the heap) so that it doesn’t interfere with the next selected map. One more condition is possible in the release() function. As shown later in the initialization function, the document object’s onmousemove event handler is assigned to the release() function (to compare the onmousemove events for the state maps go to dragIt()). The reasoning behind this document-level event assignment is that no matter how streamlined the dragging function may be, it is possible for the user to move the mouse so fast that the map can’t keep up. At that point, mousemove events are firing at the document (or other object, eventually bubbling up to the document), and not the state map. If that happens while a state map is registered as the selected object, but the image is no longer the target of the event, the code performs the same act as if the user had released the map. The label reverts to red, and all relevant globals are set to null, preventing any further interaction with the map until the user mouses down again on the map. // onmouseup, see if dragged map is near its destination // coordinates; if so, mark it as ‘done’ and color label green function release(evt) { evt = (evt) ? evt : event var target = (evt.target) ? evt.target : evt.srcElement var abbrev = (target.name && target.src) ? target.name.toLowerCase() : “” if (abbrev && selectedObj) { if (onTarget(evt)) { setBGColor(selectedStateLabel, “green”) states[abbrev].done = true if (isDone()) { show(“congrats”) } } else { setBGColor(selectedStateLabel, “red”) states[abbrev].done = false hide(“congrats”) } 1409 Chapter 56 ✦ Application: Cross-Browser DHTML Map Puzzle setZIndex(selectedObj, 0) } else if (selectedStateLabel) { setBGColor(selectedStateLabel, “red”) } selectedObj = null selectedStateLabel = null } To find out if a dropped map is in (or near) its correct position, the onTarget() function first calculates the target spot on the page by adding the location of the bgmap object to the coordinate positions stored in the states database. Because the bgmap object doesn’t come into play in other parts of this script, it is convenient to pass merely the object name to the two API functions that get the object’s left and top coordinate points. Next, the script uses platform-specific properties to get the recently dropped state map object’s current location. A large if condition checks whether the state map object’s coordinate point is within a four-pixel square region around the target point. If you want to make the game easier, you can increase the cushion values from 2 to 3 or 4. If the map is within the range, the script calls the shiftTo() API function to snap the map into the exact destination position and reports back to the release() function the appropriate Boolean value. // compare position of dragged element against the destination // coordinates stored in corresponding state object; after shifting // element to actual destination, return true if item is within // 2 pixels. function onTarget(evt) { evt = (evt) ? evt : event var target = (evt.target) ? evt.target : evt.srcElement var abbrev = (target.name && target.src) ? target.name.toLowerCase() : “” if (abbrev && selectedObj) { var x = states[abbrev].x + getObjectLeft(“bgmap”) var y = states[abbrev].y + getObjectTop(“bgmap”) var objX, objY if (selectedObj.pageX) { objX = selectedObj.pageX objY = selectedObj.pageY } else if (selectedObj.style) { objX = parseInt(selectedObj.style.left) objY = parseInt(selectedObj.style.top) } if ((objX >= x-2 && objX <= x+2) && (objY >= y-2 && objY <= y+2)) { shiftTo(selectedObj, x, y) return true } return false } return false } 1410 Part V ✦ Putting JavaScript to Work A for loop cycles through the states database (with the help of the hash table values stored indirectly in the statesIndexList array) to see if all of the done properties are set to true. When they are, the release() function (which calls the isDone() function) displays the congratulatory object. Do note that NN6.0 may exhibit rendering difficulties when hiding and showing the congrats object. This problem should be fixed in a subsequent release of the browser. // test whether all state objects are marked ‘done’ function isDone() { for (var i = 0; i < statesIndexList.length; i++) { if (!states[statesIndexList[i]].done) { return false } } return true } The help panel is created differently than the map and label objects (details com- ing up in a moment). When the user clicks the Help button at the top of the page, the instructions panel flies in from the right edge of the window (see Figure 56-2). The showHelp() function begins the process by setting its location to the current right window edge, bringing its layer to the very front of the heap, showing the object. To assist moveHelp() in calculating the center position on the screen, the showHelp() function retrieves (just once per showing) the DOM-specific property for the width of the help panel. That value is passed as a parameter to moveHelp() as it is repeatedly invoked through the setInterval() mechanism. Figure 56-2: Instructions panel “flies” in from left to center screen. 1411 Chapter 56 ✦ Application: Cross-Browser DHTML Map Puzzle /************************************************* BEGIN HELP ELEMENT FUNCTIONS **************************************************/ // initiate show action function showHelp() { var objName = “help” var helpWidth = 0 shiftTo(objName, insideWindowWidth, 80) setZIndex(objName,1000) show(objName) if (document.layers) { helpWidth = document.layers[objName].document.width } else if (document.all) { helpWidth = document.all(objName).offsetWidth } else if (document.getElementById) { if (document.getElementById(objName).offsetWidth >= 0) { helpWidth = document.getElementById(objName).offsetWidth } } intervalID = setInterval(“moveHelp(“ + helpWidth + “)”, 1) } In the moveHelp() function, the help object is shifted in five-pixel increments to the left. The ultimate destination is the spot where the object is in the middle of the browser window. That midpoint must be calculated each time the page loads, because the window may have been resized. The width of the help object, received as a parameter to the function, gets a workout in the mid-point calculation. This function is called repeatedly under the control of a setInterval() method in showHelp(). But when the object reaches the middle of the browser window, the interval ID is canceled, which stops the animation. The help object processes a mouse event to hide the object. An extra clearInterval() method is called here in case the user clicks the object’s Close button before the object has reached mid-window (where moveHelp() cancels the interval). The script also shifts the position to the right edge of the window, but it isn’t absolutely necessary, because the showHelp() method positions the window there. // iterative move help DIV to center of window function moveHelp(w) { shiftBy(“help”,-5,0) var objectLeft = getObjectLeft(“help”) if (objectLeft <= (insideWindowWidth/2) - w/2) { clearInterval(intervalID) } } // hide the help DIV function hideMe() { clearInterval(intervalID) hide(“help”) shiftTo(“help”, insideWindowWidth, 80) } 1412 Part V ✦ Putting JavaScript to Work The document’s onLoad event handler invokes the init() function, which, in turn, calls two functions and assigns the document object’s onmousemove event handler. The first is initArray(), which builds the states[] database and assigns event handlers to the state map layers. Because the layers are defined so late in the document, initializing their events after the page has loaded is safest. For convenience in moving the help window to the center of the browser win- dow, the setWinWidth() function sets a global variable (insideWindowWidth) to hold the width of the browser window. This function is also invoked by the onResize event handler for the window to keep the value up to date. // calculate center of window for help DIV function setWinWidth() { if (window.innerWidth) { insideWindowWidth = window.innerWidth } else if (document.body.scrollWidth) { insideWindowWidth = document.body.scrollWidth } else if (document.width) { insideWindowWidth = document.width } } /************************************************* INITIALIZE THE APPLICATION **************************************************/ // initialize application function init() { initArray() setWinWidth() document.onmousemove = release } </SCRIPT> </HEAD> Now comes the part of the document that generates the visible content. The <BODY> tag contains the two event handlers just discussed. An image rollover for the help icon simply displays a message in the statusbar. <BODY onLoad=”init()” onResize=”setWinWidth()”> <H1>”Lower 48” U.S. Map Puzzle&nbsp;<A HREF=”javascript:void showHelp()” onMouseOver=”status=’Show help panel ’;return true” onMouseOut=”status=’’;return true”><IMG SRC=”info.gif” HEIGHT=22 WIDTH=22 BORDER=0></A></H1> <HR> Next come tags for all of the DIV elements. The STYLE attribute for the bgmap DIV lets scripts read the positioned values to assist in calculating positions in the onTarget() function, as shown previously. The bgmap layer also contains all labels so that if the design calls for moving the map to another part of the page, the labels follow automatically. Notice how the lowercase state abbreviations are part of the names of both the label and map layers. As you saw in a few functions shown previ- ously, a systematic approach to object naming can offer powerful shortcuts in determining references to elements. 1413 Chapter 56 ✦ Application: Cross-Browser DHTML Map Puzzle <DIV ID=bgmap STYLE=”position:absolute; left:100; top:180; width:406”><IMG SRC=”us11.gif” WIDTH=306 HEIGHT=202 BORDER=1>&nbsp;</IMG> <DIV CLASS=”labels” ID=azlabel>Arizona</DIV> <DIV CLASS=”labels” ID=calabel>California</DIV> <DIV CLASS=”labels” ID=orlabel>Oregon</DIV> <DIV CLASS=”labels” ID=utlabel>Utah</DIV> <DIV CLASS=”labels” ID=walabel>Washington</DIV> <DIV CLASS=”labels” ID=nvlabel>Nevada</DIV> <DIV CLASS=”labels” ID=idlabel>Idaho</DIV> </DIV> <DIV ID=camap><IMG NAME=”CA” SRC=”ca.gif” WIDTH=47 HEIGHT=82 BORDER=0></DIV> <DIV ID=ormap><IMG NAME=”OR” SRC=”or.gif” WIDTH=57 HEIGHT=45 BORDER=0></DIV> <DIV ID=wamap><IMG NAME=”WA” SRC=”wa.gif” WIDTH=38 HEIGHT=29 BORDER=0></DIV> <DIV ID=idmap><IMG NAME=”ID” SRC=”id.gif” WIDTH=34 HEIGHT=55 BORDER=0></DIV> <DIV ID=azmap><IMG NAME=”AZ” SRC=”az.gif” WIDTH=38 HEIGHT=45 BORDER=0></DIV> <DIV ID=nvmap><IMG NAME=”NV” SRC=”nv.gif” WIDTH=35 HEIGHT=56 BORDER=0></DIV> <DIV ID=utmap><IMG NAME=”UT” SRC=”ut.gif” WIDTH=33 HEIGHT=41 BORDER=0></DIV> <DIV ID=congrats><H1>Congratulations!</H1></DIV> In developing this application, I encountered an unfriendly NN4 bug. When defin- ing the help panel as a positioned DIV element in NN4, the browser exhibited unwanted behavior after the instruction panel was shown and flown into place under script control. Even after hiding the help layer, the page no longer received mouse events, making it impossible to pick up a state map after the instructions appeared. The problem did not surface, however, if the help object was defined in the document with a <LAYER> tag. Therefore, I did what I don’t like to do unless absolutely necessary: I created branches in the content that used document.write() to create the same content with different HTML syntax, depending on the browser. For non-LAYER browsers, the page creates the same kind of block (with the <DIV> tag pair) used elsewhere in the document. Positioning properties are assigned to this block via a STYLE attribute in the <DIV> tag. You cannot assign a style in the <STYLE> tag that is visi- ble to the entire document, because that specification and a like-named <LAYER> tag get confused. For NN4, the page uses the <LAYER> tag and loads the content of the object from a separate HTML file ( instrux.htm). One advantage I had with the <LAYER> tag was that I could assign an initial horizontal position of the help object with a JavaScript entity. The entity reaches into the window.innerWidth property to set the LEFT attribute of the layer. <SCRIPT LANGUAGE=”JavaScript”> var output = “” if (document.layers) { output = “<LAYER ID=’help’ TOP=80 LEFT=&{window.innerWidth}; WIDTH=300 VISIBILITY=’HIDDEN’ SRC=’instrux.htm’></LAYER>” } else { output = “<DIV ID=’help’ onClick=’hideMe()’ STYLE=’position:absolute; visibility:hidden; top:80; width:300; border:none; background- color:#98FB98;’>\n” 1414 Part V ✦ Putting JavaScript to Work output += “<P STYLE=’margin- top:5’><CENTER><B>Instructions</B></CENTER></P>\n” output += “<HR COLOR=’seagreen’>\n<OL STYLE=’margin-right:20’>” output += “<LI>Click on a state map to pick it up. The label color turns yellow.\n” output += “<LI>Drag the map into position, and release the mouse to drop the state map.\n” output += “<LI>If you are close to the actual location, the state snaps into place and the label color turns green.\n” output += “</OL>\n<FORM>\n<CENTER><INPUT TYPE=’button’ VALUE=’Close’>\n</FORM></DIV>” } document.write(output) </SCRIPT> </BODY> </HTML> This page has a lot of code to digest in one reading. Run the application, study the structure of the source code listing file, and re-read the previous explanations. It may take several readings for a mental picture of the application to form. Lessons Learned As soon as the external cross-platform API was in place, it helped frame a lot of the other code in the main program. The APIs provided great comfort in that they encouraged me to reference a complex object fully in the main code as a platform- shared value (for example, the selectedObj and selectedStateLabel global vari- ables). At the same time, I could reference top-level elements (that is, non-nested objects) simply by their names when passing them to API functions. In many respects, the harder task was defining the style sheet attributes and syn- tax that both browsers would treat similarly. In the case of the label objects, I couldn’t reach complete parity in a cross-platform environment (the labels look dif- ferent in NN4), and in the case of the help object, I had to code the HTML sepa- rately for each platform. Therefore, when approaching this kind of project, work first with the HTML and CSS syntax to build the look that works best for all plat- forms. Then start connecting the scripted wires. You may have to adjust the CSS code if you find odd behavior in one platform or the other with your scripting, but starting with a good layout is still easier. But without a doubt the biggest lesson you learn from working on a project like this is how important it is to test an application on as many browsers and operating systems as possible. Designing a cross-platform application on one browser and having it run flawlessly on the other the first time is nearly impossible. Be prepared to go back and forth among multiple browsers, breaking and repairing existing working code along the way until you eventually reach a version that works on every browser that you can test. ✦✦✦ Application: Transforming XML Data Islands C hapter 52 ends with an example of an interactive out- liner whose data arrives in XML format. The data is embedded in an HTML document inside an XML data island, which is thus far supported only on the Windows versions of IE5 and later. The application described in this chapter picks up from there. As you recall from the Chapter 52 outline, the node struc- ture of the XML data was used as a guide to the structure for a one-time rendering of HTML elements. There was a one-to-one correlation between XML element nesting and the HTML ele- ment nesting. Adjusting style sheet properties for displaying or hiding elements controlled all interactivity. What you’re about to see here is a case for converting XML into JavaScript objects that can be used multiple times as a convenient data source for HTML that is displayed in any number of formats. In particular, you see how JavaScript’s array sorting prowess supplies XML-supplied data with extraordinary flexibility in presentation. You will see a lot of code in this chapter. The code is pre- sented here as a way to demonstrate the potential for rich data handling. At the same time, the code may provide ideas for server-side processing of XML data being output to the client. If a server program can convert the XML data into the shortcut object and array notation of Version 4 browsers or later, suddenly a broader range of browsers is capable of deal- ing with data stored as XML on the server. 57 57 CHAPTER ✦✦✦✦ In This Chapter Designing XML data islands Complex JavaScript data structures Advanced array sorting Dynamic tables ✦✦✦✦ 1416 Part V ✦ Putting JavaScript to Work Application Overview Understanding the data is a good place to start in describing this application. The scenario is a small American company (despite its grandiose name: GiantCo) that has divided the country into three sales regions. Two of the regions have two sales representatives, while the third region has three reps. The time is at the end of a fiscal year, at which point the management wants to review and present the performance of each salesperson. An XML report delivers the sales forecast and actual sales per quarter for each sales rep. A single HTML and JavaScript page (with the XML data embedded as a data island inside an IE <XML> tag) is charged with not only displaying the raw tabular data, but also allowing for a variety of views and sorting possibilities so that management can analyze performance by sales rep and region, as well as by quarter. A server-based searching and reporting program collects the requested data and outputs each sales rep’s record in an XML structure, such as the following one: <SALESREP> <EMPLOYEEID>12345</EMPLOYEEID> <CONTACTINFO> <FIRSTNAME>Brenda</FIRSTNAME> <LASTNAME>Smith</LASTNAME> <EMAIL>brendas@giantco.com</EMAIL> <PHONE>312-555-9923</PHONE> <FAX>312-555-9901</FAX> </CONTACTINFO> <MANAGER> <EMPLOYEEID>02934</EMPLOYEEID> <FIRSTNAME>Alistair</FIRSTNAME> <LASTNAME>Renfield</LASTNAME> </MANAGER> <REGION>Central</REGION> <SALESRECORD> <PERIOD> <ID>Q1_2000</ID> <FORECAST>300000</FORECAST> <ACTUAL>316050</ACTUAL> </PERIOD> <PERIOD> <ID>Q2_2000</ID> <FORECAST>280000</FORECAST> <ACTUAL>285922</ACTUAL> </PERIOD> <PERIOD> <ID>Q3_2000</ID> <FORECAST>423000</FORECAST> <ACTUAL>432930</ACTUAL> </PERIOD> <PERIOD> <ID>Q4_2000</ID> <FORECAST>390000</FORECAST> <ACTUAL>399200</ACTUAL> </PERIOD> </SALESRECORD> </SALESREP> 1417 Chapter 57 ✦ Application: Transforming XML Data Islands As you can see, the data consists of several larger blocks, such as contact infor- mation, a pointer to the rep’s manager, and then the details of each quarterly period’s forecast and actual sales. The goal is to present the data in table form with a structure similarly shown in Figure 57-1. Not only is the raw data presented, but numerous calculations are also made on the results, such as the percentage of quota attained for each reporting period, plus totals along each axis of the spreadsheet-like table. Figure 57-1: One view of the XML data output Just above the table are two SELECT elements. These controls’ labels indicate that the table’s data can be sorted by a number of criteria and the results of each sort can be ordered in different ways. Sorting in the example offers the following possibilities: Representative’s Name Sales Region Q1 Forecast Q1 Actual Q1 Performance [the last three also for Q2, Q3, Q4] Total Forecast Total Actual Total Performance Ordering of the sorted results is a choice between “Low to High” or “High to Low.” While ordering of most sort categories is obviously based on numeric value, the sorting of the representatives’ names is based on the alphabetical order of the last names. One other point about the user interface is that the design needs to signify via table cell background color the sales region of each representative. The . converting XML into JavaScript objects that can be used multiple times as a convenient data source for HTML that is displayed in any number of formats. In particular, you see how JavaScript s array. server. 57 57 CHAPTER ✦✦✦✦ In This Chapter Designing XML data islands Complex JavaScript data structures Advanced array sorting Dynamic tables ✦✦✦✦ 1416 Part V ✦ Putting JavaScript to Work Application Overview Understanding. <= y+2)) { shiftTo(selectedObj, x, y) return true } return false } return false } 1410 Part V ✦ Putting JavaScript to Work A for loop cycles through the states database (with the help of the

Ngày đăng: 06/07/2014, 06:20