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

JavaScript Bible, Gold Edition part 114 pot

10 45 0

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

THÔNG TIN TÀI LIỆU

Nội dung

978 Part IV ✦ JavaScript Core Language Reference Date and time arithmetic You may need to perform some math with dates for any number of reasons. Perhaps you need to calculate a date at some fixed number of days or weeks in the future or figure out the number of days between two dates. When calculations of these types are required, remember the lingua franca of JavaScript date values: milliseconds. What you may need to do in your date-intensive scripts is establish some variable values representing the number of milliseconds for minutes, hours, days, or weeks, and then use those variables in your calculations. Here is an example that establishes some practical variable values, building on each other: var oneMinute = 60 * 1000 var oneHour = oneMinute * 60 var oneDay = oneHour * 24 var oneWeek = oneDay * 7 With these values established in a script, I can use one to calculate the date one week from today: var targetDate = new Date() var dateInMs = targetDate.getTime() dateInMs += oneWeek targetDate.setTime(dateInMs) Another example uses components of a date object to assist in deciding what kind of greeting message to place in a document, based on the local time of the user’s PC clock. Listing 36-2 adds to the scripting from Listing 36-1, bringing some quasi-intelligence to the proceedings. Again, this script uses the older array creation mechanism to be compatible with Navigator 2 and Internet Explorer 3. Listing 36-2: A Dynamic Welcome Message <HTML> <HEAD> <TITLE>Date String Maker</TITLE> <SCRIPT LANGUAGE=”JavaScript”> function MakeArray(n) { this.length = n return this } monthNames = new MakeArray(12) monthNames[1] = “January” monthNames[2] = “February” monthNames[3] = “March” monthNames[4] = “April” monthNames[5] = “May” monthNames[6] = “June” monthNames[7] = “July” monthNames[8] = “August” monthNames[9] = “September” monthNames[10] = “October” monthNames[11] = “November” monthNames[12] = “December” 979 Chapter 36 ✦ The Date Object dayNames = new MakeArray(7) dayNames[1] = “Sunday” dayNames[2] = “Monday” dayNames[3] = “Tuesday” dayNames[4] = “Wednesday” dayNames[5] = “Thursday” dayNames[6] = “Friday” dayNames[7] = “Saturday” function customDateString(oneDate) { var theDay = dayNames[oneDate.getDay() + 1] var theMonth = monthNames[oneDate.getMonth() + 1] var theYear = oneDate.getYear() theYear += (theYear < 100) ? 1900 : 0 return theDay + “, “ + theMonth + “ “ + oneDate.getDate() + “, “ + theYear } function dayPart(oneDate) { var theHour = oneDate.getHours() if (theHour <6 ) return “wee hours” if (theHour < 12) return “morning” if (theHour < 18) return “afternoon” return “evening” } </SCRIPT> </HEAD> <BODY> <H1> Welcome!</H1> <SCRIPT LANGUAGE=”JavaScript”> today = new Date() var header = (customDateString(today)).italics() header += “<BR>We hope you are enjoying the “ header += dayPart(today) + “.” document.write(header) </SCRIPT> <HR> </BODY> </HTML> The script divides the day into four parts and presents a different greeting for each part of the day. The greeting that plays is based, simply enough, on the hour element of a date object representing the time the page is loaded into the browser. Because this greeting is embedded in the page, the greeting does not change no matter how long the user stays logged on to the page. Counting the days You may find one or two more date arithmetic applications useful. One displays the number of shopping days left until Christmas (in the user’s time zone); the other is a countdown timer to the start of the year 2100. 980 Part IV ✦ JavaScript Core Language Reference Listing 36-3 demonstrates how to calculate the number of days between the current day and some fixed date in the future. The assumption in this application is that all calculations take place in the user’s time zone. The example shows the display of the number of shopping days before the next Christmas day (December 25). The basic operation entails converting the current date and the next December 25 to milliseconds, calculating the number of days represented by the difference in milliseconds. If you let the millisecond values represent the dates, JavaScript auto- matically takes care of leap years. The only somewhat tricky part is setting the year of the next Christmas day correctly. You can’t just slap the fixed date with the current year, because if the program is run on December 26, the year of the next Christmas must be incremented by one. That’s why the constructor for the Christmas date object doesn’t supply a fixed date as its parameters but, rather, sets individual components of the object. Listing 36-3: How Many Days Until Christmas <HTML> <HEAD> <TITLE>Christmas Countdown</TITLE> <SCRIPT LANGUAGE=”JavaScript”> function getDaysUntilXmas() { var oneMinute = 60 * 1000 var oneHour = oneMinute * 60 var oneDay = oneHour * 24 var today = new Date() var nextXmas = new Date() nextXmas.setMonth(11) nextXmas.setDate(25) if (today.getMonth() == 11 && today.getDate() > 25) { nextXmas.setFullYear(nextXmas.getFullYear() + 1) } var diff = nextXmas.getTime() - today.getTime() diff = Math.floor(diff/oneDay) return diff } </SCRIPT> </HEAD> <BODY> <H1> <SCRIPT LANGUAGE=”JavaScript”> var header = “You have <I>” + getDaysUntilXmas() + “</I> “ header += “shopping days until Christmas.” document.write(header) </SCRIPT> </H1><HR> </BODY> </HTML> 981 Chapter 36 ✦ The Date Object The second variation on calculating the amount of time before a certain event takes time zones into account. For this demonstration, the page is supposed to display a countdown timer to the precise moment when the flame for the 2004 Summer Games in Athens is to be lit. That event takes place in a time zone that may be different from that of the page’s viewer, so the countdown timer must calculate the time difference accordingly. Listing 36-4 shows a simplified version that simply displays the ticking timer in a text field. The output, of course, could be customized in any number of ways, depending on the amount of dynamic HTML you want to employ on a page. The time of the lighting for this demo is set at 17:00 GMT on August 13, 2004 (the date is certainly accurate, but the officials may set a different time closer to the actual event). Because this application is implemented as a live ticking clock, the code starts by setting some global variables that should be calculated only once so that the function that gets invoked repeatedly has a minimum of calculating to do (to be more efficient). The Date.UTC() method provides the target time and date in standard time. The getTimeUntil() function accepts a millisecond value (as provided by the targetDate variable) and calculates the difference between the target date and the actual internal millisecond value of the client’s PC clock. The core of the getCountDown() function peels off the number of whole days, hours, minutes, and seconds from the total number of milliseconds difference between now and the target date. Notice that each chunk is subtracted from the total so that the next smaller chunk can be calculated from the leftover milliseconds. One extra touch on this page is that users of Windows operating systems have a display of the local date and time of the actual event. The Mac is excluded because it does not provide accurate daylight saving time adjustments for local dates. Some UNIX flavors may do the right thing, but they were not tested for this example. Listing 36-4: Summer Games Countdown <HTML> <HEAD> <TITLE>Summer Games Countdown</TITLE> <SCRIPT LANGUAGE=”JavaScript”> // globals calculate only once // set target date to 1700GMT on August 13, 2004 var targetDate = Date.UTC(2004, 7, 13, 17, 0, 0, 0) var oneMinute = 60 * 1000 var oneHour = oneMinute * 60 var oneDay = oneHour * 24 function getTimeUntil(targetMS) { var today = new Date() var diff = targetMS - today.valueOf() return Math.floor(diff) } function getCountDown() { var ms = getTimeUntil(targetDate) var output = “” var days, hrs, mins, secs if (ms >= 0) { Continued 982 Part IV ✦ JavaScript Core Language Reference Listing 36-4 (continued) days = Math.floor(ms/oneDay) ms -= oneDay * days hrs = Math.floor(ms/oneHour) ms -= oneHour * hrs mins = Math.floor(ms/oneMinute) ms -= oneMinute * mins secs = Math.floor(ms/1000) output += days + “ Days, “ + hrs + “ Hours, “ + mins + “ Minutes, “ + secs + “ Seconds” } else { output += “The time has passed.” } return output } function updateCountDown() { document.forms[0].timer.value = getCountDown() setTimeout(“updateCountDown()”, 1000) } </SCRIPT> </HEAD> <BODY onLoad=”updateCountDown()”> <H1>Athens Games Torch Lighting Countdown</H1> <P> <SCRIPT LANGUAGE=”JavaScript”> if (navigator.userAgent.indexOf(“Win”) >= 0) { document.write(“(“ + (new Date(targetDate)).toLocaleString()) document.write(“ in your time zone.)”) } </SCRIPT> </P> <FORM> <INPUT TYPE=”text” NAME=”timer” SIZE=60> </FORM> <HR> </BODY> </HTML> Date bugs and gremlins Each new browser generation improves the stability and reliability of scripted date objects. Unfortunately, Navigator 2 has enough bugs and crash problems across many platforms to make scripting complex world-time applications for this browser impossible. The Macintosh version also has bugs that throw off dates by as much as a full day. I recommend avoiding NN2 on all platforms for serious date and time scripting. 983 Chapter 36 ✦ The Date Object The situation is much improved for NN3. Still, some bugs persist. One bug in particular affects Macintosh versions of NN3. Whenever you create a new date object with daylight saving time engaged in the Date and Time control panel, the browser automatically adds one hour to the object. See the time-based application in Chapter 54 for an example of how to counteract the effects of typical time bugs. Also afflicting the Macintosh in NN3 is a faulty calculation of the time zone offset for all time zones east of GMT. Instead of generating these values as negative numbers (getting lower and lower as you head east), the offset values increase continuously as you head west from Greenwich. While the Western Hemisphere is fine, the values continue to increase past the international date line, rather than switch over to the negative values. Internet Explorer 3 isn’t free of problems. It cannot handle dates before January 1, 1970 (GMT). Attempts to generate a date before that one result in that base date as the value. IE3 also completely miscalculates the time zone offset, following the erroneous pattern of Navigator 2. Even Navigators 3 and 4 have problems with historic dates. You are asking for trouble if the date extends earlier than January 1, A.D. 1. Internet Explorer 4, on the other hand, appears to sail very well into ancient history. You should be aware of one more discrepancy between Mac and Windows versions of Navigator through Version 4. In Windows, if you generate a date object for a date in another part of the year, the browser sets the time zone offset for that object according to the time zone setting for that time of year. On the Mac, the current setting of the control panel governs whether the normal or daylight saving time offset is applied to the date, regardless of the actual date within the year. This discrepancy affects Navigator 3 and 4 and can throw off calculations from other parts of the year by one hour. It may sound as though the road to Date object scripting is filled with land mines. While date and time scripting is far from hassle free, you can put it to good use with careful planning and a lot of testing. Validating Date Entries in Forms Given the bug horror stories in the previous section, you may wonder how you can ever perform data entry validation for dates in forms. The problem is not so much in the calculations as it is in the wide variety of acceptable date formats around the world. No matter how well you instruct users to enter dates in a particular format, many will follow their own habits and conventions. Moreover, how can you know whether an entry of 03/04/2002 is the North American March 4, 2002, or the European April 3, 2002? The answer: You can’t. My recommendation is to divide a date field into three components: month, day, and year. Let the user enter values into each field and validate each field individually for its valid range. Listing 36-5 shows an example of how this is done. The page includes a form that is to be validated before it is submitted. Each component field does its own range checking on the fly as the user enters values. But because this kind of validation can be defeated, the page includes one further check triggered by the form’s onSubmit event handler. If any field is out of whack, the form submission is canceled. 984 Part IV ✦ JavaScript Core Language Reference Listing 36-5: Date Validation in a Form <HTML> <HEAD> <TITLE>Date Entry Validation</TITLE> <SCRIPT LANGUAGE=”JavaScript”> <! // **BEGIN GENERIC VALIDATION FUNCTIONS** // general purpose function to see if an input value has been entered at all function isEmpty(inputStr) { if (inputStr == “” || inputStr == null) { return true } return false } // function to determine if value is in acceptable range for this application function inRange(inputStr, lo, hi) { var num = parseInt(inputStr, 10) if (num < lo || num > hi) { return false } return true } // **END GENERIC VALIDATION FUNCTIONS** function validateMonth(field, bypassUpdate) { var input = field.value if (isEmpty(input)) { alert(“Be sure to enter a month value.”) select(field) return false } else { input = parseInt(field.value, 10) if (isNaN(input)) { alert(“Entries must be numbers only.”) select(field) return false } else { if (!inRange(input,1,12)) { alert(“Enter a number between 1 (January) and 12 (December).”) select(field) return false } } } if (!bypassUpdate) { calcDate() } return true } function validateDate(field) { var input = field.value 985 Chapter 36 ✦ The Date Object if (isEmpty(input)) { alert(“Be sure to enter a date value.”) select(field) return false } else { input = parseInt(field.value, 10) if (isNaN(input)) { alert(“Entries must be numbers only.”) select(field) return false } else { var monthField = document.birthdate.month if (!validateMonth(monthField, true)) return false var monthVal = parseInt(monthField.value, 10) var monthMax = new Array(31,31,29,31,30,31,30,31,31,30,31,30,31) var top = monthMax[monthVal] if (!inRange(input,1,top)) { alert(“Enter a number between 1 and “ + top + “.”) select(field) return false } } } calcDate() return true } function validateYear(field) { var input = field.value if (isEmpty(input)) { alert(“Be sure to enter a year value.”) select(field) return false } else { input = parseInt(field.value, 10) if (isNaN(input)) { alert(“Entries must be numbers only.”) select(field) return false } else { if (!inRange(input,1900,2005)) { alert(“Enter a number between 1900 and 2005.”) select(field) return false } } } calcDate() return true } function select(field) { field.focus() field.select() } Continued 986 Part IV ✦ JavaScript Core Language Reference Listing 36-5 (continued) function calcDate() { var mm = parseInt(document.birthdate.month.value, 10) var dd = parseInt(document.birthdate.date.value, 10) var yy = parseInt(document.birthdate.year.value, 10) document.birthdate.fullDate.value = mm + “/” + dd + “/” + yy } function checkForm(form) { if (validateMonth(form.month)) { if (validateDate(form.date)) { if (validateYear(form.year)) { return true } } } return false } // > </SCRIPT> </HEAD> <BODY> <FORM NAME=”birthdate” ACTION=”mailto:fun@dannyg.com” METHOD=POST onSubmit=”return checkForm(this)”> Please enter your birthdate <BR> Month:<INPUT TYPE=”text” NAME=”month” VALUE=1 SIZE=2 onChange=”validateMonth(this)”> Date:<INPUT TYPE=”text” NAME=”date” VALUE=1 SIZE=2 onChange=”validateDate(this)”> Year:<INPUT TYPE=”text” NAME=”year” VALUE=1900 SIZE=4 onChange=”validateYear(this)”> <P> Thank you for entering:<INPUT TYPE=”text” NAME=”fullDate” SIZE=10><P> <INPUT TYPE=”submit”> <INPUT TYPE=”Reset”> </FORM> </BODY> </HTML> The page shows the three entry fields as well as a field that is normally hidden on a form to be submitted to a CGI program. On the server end, the CGI program responds only to the hidden field with the complete date, which is in a format for entry into, for example, an Informix database. Not every date entry validation must be divided in this way. For example, an intranet application can be more demanding in the way users are to enter data. Therefore, you can have a single field for date entry, but the parsing required for such a validation is quite different from that shown in Listing 36-5. See Chapter 43 for an example of such a one-field date validation routine. ✦✦✦ The Array Object A n array is the sole JavaScript data structure provided for storing and manipulating ordered collections of data. But unlike some other programming languages, JavaScript’s arrays are very forgiving as to the kind of data you store in each cell or entry of the array. This allows, for example, an array of arrays, providing the equivalent of multi- dimensional arrays customized to the kind of data your appli- cation needs. If you have not done a lot of programming in the past, the notion of arrays may seem like an advanced topic. But if you ignore their capabilities, you set yourself up for a harder job when implementing many kinds of tasks. Whenever I approach a script, one of my first thoughts is about the data being controlled by the application and whether handling it as an array will offer some shortcuts for creating the document and handling interactivity with the user. I hope that by the end of this chapter, you will not only be familiar with the properties and methods of JavaScript arrays, but you will begin to look for ways to make arrays work for you. Structured Data In programming, an array is defined as an ordered collec- tion of data. You can best visualize an array as a table, not much different from a spreadsheet. In JavaScript, arrays are limited to a table holding one column of data, with as many rows as needed to hold your data. As you have seen in many chapters in Part III, a JavaScript-enabled browser creates a number of internal arrays for the objects in your HTML docu- ments and browser properties. For example, if your document contains five links, the browser maintains a table of those links. You access them by number (with 0 being the first link) in the array syntax: the array name is followed by the index number in square brackets, as in document.links[0], which represents the first link in the document. For many JavaScript applications, you will want to use an array as an organized warehouse for data that users of your page access, depending on their interaction with form ele- ments. In the application shown in Chapter 50, for example, I demonstrate an extended version of this usage in a page that lets users search a small table of data for a match between the 37 37 CHAPTER ✦✦✦✦ In This Chapter Working with ordered collections of data Simulating multidimensional arrays Manipulating information stored in an array ✦✦✦✦ . canceled. 984 Part IV ✦ JavaScript Core Language Reference Listing 36-5: Date Validation in a Form <HTML> <HEAD> <TITLE>Date Entry Validation</TITLE> <SCRIPT LANGUAGE= JavaScript > <!. spreadsheet. In JavaScript, arrays are limited to a table holding one column of data, with as many rows as needed to hold your data. As you have seen in many chapters in Part III, a JavaScript- enabled. “.” document.write(header) </SCRIPT> <HR> </BODY> </HTML> The script divides the day into four parts and presents a different greeting for each part of the day. The greeting that plays is based, simply enough, on the

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