Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 12 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
12
Dung lượng
126,44 KB
Nội dung
Chapter 20. CompatibilityTechniques JavaScript, like Java, is one of a new breed of platform-independent languages. That is, you can develop a program in JavaScript and expect to run it unchanged in a JavaScript- enabled web browser running on any type of computer with any type of operating system. Though this is the ideal, we live in an imperfect world and have not yet reached that state of perfection. There are, and probably always will be, compatibility problems that JavaScript programmers must bear in mind. The one fact that we must always remember is that it is a heterogeneous network out there. Your JavaScript programs may run on three or more operating systems, using three or more versions of browsers from at least two different vendors. This can be difficult to keep in mind for those of us who come from the nonportable past, when programs were developed on a platform-specific basis. Remember: which platform you develop a program on doesn't matter. It may work fine on that platform, but the real test is whether it works (or fails gracefully) on all platforms on which it is used. The compatibility issues fall into two broad categories: platform-specific, browser- specific, and version-specific features on one hand; and bugs and language-level ity of JavaScript When developing production-quality JavaScript code, testing and knowledge of platform- ecific, vendor-specific, and version-specific incompatibilities are your chief allies. If you know, for example, that Netscape 2 on Macintosh platforms always gets the time wrong by about an hour, you can take steps to deal with this problem. If you know that Netscape 2 and 3 on Windows platforms do not automatically clear your setting of the se Knowledge of existing incompatibilities is crucial to writing compatible code. incompatibilities, including the incompatibil with non-JavaScript browsers, on the other. This chapter discusses techniques for coping with compatibility issues in both of these areas. If you've worked your way through all the previous chapters in this book, you are probably an expert JavaScript programmer, and you may already be writing serious JavaScript programs. Don't release those programs on the Internet (or onto a heterogeneous intranet) before you've read this chapter, though! 20.1 Platform and Browser Compatibility sp status line when the mouse moves off a hypertext link, you can provide an appropriate event handler to explicitly clear the status line. If you know that Internet Explorer 4 and Netscape 4 support vastly different Dynamic HTML models, you can write pages that u the appropriate mechanism depending on the browser in use. Unfortunately, producing a definitive listing of all known vendor, version, and platform incompatibilities would be an enormous task. It is beyond the scope and mission of this book, and it has apparently never even been seriously attempted. You may find some assistance on the Internet, but you will have to rely primarily on your own experience and testing. Once you have identified an area of incompatibility, however, there are a number ing sections. atibilities is to avoid them like the plague. For t of basic approaches you can take to coping with it, as described in the follow 20.1.1 The Least-Common-Denominator Approach One technique for dealing with incomp example, the Date object is notoriously buggy in Netscape 2. If you want Netscape 2 object ausers to be able to use your programs, you can simply avoid relying on the Date all. [1] [1] I don't actually recommend doing this. At the time of this writing, Netscape 2 is so far out of date that it is safe to ignore it. -denominator approach says tead, ou can create an equivalent property of your own whenever you open a new window: newwin = window.open("", "new", "width=500, height=300"); newwin.creator = self; If you consistently set a creator property for each new window you create, you can rely on that property instead of the nonportable opener property. (Another alternative, as we'll see later, is to give up on compatibility with Netscape 2 and require a browser that supports JavaScript 1.1 or later, as all such browsers support the opener property.) With this technique, you use only features that are known to work on all your target ut it 20.1.2 Defensive Coding code that contains . For example, s that ing with incompatibilities. If you want to ript that ted on the As another example, Netscape 3 and IE 3 both support the opener property of the Window object, but Netscape 2 does not. The least-common ld not use this property if compatibility with Netscape 2 is a goal. Insthat you shou y platforms. It doesn't allow you to write cutting-edge programs or push the envelope, b results in portable, safe programs that can serve many important functions. With the defensive coding approach to compatibility, you write platform-independent workarounds for platform-specific incompatibilities if you set the status property of a Window object from the onmouseover event handler to display a custom message in the status line, the status line is cleared when you move the mouse off the hyperlink, except in Windows versions of Netscape 2 and 3. To correct for this problem, you could get in the habit of including an onmouseout event handler to clear the status line. This precaution fixes the bug in current (and future) platform have it and doesn't do any harm on platforms that don't have the bug. 20.1.3 Feature Testing Feature testing is a powerful technique for cop use a feature that may not be supported by all browsers, include code in your sc tests to see whether that feature is supported. If the desired feature is not suppor current platform, either do not use it on that platform or provide alternative code that platforms. onsider again the opener property. In the least-common-denominator approach, we simply avoided the use of this property and used an alternative on all platforms. With the feature-testing approach, we provide the alternative only when the current platform does rks the existence of methods. For example, the split( ) method of the String d like to use uilt-in method on those platforms that do support it. Thus, our feature-testing is safe to invoke it ting is commonly used for performing DHTML effects that are supported only or are implemented differently in different browsers. For example, if fects, you can use feature testing ages) { // If the browser defines an images[] array, } // Otherwise, we simply omit the image rollover effect ure testing to see which API is supported by the current browser with code like this: OM API f (document.all) { // If the IE 4 API is supported, // do our DHTML using the IE 4 API } else if (document.layers) { // If the Netscape 4 API is supported, // do the DHTML effect (as best we can) using the Netscape 4 API } works on all C not support opener: newwin = window.open("", "new", "width=500, height=300"); if (!newwin.opener) newwin.opener = self; Note how we tested for the existence of the opener property. The same technique wo to test for object exists only for JavaScript 1.1 implementations. We can write our own version of this function that works in all versions of JavaScript, but for efficiency we' the fast, b code to split( ) a string might end up looking like this: if (s.split) // Check if the method exists, without invoking it a = s.split(":"); // If it does exist, it else // Otherwise: ion a = mysplit(s, ":"); // use our alternative implementat Feature tes on some browsers you are designing a site that includes image rollover ef with code like this: if (docu // we include image rollover code here ment.im As another example, suppose we want to work with a dynamically positioned document element. Different browsers have different APIs for doing this, so we first use feat if (document.getElementById) { // If the W3C DOM API is supported, // do our DHTML using the W3C D } else i else { // Otherwise, DHTML is not supported, // so provide a static alternative to DHTML, if we can } Feature testing is well suited to checking for support of large functional areas. You can API, s ence ed e The nice thing about the feature-testing technique is that it results in code that is not tied to a specific list of browser vendors or browser version numbers. It works with the set of browsers that exist today and should continue to work with future browsers, whatever feature sets they implement. 20.1.4 Platform-Specific Workarounds use it to determine whether a browser supports image rollovers or the W3C DOM for example. On the other hand, sometimes you may need to work around individual bug or quirks in a particular browser, and there may be no easy way to test for the exist of the bug. In this case, you will need to create a platform-specific workaround that is ti to a particular browser vendor, version, or operating system (or some combination of th three). Recall from Chapter 13 that the navigator property of the Window object provides information about the vendor and version of the browser and the operating system on which it is running. You can use this information to insert platform-specific code into your program. An example of a platform-specific workaround involves the bgColor property of the Document object. On Windows and Macintosh platforms, you can set this property at runtime to change the background color of a document. Unfortunately, when you do this on Unix versions of Netscape 2 and 3, the color changes but the document contents temporarily disappear. If you wanted to create a special effect using a changing background color, you could use the Netscape object to test for Unix platforms and simply skip the special effect for those platforms. The code could look like this: // Check whether we're running Netscape 2 or 3 on a Unix platform var nobg = (parseInt(navigator.appVersion) < 4) && // Version // If we're not, then go ahead and animate the page background color ommon to use " client-sniffer" code tform is, based (typically) on the properties of the and it sets variables that rse the properties of navigator for each platform-specific bit of code you write; you can simply use the variables set by (navigator.appName.indexOf("Netscape") != -1) && // Vendor (navigator.appVersion.indexOf("X11") != -1); // OS if (!nobg) animate_bg_color( ); When writing platform-specific workarounds, it is c to determine what the current pla navigator object. You run your client-sniffer code once, current platform. Then you don't have to repadescribe the the sniffer code. A simple sniffer that may be sufficient for many purposes might look like this: var browserVersion = parseInt(navigator.appVersion); var isNetscape = navigator.appName.indexOf("Netscape") != -1; var isIE = navigator.appName.indexOf("Microsoft") != -1; var agent = navigator.userAgent.toLowerCase( ); var isWindows = agent.indexOf("win") != -1; var isMac = agent.indexOf("mac") != -1; var isUnix = agent.indexOf("X11") != -1; With variables like these defined, you might write code like the following: if (isNetscape && browserVersion < 4 && isUnix) { r/browser_type.html // Work around a bug in Netscape 3 on Unix platforms here } A variety of prewritten client sniffers are available on the Internet. You can find a thorough one (along with a helpful discussion of its use) at http://www.mozilla.org/docs/web-developer/sniffe . Server-Side Scripts patibility is possible if your web application se of server-side scripts, such as CGI scripts or server-side JavaScript. A rogram on the server side can inspect the User-Agent field of the HTTP request header, which allows it to determine exactly what browser the user is running. With this s that do not require JavaScript at all. An important drawback to this approach is that a server-side script cannot detect when a user has disabled JavaScript support in her browser. d ring any incompatibility is, how important is smetic, affects a browser or platform that is not r affects only an out-of-date version of a browser, you might simply decide lem and let the users affected by it cope with it on their own. is 20.1.5 Compatibility Through Another platform-specific approach to com includes the u p information, the program can generate customized JavaScript code that is known to work correctly on that browser. Or, if the server-side script detects that the user's browser does not support JavaScript, it can generate web page Note that the topics of CGI programming and server-side scripting in general are beyon the scope of this book. 20.1.6 Ignore the Problem An important question to ask when conside it? If the incompatibility is minor or co widely used, o to ignore the prob For example, earlier I suggested defining an onmouseout event handler to correct for the fact that Netscape 2 and 3 for Windows do not correctly clear the status line. Netscape 2, so thUnfortunately, the onmouseout event handler is not supported in workaround won't work for that platform. If you expect your application to have a lot of etscape 2 on Windows and you think that it is really important to get that status line cleared, you'll have to develop some other workaround. You could use setTimeout( ) in your onmouseover event handler to arrange for the status line to be cleared in two seconds. But this solution brings problems with it: what if the mouse is still over the hypertext link and the status line shouldn't be cleared in two seconds? In this case, a simpler approach might be to simply ignore the problem. This approach can easily be justified, because Netscape 2 is by now well out of date; any users still relying on it should be encouraged to upgrade. lly inally, there are some incompatibilities that cannot be ignored and cannot be worked round. In these cases, your program should work correctly on all platforms, browsers, nd versions that provide the needed features and fail gracefully on all others. Failing racefully means recognizing that the required features are not available and informing e user that he will not be able to use your JavaScript program. ple, the image-replacement technique we saw during the discussion of images in hapter 14 users who use N 20.1.7 Fail Gracefu F a a g th For exam C does not work in Netscape 2 or Internet Explorer 3, and there is really no ulate it. Therefore, we should not even attempt to run the rogram on those platforms; instead, we should politely notify the user of the compatibility. Much of the rest of this chapter explains chniques for doing so. The previous section discussed general compatibilitytechniques that are useful for oping with incompatibilities between different versions of browsers from different vendors running on different platforms. This section addresses another compatibility oncern: how to use new features of the JavaScript language in a way that does not cause errors on browsers that do not support those features. Our goals are simple: we need to prevent JavaScript code from being interpreted by browsers that don't understand it, and we need to display special messages on those browsers that inform users that their rowsers cannot run the scripts. 0.2.1 The language Attribute he first goal is easy. As we saw in Chapter 12 workaround that can sim p in Failing gracefully can be harder than it sounds. te 20.2 Language Version Compatibility c c b 2 T , we can prevent a browser from attempting to run code that it cannot understand by setting the language attribute of the script> tag appropriately. For example, the following <script> tag specifies that the code it contains uses features of JavaScript 1.1 and that browsers that do not support that ersion of the scripting language should not attempt to run it: < v <script language="JavaScript1.1"> // JavaScript 1.1 code goes here </script> at Unfortunately, the language attribute is marred by the fact that specifying language="JavaScript1.2" causes Netscape to behave in ways that are incompatible with the ECMA-262 standard. For example, as we saw in Chapter 5 Note that the use of the language attribute is a general technique. When set to the string "JavaScript1.2", the attribute prevents JavaScript 1.0 or 1.1 browsers from attempting to run the code. At the time of this writing, the latest browsers (Netscape 6 and IE 6) support language versions 1.0, 1.1, 1.2, 1.3, 1.4, and 1.5. If you write JavaScript code th includes the try/catch exception-handling statement, for example, you should include it in a <script> tag with language="JavaScript1.5" to prevent browsers that do not understand this statement from trying to run it. , setting the language attribute to this value causes the == operator to perform equality comparisons without doing any type conversions. And as we saw in Chapter 8, specifying "JavaScript1.2" also causes the toString( ) method to behave quite differently. Unless you explicitly want these new, incompatible behaviors, or unless you can carefully avoid all incompatible features, you should avoid the use of language="JavaScript1.2". ute rs or e t age. Example 20-1 Note that the version numbers used by the language attribute match the version numbers of Netscape's (and now Mozilla's) JavaScript interpreter. Microsoft's interpreter has more or less followed the evolution of Netscape's, but bear in mind that the language attrib is still somewhat vendor-specific: the language features supported by different vendo for a given version number are not guaranteed to be the same. This is particularly so f language="JavaScript1.2", but caution is advisable for other versions as well. Unfortunately, there is no way to specify a specification version with the language attribute. That is, you cannot write: <script language="ECMAScript3"> .</script> 20.2.2 Explicit Version Testing The language attribute provides at least a partial solution to the problem of language version compatibility, but it solves only half of the problem. We also need to be able to fail gracefully for browsers that do not support the desired version of JavaScript. If w require JavaScript 1.1, we'd like to be able to notify users of JavaScript 1.0 browsers tha they cannot use the p shows how we can do this. ort --> Example 20-1. A message for browsers that do not support JavaScript 1.1 <!-- Set a variable to determine what version of JavaScript we supp --> <!-- This technique can be extended to any number of language versions <script language="JavaScript"> var _version = 1.0; </script> <script language="JavaScript1.1"> _version = 1.1; </script> <script language="JavaScript1.2"> _version = 1.2; </script> <!-- Run this code on any JavaScript-enabled browser --> <!-- If the version is not high enough, display a message --> <script language="JavaScript"> if (_version < 1.1) { document.write('<hr><h1>This Page Requires JavaScript 1.1</h1>'); document.write('Your JavaScript 1.0 browser cannot run this page.<hr>'); } </script> <!-- Now run the actual program only on JavaScript 1.1 browsers --> <script language="JavaScript1.1"> // The actual JavaScript 1.1 code goes here </script> 20.2.3 Suppressing Version-Related Errors Example 20-1 showed how we can write JavaScript 1.1 code that JavaScript 1.0 browse do not attempt to execute. What if we wanted to write JavaScript 1.2 code that JavaScri 1.1 browsers do not attempt to execute? We could use the language attribute to explicitly specify "JavaScript1.2", but as we discussed earlier, this causes Netscape to behave incompatibly. Unfortunately, JavaScript 1.2 adds a lot of new syntax to the language. If you write code that uses a switch statement, an object initializer, or a function liter then run that code on a JavaScript 1.1 browser, you'll cause runtime syntax errors. rs pt al and One way to work around this problem is simply to suppress any errors that occur on JavaScript 1.1 browsers. Example 20-2 shows how this can be done using the onerror error handler of the Window object (which was described in Chapter 13). display --> <!-- an error message and suppress any syntax errors that occur. --> <script language="JavaScript1.1"> // If JavaScript 1.2 is not supported, fail gracefully function suppressErrors( ) { return true; } if (!_js12_) { window.onerror = suppressErrors; alert("This program requires a browser with JavaScript 1.2 support"); } Example 20-2. Suppressing version-related errors <!-- Check whether JavaScript 1.2 is supported --> <script language="JavaScript1.2">var _js12_ = 1.2</script> <!-- Now avoid the problems with JavaScript 1.2 on Netscape by running --> <!-- the following code on any browser that supports JavaScript 1.1. If --> <!-- the browser does not support JavaScript 1.2, however, we'll // Now proceed with the JavaScript 1.2 code </script> 20.2.4 Loading a New Page for Compatibility Another approach to version compatibility is to load a web page that requires a specific level of JavaScript support only after determining whether the browser provides that level of support. Example 20-3 shows how this might be done with a short script that tests whether JavaScript 1.2 is supported. If the browser supports this version, the script uses the Location.replace( ) method to load in a new web page that requires JavaScript 1.2. If JavaScript 1.2 is not supported, the script displays a message saying that it is required. Examp <head> <scrip // If JavaScript 1.2 is supported, extract a new URL from the portion of // our URL following the question mark, and load in that new URL location.replace(location.search.substring(1)); // Enter a really long, empty loop, so that the body of this document // doesn't get displayed while the new document is loading for(var i = 0; i < 10000000; i++); </script> </head> <body> <hr size="4"> <h1>Th Your b supports JavaScript 1.2, such as Netscape 4 or Internet Explorer 4. <hr i </b y The mo JavaSc d in the search portion of the original URL; that file is loaded only if JavaScript 1.2 is supported. Thus, if the file in this example has the ne shown in this hyperlink: le 20-3. A web page to test for JavaScript compatibility t language="JavaScript1.2"> is Page Requires JavaScript 1.2</h1> rowser cannot run this page. Please upgrade to a browser that s ze="4"> od > st interesting thing about this example is that it is a generic one -- the name of the ript 1.2 file to be loaded is encode name testjs12.html, you can use it in URLs like the o <a href="http://my.isp.net/~david/utils/testjs12.html? /js/cooljs12.html" > Visit my cool JavaScript 1.2 page! </a> The other thing to note about Example 20-3 is that calling Location.replace( ) starts a new page loading but does not immediately stop the current page from loading. Therefore, the JavaScript code in this example enters a long, empty loop after it calls replace( ). This prevents the rest of the document from being parsed and displayed, s that users of JavaScript 1.2 browsers do not see the message intended for users of o browsers that do not support JavaScript 1.2. Finally, note that the technique shown in Example 20-3 is useful not only to distinguish one version of JavaScript from another, but also to distinguish between browsers that support JavaScript and those that do not. The next section discusses other compatibilitytechniques that are useful with non-JavaScript browsers. 20.3 Compatibility with Non-JavaScript Browsers The previous section discussed compatibility with browsers that do not support a particular version of JavaScript. This section considers compatibility with browsers that do not support JavaScript at all. These are either browsers that have no JavaScript capability or browsers in which the user has disabled JavaScript (which some users do because of security concerns). Because a number of such browsers are still in use, you should design your web pages to fail gracefully when read into browsers that do not understand JavaScript. There are two parts to doing this: first, you must take care to ensure that your JavaScript code does not appear as if it were HTML text; and second, you should arrange to display a message informing the visitor that her browser cannot correctly handle the page. wever (and there are still some out there), at they ignore the to be displayed. Unless you take steps to prevent it, users of these old browsers see your JavaScript code 20.3.1 Hiding Scripts from Old Browsers Web browsers that support JavaScript execute the JavaScript statements that appear between the <script> and </script> tags. Browsers that don't support JavaScript but recognize the <script> tag simply ignore everything between <script> and </script>. This is as it should be. Really old browsers, ho do not even recognize the <script> and </script> tags. This means th tags themselves and treat all the JavaScript between them as HTML text formatted into big meaningless paragraphs and presented as web page content! To prevent this, enclose the body of your script within an HTML comment, using the format shown in Example 20-4. Example 20-4. A script hidden from old browsers <script language="JavaScript"> <!-- Begin HTML comment that hides the script // JavaScript statements go here // . // . // End HTML comment that hides the script --> </script> . compatibility techniques that are useful with non-JavaScript browsers. 20.3 Compatibility with Non-JavaScript Browsers The previous section discussed compatibility. user of the compatibility. Much of the rest of this chapter explains chniques for doing so. The previous section discussed general compatibility techniques