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

ASP.NET AJAX Programmer’s Reference - Chapter 24 ppsx

96 235 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Asynchronous Partial Page Rendering: Client-Side Processing
Trường học University of Technology Ho Chi Minh City
Chuyên ngành Computer Science
Thể loại Lecture Note
Năm xuất bản 2007
Thành phố Ho Chi Minh City
Định dạng
Số trang 96
Dung lượng 625,95 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

if parserErrorDetails{ this._endPostBackthis._createPageRequestManagerParserError String.formatSys.WebForms.Res.PRM_ParserErrorDetails, parserErrorDetails, sender; return; } Next, th

Trang 1

Asynchronous Par tial Page Rendering: Client-Side

Processing The previous chapter followed the Page through its life cycle phases to process the asynchronous page postback request made by the current client-side PageRequestMananger instance We followed the request from the time it arrived in ASP.NET to the time the server response text was finally sent back to the client

This chapter will move on to the client side, where this server response text arrives, and follow the client-side PageRequestManager instance through its life cycle phases to process the server response

Arrival of the Ser ver Response Text

Recall from Listing 22-22 that the _onFormSubmit method of the current client-side

PageRequestManager instance is where the current client-side PageRequestManager instance made its asynchronous page postback to the server Listing 24-1 presents a portion of the

_onFormSubmit method As the highlighted portion of this code listing shows, the current client-side PageRequestManager instance registers its _onFormSubmitCompleted method as

an event handler for the completed event of the WebRequest object that represents the current request

request.add_completed(Function.createDelegate(this, this._onFormSubmitCompleted));

As the name suggests, the WebRequest object fires its completed event when the current request

is finally completed

Trang 2

var count = form.elements.length;

for (var i = 0; i < count; i++)

Recall from Listing 12-41 of Chapter 12 that when the request is finally completed, the

_onReadyStateChange method of the current XMLHttpExecutor is invoked, as shown again in

Listing 24-2 As you can see from the highlighted portion of this code listing, the _onReadyStateChange

method invokes the completed method on the WebRequest object that represents the current request

Listing 24-2: The _onReadyStateChange Method

Trang 3

Recall from Listing 12-11 of Chapter 12 that the completed method of the WebRequest object in turn calls the event handlers registered for the completed event of the WebRequest object, as shown again in the highlighted portion of Listing 24-3

Listing 24-3: The Completed Method

function Sys$Net$WebRequest$completed(eventArgs) {

var handler = Sys.Net.WebRequestManager._get_eventHandlerList().getHandler(

“completedRequest”);

if (handler) handler(this._executor, eventArgs);

handler = this._get_eventHandlerList().getHandler(“completed”);

if (handler) handler( this._executor, eventArgs);

}

As the boldface portion of Listing 24-3 shows, when the completed method of the WebRequest object invokes the event handlers registered for its completed event, it passes a reference to the

WebRequestExecutor object responsible for executing the current request This means that the first parameter of the _onFormSubmitCompleted method of the current client-side PageRequestManager instance references this WebResquestExecutor object You’ll see the internal implementation of the

_onFormSubmitCompleted method later in the chapter

As I mentioned earlier, our goal in this chapter is to follow the current PageRequestMananger instance through its life cycle phases to process the server response Since the current PageRequestManager instance’s life cycle is rather complex and involves a lot of method calls, I’ve captured almost all of them

in a two-part diagram shown in Figures 24-1 and 24-2 to make it easier for you to follow our discussions The vertical axis in this two-part diagram measures increasing time (early on the top, late on the bottom)

Keep this two-part diagram in mind as you’re reading through this chapter Also keep in mind where we are on this diagram at every stage of the current PageRequestManager instance’s life cycle

As you can see from Listing 24-3 , the _onFormSubmitCompleted method of the current

PageRequestManager instance sets the _processingRequest field on the current side PageRequestManager instance to true to signal that the request is now being processed:

this._processingRequest = true;

Just because the WebRequest object has fired the completed event and consequently called the

_onFormSubmitCompleted method does not mean that everything went fine and the server response has arrived The WebRequest object fires the completed event for a number of reasons Therefore, the

_onFormSubmitCompleted method takes the following steps to determine why the completed event was raised First, it calls the get_timedOut method on the WebRequestExecutor object to return a

Trang 4

Boolean value that specifies whether the completed event was raised because of a timeout If so, it calls

the _endPostBack method on the current PageRequestManager instance to end the ongoing

asynchro-nous postback request and returns the following:

Next, it calls the get_aborted method on the WebRequestExecutor to return a Boolean value that

specifies whether the completed event was raised because the request aborted If so, it calls the

_endPostBack method on the current PageRequestManager instance to end the ongoing request

and returns this:

WebRequestExecutor to return a reference to the WebRequest object that represents the request that

the WebRequestExecutor executed It then compares this with the WebRequest object that the

_childUpdatePanelIDs _panelsToRefreshIDs

EventHandlerList

_endPostBack () _onFormSubmitCompleted ()

_endPostBack ()

get_timedOut () get_aborted () get_statusCode ()

_endPostBack ()

get_responseData ()

_endPostBack ()

add (dataItem) getHandler (‘‘pageLoading’’)

_endPostBack ()

innerHTML = htmlMarkup

_updateControls (updatePanelIDs, asyncPostBackControlIDs, postBackControlIDs, asyncPostBackTimeout) _endPostBack ()

_updatePanel (updatePanelID, htmlMarkup)

get_webRequest ()

add(updatePanelID)

window _dataItems

eval (_scriptDisposes[updatePanelID]) _destroyTree (updatePanel ID)

Trang 5

of Listing 24-1 shows, the current PageRequestManager instance assigns the WebRequest object to

an internal field named _request before it executes the request.) If these two WebRequest objects are different, the completed event was raised for a different request and consequently the

_onFormSubmitCompleted method simply returns this:

if (!this._request || sender.get_webRequest() !== this._request) return;

As you can see, if an application makes several overlapping asynchronous page postback requests to the server, the last request wins

Next, the _onFormSubmitCompleted method calls the get_statusCode method on the

WebRequestExecutor object to return an integer that contains the response status code If this code

is not 200 , it is an indication that a server error occurred, and consequently the method calls the

_endPostBack method on the current PageRequestManager instance to end the current request and returns this:

if (sender.get_statusCode() !== 200) {

this._endPostBack(

this._createPageRequestManagerServerError(sender.get_statusCode()), sender); return;

}

PageRequestManager _scriptDisposes

[updatePanelID] _registerDisposeScript (updatePanelID, disposeScript) add (disposeScript)

_loadScriptsInternal () nextScript = dequeue ()

WebForm AutoFocus (controlIDToFocus) scrollTo (_scrollPosition.x,_scrollPosition.y)

add (arrayScript) add (expandoScript) add (scriptUrl) add (scriptAttributes) add (onSubmitStatementScript) queueCustomScriptTag (scriptAttributes)

queueScriptBlock (onSubmitStatementScript)

_pageLoaded () scriptElement = _createScriptElement (nextScript)

Trang 6

var reply = sender.get_responseData();

Recall from Listing 23-52 that the server response text is a string that contains a bunch of substrings in

the format length|type|id|content , where:

❑ The length part tells the current client-side PageRequestManager instance how many

characters there are in the content part of the substring

❑ The type part tells the current client-side PageRequestManager instance what type of

information the content part contains

❑ The optional id part specifies the ClientID property value of the server control associated with

the information contained in the content part

❑ The content part contains the actual information that the current server-side

PageRequestManager instance has sent to the current client-side PageRequestManager

instance

Listing 24-4 contains an example of a server response text that the current server-side PageRequestManager

instance sends to the current client-side PageRequestManager instance Keep this code listing in mind as

we’re walking through the implementation of the _onFormSubmitCompleted method The main

responsibility of this method is to parse a response text similar to Listing 24-4

Listing 24-4: An Example of a Server Response Text that the Current Client-Side

PageRequestManager Might Receive

Trang 7

|hiddenField| EVENTVALIDATION|/wEWBAKj4cTUAgLs0bLrBgLs0fbZDAKM54rGBv6aI9H0BYIx273PdOWCCpAOOHzF|0|asyncPostBackControlIDs|||0|postBackControlIDs|||13|updatePanelIDs||tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPostBackTimeout||90|12|formAction||Default.aspx|13|pageTitle||Untitled Page

The _onFormSubmitCompleted method recursively takes the following steps to parse each substring in the server response string:

❑ It accesses the index of the first delimiter | character of the substring:

delimiterIndex = reply.indexOf(‘|’, replyIndex);

❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls another method named _findText , stores the return value of this method in a local field named

parserErrorDetails , and exits the while loop that loops through the substrings in the server response string In other words, it does not attempt to parse the rest of the server response string There is no point in processing an erroneous server response As you’ll see shortly, the first statement after this while loop checks whether the value of the parserErrorDetails field is set If so, it takes the appropriate action to end the current request

if (delimiterIndex === -1) {

parserErrorDetails = this._findText(reply, replyIndex);

break;

}

❑ The following code listing presents the implementation of the _findText method:

function Sys$WebForms$PageRequestManager$_findText(text, location){

var startIndex = Math.max(0, location - 20);

var endIndex = Math.min(text.length, location + 20);

return text.substring(startIndex, endIndex);

} ❑ The _onFormSubmitCompleted method parses the first part (that is, the length part) of the substring:

len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);

replyIndex = delimiterIndex + 1;

❑ It accesses the index of the second delimiter:

delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls the

_findText method, stores the return value of this method in the parserErrorDetails local field, and exits the while loop, as discussed earlier

Trang 8

parserErrorDetails = this._findText(reply, replyIndex);

❑ It accesses the index of the third delimiter | :

delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls the

_findText method, stores the return value of this method in the parserErrorDetails local

field, and exits the while loop, as discussed earlier

❑ Recall that the len local field contains the length of the content part of the substring

_onFormSubmitCompleted first checks whether the index of the expected last character of the

content part of the substring is a value that exceeds the length of the substring If so, this is an

indication that the server response has problems and consequently _onFormSubmitCompleted

takes the same steps discussed earlier and exits the while loop

if ((replyIndex + len) >= reply.length)

{

parserErrorDetails = this._findText(reply, reply.length);

break;

}

❑ The _onFormSubmitCompleted method accesses the fourth part (that is, the content part) of

the substring (Note that the length of the fourth part is given by the first part of the

length|type|id|content format.)

content = this._decodeString(reply.substr(replyIndex, len));

replyIndex += len;

Trang 9

❑ Next, _onFormSubmitCompleted checks whether the last character of the substring is the delimiter character (|) If not, this is an indication that the server response has problems and consequently _onFormSubmitCompleted method takes the same steps discussed earlier and exits the while loop

if (reply.charAt(replyIndex) !== delimitByLengthDelimiter) {

parserErrorDetails = this._findText(reply, replyIndex);

break;

} ❑ The _onFormSubmitCompleted method creates an object literal with three name/value pairs The name part of the first pair is the word type and its value part is the second part of the substring (that is, the type part) The name part of the second name/value pair is the word id and its value part is the third part of the substring (that is, the id part) The name part of the third name/value pair is the word content and its value part is the fourth part of the substring (that is, the content part)

var obj = {type: type, id: id, content: content};

❑ The _onFormSubmitCompleted method stores the above object literal in a local array named

delta

Array.add(delta, obj);

As you can see, the _onSubmitFormCompleted method parses each substring (in the

length|type|id|content format) into an object literal and stores the object in a local array named delta

After existing the while loop, the _onSubmitFormCompleted method first checks whether the value of the parseErrorDetails local field is set If so, this is an indication that the server response had some problems and consequently _onSubmitFormCompleted invokes the _endPostBack method to end the current asynchronous page postback request

if (parserErrorDetails){

this._endPostBack(this._createPageRequestManagerParserError(

String.format(Sys.WebForms.Res.PRM_ParserErrorDetails, parserErrorDetails)), sender);

return;

}

Next, the method iterates through the object literals in the delta array and checks the value of the type property of each enumerated object (recall that the value associated with the type property of the object contains the second part of the length|type|id|content format):

❑ If the type is the string “updatePanel” , the _onFormSubmitCompleted method adds the enumerated object to a local array named updatePanelNodes The value of the id property of this object is a string that contains the value of the UniqueID property of an UpdatePanel

Trang 10

case “updatePanel”:

Array.add(updatePanelNodes, deltaNode);

break;

❑ If the type is the string “hiddenField” , the _onFormSubmitCompleted method adds the

enumerated object to a local array named hiddenFieldNodes The value of the id property of

this object is a string that contains the name of the hidden field and the value of the content

property is a string that contains the value of the hidden field

case “hiddenField”:

Array.add(hiddenFieldNodes, deltaNode);

break;

❑ If the type is the string “arrayDeclaration” , the _onFormSubmitCompleted method adds

the enumerated object to a local array named arrayDeclarationNodes This object describes

an array declaration in which the value of the id property of the object is a string that contains

the name of the JavaScript array The value of the content property of this object is a string that

contains the value being added to the array

case “arrayDeclaration”:

Array.add(arrayDeclarationNodes, deltaNode);

break;

❑ If the type is the string “scriptBlock” , the _onFormSubmitCompleted method adds the

enumerated object to a local array named scriptBlockNodes This object describes a script

block in which the value of the id property of the object is one of the following string values:

“ScriptContentNoTags” , “ScriptContentWithTags” , or “ScriptPath”, and in which the

value of the content property is a string that contains the associated script block:

case “scriptBlock”:

Array.add(scriptBlockNodes, deltaNode);

break;

❑ If the type is the string “expando” , the _onFormSubmitCompleted method adds the

enumerated object to a local array named expandoNodes This object describes an expando

attribute in which the value of the id property of the object is a string that contains the name of

the expando attribute, and the value of the content property is a string that contains the value

of the expando attribute

case “expando”:

Array.add(expandoNodes, deltaNode);

break;

❑ If the type is the string “onSubmit” , the _onFormSubmitCompleted method adds the

enumer-ated object to a local array named onSubmitNodes This object describes a dynamically added

form onsubmit statement in which the value of the id property of the object is an empty string

and the value of the content property of the object is a string that contains the dynamically

Trang 11

is a string that contains a comma-separated list of substrings, each substring containing the value of the UniqueID property of a server control that causes a synchronous page postback

UpdatePanel server controls on the current page The value of the id property of this object is

an empty string, and the value of the content property is a string that contains a separated list of substrings, each substring containing the value of the UniqueID property of an

comma-UpdatePanel server control

case “asyncPostBackTimeout”:

asyncPostBackTimeoutNode = deltaNode;

break;

Trang 12

describes all the child UpdatePanel server controls on the current page that need updating

because their parent UpdatePanel server controls need updating The value of the id property

of this object is an empty string, and the value of the content property is a string that contains a

comma-separated list of substrings, each substring containing the value of the UniqueID

property of a child UpdatePanel server control

case “childUpdatePanelIDs”:

childUpdatePanelIDsNode = deltaNode;

break;

❑ If the type is the string “panelsToRefreshIDs” , the _onFormSubmitCompleted method

assigns the enumerated object to a local field named panelsToRefreshNode This object

describes all the UpdatePanel server controls on the current page that need updating The

value of the id property of this object is an empty string, and the value of the content property

is a string that contains a comma-separated list of substrings, each substring containing the

value of the UniqueID property of an UpdatePanel server control

case “panelsToRefreshIDs”:

panelsToRefreshNode = deltaNode;

break;

❑ If the type is the string “formAction” , the _onFormSubmitCompleted method assigns the

enumerated object to a local field named formActionNode This object describes the current

form action The value of the id property of this object is an empty string, and the value of the

content property is a string that contains the value of the action property of the form

case “formAction”:

formActionNode = deltaNode;

break;

❑ If the type is the string “dataItem” , the _onFormSubmitCompleted method adds the

enumer-ated object to a local array named dataItemNodes This object describes a data item associated

with a server control The value of the id property of the object is the value of the ClientID

property of the server control, and the value of the content property is a string that contains

the string representation of the data item For example, this string representation could be an

XML representation of the data item

case “dataItem”:

Array.add(dataItemNodes, deltaNode);

break;

❑ If the type is the string “dataItemJson” , the _onFormSubmitCompleted method adds the

enumerated object to a local array named dataItemJsonNodes This object describes a data

item associated with a server control The value of the id property of the object is the value of

the ClientID property of the server control, and the value of the content property is a string

that contains the JSON representation of the data item

case “dataItemJson”:

Trang 13

❑ If the type is the string “scriptDispose” , the _onFormSubmitCompleted method adds the enumerated object to a local array named scriptDisposeNodes This object describes a script that contains a call into a dispose method associated with an UpdatePanel server control The value of the id property of the object is the value of the ClientID property of the UpdatePanel server control, and the value of the content property is a string that contains the calls into the

Sys.WebForms.PageRequestManager.getInstance()._registerDisposeScript(“UpdatePanel1” ,”$find(‘UpdatePanel1’).dispose();”);

❑ If the type is the string “pageRedirect” , the _onFormSubmitCompleted method assigns the value of the content property of the enumerated object to the href property of the location property of the window object As you can see, the value of the content property of this object is

a string that contains the URL to which the current window will be redirected:

case “pageRedirect”:

window.location.href = deltaNode.content;

return;

❑ If the type is the string “error” , the enumerated object describes a server error: the value of the

id property of the object is a string that contains the number associated with the error, and the value of the content property of the object is a string that contains the error message As you can see, the _onFormSubmitCompleted method calls the _endPostBack method on the current

PageRequestManager instance to end the current request:

content property to the title property of the document object

case “pageTitle”:

document.title = deltaNode.content;

break;

Trang 14

the content property is a string that contains the value of the ClientID property of the server

control that must have the focus As you can see, the _onFormSubmitCompleted method

assigns the value of the content property of the object to the _controlIDToFocus field of the

current PageRequestManager instance:

case “focus”:

this._controlIDToFocus = deltaNode.content;

break;

❑ If the type is none of the preceding strings, the _onFormSubmitCompleted method calls the

_endPostBack method on the current PageRequestManager instance to end the current

Next, the _onFormSubmitCompleted method stores the contents of the _updatePanelIDs array in the

_oldUpdatePanelIDs array field of the current PageRequestManager instance:

this._oldUpdatePanelIDs = this._updatePanelIDs;

Then the method uses the childUpdatePanelIDsNode to populate the _childUpdatePanelIDs array

of the current PageRequestManager instance Keep in mind that this array contains the value of the

UniqueID properties of the UpdatePanel server controls that need updating because their parent

UpdatePanel server control needs updating:

var childUpdatePanelIDsString = childUpdatePanelIDsNode.content;

this._childUpdatePanelIDs =

childUpdatePanelIDsString.length ? childUpdatePanelIDsString.split(‘,’) : [];

Next, the method uses the panelsToRefreshNode to populate the _panelsToRefreshIDs array of the

current PageRequestManager instance Keep in mind that this array contains the value of the UniqueID

properties of the UpdatePanel server controls that need updating:

this._panelsToRefreshIDs = this._splitNodeIntoArray(panelsToRefreshNode);

Next the method iterates through the UniqueID property values in the _panelsToRefreshIDs array,

passes each enumerated value into the _uniqueIDToClientID method to return the value of its

associated ClientID property, and finally calls the getElementById method, passing in this ClientID

property value to check whether the current page contains an UpdatePanel server control with the

specified UniqueID and ClientID property values If not, it calls the _endPostBack method to end the

current request:

Trang 15

for (i = 0; i < this._panelsToRefreshIDs.length; i++) {

var panelClientID = this._uniqueIDToClientID(this._panelsToRefreshIDs[i]);

if (!document.getElementById(panelClientID)) {

this._endPostBack(Error.invalidOperation(

String.format(Sys.WebForms.Res.PRM_MissingPanel, panelClientID)), sender); return;

} }

Next, the _onFormSubmitCompleted method calls the _splitNodeIntoArray method of the

PageRequestManager three times to convert asyncPostBackControlIDsNode ,

postBackControlIDsNode , and updatePanelIDsNode into arrays:

var asyncPostBackControlIDsArray = this._splitNodeIntoArray(asyncPostBackControlIDsNode); var postBackControlIDsArray = this._splitNodeIntoArray(postBackControlIDsNode); var updatePanelIDsArray = this._splitNodeIntoArray(updatePanelIDsNode);

var asyncPostBackTimeout = asyncPostBackTimeoutNode.content;

Next, it calls the _updateControls method on the current PageRequestManager instance, passing in the following parameters:

❑ updatePanelIDsArray : This parameter is an array that contains the values of the UniqueID properties of all UpdatePanel server controls on the current page after the update I say “after the update” because this array has just arrived from the server Because of this, the content

of the _updatePanelIDs array of the current PageRequestManager instance could be out of date: the server code may have added a new UpdatePanel server control or deleted an existing

UpdatePanel server control

❑ asyncPostBackControlIDsArray : This parameter is an array that contains the values of the

UniqueID properties of all the server controls on the current page that cause asynchronous page postbacks

❑ postBackControlIDsArray : This parameter is an array that contains the values of the

UniqueID properties of all the server controls on the current page that cause normal synchronous page postbacks

❑ asyncPostBackTimeout : This parameter is a string that contains the timeout value for asynchronous page postbacks:

this._updateControls(updatePanelIDsArray, asyncPostBackControlIDsArray, postBackControlIDsArray, asyncPostBackTimeout);

I thoroughly discussed the _updateControls method of the PageRequestManager in Chapter 22

Next, the _onFormSubmitCompleted method iterates through the objects in the dataItemNodes array (recall that this array contains all the objects that represent data items) and uses the value of the id property of each enumerated object as an index into the _dataItems collection of the current

Trang 16

contains the string representation of the data item associated with the server control whose UniqueID

property value is given by the value of the id property of the enumerated object In other words, each

item in the _dataItems collection of the current PageRequestManager instance contains the string

representation of a data item associated with a server control that has a specified UniqueID

Next, the _onFormSubmitCompleted method iterates through the objects in the dataItemJsonNodes

array (recall that this array contains all the objects that represent JSON data items) and uses the value of

the id property of each enumerated object as an index into the _dataItems collection of the current

PageRequestManager instance to store the value of the content property of the enumerated object into

the collection Recall that the value of the content property of the enumerated object is a string that

contains the JSON representation of the data item associated with the server control whose UniqueID

property value is given by the value of the id property of the enumerated object:

for (i = 0; i < dataItemJsonNodes.length; i++)

{

var dataItemJsonNode = dataItemJsonNodes[i];

this._dataItems[dataItemJsonNode.id] = eval(dataItemJsonNode.content);

}

Next, the _onFormSubmitCompleted method calls the get_eventHandlerList method on the current

PageRequestManager instance to return a reference to the EventHandlerList that contains all the

event handlers registered for the events of the PageRequestManager instance Then it calls the

getHandler method on this EventHandlerList to return a reference to a JavaScript function whose

invocation automatically invokes all the event handlers registered for the pageLoading event of the

current PageRequestManager instance:

var handler = this._get_eventHandlerList().getHandler(“pageLoading”);

Next, it calls the _getPageLoadingEventArgs method on the current PageRequestManager instance to

instantiate and return a PageLoadingEventArgs object As you’ll see later, the PageLoadingEventArgs

is the event data class for the pageLoading event of the PageRequestManager class:

var Sys.WebForms.PageLoadingEventArgs args = this._getPageLoadingEventArgs();

Then it calls the previously mentioned JavaScript function and consequently all the event handlers

registered for the pageLoading event of the current PageRequestManager instance, passing in a

reference to the current PageRequestManager instance and the PageLoadingEventArgs object:

handler(this, args);

Trang 17

If you register an event handler for the pageLoading event of the current PageRequestManager instance, your event handler will receive the previously mentioned two references Your handler can then use these two references to get the complete information about the current request and use this information to perform application-specific page-loading tasks

Next, the _onFormSubmitCompleted method checks whether the formActionNode local variable is

null Recall that this variable references the object that describes the action property of the current form If the variable is not null , the method assigns the value of the content property of this object to the action property of the form You may be wondering why an asynchronous page postback may end

up changing the action property of the current form This normally happens when cookieless sessions are used, in which the session ID is embedded in the target URL, which changes the action value:

if (formActionNode) this._form.action = formActionNode.content;

Next, the method iterates through the objects in the updatePanelNodes array (recall that each object in this array describes an UpdatePanel server control that needs updating) and takes the following steps for each enumerated object First, it calls the getElementById method on the document object, passing

in the value of the id property of the enumerated object Recall that the value of this property is a string that contains the value of the ClientID property of the UpdatePanel server control that the object describes Therefore, the getElementById method returns a reference to the DOM element associated with the UpdatePanel server control:

var deltaUpdatePanel = updatePanelNodes[i];

var updatePanelElement = document.getElementById(deltaUpdatePanel.id);

If the current page does not contain a DOM element associated with the UpdatePanel server control, the _onFormSubmitCompleted method calls the _endPostBack method on the current PageRequestManager instance to end the current request:

if (!updatePanelElement) {

this._updatePanel(updatePanelElement, deltaUpdatePanel.content);

Next, the method iterates through the objects in the scriptDisposeNodes array Recall that the value

of the content property of each object in this array contains a script that disposes the server control whose ClientID property value is given by the value of the id property of the object The

_onFormSubmitCompleted method calls the _registerDisposeScript method on the current

PageRequestManager instance, passing in the values of the id and content properties of the

Trang 18

server control:

for (i = 0; i < scriptDisposeNodes.length; i++)

{

var disposePanelId = scriptDisposeNodes[i].id;

var disposeScript = scriptDisposeNodes[i].content;

this._registerDisposeScript(disposePanelId, disposeScript);

}

Next, the method iterates through the objects in the hiddenFieldNodes array Recall that each object in

this array describes a hidden field for which the value of the id property of the object contains the value

of the id HTML attribute of the hidden field, and the value of the content property of the object

con-tains the value that must be stored in the hidden field The _onFormSubmitCompleted method takes the

following steps for each enumerated object First, it calls the getElementById method on the document

object to check whether the current page already contains a hidden field with the specified id HTML

attribute value

var hiddenFieldElement = document.getElementById(hiddenFieldNodes[i].id);

If so, it simply stores the value of the content property of the enumerated object in the existing

hidden field:

hiddenFieldElement.value = value;

If not, it takes the following steps to create a new hidden field First, it calls the createElement method

on the document object to create a new input HTML element:

hiddenFieldElement = document.createElement(‘input’);

Then it assigns the value of the id property of the enumerated object to the id property of the newly

instantiated input HTML element:

hiddenFieldElement.id = hiddenFieldNodes[i].id;

Next, the _onFormSubmitCompleted method assigns the value of the id property of the enumerated

object to the name property of the newly instantiated input HTML element:

hiddenFieldElement.name = hiddenFieldNodes[i].id;

Next, it sets the type property of the newly instantiated input HTML element to hidden :

hiddenFieldElement.type = ‘hidden’;

Finally, it calls the appendChild method on the form element to append the newly instantiated hidden

field as the child of the form element:

this._form.appendChild(hiddenFieldElement);

Trang 19

Next, the _onFormSubmitCompleted method iterates through the objects in the arrayDeclarationNodes array Recall that each object in this array represents an array declaration for which the value of the id property of the object contains the name of the array being declared, and the value of the content property

of the object contains the value being stored in the array As you can see, the method takes the following steps for each object in the arrayDeclarationNodes array First, it creates a string that contains a call into the _addArrayElement static method of the PageRequestManager class, passing in the values of the

id and content properties of the object as the arguments of the method Next, it adds this string to

a local string named arrayScript that accumulates all the strings associated with the objects in the

arrayDeclarationNodes[i].content + “);\r\n”;

}

Next, the _onFormSubmitCompleted method iterates through the objects in the expandoNodes array

Recall that each object in this array describes an expando attribute for which the values of the id and

content properties of the object contain the name and value, respectively of the expando attribute As you can see, the _onFormSubmitCompleted method forms a string for each object that consists of two substrings separated by the equals sign, these substrings containing the name and value, respectively, of the associated expando attribute Note that the expandoScript string accumulates all these strings

var expandoScript = ‘’;

for (i = 0; i < expandoNodes.length; i++) {

var propertyReference = expandoNodes[i].id;

var propertyValue = expandoNodes[i].content;

expandoScript += propertyReference + “ = “ + propertyValue + “\r\n”;

}

As you can see, the server response to an asynchronous page postback may contain scripts The current page may also contain scripts Therefore, you need a way to avoid duplicate scripts The ASP.NET AJAX client-side framework comes with an internal class named _ScriptLoader that provides the current

PageRequestManager instance with script-loading services The _onFormSubmitCompleted method of the current PageRequestManager instance, shown in Listing 24-5 , uses these services to avoid loading duplicate scripts as follows:

❑ The method begins by calling the readLoadedScripts static method on the _ScriptLoader class As you’ll see later, this static method populates an internal static collection named

_referencedScripts with the values of the src HTML attributes of all the script HTML

elements that currently exist on the current page I say currently because the server response to

the current asynchronous page postback request may contain references to script files that the existing script HTML elements on the current page may or may not reference

Sys._ScriptLoader.readLoadedScripts();

Trang 20

class As you’ll see later, the getInstance method checks whether an internal static field named

_instance references an instance of the _ScriptLoader class If so, it simply returns this

reference If not, it creates and returns a new instance of the _ScriptLoader class and stores

this instance in this internal field for future use This ensures that the current page always uses

the same instance of the _ScriptLoader class

var scriptLoader = Sys._ScriptLoader.getInstance();

❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance

to queue the script contained in the arrayScript string Recall that the arrayScript string

contains the script that declares one or more JavaScript arrays The current page may or may not

contain the same ones

❑ As you’ll see later, the queueScriptBlock method simply adds the specified script to an

inter-nal collection named _scriptsToLoad :

if (arrayScript.length)

scriptLoader.queueScriptBlock(arrayScript);

❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance

to queue the script contained in the expandoScript string Recall that the expandoScript

string contains the script that defines one or more expando attributes:

if (expandoScript.length)

scriptLoader.queueScriptBlock(expandoScript);

❑ Then the method iterates through the objects in the scriptBlockNodes array and takes the

following steps for each enumerated object:

❑ If the value of the id property of the object is the string “ScriptContentNoTags” , this

is an indication that the value of the content property of the object contains a script block Therefore, the method calls the queueScriptBlock method on the current

_ScriptLoader instance to queue this script block:

case “ScriptContentNoTags”:

scriptLoader.queueScriptBlock(scriptBlockNodes[i].content);

break;

❑ If the value of the id property of the object is the string “ScriptContentWithTags” , this

is an indication that the value of the content property of the object does not contain a script block Instead it contains the JSON representation of the attributes of a script HTML element You can think of this JSON representation as the serialized form of these attri-butes It contains one name/value pair for each attribute, where the name part of the pair

is a string that contains the name of the attribute, and the value part is a string that tains the value of the attribute Keep in mind that some of these attributes may be custom attributes

Trang 21

con-❑ The _onFormSubmitCompleted method first checks whether this JSON representation contains a name/value pair for the src HTML attribute If so, it uses the name part of this pair — that is, the keyword src — to access the value part of the pair — that is, the URL of the referenced script file — and calls the isScriptLoaded static method on the

_ScriptLoader class to check whether the internal _referencedScripts collection contains an entry for this URL (Recall that this collection contains the URLs of all the

currently referenced script files.) If so, the _onFormSubmitCompleted method skips the enumerated object If not, it calls the queueCustomScriptTag method on the current

_ScriptLoader instance, passing in the JSON representation of the script attributes As you’ll see later, this method simply adds this JSON representation to an internal collection named _scriptsToLoad This collection contains one object for each script file that needs

to be loaded, and describes the HTML standard and custom script attributes

scriptLoader.queueCustomScriptTag(scriptTagAttributes);

break;

❑ If the value of the id property of the object is the string “ScriptPath” , this is an indication that the value of the content property of the object does not contain a script block Instead it contains the URL of a script file The _onFormSubmitCompleted method first calls the isScriptLoaded static method on the _ScriptLoader class to check whether the internal _referencedScripts collection contains an entry for this URL If

so, it simply skips the enumerated object because the associated script has already been loaded

If not, it calls the queueScriptReference method on the current _ScriptLoader instance, passing in the value of the content property of the enumerated object — that is, the URL As you’ll see later, this method creates an object with a single name/value pair and adds the object to the internal _scriptsToLoad collection The name part of this name/value pair is the keyword src and the value part is the URL

❑ Keep in mind that _scriptsToLoad is a collection of objects in which each object describes the HTML standard and custom script attributes associated with a particular script file To put it differently, this collection contains information about the script files that need to be downloaded from the server

case “ScriptPath”:

if (Sys._ScriptLoader.isScriptLoaded(scriptBlockNodes[i].content)) continue;

scriptLoader.queueScriptReference(scriptBlockNodes[i].content);

break;

❑ Next, the _onFormSubmitCompleted method iterates through the objects in the onSubmitNodes array Recall that each object in this array describes a dynamically added form onsubmit state-ment for which the value of the id property of the object is an empty string and the value of the

content property is a string that contains the dynamically added form onsubmit statement

Trang 22

_onSubmitStatements collection of the current PageRequestManager instance Note that

the method iterates through the objects in the onSubmitNodes collection and adds the value

of the content property of each enumerated object to the body of this dynamically generated

❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance

that is passing in the local onSubmitStatementScript string As you’ll see later, the

queueScriptBlock method creates a object with a single name/value pair and adds the object

to the internal _scriptsToLoad collection of the current _ScriptLoader instance The name

part of this name/value pair is the keyword text and the value part contains the content of the

❑ Next, the _onFormSubmitCompleted method stores the reference to the WebRequestExecutor

object responsible for executing the current request in the _response field of the current

PageRequestManager instance:

this._response = sender;

❑ Next, the _onFormSubmitCompleted method calls the createDelegate static method on the

function to create a delegate that represents the _scriptsLoadComplete method of the current

PageRequestManager instance:

var scriptLoadCompleteDelegate = Function.createDelegate(this,

this._scriptsLoadComplete);

❑ Finally, the _onFormSubmitCompleted method calls the loadScripts method on the current

_ScriptLoader instance, passing in the delegate As you’ll see later, this method will load the

scripts in the _scriptsToLoad collection:

scriptLoader.loadScripts(0, scriptLoadCompleteDelegate, null, null);

Trang 23

Listing 24-5 : The _onFormSubmitCompleted Method of the PageRequestManager

function Sys$WebForms$PageRequestManager$_onFormSubmitCompleted(sender, eventArgs){

this._processingRequest = true;

var delimitByLengthDelimiter = ‘|’;

if (sender.get_timedOut()) {

this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);

return;

}

if (sender.get_aborted()) {

this._endPostBack(

this._createPageRequestManagerServerError(sender.get_statusCode()), sender); return;

} var reply = sender.get_responseData();

var delimiterIndex, len, type, id, content;

var replyIndex = 0;

var parserErrorDetails = null;

while (replyIndex < reply.length) {

delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

if (delimiterIndex === -1) {

parserErrorDetails = this._findText(reply, replyIndex);

break;

}

len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);

if ((len % 1) !== 0) {

parserErrorDetails = this._findText(reply, replyIndex);

break;

} replyIndex = delimiterIndex + 1;

delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

(continued)

Trang 25

for (var i = 0; i < delta.length; i++) {

var deltaNode = delta[i];

switch (deltaNode.type) {

Trang 26

if (asyncPostBackControlIDsNode && postBackControlIDsNode &&

updatePanelIDsNode && panelsToRefreshNode &&

asyncPostBackTimeoutNode && childUpdatePanelIDsNode)

var postBackControlIDsArray = this._splitNodeIntoArray(postBackControlIDsNode);

var updatePanelIDsArray = this._splitNodeIntoArray(updatePanelIDsNode);

Trang 27

if (handler) handler(this, this._getPageLoadingEventArgs());

if (formActionNode) {

this._form.action = formActionNode.content;

this._form._initialAction = this._form.action;

} for (i = 0; i < updatePanelNodes.length; i++) {

var deltaUpdatePanel = updatePanelNodes[i];

var deltaPanelID = deltaUpdatePanel.id;

var deltaPanelRendering = deltaUpdatePanel.content;

var updatePanelElement = document.getElementById(deltaPanelID);

if (!updatePanelElement) {

this._endPostBack(Error.invalidOperation(

String.format(Sys.WebForms.Res.PRM_MissingPanel, deltaPanelID)), sender); return;

} this._updatePanel(updatePanelElement, deltaPanelRendering);

} for (i = 0; i < scriptDisposeNodes.length; i++) {

var disposePanelId = scriptDisposeNodes[i].id;

var disposeScript = scriptDisposeNodes[i].content;

this._registerDisposeScript(disposePanelId, disposeScript);

} for (i = 0; i < hiddenFieldNodes.length; i++) {

var id = hiddenFieldNodes[i].id;

var value = hiddenFieldNodes[i].content;

var hiddenFieldElement = document.getElementById(id);

if (!hiddenFieldElement) {

}

(continued)

Trang 28

var propertyReference = expandoNodes[i].id;

var propertyValue = expandoNodes[i].content;

expandoScript += propertyReference + “ = “ + propertyValue + “\r\n”;

Trang 29

var onSubmitStatementScript = ‘’;

for (var i = 0; i < onSubmitNodes.length; i++) {

if (i === 0) onSubmitStatementScript =

‘Array.add(Sys.WebForms.PageRequestManager.getInstance()._onSubmitStatements,function() {\r\n’;

onSubmitStatementScript += onSubmitNodes[i].content + “\r\n”;

}

if (onSubmitStatementScript.length) {

onSubmitStatementScript += “\r\nreturn true;\r\n});\r\n”;

scriptLoader.queueScriptBlock(onSubmitStatementScript);

} this._response = sender;

scriptLoader.loadScripts(0, Function.createDelegate(this, this._scriptsLoadComplete), null, null);

_updatePanel method is to the update the content of the specified UpdatePanel server control with the specified HTML markup text

As Listing 24-6 shows, this method searches through the _scriptDisposes dictionary of the current

PageRequestManager instance for the collection or array that contains all the script disposes associated with the specified UpdatePanel server control If it finds such a collection, it iterates through the script disposes in this collection and calls the eval JavaScript function on each script dispose to execute the script This will allow these script disposes to release the resources that the UpdatePanel server control and its constituent client components are holding before the server control and its content are disposed

of It is necessary to release these resources because the UpdatePanel server control and its content is about to reload or refresh

var disposeScripts = this._scriptDisposes[updatePanelID];

for (var i = 0; i < disposeScripts.length; i++) {

eval(disposeScripts[i]);

}

Trang 30

specified UpdatePanel server control on the current page Recall that the RegisterDispose

method takes two parameters The first references the child server control for which the dispose script is

being registered; the second is a string that contains the actual dispose script being registered

Next, the _onFormSubmitCompleted method deletes the collection from the _scriptDisposes

dictionary

delete this._scriptDisposes[updatePanelID];

Next, it invokes the _destroyTree method on the current PageRequestManager instance, passing

in the reference to the specified UpdatePanel server control to delete the DOM hierarchy associated

with the server control and its content:

this._destroyTree(updatePanelElement);

Finally, it assigns the string that contains the updated HTML markup text to the innerHTML property of

the specified UpdatePanel server control:

var runDisposeScripts = false;

var element = document.getElementById(updatePanelID);

var disposeScripts = this._scriptDisposes[updatePanelID];

for (var i = 0; i < disposeScripts.length; i++)

Trang 31

The registerDisposeScript Method

of PageRequestManager

Recall from Listing 24-5 that the _onFormSubmitCompleted method of the current PageRequestManager instance iterates through a local collection named scriptDisposeNodes , as shown again in the following code listing:

for (i = 0; i < scriptDisposeNodes.length; i++) {

var disposePanelId = scriptDisposeNodes[i].id;

var disposeScript = scriptDisposeNodes[i].content;

this._registerDisposeScript(disposePanelId, disposeScript);

}

As discussed earlier, the scriptDisposeNodes is a collection of objects, each of which describes a pose script Recall that the value of the id property of each object is a string that contains the ClientID property value of the UpdatePanel server control for which the dispose script is being registered, and that the value of the content property of this object is a string that contains the actual dispose script being registered As the preceding code listing shows, the _onFormSubmitCompleted method calls the

dis-_registerDisposeScript method on the current PageRequestManager instance to register the specified dispose script for the UpdatePanel server control with the specified ClientID property value

Listing 24-7 presents the internal implementation of the _registerDisposeScript method As you can see, this method first uses the ClientID property value as an index into the _scriptDisposes collection to return the array that holds all the dispose scripts registered for the UpdatePanel server control that has the specified ClientID property value (Recall that the _scriptDisposes collection

of the current PageRequestManager instance maintains one array for each server control.) Next, the

_registerDisposeScript method adds the specified dispose script to the associated array

Listing 24-7 : The _registerDisposeScript Method of the PageRequestManager

function Sys$WebForms$PageRequestManager$_registerDisposeScript(panelID, disposeScript){

if (!this._scriptDisposes[panelID]) this._scriptDisposes[panelID] = [disposeScript];

else Array.add(this._scriptDisposes[panelID], disposeScript);

}

_destroyTree

Recall from Listing 24-6 that the _updatePanel method of the current PageRequestManager instance invokes the _destroyTree method on the current PageRequestMananger instance to destroy the entire DOM hierarchy that has the specified root DOM element The _destroyTree method takes a reference

to a DOM element and deletes it and all its descendant DOM elements As Listing 24-8 shows, this method first makes sure that its argument is indeed an element Then it iterates through the child DOM

Trang 32

DOM element does not support the method but does expose a property named control that supports

the method, _destroyTree calls the method on this property (Recall that the control property of a

DOM element references the client control associated with the element.) Next, it calls the getBehaviors

method to return an array that contains all the behaviors associated with the enumerated DOM element

and calls the dispose methods of these behaviors Finally, it calls _destroyTree to destroy all the

descendant DOM elements of the enumerated child element As you can see, _destroyTree is a

var childNodes = element.childNodes;

for (var i = childNodes.length - 1; i >= 0; i )

var behaviors = Sys.UI.Behavior.getBehaviors(node);

for (var j = behaviors.length - 1; j >= 0; j )

The main responsibility of the _ScriptLoader class is to load the required scripts As you saw, Listing

24-5 makes extensive use of this class In this section, I’ll walk you though the implementation of the

methods of the class

readLoadedScripts

Recall from Listing 24-5 that the _onSubmitFormCompleted method invokes the readLoadedScripts

static method on the _ScriptLoader class As Listing 24-9 shows, the readLoadedScripts method

Trang 33

Sys._ScriptLoader._referencedScripts = [];

Next, it calls the getElementByTagName method on the document object to return an array that contains references to all the script HTML elements on the current page:

var existingScripts = document.getElementsByTagName(‘SCRIPT’);

Finally, readLoadedScripts iterates through these script HTML elements and adds the value of the src HTML attribute of each element to the _referencedScripts static collection of the

_ScriptLoader class:

Array.add(Sys._ScriptLoader._referencedScripts, existingScripts[i].src);

Listing 24-9: The readLoadedScripts Static Method of the _ScriptLoader Class

Sys._ScriptLoader.readLoadedScripts = function Sys$_ScriptLoader$readLoadedScripts(){

if(!Sys._ScriptLoader._referencedScripts) {

var existingScripts = document.getElementsByTagName(‘SCRIPT’);

for (i = existingScripts.length - 1; i >= 0; i ) {

if (existingScripts[i].src.length) {

if (!Array.contains(Sys._ScriptLoader._referencedScripts, existingScripts[i].src))

Array.add(Sys._ScriptLoader._referencedScripts, existingScripts[i].src);

} } }}

getInstance

As Listing 24-10 shows, the getInstance static method of the _ScriptLoader class ensures that each page can have only one instance of the _ScriptLoader class

Listing 24-10: The getInstance Static Method of the _ScriptLoader Class

Sys._ScriptLoader.getInstance = function Sys$_ScriptLoader$getInstance(){

if(!Sys._ScriptLoader._activeInstance) Sys._ScriptLoader._activeInstance = new Sys._ScriptLoader();

return Sys._ScriptLoader._activeInstance;

}

Trang 34

As you can see from Listing 24-11 , the queueScriptBlock method of the _ScriptLoader class creates

an object with a single name/value pair and adds it to the _scriptToLoad array of the current

_ScriptLoader instance Note that the name part of this name/value pair is the keyword text and

the value part contains the script being queued

Listing 24-11: The queueScriptBlock Method of the _ScriptLoader Class

Recall from Listing 24-5 that the _onFormSubmitCompleted method of the current PageRequestManager

instance calls the queueCustomScriptTag method on the current _ScriptLoader instance, passing in

the object that represents the serialized form of the attributes of a script HTML element As Listing 24-12

shows, the queueCustomScriptTag method adds this object to the _scriptsToLoad collection of the

current _scriptLoader instance

Listing 24-12: The queueCustomScriptTag Method of the _ScriptLoader Class

Recall from Listing 24-5 that the _onFormSubmitCompleted method of the current PageRequestManager

instance invokes the isScriptLoaded static method on the _ScriptLoader class to determine whether

the script file with the specified URL has already been loaded Listing 24-13 presents the implementation of

Trang 35

_getLoadedScript

As Listing 24-14 shows, the _getLoadedScripts static method of the _ScriptLoader class simply returns a reference to the _referencedScripts collection, which contains the values of the src HTML

attributes of all the script HTML elements that currently exist on the current page

Listing 24-14: The _getLoadedScripts Static Method of the _ScriptLoader Class

Sys._ScriptLoader._getLoadedScripts = function Sys$_ScriptLoader$_getLoadedScripts(){

if(!Sys._ScriptLoader._referencedScripts) {

PageRequestManager instance calls the queueScriptReference method on the current

_ScriptLoader instance to queue the specified script reference As Listing 24-15 shows, this method creates an object with a single name/value pair, the name part of the pair being the keyword src and the value part the URL of the JavaScript file passed into the method as its only argument The method then adds this object to the _scriptsToLoad collection of the current _ScriptLoader instance

Listing 24-15: The queueScriptReference Method of the _ScriptLoader Class

function Sys$_ScriptLoader$queueScriptReference(scriptUrl){

if(!this._scriptsToLoad) this._scriptsToLoad = [];

PageRequestManager instance calls the loadScripts method on the current _ScriptLoader instance

to load the scripts in the _scriptsToLoad collection As Listing 24-16 shows, this method takes four parameters The first contains the script loading timeout, the second references the JavaScript function that will be automatically invoked if all the scripts in the _scriptsToLoad collection are loaded, the third references the JavaScript function that will be automatically invoked if the script loading fails, and the fourth parameter references the JavaScript function that will be automatically invoked if the scripts in the _scriptsToLoad collection do not load within the time specified by the first parameter

of the method

Trang 36

_scriptsToLoad collection are already being loaded Therefore, an invalid operation exception is raised:

if(this._loading)

throw Error.invalidOperation(Sys.Res.scriptLoaderAlreadyLoading);

Next, the loadScripts method sets the _loading flag to true to signal that the scripts in the

_scriptsToLoad collection are being loaded:

this._loading = true;

Then it stores its second parameter in the _allScriptsLoadedCallback field of the current

_ScriptLoader instance:

this._allScriptsLoadedCallback = allScriptsLoadedCallback;

Recall from Listing 24-5 that the _onFormSubmitCompleted method of the current PageRequestManager

instance passes the following delegate as the second parameter of the loadScripts method:

Function.createDelegate(this, this._scriptsLoadComplete)

As you can see, this delegate represents the _scriptLoadComplete method of the current

PageRequestManager instance This means that when all the scripts in the _scriptsToLoad collection

of the current PageRequestManager instance are finally loaded, the current _ScriptLoader instance

will automatically invoke this delegate and consequently the _scriptsLoadComplete method that it

represents

As Listing 24-16 shows, the loadScripts method finally invokes the _loadScriptsInternal method

on the current _ScriptLoader instance to load the scripts in the _scriptsToLoad collection of the

cur-rent _ScriptLoader instance:

this._loadScriptsInternal();

Listing 24-16: The loadScripts Method of the _ScriptLoader Class

function Sys$_ScriptLoader$loadScripts(scriptTimeout, allScriptsLoadedCallback,

Trang 37

_loadScriptsInternal

Listing 24-17 presents the internal implementation of the _loadScriptsInternal method of the current _ScriptLoader instance Recall that the _scriptsToLoad array of the current _ScriptLoader instance contains one object for each script that needs to be loaded This object contains the complete information about its associated script

Note that the _loadScriptsInternal method is a recursive function, meaning that the method calls itself to load the script described by the next object in the _scriptsToLoad array This method checks whether the _scriptsToLoad collection contains any more objects If not, it first calls the _stopLoading method on the current _ScriptLoader instance to end the script-loading process and then calls the

_allScriptsLoadedCallback method to notify its caller that all the scripts have been loaded As discussed earlier, the _allScriptsLoadedCallback field of the current _ScriptLoader instance references the delegate that represents the _scriptsLoadComplete method of the current

PageRequestManager instance

var callback = this._allScriptsLoadedCallback;

this._stopLoading();

if(callback) callback(this);

If the _scriptsToLoad collection contains more objects, the _loadScriptsInternal method calls the

dequeue static method on the Array to dequeue the next object from the _scriptsToLoad collection:

var nextScript = Array.dequeue(this._scriptsToLoad);

Next, it calls the _createScriptElement method on the current _ScriptLoader instance that is passing in the dequeued object As you’ll see later, this method creates an HTML script element and uses the values of the properties of the object to initialize the attributes of this script element

var scriptElement = this._createScriptElement(nextScript);

Next, the _loadScriptsInternal method checks whether the object contains a name/value pair associated with the src script attribute If so, this is an indication that the object describes a script file that must be downloaded from the server Because of this, we have to worry about issues such as timeout

Therefore, the _loadScriptsInternal method instantiates an instance of an ASP.NET AJAX class named _ScriptLoaderTask , passing a reference to the newly instantiated script element and a reference

to the delegate referenced by the _scriptLoadedDelegate field of the current _ScriptLoader instance As you’ll see later, the constructor of the _ScriptLoader class creates a delegate that represents the _scriptLoadedHandler method of the current _ScriptLoader instance and assigns this delegate

to the _scriptLoadedDelegate field

this._currentTask = new Sys._ScriptLoaderTask(scriptElement, this._scriptLoadedDelegate);

Next, the _loadScriptsInternal method invokes the execute method on the current

ScriptLoaderTask instance to execute the task The execute method basically downloads the script file referenced by the specified script element:

this._currentTask.execute();

Trang 38

eral script Therefore the _loadScriptsInternal method first accesses the head HTML element:

var headElement = document.getElementsByTagName(‘HEAD’)[0];

Next, it calls the appendChild method on the head HTML element to append the script element as its

child element Appending this script element immediately runs the script enclosed within the opening

and closing tags of the script element:

headElement.appendChild(scriptElement);

Next, the _loadScriptsInternal method removes the script element because you do not need the

element after running its contained script:

scriptElement.parentNode.removeChild(scriptElement);

Finally, it calls the _loadScriptsInternal method to load the script associated with the next object in

the _scriptsToLoad collection:

var nextScript = Array.dequeue(this._scriptsToLoad);

var scriptElement = this._createScriptElement(nextScript);

if (scriptElement.text && Sys.Browser.agent === Sys.Browser.Safari)

Trang 39

else { var callback = this._allScriptsLoadedCallback;

this._stopLoading();

if(callback) callback(this);

}}

_createScriptElement

Listing 24-18 presents the internal implementation of the _createScriptElement method of the

_ScriptLoader class This method takes a single object that describes the standard and custom HTML attributes of the HTML script element being created As you can see, this method first calls the

createElement method on the document object to create the script HTML element:

var scriptElement = document.createElement(‘SCRIPT’);

Next, it sets the type attribute of the script HTML element to a default value Note that the object may contain a name/value pair for the type HTML attribute, which means that this default value may be overridden:

scriptElement.type = ‘text/javascript’;

Finally, it iterates through the name/value pairs of the object, uses the name part of each as an index into the object to return the value part of the pair, and finally uses the name part of each as an index into the newly instantiated script element to store the value part of the pair

for (var attr in queuedScript) {

scriptElement[attr] = queuedScript[attr];

}

Listing 24-18: The _createScriptElement Method of the _ScriptLoader Class

function Sys$_ScriptLoader$_createScriptElement(queuedScript){

var scriptElement = document.createElement(‘SCRIPT’);

Trang 40

As Listing 24-19 shows, the constructor of the _ScriptLoader class sets the _scriptsToLoad collection

to null , creates a delegate the represents the _scriptLoadedHandler method of the current

_ScriptLoader instance, and stores this delegate in a field named _scriptLoadedDelegate

Listing 24-19: The Constructor of the _ScriptLoader Class

Sys._ScriptLoader = function Sys$_ScriptLoader()

Listing 24-20 presents the internal implementation of the _scriptLoadedHandler method of the

_ScriptLoader class As discussed earlier, the current ScriptLoaderTask instance calls this method

when it is finished loading the specified script in the _scriptsToLoad collection As you can see, this

method calls the _getLoadedScripts static method on the _ScriptLoader class to return a reference

to the _referencedScripts static collection of the class (Recall that this collection stores the URLs of

all the loaded script files.) The _scriptLoadedHandler method adds the URL of the newly loaded

script file into this collection:

Array.add(Sys._ScriptLoader._getLoadedScripts(), scriptElement.src);

Next, it calls the dispose method on the current ScriptLoaderTask instance to allow the instance to

release the resources it is holding before the instance is disposed of:

this._currentTask.dispose();

Next, the _scriptLoadedHandler method calls the _loadScriptsInternal method to load the script

described by the next object in the _scriptsToLoad collection As you can see, the scripts described by

the objects in the _scriptsToLoad collection are loaded one at a time; in other words, the loading of the

next script does not start until the previous script is completely loaded

Listing 24-20: The _scriptLoadedHandler Method of the _ScriptLoader Class

function Sys$_ScriptLoader$_scriptLoadedHandler(scriptElement, loaded)

Ngày đăng: 09/08/2014, 06:23

TỪ KHÓA LIÊN QUAN