Deploying Code Through Web Parts

Tip

Tip

If you are already familiar with Web Parts in SharePoint, you may want to skip ahead to the section "Deploying the AJAX Runtime Through the ScriptManager Control."

A typical application in SharePoint is developed through the use of Web Parts. A Web Part can be added to a page through configuration or by an end user and is serialized into the application’s database by the Web Part framework. A Web Part is a class that derives from the class System.Web.UI.WebControls.WebParts.WebPart, which is a special type of WebControl that runs in the ASP.NET Web Part framework.

The only reason to deploy code as a Web Part is to give end users the capability to add and configure the Web Part in any page. If the code is tied to a page location or you need to develop a full-page user interface, you’re better off deploying code in a page context. My commercial products at NewsGator employ both of these techniques, pages and Web Part applications, using the same common JavaScript library and Web service API. AJAX code is developed independently of its deployment target, although Web Part applications require a different deployment strategy, as I’ll discuss in this section.

Utilizing the Web Part framework in an ASP.NET application can be complex, but SharePoint includes support for Web Parts in almost all its pages and includes a built-in Web Part gallery from which users can select Web Parts at run time.

More Information

More Information

For full MSDN documentation on the Web Part class, see http://msdn.microsoft.com/system.web.ui.webcontrols.webparts.webpart.aspx. Avoid using code in the Microsoft.SharePoint.WebPartPages namespace; this namespace is included for backward compatibility.

As I mentioned previously, to create a Web Part, you create a public class that inherits from System.Web.UI.WebControls.WebParts.WebPart. The Hello World Web Part is shown in Example 11-1. This Web Part simply writes the text "Hello, World!" to the page during the Render method. The main methods that you override to provide custom functionality are CreateChildControls, which is used to add controls to the Controls collection, and RenderContents, which is used to render the output to the page. Note that the outer Render method is used by the Web Part framework to render "chrome" that wraps the Web Part with an administrative interface that allows an end user to customize the Web Part.

Example 11-1. To create a Web Part, derive from System.Web.UI.WebControls.WebParts.WebPart (SOAjax. SharePoint/HelloWorldWebPart.cs).

using System;
using System.Web.UI.WebControls.WebParts;

namespace SOAjax.SharePoint
{
    /// <summary>A very simple Web Part</summary>
    public class HelloWorldWebPart : WebPart
    {
        protected override void CreateChildControls()
        {
            // Add any child controls here, such as the Script Manager.
            base.CreateChildControls();
        }

        protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
        {
            // Use this to write HTML directly to the page
            writer.Write("Hello World!");
        }
    }
}

To get the Web Part to the Web Part page, the DLL must be deployed in the bin directory or in the GAC, and the namespace must be registered in web.config. To review, the following entry must be included in web.config inside the SafeControls element. This entry allows execution of any Web Part code in the namespace SOAjax.SharePoint in the assembly SOAjax. SharePoint.dll. If the assembly is strongly named and deployed to the GAC, the assembly name must include the full strong name of the assembly.

<SafeControl Assembly="SOAjax.SharePoint" Namespace="SOAjax.SharePoint"
    TypeName="*" Safe="True" AllowRemoteDesigner="True" />

After adding the web.config entry, you can add the Web Part to the Web Part gallery, which makes it easy to add to pages. This step is done by going to the Site Settings page (available from the Site Actions link on the page) and navigating to the Web Part gallery. From the gallery, click the New button, which takes you to the New Web Parts page at http://localhost/_layouts/NewDwp.aspx. This page lists every public Web Part type that is available in the bin directory or the GAC and that is in a namespace registered through a SafeControls entry. You will use this page during development to add every Web Part class that you want to make available in the Web Part gallery.

Tip

Tip

For production applications, you export the .webpart file generated by the Web Part gallery, edit it, and deploy it through a SharePoint Feature. Again, this information is detailed in Inside Microsoft Windows SharePoint Services 3.0.

After adding the Web Part gallery entry, on the SharePoint Web page click Site Actions, Edit Page. From here you can add any Web Part in the Web Part gallery to the page within Web Part Zones. A Web Part Zone is a special container control on the page that supports the addition of Web Parts. You can only add Web Parts at run time to Web Part Zones that are defined on the page. Web Part Zones save their serialized Web Part states into the SharePoint database. The interface for adding Web Parts to Web Part Zones is shown in Figure 11-1.

Web Parts can be added using the Add button when the page is in design mode.

Figure 11-1. Web Parts can be added using the Add button when the page is in design mode.

To add properties that will be stored by the Web Part framework, add the Personalizable attribute to a property. The Personalizable attribute is defined in the System.Web.UI.WebControls.WebParts namespace. When it is applied to a public property along with the WebBrowsable attribute, SharePoint displays an interface for editing the property in the Web Page when the user edits the Web Part. Example 11-2 demonstrates a simple property. Figure 11-3 shows the Edit Web Part interface for this Web Part instance, demonstrating the user interface for the custom property Message.

Example 11-2. To add persistent properties to a Web Part, use the Personalizable attribute (SOAjax. SharePoint/HelloWorldWebPart.cs).

using System;
using System.Web.UI.WebControls.WebParts;
using System.ComponentModel;

namespace SOAjax.SharePoint
{
    /// <summary>A very simple Web Part</summary>
    public class HelloWorldWebPart : WebPart
    {
        [WebBrowsable]
        [WebDescription("The message we want to render")]
        [WebDisplayName("Message")]
        [Personalizable(PersonalizationScope.Shared)]
        [Category("Text")]
        public string Message {get; set;}

        protected override void CreateChildControls()
        {
            // Add any child controls here, such as the Script Manager.
            base.CreateChildControls();
        }

        protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
        {
            // Use this to write HTML directly to the page
            writer.Write("Hello World! ");
            writer.Write(this.Message);
        }
    }
}

To edit the Web Part, use the Edit Web Part menu and choose Modify Shared Web Part, as shown in Figure 11-2. This will display the Web Part Properties dialog box, as shown in Figure 11-3.

To edit a Web Part, select Modify Shared Web Part from the Web Part’s Edit menu while you are editing the page.

Figure 11-2. To edit a Web Part, select Modify Shared Web Part from the Web Part’s Edit menu while you are editing the page.

Web Part properties can be edited from the SharePoint page.

Figure 11-3. Web Part properties can be edited from the SharePoint page.

While the Web Part framework itself isn’t AJAX-enabled, we’ll use the Web Part framework to deploy placeholder DIV elements and JavaScript to the page. We will then use the JavaScript to create AJAX controls in the Web Part Zone. In the following section, I’ll describe a custom server control that programmatically includes and configures the ASP.NET ScriptManager control and can be included in multiple Web Parts. This technique was also covered in detail in Chapter 4. Then we’ll look at using this control in Web Parts to implement AJAX controls deployed through Web Parts.

Deploying the AJAX Runtime Through the ScriptManager Control

In a typical ASP.NET application the script manager is declared in the page, but SharePoint is not your typical Web application. In a typical SharePoint project, you develop Web Parts that can be placed on customer pages alongside existing functionality and other people’s code. It’s important that your code doesn’t break existing code, Microsoft’s functionality, or even third-party functionality. This means that your Web Part code must coexist with existing application code, and you may or may not "own" the page that the Web Part is deployed to. With Web Part applications, you must not break functionality in other Web Parts. The AJAX-enabled Web Part must deploy a ScriptManager control only if there isn’t one already in the page. Example 11-3 demonstrates a ScriptManager control that can be included as a child control of a Web Part. (Note that this class was shown earlier in the book, as Example 4-3. This code sample has simply been renamed and included in this assembly.)

Example 11-3. The ScriptRuntimeControl is a critical component in a Web Part–deployed AJAX application (SOAjax.SharePoint/ScriptRuntimeControl.cs).

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web;
using System.Drawing.Design;
using System.Globalization;
using System.Security.Permissions;
using System.Reflection;

namespace SOAjax.SharePoint
{
    public class ScriptRuntimeControl : Control
    {
        private ScriptReferenceCollection _scripts;
        public ScriptReferenceCollection Scripts
        {
            get
            {
                if (this._scripts == null)
                    this._scripts = new ScriptReferenceCollection();
                return this._scripts;
            }
        }

        private ServiceReferenceCollection _services;
        public ServiceReferenceCollection Services
        {
            get
            {
                if (this._services == null)
                    this._services = new ServiceReferenceCollection();
                return this._services;
            }
        }

        private ScriptManager scriptMan;
        // A null-safe reference to the page's script manager.
        public ScriptManager ScriptManager
        {
            get
            {
                EnsureScriptManger();
                return scriptMan;
            }
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            EnsureScriptManger();
        }
        // Make sure there is only 1 script manager on the page.
        private void EnsureScriptManger()
        {
            if (scriptMan == null)
            {
                scriptMan = ScriptManager.GetCurrent(this.Page);
                if (scriptMan == null)
                {
                    scriptMan = new ScriptManager();
                    this.Controls.Add(scriptMan);
                }
            }
        }

        private string cacheKey;
        /// <summary>A cache key for script paths</summary>
        /// <remarks>Ideally, this would be generated from the build.</remarks>
        public string CacheKey
        {
            get
            {
                if (cacheKey == null)
                    cacheKey =
          Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId.ToString();
                return cacheKey;
            }
        }

        // Add any scripts and service references to the real script manager.
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            this.EnsureChildControls();
            // Add a cache key to every script in the manager.
            foreach (ScriptReference script in this.ScriptManager.Scripts)
            {
                if (!string.IsNullOrEmpty(script.Path) &&
                    !script.Path.ToLowerInvariant().Contains("cache"))
                {
                    char seperator = script.Path.Contains("?") ? '&' : '?';
                    script.Path = string.Format("{0}{1}cache={2}",
                        script.Path, seperator, this.CacheKey);
                }
            }
            foreach (ScriptReference script in this.Scripts)
            {
                if (!string.IsNullOrEmpty(script.Path)){
                    char seperator = script.Path.Contains("?") ? '&' : '?';
                    script.Path = string.Format("{0}{1}cache={2}",
                        script.Path, seperator, this.CacheKey);
                }
                this.ScriptManager.Scripts.Add(script);
            }
            foreach (ServiceReference proxy in this.Services)
                this.ScriptManager.Services.Add(proxy);

            // Common scipt manager configuration:
            this.ScriptManager.EnableHistory = true;
        }
    }
}

ScriptRuntimeControl can be included in any Web Part by adding it to the Controls collection in the CreateChildControls method. Example 11-4 demonstrates a simple base class for an AJAX Web Part that registers the ScriptRuntimeControl.

Example 11-4. The ScriptRuntimeControl is a critical component in a Web Part–deployed AJAX application (SOAjax.SharePoint/AjaxWebPart.cs).

using System.Web.UI.WebControls.WebParts;

namespace SOAjax.SharePoint
{
    /// <summary>A base class for AJAX Web Parts.</summary>
    public abstract class AjaxWebPart : WebPart
    {
        private ScriptRuntimeControl ajaxRuntime = new ScriptRuntimeControl();

        /// <summary>Gets the ScriptManager for this page </summary>
        public ScriptRuntimeControl ScriptManager
        {
            get
            {
                return this.ajaxRuntime;
            }
        }

        /// <summary>Includes the ajax runtime components.</summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            this.Controls.Add(this.ajaxRuntime);
        }
    }
}

The technique to create an AJAX control in SharePoint is similar to the technique used in previous chapters—you simply render a DIV that is a placeholder and create the AJAX control instance in the page initialization through the Sys.Application.init event.

In the Web Part, you render a DIV that is used as the element of the control. However, with Web Parts, you want to support multiple instances of the Web Part, so you need unique IDs for each placeholder DIV element. You won’t know these until the Web Part renders, and because of this, you won’t be able to use statically named items in the JavaScript page initialization code. To account for this and to make your code even more portable, you need to render JSON-serialized object templates that can be read during the page initialization. This lets you map Web Part properties to AJAX control properties.

To demonstrate this technique, we’ll create a Web Part implementation of the JavaScript AJAX control XmlControl that was built in Chapter 9. First we need to implement the page initialization method that is added to the XmlControl.js file. Then we’ll implement a control template in the Web Part class AjaxXmlControl and include the necessary script library through the previously explained ScriptRuntimeControl.

Tip

Tip

The AJAX Xml Web Part architecture can be used to produce very complex AJAX Web Part applications with little effort. It is the main architecture behind commercial products we’ve built at NewsGator.

To review, the XmlControl has the properties xmlUrl, xsltUrl, and reloadInterval. When an XmlControl is initialized with xmlUrl and xsltUrl, it loads XML data and the XSLT transform file from these locations and performs a client-side render.

The JavaScript object template that we will use for the XmlControl looks like the following JavaScript object. In the Web Part, we’ll render this in the page in a JavaScript array with a known naming convention, which we’ll pick up in the AJAX Sys.Application.init event.

var template = {
    elementID: ElementID,
    properties : {
        xmlUrl : URL,
        xsltUrl : XSLT_URL,
        reloadInterval : '3000'
    }
};

To add a page initialization script, look for the JavaScript array of control templates with your given naming convention. A uniquely named array should be used for each type of AJAX control. The following JavaScript method adds a page initialization script that creates instances of XmlControl based on the templates added to the window._XmlControlTemplates variable.

// Initializes the XmlControl templates during the page load.
SOAjax.Controls.XmlControl.OnPageInit = function() {
    if (window.__XmlControlTemplates != 'undefined' &&
            window.__XmlControlTemplates != null) {
        while (window.__XmlControlTemplates.length > 0) {
            var template = Array.dequeue(window.__XmlControlTemplates);
            var element = $get(template.elementID);
            var control = $create(SOAjax.Controls.XmlControl,
            template.properties, template.events, template.references, element);
        }
        window.__XmlControlTemplates = null;
    }
}
Sys.Application.add_init(SOAjax.Controls.XmlControl.OnPageInit);

To create a Web Part that utilizes XmlControl, we need to write a simple Web Part that creates a JavaScript template and a placeholder, while including the ASP.NET ScriptManager and the custom library that contains the XmlControl.js JavaScript file. Example 11-5 demonstrates a simple Web Part that includes the properties XmlUrl, XsltUrl, and RefreshInterval, all of which are written to the JavaScript template. In the sample code, a default XML and XSLT file are included that supply the initial render. AjaxXmlWebPart can be used to implement views of any XML data source, including RSS feeds that are included out of the box with SharePoint.

Example 11-5. The AjaxXmlWebPart class is a Web Part wrapper for XmlControl (SOAjax.SharePoint/AjaxXmlWebPart.cs).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.Utilities;

namespace SOAjax.SharePoint
{
    public class AjaxXmlWebPart : AjaxWebPart, IXmlWebPart
    {
        /// <summary>
        /// Gets a string specifying the client ID of the XmlControl
        /// </summary>
        public string XmlControlID
        {
            get{return (@"XmlControl" + this.ClientID);}
        }

        /// <summary>Defines the client data refresh interval in seconds</summary>
        [WebBrowsable]
        [WebDescription("Defines the client data refresh interval in seconds")]
        [WebDisplayName("Refresh Interval (seconds)")]
        [Personalizable(PersonalizationScope.Shared)]
        [Category("AJAX")]
        public uint RefreshInterval { get; set;}

        /// <summary>Xml Url defines the client Xml data source URL </summary>
        [WebBrowsable(true)]
        [WebDisplayName("Xml Url")]
        [Personalizable(PersonalizationScope.Shared)]
        public string XmlUrl { get; set; }

        /// <summary>Xslt Url defines the client XSLT source URL</summary>
        /// <remarks>If empty the SharePoint.AJAX RSS XSLT will be used.</remarks>
        [WebBrowsable(true)]
        [WebDisplayName("Custom Xslt Url Override")]
        [Personalizable(PersonalizationScope.Shared)]
        public string XsltUrl { get; set; }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            this.ScriptManager.Scripts.Add(
                new ScriptReference("/_layouts/soajax.script/xmlcontrol.js"));
            this.ScriptManager.Scripts.Add(
                new ScriptReference("/_layouts/soajax.script/soajax.js"));
        }

        /// <summary>
        /// Renders the contents of this control.
        /// This is where we will register the XmlComponent instances.
        /// </summary>
        /// <param name="writer">HtmlTextWriter</param>
        protected override void RenderContents(HtmlTextWriter writer)
        {
            var xml = this.XmlUrl;
            // Only provide a default for the XmlWebPart-- not inherited parts.
            if (this.GetType() == typeof(AjaxXmlWebPart)
                    && string.IsNullOrEmpty(xml))
                xml = @"/_layouts/soajax.script/Sample.xml";
            var xsl = this.XsltUrl;
            if (xsl == null)
                xsl = @"/_layouts/soajax.script/Sample.xslt";

            writer.Write(@"<div id=""XmlControl_{0}"" style=""display:block;"">",
                this.ClientID);
            this.RenderInitialContents(writer);
            writer.Write(@"</div>");

            var scriptFormat =
                @"if (window.__XmlControlTemplates == null){{
                    window.__XmlControlTemplates = new Array();
                    }}
                    var template = {{
                        elementID: 'XmlControl_{0}',
                        properties : {{   xmlUrl : '{1}',
                            xsltUrl : '{2}',
                            reloadInterval : '{3}'
                        }}
                    }};
                    window.__XmlControlTemplates.push(template);
                ";

            var script = string.Format(scriptFormat,
                this.ClientID,
                SPEncode.ScriptEncode(this.XmlUrl),
                SPEncode.ScriptEncode(xsl),
                this.RefreshInterval * 1000);
            writer.Write(@"<script type=""text/javascript""
                language=""javascript"">");
            writer.Write(script);
            writer.Write(@"</script>");
        }

        /// <summary>
        /// Used to write the inside part of the XmlComponent.
        /// By default, it will render "Loading"
        /// </summary>
        /// <param name="writer">HtmlTextWriter</param>
        protected virtual void RenderInitialContents(HtmlTextWriter writer)
        {
            writer.Write(@"<div style=""margin:3px;"" class=""SOAjaxLoading"">
                            <span style=""font-size:smaller;"">Loading...</span>
                           </div>");
        }
    }
}

The full XmlControl JavaScript class is included in Example 11-6. This control dynamically loads and renders XML data sources with XSLT files that are loaded from the client as well. The XmlControl class implements logic for reloading where it can reload on an interval or through the reload method. This control can be used as the core run-time component for AJAX applications.

Example 11-6. The XmlControl class is used to dynamically load and render XML data sources from the client (SOAjax.SharePointSOAjax.ScriptXmlControl.js).

/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace('SOAjax.Controls'),

SOAjax.Controls.XmlControl = function(element) {
    /// <summary>
    /// A component that loads and renders XML on the client.
    /// </summary>
    SOAjax.Controls.XmlControl.initializeBase(this, [element]);
}

SOAjax.Controls.XmlControl.prototype = {
    // ------------ Private fields ---------
    _xml: null,
    _xslt: null,
    _xsltUrl: null,
    _xmlUrl: null,
    _reloadInterval: null,
    _active: true,
    _interval: null,
    _timeoutID: null,
    _lastMod: null,
    // ------------- Properties -------------
    get_active: function() {
        /// <value>Gets or sets the XML data of the control.</value>
        return this._active;
    },
    set_active: function(value) {
        if (this._active !== value) {
            this._active = value;
            this.raisePropertyChanged('active'),
            if (this._active && _reloadInterval > 100) {
                window.setTimeout(
                    String.format("SOAjax.Controls.XmlControl.Refresh('{0}')",
                        this.get_element().id),
                    this._reloadInterval);
            }
        }
    },

    get_xml: function() {
        /// <value>Gets or sets the XML data of the control.</value>
        return this._xml;
    },
    set_xml: function(value) {
        if (this._xml !== value) {
            this._xml = value;
            this.raisePropertyChanged('xml'),
        }
        if (this._xml && this._xslt) this._render();
    },

    get_xslt: function() {
        /// <value>Gets or sets the XSLT rendering logic for the control.</value>
        return this._xslt;
    },
    set_xslt: function(value) {
        if (this._xslt !== value) {
            this._xslt = value;
            this.raisePropertyChanged('xslt'),
        }
        if (this._xml && this._xslt) this._render();
    },

    get_xsltUrl: function() {
        /// <value>The URL to load the XSLT from.</value>
        return this._xsltUrl;
    },
    set_xsltUrl: function(value) {
        if (this._xsltUrl !== value) {
            this._xsltUrl = value;
            this.raisePropertyChanged('xsltUrl'),
            if (this._xsltUrl && !this.get_isUpdating())
                this._loadXslt(this._xsltUrl);
        }
    },
    get_xmlUrl: function() {
        /// <value>The URL to load the data from.</value>
        return this._xmlUrl;
    },
    set_xmlUrl: function(value) {
        if (this._xmlUrl !== value) {
            this._lastMod = null;
            this._xmlUrl = value;
            this.raisePropertyChanged('xmlUrl'),
            if (this._xmlUrl && !this.get_isUpdating())
                this._loadXml(this._xmlUrl);
        }
    },

    get_reloadInterval: function() {
        /// <value>The interval at which we'll reload the control.</value>
        return this._reloadInterval;
    },
    set_reloadInterval: function(value) {
        if (this._reloadInterval !== value) {
            if (value != 0 && value < 99) {
                throw Error.argumentOutOfRange('reloadInterval',
                  value, 'The reload interval must be 0 or over 100 milliseconds.'),
            }
            this._reloadInterval = value;
            this.raisePropertyChanged('reloadInterval'),
        }
    },

    reload: function() {
        if (this._timeoutID) window.clearTimeout(this._timeoutID);
        this._reload();
    },

    _reload: function() {
        var xmlUrl = this.get_xmlUrl();
        if (xmlUrl != null) { this._loadXml(xmlUrl); }
    },

    // Events --------------------------------------------------------
    add_xmlLoaded: function(handler) {
        /// <value>Bind and unbind to the xmlLoaded event.</value>
        this.get_events().addHandler('xmlLoaded', handler);
    },
    remove_xmlLoaded: function(handler) {
        this.get_events().removeHandler('xmlLoaded', handler);
    },

    add_xsltLoaded: function(handler) {
        /// <value>Bind and unbind to the xsltLoaded event.</value>
        this.get_events().addHandler('xsltLoaded', handler);
    },
    remove_xsltLoaded: function(handler) {
        this.get_events().removeHandler('xsltLoaded', handler);
    },
    add_render: function(handler) {
        /// <value>Bind and unbind to the render event.</value>
        this.get_events().addHandler('render', handler);
    },
    remove_render: function(handler) {
        this.get_events().removeHandler('render', handler);
    },

    add_prerender: function(handler) {
        /// <value>Bind and unbind to the prerender event.</value>
        this.get_events().addHandler('prerender', handler);
    },
    remove_prerender: function(handler) {
        this.get_events().removeHandler('prerender', handler);
    },

    add_error: function(handler) {
        /// <value>Bind and unbind to the prerender event.</value>
        this.get_events().addHandler('error', handler);
    },
    remove_error: function(handler) {
        this.get_events().removeHandler('error', handler);
    },

    initialize: function() {
        SOAjax.Controls.XmlControl.callBaseMethod(this, 'initialize'),
        if (this._xsltUrl && !this.get_isUpdating())
            this._loadXslt(this._xsltUrl);
        if (this._xmlUrl && !this.get_isUpdating())
            this._loadXml(this._xmlUrl);
    },

    _loadXml: function(url) {
        if (this._timeoutID) window.clearTimeout(this._timeoutID);
        this.xmlUrl = url;
        if (url == null || url == '') return;

        var request = new Sys.Net.WebRequest();
        //Sys.Debug.trace("XML Data load: " + url);
        var context = new Object();
        request.add_completed(Function.createDelegate(this, this._loadXmlComplete));
        request.set_userContext(context);
        if (this._lastMod)
            request.get_headers()['If-Modified-Since'] = this._lastMod;
        request.set_url(url);
        request.invoke();
    },

    _loadXmlComplete: function(response) {
        if (response == null) { response = new Sys.Net.WebRequestExecutor(); }
        var context = response.get_webRequest().get_userContext();
        var status = response.get_statusCode();
        var url = response.get_webRequest().get_url();
        var xml;
        if (status == 200) {
            try {
                var lastMod = response.getResponseHeader('Last-Modified'),
                if (lastMod && lastMod != '' && this._lastMod == lastMod) {
                    this.queueReload();
                    return;
                }
                else this._lastMod = lastMod;

                xml = response.get_xml();
                if (xml == null)
                    xml = response.get_responseData();
                if (!xml) throw Error.create(
                    'We could not load the XML data at the URL ' + url);
                var xmlLoadedHandler = this.get_events().getHandler('xmlLoaded'),
                if (xmlLoadedHandler) xmlLoadedHandler(this, Sys.EventArgs.Empty);
                this.set_xml(xml);
            } catch (e) {
                Sys.Debug.fail('Could not process callback method.'),
            }
        }
        else if (status == 304){
            // not modified.
            this.queueReload();
        }
        else { // Process the status. Could be 401, 404 (not found), 410 (gone)
            var statusText = response.get_statusText();
            Sys.Debug.trace(
         String.format('ERROR: {0} replied "{1}" ({2}).', url, statusText, status));
            var errorHandler = this.get_events().getHandler('error'),
            if (!errorHandler) {   // Default error handler
                switch (status) {
                    case 410: // HttpStatusCode.Gone:
                        alert('Content has been removed.'),
                        break;
                    case 404: // HttpStatusCode.NotFound:
                        alert('Could not find resource.'),
                        break;
                    default:
                        alert(String.format('ERROR: {0} replied "{1}" ({2}).',
                            url, statusText, status));
                }
            } else {
                errorHandler(response, Sys.EventArgs.Empty);
            }
        }
    },

    _loadXslt: function(url) {
        this.xslUrl = url;
        if (url == null || url == '') return;
        var request = new Sys.Net.WebRequest();
        Sys.Debug.trace("XSLT Load: " + url);
        request.add_completed(Function.createDelegate(
            this, this._loadXsltComplete));
        request.set_url(url);
        request.invoke();
    },
    _loadXsltComplete: function(response) {
        var context = response.get_webRequest().get_userContext();
        var status = response.get_statusCode();
        var xml;
        if (status == 200) {
            try {
                xml = response.get_xml();
                if (xml == null)
                    xml = response.get_responseData();

                var xsltLoadedHandler = this.get_events().getHandler('xsltLoaded'),
                if (xsltLoadedHandler) xsltLoadedHandler(this, Sys.EventArgs.Empty);
                if (xml) this.set_xslt(xml);
            } catch (e) {
                var errorHandler = this.get_events().getHandler('error'),
                if (errorHandler) errorHandler(response, Sys.EventArgs.Empty)
                else
                    Sys.Debug.trace('Could not process callback method.'),
            }
        }
    },

    _render: function() {
        Sys.Debug.trace('XmlControl Render'),
        var control = this.get_element();
        if (control == null || this._xml == null || this._xslt == null)
            return;

        var prerenderHandler = this.get_events().getHandler('prerender'),
        var needsRendering = true;
        if (prerenderHandler) needsRendering = prerenderHandler(this, Sys.EventArgs.
Empty);

        if (needsRendering)
            SOAjax.XmlTransform(this._xml, this._xslt, control);
        //control.style.display = '';
        this._rendered = true;

        var renderHandler = this.get_events().getHandler('render'),
        if (renderHandler) renderHandler(this, Sys.EventArgs.Empty);
        this.queueReload();
    },

    queueReload: function() {
        if (!this._active) return;
        if (this._timeoutID) window.clearTimeout(this._timeoutID);
        this._timeoutID = window.setTimeout(
            String.format("SOAjax.Controls.XmlControl.Refresh('{0}')",
                this.get_element().id), this._reloadInterval);
    },
    dispose: function() {
        ///<summary>Release resources before control is disposed.</summary>
        var element = this.get_element();
        if (element) $clearHandlers(this.get_element());
        SOAjax.Controls.XmlControl.callBaseMethod(this, 'dispose'),
    }
}
SOAjax.Controls.XmlControl.registerClass(
    'SOAjax.Controls.XmlControl', Sys.UI.Control);

SOAjax.Controls.XmlControl.Refresh = function(elementID) {
    var xmlControl = $find(elementID);
    if (xmlControl && xmlControl.reload)
        xmlControl.reload();
}

// Initializes the XmlControl templates during the page load.
SOAjax.Controls.XmlControl.OnPageInit = function() {
    Sys.Debug.trace('SOAjax.Controls.XmlControl.OnPageInit.'),
    if (window.__XmlControlTemplates != 'undefined' &&
            window.__XmlControlTemplates != null) {
        while (window.__XmlControlTemplates.length > 0) {
            var template = Array.dequeue(window.__XmlControlTemplates);
            try {
                var element = $get(template.elementID);
                var control = $create(SOAjax.Controls.XmlControl,
                template.properties, template.events, template.references, element);
            } catch (e) {
                Sys.Debug.trace(
                    'Could not create XmlControl instance from template.'),
                Sys.Debug.traceDump(template, 'invalid XmlControl template'),
                if (Sys.Debug.isDebug)
                    Sys.Debug.fail('Error in XmlControl onpageinit.'),
            }
        } // end while
    }
}
Sys.Application.add_init(SOAjax.Controls.XmlControl.OnPageInit);
Sys.Application.notifyScriptLoaded();
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset