Framework / Web Forms / AJAX / Extending Nevron JavaScript Library

In This Topic
    Extending Nevron JavaScript Library
    In This Topic
     Extending Nevron JavaScript Library

    The Nevron JavaScript Library (or Library for short) is designed to allow third party developers to easily add new client side and AJAX functionality to the Nevron web controls. There are two ways to extend the Library, recommended by Nevron: creating custom AJAX commands and creating custom tools.

     Custom AJAX Commands

    On a lower level the Library communicates with the server by sending AJAX commands through asynchronous requests and reading the response to get the command results. An AJAX command is a string, accompanied by an associative array of arguments. Any text can be used as an AJAX command and any set of arguments can be sent to the server. 

    There are several AJAX commands with predefined arguments that are used intrinsically: “mouseClick“,“mouseDoubleClick“,“mouseDown“,“mouseUp“,“mouseMove“,“mouseOver“,“mouseOut“,“autoRefresh“,“refresh“, and “getImageMapXml“. All mouse AJAX commands are sent to the server on user mouse input and cause the mouse-related server side events of the corresponding Nevron web control to be fired. The “autoRefresh“AJAX command is sent to the server periodically when auto refresh is enabled. The “refresh“ and “getImageMapXml“AJAX commands can be invoked from user JavaScript in order to refresh the chart forcibly or acquire the current image map data. 

    Additionally, custom AJAX commands can be sent to the server side control from within user JavaScript, like this:

     

    JavaScript
    Copy Code
    //Make sure the NChartCallbackServicetype is loaded
    if(typeof(NChartCallbackService) !="undefined")
    {
    //Acquire the instance of the client side JavaScript object
    // that is associated with the web control
    varcs = NChartCallbackService.GetCallbackService('MyChartControl');
     
    //Build an associative array to store the arguments
    varattributes = new Array();
    attributes["arg1"] = "value 1";
    attributes["arg2"] = "value 2";
     
    //Invoke the custom AJAX command
    cs.InvokeCustomCommand("customCommand",attributes);
    }
    

     

    At the server, when the command is received, the AsyncCustomCommand event of MyChartControl is fired:

    C#
    Copy Code
    protected void MyChartControl_AsyncCustomCommand(object sender, EventArgs e)
    {
        NCallbackCustomCommandArgs args = e as NCallbackCustomCommandArgs;
        NCallbackCommand command = args.Command;
     
        switch (command.Name)
        {
            case "customCommand":
                string arg1Text = command.Arguments["arg1"] as string;
                stringarg2Text = command.Arguments["arg2"] as string;
                ...
                //Perform some action
                ...
                break;
        }
    }
    
    Visual Basic
    Copy Code
    Protected Sub MyChartControl_AsyncCustomCommand(ByVal Sender As Object, ByVal E As EventArgs)
        Dim Args As ArgsNCallbackCustomCommandArgs = TryCast(E, NCallbackCustomCommandArgs)
        Dim Command  As NCallbackCommand = Args.Command
     
        Select Case Command.Name
            Case "customCommand"
                Dim Arg1Text AS String = CString(Command.Arguments("arg1"))
                Dim Arg2Text As String = CString(Command.Arguments("arg2"))
                ...
                'Perform some action
                ...
        End Select
    End Sub
    

    If the command is supposed to return result to the client, the AsyncQueryCommandResult event of the web control must also be handled:

    C#
    Copy Code
    protected void MyChartControl_AsyncQueryCommandResult(object sender, EventArgs e)
    {
        NCallbackQueryCommandResultArgs args = e as NCallbackQueryCommandResultArgs;
        NCallbackCommand command = args.Command;
        NAjaxXmlTransportBuilder resultBuilder = args.ResultBuilder;
     
        switch (command.Name)
        {
            case "customCommand":
                //    add a built-in data section that will enforce full
                //    image refresh at the client
                if (!resultBuilder.ContainsRedrawDataSection())
                    resultBuilder.AddRedrawDataSection(MyChartControl);
    
                NAjaxXmlDataSection dataSection = new NAjaxXmlDataSection("someSection");
                dataSection.Data ="Some data";
                resultBuilder.AddDataSection(dataSection);
                break;
        }
    }
    
    Visual Basic
    Copy Code
    Protected Sub MyChartControl_AsyncQueryCommandResult(ByVal Sender As object, ByVal E As EventArgs)
        Dim Args NCallbackQueryCommandResultArgs = TryCast(E, NCallbackQueryCommandResultArgs)
        Dim Command As NCallbackCommand = Args.Command
        Dim ResultBuilder As NAjaxXmlTransportBuilder = Args.ResultBuilder
     
        Select Case command.Name
            Case "customCommand"
                '    add a built-in data section that will enforce full
                '    image refresh at the client
                If  Not ResultBuilder.ContainsRedrawDataSection() Then _ 
                    ResultBuilder.AddRedrawDataSection(MyChartControl)
    
                Dim DataSection As NAjaxXmlDataSection = New NAjaxXmlDataSection("someSection")
                DataSection.Data ="Some data"
                ResultBuilder.AddDataSection(DataSection)
        End Select
    End Sub
    

    The result can be read at the client in the following way:

    JavaScript
    Copy Code
    //  subscribe for the callback success event
    NEventSinkService.AsyncCallbackSucceeded.Subscribe(CallbackSucceeded);
    
    //  event handler that is invoked when an async command is completed successfully
    functionCallbackSucceeded(self, result, context)
    {
        switch(context.command)
        {
            case 'customCommand':
                var transport = new NAjaxXmlTransport();
                transport.Deserialize(result);
                if(!NReflection.IsInstance(transport.DataSections["someSection"]))
                    break;
                var someSectionText = transport.DataSections["someSection"].Data;
                ...
                //Peroform some action
                ...
                break;
        }
    }
    

    Custom AJAX commands can be used for both extending the interactivity of the web control and performing any general client-server tasks that must be synchronized with the web control event handling. 

    Both the Nevron Chart and Diagram web examples that are installed by the Nevron .NET Vision installation contain an example on custom commands, which is located at AJAX\Engine\NCustomCommandsUC.ascx.

     Custom Tools

    A higher level abstraction of the event processing is provided by the controller-tools architecture that is part of the Nevron JavaScript Library. All client-side interactivity is streamlined through a controller object, which maintains a collection of tools. All tools that are able to process a specific event generate commands (please note the difference between the controller commands and the AJAX commands) until all tools have been queried or a tool has marked the event as handled. Next, the controller commands are executed in a row. Some of the controller commands perform pure client side actions, and others send AJAX commands to the server. 

    All AJAX commands described in the previous section are generated by corresponding tools. Additional tools are implemented by Nevron to provide client side tooltips, dynamic cursors, browser redirect and other basic and advanced features. 

    Custom tools can be implemented in order to extend the interactivity of a web control, while remaining compatible with the existing interactive tools.  

    To implement a custom tool, new classes must be implemented at both server and client side. At server side, a tool definition class must be created that derives from NAjaxToolDefinition:

    C#
    Copy Code
    [Serializable]
    public class NAjaxCustomTool : NAjaxToolDefinition
    {
        public NAjaxCustomTool(bool defaultEnabled, string customConfField)
              : base("NCustomTool", defaultEnabled)
        {
            this.customConfField = customConfField;
        }
     
        protected override string GetConfigurationObjectJavaScript()
        {
            return string.Format("new NCustomToolConfig('{0}')", this.customConfField);
        }
     
        private string customConfField;
    }
    
    Visual Basic
    Copy Code
    <Serializable>
    Public Class NAjaxCustomTool 
        Inherits NAjaxToolDefinition
        Public Sub New(ByVal DefaultEnabled As Boolean , ByVal CustomConfField As String)
            MyBase("NCustomTool", DefaultEnabled)
            Me.CustomConfField = CustomConfField
        End Sub
     
        Protected Overrides Function GetConfigurationObjectJavaScript() As String
            Return String.Format("New NCustomToolConfig('{0}')", Me.CustomConfField)
        End Function
     
        Private CustomConfField As String
    End Class
    

    The "NCustomTool"parameter in the base class constructor invocation specifies the name of the JavaScript class that will represent the tool at the client. The return value of the GetConfigurationObjectJavaScript() method is the actual JavaScript code that will be used to create the tools configuration JavaScript, when the web control is being rendered to HTML. Additionally, the above sample code demonstrates how tool configuration fields defined at the server can be communicated to the client tools. When writing your own tool definitions, please make sure to mark them as serializable. 

    The complete Nevron JavaScript Library is implemented with JavaScript classes. A JavaScript class is a Nevron extension to the JavaScript object and provides common OOP features like inheritance, virtual methods, events, static methods and runtime type information. There are certain coding patterns that must be followed in order to implement a JavaScript class, rather than a simple JavaScript object. These patterns are illustrated in the code below:

    JavaScript
    Copy Code
    functionNCustomToolConfig(customConfField)
    {
        this.InitializeRuntimeTypeInfo(NCustomToolConfig.prototype);
        this.NAjaxToolConfig(false);
     
        this.customConfField = customConfField;
    };
    NCustomToolConfig.DeriveFrom(NAjaxToolConfig);
    

    This JavaScript code defines the new JavaScript class NcustomToolConfig.The InitializeRuntimeTypeInfo call is required to read and cache all runtime type information like the name of the class and the name of the base class. The line this.NAjaxToolConfig(false);invokes the parent constructor and is an analogue to the :base(false)C# syntax. The DeriveFromcall copies all methods and fields from the base object’s prototype to the NCustomToolConfig prototype, making them available in the derived class. 

    The NCustomToolConfig JavaScript class implements the configuration class of a new custom tool. An instance of this class will be passed to the tool, making the server side configuration available in the client side JavaScript code. 

    To implement a complete custom tool, more new JavaScript classes must be defined. The following code demonstrates how to implement the class of the tool itself:

    JavaScript
    Copy Code
    functionNCustomTool(callbackService, toolConfig)
    {
        this.InitializeRuntimeTypeInfo(NCustomTool.prototype);
        this.NAjaxTool(callbackService, toolConfig);
          
        //    initialize any internal tool fields
        this.internalToolField=null;
        ...
          
        if (NReflection.IsInstance(toolConfig.configurationObject))
            this.config = toolConfig.configurationObject;
        else
            this.config = new NCustomToolConfig();
    };
    NCustomTool.DeriveFrom(NAjaxTool);
    

    The above class specifies its base class, a constructor and possible data members, but is missing any methods. The class definition continues with a method that overrides a virtual method from the NajaxTool base class:

    JavaScript
    Copy Code
    NCustomTool.prototype.RequiresMouseMoveEvent = function(self)
    {            
        return true;
    };
    

    Please note the self argument. It is an alternative for this,explicitly passed as a parameter. self must be used instead of this in all virtual functions, overrides, and event handlers that are implemented within JavaScript classes. The specific method in the above code is implemented in order to notify the controller that the tool will process mouse events.

    JavaScript
    Copy Code
    NCustomTool.prototype.ProcessMouseMove = function(self, commandQueue, eventData)
    {            
        //    Implement some logic here, prior to enqueuing new commands
     
        commandQueue.Enqueue(new NCustomControllerCommand(self.callbackService, self, commandQueue, eventData));
    };
    

    This is another method that overrides a base virtual method. It generates new controller commands and appends them to the command queue.  

    Next, the NcustomControllerCommand class must be defined:

    JavaScript
    Copy Code
    functionNDisplayDetailedChartCommand(callbackService, tool, commandQueue, eventData)
    {
        this.InitializeRuntimeTypeInfo(NDisplayDetailedChartCommand.prototype);
        this.NCallbackCommand(callbackService, tool, commandQueue);
     
        this.eventData = null;
     
        if (NReflection.IsInstance(eventData))
            this.eventData = eventData;
    };
    NDisplayDetailedChartCommand.DeriveFrom(NCallbackCommand);
     
    NDisplayDetailedChartCommand.prototype.Execute = function(self)
    {
        // Here comes the actual code that is performed by the command
        ...
     
        NDisplayDetailedChartCommand.GetBase().Execute(self);
    };
    

    Please note the syntax of the base method invocation. It also requires the explicit selfparameter. 

    There is one more class to implement in order to allow the creation of the custom tool object. A custom tool factory must be defined that knows of the NCustomToolConfig class:

    JavaScript
    Copy Code
    functionNCustomToolFactory()
    {
        this.InitializeRuntimeTypeInfo(NCustomToolFactory.prototype);
        this.NToolFactory(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]);
    };
    NCustomToolFactory.DeriveFrom(NToolFactory);
     
    NCustomToolFactory.prototype.InitializeTools = function(self, callbackService)
    {
        //    initialize the built-in tools
        NCustomToolFactory.GetBase().InitializeTools(self, callbackService);
          
        //    initialize the custom tools
        for (var i = 0; i < self.configurationItems.dictionaryEntries.length; i++)
        {
            var de = self.configurationItems.dictionaryEntries[i];
            var toolConfig = de.val;
            var tool = null;
                
            if (toolConfig.toolId == NCustomTool.GetClassName())
            {
                tool = new NCustomTool(callbackService, toolConfig);
            }
                      
            if (tool != null)
            {
                callbackService.controller.tools[callbackService.controller.tools.length] = tool;
                tool.controller = callbackService.controller;
            }
        }
    };
    

    And finally, the server side web control must be configured to use the new custom tool factory in the generated JavaScript code:

    C#
    Copy Code
    protected void Page_Load(object sender, System.EventArgs e)
    {
        MyChartControl.AjaxToolsFactoryType = "NCustomToolFactory";
        ...
    }
    
    Visual Basic
    Copy Code
    Protected Sub Page_Load(ByVal Sender As Object ,ByVal E As System.EventArgs)
        MyChartControl.AjaxToolsFactoryType = "NCustomToolFactory"
        ...
    End Sub
    

    The Nevron documentation contains a complete code reference for the Nevron JavaScript Library and can be of assistance to developers who want to implement custom AJAX tools. 

    Both the Nevron Chart and Diagram web examples that are installed by the Nevron .NET Vision installation contain an example on custom tools, which is located at AJAX\Engine\NCustomToolsUC.ascx.