Case Study: Adding History to the Wiki Application

The wiki knowledge base application we’ve worked on in previous chapters is a larger-scale application than the simple code samples present. The main functionality for the application is provided in a WikiControl instance that implements the Sys.UI.Control class and renders content that is loaded on demand from Windows Communication Foundation (WCF) back-end services. The WikiControl instance also lets users edit and save content through Web services. Additionally, the application includes authentication logic and an external navigation component that lets users navigate through links in the content or through an external catalog of topics that is rendered as an XmlControl (a control that loads XML data and renders it using client-side XSLT), which we implemented in Chapter 9.

In the application, we don’t want to implement history support for user actions such as logging in or out, or even actions such as editing data. Instead we want to support history wherever users perform navigational actions. Although a user can browse through the wiki content by performing one of several navigational actions, the WikiControl itself is responsible for loading the data. The load method, which is called to cause the wiki to load data for the specified topic, is called by several code paths and is the most appropriate place to add history support. Here is the code for the load method:

load: function(topic) {
    this.set_isLoading(true);
    this._topic = topic;
    this._titleDiv.innerHTML = topic;
    SOAjax.ClearHandlers(this._renderDiv);
    this._renderDiv.innerHTML = 'Loading...';
    this._editControl.value = '';

    Sys.Debug.trace(String.format('WikiControl:load("{0}")', this._topic));

    knowledgebase.DataService.GetData(this._catalog, this._topic,
        Function.createDelegate(this, this.onLoadComplete),
        Function.createDelegate(this, this.onFailure),
        this);
}

To add history support, we can break the load method into three methods. These new methods are defined in Example 10-4. First we’ll change the load method to a private method called _load. Next we’ll add a method named load that simply creates a history point. Upon creation of the history point, the navigate event is raised, and this event will be handled by the newly created onHistoryNavigate method. The onHistoryNavigate method in turn determines whether the event’s history is from this control instance by comparing the controlID that identifies the history state with its own ID. If it is, onHistoryNavigate calls the private _load method. This strategy ensures that the WikiControl does not handle history state that was generated by another control.

Example 10-4. The WikiControl demonstrates the design pattern for history support (Web/Script/Controls/ WikiControl.js).

load: function(topic) {
    if (Sys.Application.get_enableHistory()) {
        var state = { controlID: this.get_id(), topic: topic };
        Sys.Application.addHistoryPoint(state, topic);
    } else {
        this._load(topic);
    }
},

onHistoryNavigate: function(sender, historyEventArgs) {
    var state = historyEventArgs.get_state();
    if (state.controlID == this.get_id()) {
        this._load(state.topic);
    }
},

_load: function(topic) {
    this.set_isLoading(true);
    this._topic = topic;
    this._titleDiv.innerHTML = topic;
    SOAjax.ClearHandlers(this._renderDiv);
    this._renderDiv.innerHTML = 'Loading...';
    this._editControl.value = '';

    Sys.Debug.trace(String.format('WikiControl:load("{0}")', this._topic));

    knowledgebase.DataService.GetData(this._catalog, this._topic,
        Function.createDelegate(this, this.onLoadComplete),
        Function.createDelegate(this, this.onFailure),
        this);
}

After implementing the navigate handler as demonstrated in Example 10-4, the next step is to add the navigate event handler to the actual navigate event. In the WikiControl’s initialize method, the following code can be used to create a delegate to the event handler and add it to Sys.Application’s navigate event:

this.historyDelegate = Function.createDelegate(this, this.onHistoryNavigate);
Sys.Application.add_navigate(this.historyDelegate);

When adding the handler to the initialize event, it’s also important to remove it in the dispose event. The following sample code removes and deletes the historyDelegate in the dispose method of the WikiControl:

if (this.historyDelegate) {
    Sys.Application.remove_navigate(this.historyDelegate);
    delete this.historyDelegate;
}

With this technique, you can add history support to an existing AJAX control with minimal coding effort. You simply serialize the control’s state in an object and add it as a history point. The framework handles creating the history point, and the control loads the data—whether it’s coming from a direct user action such as a navigation click or the user clicks the Back or Forward button.

Tip

Tip

The entire code sample for the AJAX wiki application is available online at http://www.microsoft.com/mspress/companion/9780735625914.

..................Content has been hidden....................

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