Skin Widgets in DotNetNuke

DotNetNuke has long had many ways to extend the application to fit your needs. This included providers, skins, modules, and more. It wasn’t until the first release of the version 5 series of DotNetNuke that there was finally a built-in and supported extension point that allowed you to extend the platform after the page loaded. This all changed with the introduction of the Skin Widget framework. Now, it was possible to do things that were previously only possible using a module or the skin itself, using JavaScript, and in most cases, the jQuery framework.

What is a Skin Widget?

Skin widgets are meant to bridge the gap between the delivery of the content to the website visitor, and the interactivity of the content between the visitor and the web browser. Whereas the web server itself processes requests, interacts with the database, and delivers static content to the visitor, skin widgets allow you to perform a variety of tasks upon the presented content, after it has been loaded into the web browser. This effectively allows you to separate HTML and JavaScript-based behaviors from your mark-up, create testable code snippets that are reusable, and provide user interface modifications with the highest performance possible.
 
When you separate the behavior modifications from your module and skins mark-up, you gain many benefits. You remove unnecessary mark-up from your HTML, such as attributes like ONCLICK, ONMOUSEOVER, and ONMOUSEOUT. This makes your HTML easier to read, but also is more friendly to search engines, since there’s less HTML to parse and index – leaving more time for the search engine to index your content. Your pages will also load faster, because like the search engines, there’s less HTML to parse and react to during the rendering process. There are many other related benefits, but this behavior separation also makes your mark-up easier to maintain, both from a developer perspective, but also from a designer perspective. The mark-up is simply cleaner and easier to read.
 
A widget in your design or module is nothing more than an HTML object tag, with any necessary or required PARAM tags. To illustrate this, here is a code snippet using the built-in Relocation Widget (see Listing 1).
 
<object id="wdgRelocate" codebase="RelocationWidget"
codetype="dotnetnuke/client" declare="declare">
 <param name="sourceId" value="FooterMenuContainer" />
 <param name="targetId" value="HeaderMenuContainer" />
</object>
Listing 1: Example Widget Code
 
Looking at the previous example, it should be fairly clear that this method of applying behavioral modification is very easy to read, test, and reuse throughout your site. A widget is easily tested because all of its dependencies are already loaded by DotNetNuke. You can just test the widget code itself. This method of HTML mark-up is also very easy to read, allowing nearly anyone that can write HTML to use and reuse an existing widget.
The widget framework was written to run in a way to ensure that the web page has completely loaded prior to the JavaScript within the widget executing. This reduces the number of potential DOM-related errors, and reduces page load time, since the web browser doesn’t have to switch back and forth between the HTML and JavaScript rendering engines as much. This also results in a better user experience, since the page dependencies are already loaded into the web browser, before your widgets get to work.
 
For more information about DOM and what it is, see: http://www.w3schools.com/HTMLDOM/
 
Widgets can be used in modules as part of the static or generated mark-up, in skins, and even as dynamic content in existing modules. For example, it’s not uncommon for someone to add an HTML module to the page specifically for the purposed of adding a widget to the page. This makes widgets extremely flexible in their scope, and the number of use cases they can be used for. This level of flexibility also keeps the possibilities of what a widget can be wide open.

How do Widgets work?

The widget framework is a built-in extension point of the DotNetNuke web application framework. This means that like modules and skins, they can be packaged, installed, and managed in exactly the same way. You can package widgets alone, or with other extensions. If you have a skin package that requires a widget, it would be easy enough to build a widget and include it within the package as a dependency. Now, we’re going to dive into how this is all possible.
 
The framework was written by Nik Kalyani (www.kalyani.com), one of the co-founders of the DotNetNuke Corporation. He specifically architected the widget framework to sit on top of the Microsoft ASP.Net AJAX client-side library, as an extension of that library. If it isn’t already apparent, this is completely a client-side solution. This allows you to take advantage of any type of client-side technologies and methodologies that you want.
 
While the widget framework is written in JavaScript, it makes extensive use of the jQuery library for ease of development, speed, and cross-browser compatibility. The chief advantage using this approach is to allow all of the required scripts to be loaded asynchronously. This enables your web browser to process the page, without waiting for the widget framework to load. The loading of the widget framework happens independently of the web page itself.
 
Widgets are rendered in a four step process, initialized after the page loads. This is all dependent upon the widgets being enabled in the Site Settings, allowing each site in a multi-portal instance to independently decide if they want to allow widgets to be used. 
 
If you do not think widgets will be used on your site, it might be beneficial to you from a performance perspective to disable the widgets. This can be done by unchecking the “Enable Skin Widgets” checkbox in your Site Settings. Widgets are enabled by default in all new installations of DotNetNuke. In instances where the site was upgraded from the 04.xx series, widgets are not enabled unless you manually enable them in Site Settings (figure 1).
 
Figure 1: Enabling Skin Widgets in Site Settings
 
 
If the widgets are included in your site and the framework is disabled, nothing really bad will happen. Since they make use of an OBJECT tag, there is likely nothing rendered on the page in most instances. This should especially be true if you use the DECLARE attribute of the OBJECT tag. However, the results that you expect to see from the widgets that are in your skin or modules will not be realized.
 
As I mentioned before, the widget framework is initialized upon the page load in four steps: Initialization, Detection, Instantiation, and Rendering. This is very well-documented in this diagram by Nik Kalyani (figure 2).
 
Figure 2: Skin Widget Framework Architecture
 

Initialization

Widgets are initialized after the DOM has loaded. The first thing that happens is that the initWidgets.js file is loaded. This initialization script checks to see if the widget framework dependencies are loaded. If they aren’t, the script will load them asynchronously. This includes the Microsoft ASP.Net AJAX library, and setting up some global variables for the widget framework to use later. Finally, this script initiates a sequence of other scripts and events, including loading the DotNetNuke AJAX library and the JavaScript classes that define the widget framework.

Detection

The first thing the widget framework does after loading is parse the DOM for any widgets. The framework is querying the DOM for any OBJECT tag with the CODETYPE attribute of “dotnetnuke/client” as the value. The framework then loads the code associated with each widget. The location of the code to execute is defined by the CODEBASE attribute of the OBJECT tag. 
 
In the case of the Relocation Widget listing 2 below, the OBJECT tag tells the framework to find the widget code for the Relocation Widget, and execute it.
 
<object id="wdgRelocate" codebase="RelocationWidget"
codetype="dotnetnuke/client" declare="declare">
Listing 2: Relocation Widget Open Tag
 
In the background, the framework looks for the following widget file to execute.
 
<website root>/Resources/Widgets/DNN/RelocationWidget.js
 
Custom widgets that you or others might write are detected a bit differently. If I had created a widget called SampleWidget and installed it using the standard method (described later), the OBJECT tag would look more like listing 3 below.
 
<object id="wdgSample"
codebase="YourCompany.Widgets.SampleWidget"
codetype="dotnetnuke/client" declare="declare">
Listing 3: Example Widget Open Tag
 
In the background, the widget framework would instead look for the following file.
 
<website root>/Resources/Widgets/User/YourCompany/YourCompany.Widgets.SampleWidget.js
 
There is a direct dependency between the CODEBASE attribute value, and the file and folder names. If the pattern above is not followed, the widget will not be found, and the rendering will not occur since the code cannot be executed.

Instantiation

The framework now caches the type for each widget it finds to make the widgets execute faster, and then instantiates each widget type in preparation of executing them in the next step. It’s possible for the same widget type to be added to a single page multiple times.
Rendering
 
When building a widget for DotNetNuke, developers execute all of their code in a predefined RENDER method. The rendering step is executed 20 milliseconds after the DOM loads, and looks through all widgets in the cache, executing the RENDER method for each of them. Each widget will render in a different way, depending on what the developer built it to do. No matter what the widget itself does, the OBJECT tag will get replaced by a DIV tag. In many cases, there will also be additional elements injected into the DIV tag too. In the case of the built-in Embed Widget, the injected content might be a video or other media.
 
The Relocation Widget sample in listing 3 would be rendered like shown in listing 4 below, along with any additional attributes and content that the widget code might define. The new attributes might define CSS class names, title, and more.
 
<div id="wdgRelocate_wrapper">
</div>
Listing 4: Relocation Widget After Page Render

Built-In (Core) Widgets

There are several widgets that already pre-installed into DotNetNuke to help you with your client-side rendering and interaction needs, out-of-the-box. Some are quite simply, while others are very flexible, allowing you to use them to fit a variety of needs.
 
Embed Widget
The Embed Widget is probably the most flexible widget in the built-in arsenal that ships with DotNetNuke. It has several pre-defined types of content that it allows you to literally embed into your site. They include: Disqus, Flash, Flickr, Google Analytics, Widget Box, and YouTube. When using this widget, you can easily inject content from any of those providers, and even use it as a rendering engine to specify and embed your own. It’s quite flexible not only in allowing you to provide your own embed types, but it also allows you to specify any number of custom parameters in your custom embed widgets.
 
Relocation Widget
The Relocation Widget is often called the “SEO Widget” by those that use it. That’s because it has a single purpose. It allows you to format the structure of your HTML in any way that you’d like. Then, when the widget executes, it relocates a specified block of HTML from any location in the page, to any other. Think of examples like your menu being at the bottom of the page, and then it magically being moved to the top of the page. This has the benefit of search engines seeing one version of your HTML page, and your website visitors seeing another entirely.
 
Rotator Widget
If you’ve ever wanted an easy way to rotate content in your website, the Rotator Widget has your interest in mind. It allows you to rotate content within a predefined HTML element on your page. Some of the most interactive home pages have something like this in place, changing an image-based section of content with another at a defined interval.
 
Style Scrubber Widget
There are many times when a built-in component or 3rd party extension in your site might have embedded styles or attributes that are breaking your design, or otherwise causing you grief due to not being able to manage those attributes in your skin. The Style Scrubber Widget was built with this use-case in mind. You can easily replace or remove styles and attributes from elements of the page that you don’t have control over.
 
Style Sheet Widget
This is probably the most popular of the existing widgets, simply because you’ve seen it in use numerous times. Chances are, many of you have looked at it on a daily basis and didn’t know it. This is because the Style Sheet Widget is included in the default skin that’s been pre-installed on all of the version 5 series of DotNetNuke websites. So, as soon as you see your installation is successful, this widget has been staring you in the face. This widget allows you to dynamically switch out the style sheets of your site with a single click. In the Minimal Extropy skin, this widget is included as a well-defined example, in the form of the font size and page width icons on the right side of the page, near the top.
 
Visibility Widget
The Visibility Widget might sound self-explanatory, and it probably should. It does exactly what the name implies – it allows you to toggle the visibility of any specified elements on the page. If used creatively, this widget can have a lot of usefulness. For example, when DotNetNuke version 5 was first announced, this widget helped to show and hide an embedded style sheet during the demonstration. It allowed a skin switching control panel to be hidden and shown on demand.

Real World Widgets in Use

Widgets are a poorly documented and very under-utilized part of the DotNetNuke framework. Very few people understand or use them. It’s not very clear what they are and why or how you can benefit from using them unless you just dive in. Hopefully, this article will help to change that, and the community wiki is doing a very good job of helping too.
 
A widget can do anything that you want it to, within the boundaries of writing client-side code against the web browser. There are existing widgets that can give you alternate print views, change out style sheets on demand, include new script files, embed content, check for cookies, include jQuery plugins, and more.
 
Nik Kalyani has a couple of example widgets available for download in his blog, including the print view one mentioned above. 
 
There is also an open source project called the Widget Suite that offers you 19 widgets as of the time of this writing. The project is run by both authors of this article, and Mark Allan (known best for the DDRmenu by DNNGarden.com). The widgets in the suite range from breaking your site out of frames, to marking and managing external links on your site, to implementing jQuery content sliders, and more. 
 
One of the more popular widgets in the Widget Suite acts as a wrapper for the Facebook social plug-ins. If you’re not familiar with the social plug-ins offered by Facebook, they allow you to integrate the social graph features they offer into your website. Think of things like activity feeds, comments, likes, and sharing. These plug-ins are not things that you would want pre-loaded on your website for search engines to crawl through. Having these plug-ins available as widgets allows you to take advantage of their functionality without forcing your web server to do the work. Your visitor’s web browser will load and render the Facebook plug-ins instead. This is a great benefit, along with the search engines not having to parse through the plug-in code. The search engine will index your content instead.

Building a Widget

Now that you know more of the inner workings of the widget framework and widgets itself it's time to write your own. A great way to start is by converting over a jQuery plug-in to a DotNetNuke widget. Because there is not much fancy JavaScript involved in this, it is a great way to get your hands dirty coding your first widget to get an understanding of how the jQuery/widget setups works. You can start each of your jQuery plug-in based widgets using the following setup. In the rest of this article we will explain this step-by-step.
 
The code example below shows you the base framework that you would want to have in place when starting to build your own widgets.
 
//////////////////////////////
// BEGIN: PluginName class //
////////////////////////////
 
// BEGIN: Namespace management
Type.registerNamespace("YourCompany.Widgets");
// END: Namespace management
 
YourCompany.Widgets.PluginName = function(widget) {
 YourCompany.Widgets.PluginName.initializeBase(this,
   [widget]);
}
 
YourCompany.Widgets.PluginName.prototype =
{
 // BEGIN: render
 render: function() {
    var widget = this._widget;
 
    (function($) {
      // Default parameters
      var wrapper = ".wrapper";
      var param1 = "test";
      // Parse parameters
      $(widget).children().each(function() {
        if (this.name && this.value) {
          var paramName = this.name.toLowerCase();
          var paramValue = this.value;
 
          switch (paramName) {
            case "wrapper":
              wrapper = paramValue;
              break;
            case "param1":
              param1 = paramValue;
              break;
          }
        }
      });
 
      // Get widget location
      var pageHost = document.location.host;
 
      // Set default values for original jQuery plugin
      var options = {
        param1: param1,
      }
 
      // Check if plugin is allready loaded
      if (jQuery.fn.PluginName) {
        // Plugin already loaded no need to load script
        // just call the plugin
        $(wrapper).PluginName(options);
      } else {
        // Plugin not loaded so first load the plugin
        // and then call it
        jQuery.getScript($dnn.baseResourcesUrl +
          "Widgets/User/YourCompany/js/PluginName.js",
          function() {
            $(wrapper).PluginName(options);
         });
      }
 
       })(jQuery);
    }
    // END: render
}
 
YourCompany.Widgets.PluginName.inheritsFrom(
 DotNetNuke.UI.WebControls.Widgets.BaseWidget);
YourCompany.Widgets.PluginName.registerClass(
 "YourCompany.Widgets.PluginName", DotNetNuke.UI.WebControls.Widgets.BaseWidget);
DotNetNuke.UI.WebControls.Widgets.renderWidgetType(
 "YourCompany.Widgets.PluginName");
// END: PluginName class
Listing 5: Example Widget Code Starting Point
 
In this article we will use the above code snippet to create a widget for the Hilight jQuery plug-in as described in http://www.learningjquery.com/2007/10/a-plugin-development-pattern.  This is a great article to learn how to build your own jQuery plug-in which will come in handy as well if you develop more widgets.
 
The Hilight plugin is just a simple example of building a jQuery plug-in. It allows you to be able to highlight text in your page.
 
At this point, you should have some understanding on how a widget works and seen some code so we will only focus on the important parts of the widget and code we have not yet discussed in detail.
 
First, we start of by defining the default values for the widget parameters. These are the same values as defined by the plug-in developer as the default values in the plug-in. It is a best practice to set it up like this , since we don't need to check for empty values.  We will setup the 2 parameters as required by the Hilight plug-in, as well as the wrapper element that we will use this plug-in on.
 
// Default parameters
var wrapper = ".highlight";
var foreground = "red";
var background = "yellow";
Listing 6: Assigning Default Parameter Values
 
Now that we have the default parameters set we add the code that passes these parameters to the widget.
 
// Parse parameters
$(widget).children().each(function() {
 if (this.name && this.value) {
    var paramName = this.name.toLowerCase();
    var paramValue = this.value;
 
    switch (paramName) {
      case "wrapper":
        wrapper = paramValue;
        break;
      case "background":
        navigation = paramValue;
        break;
      case "foreground":
        caption = paramValue;
        break;
    }
 }
});
Listing 7: Parsing the Widget for Parameter Values
 
Before we can use any external script file we need to define the location of the widget so, it knows where to look for any external css or js file. This is not necessary in all widgets, but is often necessary for widgets like this one.
 
// Get widget location
var pageHost = document.location.host;
Listing 8: Defining the Widget Web Page Location
 
Now we pass the values into a jQuery object so it can be used directly by the plug-in. The code snippet in listing 9 is not the only way to accomplish this. If you’re well-versed in JavaScript, you will know that this is only one of many ways to assign values in JavaScript objects.
 
// Set default values for original jQuery plugin
var options = {
    background: background,
    foreground: foreground
}
Listing 9: Assigning Values to the Plug-In, from the Parameter
 
Following listing 10, we would have everything we need in order for the plug-in to work. Notice that we first check if the plug-in is already loaded and based on that we load the script or call the plug-in function. We do this because the jQuery.getScript() function does not cache the script file, so if we call the widget multiple times on the same page, it would also load the external script file several times.
 
// Check if plugin is allready loaded
if (jQuery.fn.PluginName) {
 // Plugin allready loaded no need to load script just call the plugin
 $(wrapper).PluginName(options);
} else {
 // Plugin not loaded so first load the plugin and then call it
 jQuery.getScript($dnn.baseResourcesUrl +
    "Widgets/User/YourCompany/js/jquery.PluginName.js",
    function() {
      $(wrapper).PluginName(options);
    });
}
Listing 10: Include the jQuery Plug-In
 
Now we have a working widget!
 
If you’re following along, then you would end up with a widget file that consists of jQuery and raw JavaScript, named something like:
 
YourCompany.Widgets.WidgetName.js
 
All widget code would be somewhat different, but the code in our Hilight widget should look like listing 11 below.
 
// BEGIN: Namespace management
Type.registerNamespace("YourCompany.Widgets");
// END: Namespace management
 
YourCompany.Widgets.Hilight = function(widget) {
 YourCompany.Widgets.Hilight.initializeBase(this,
  [widget]);
}
 
YourCompany.Widgets.Hilight.prototype =
{
 // BEGIN: render
 render: function() {
    var widget = this._widget;
 
    (function($) {
      // Default parameters
      var wrapper = ".hilight";
      var foreground = "red";
      var background = "yellow";
 
      // Parse parameters
      $(widget).children().each(function() {
        if (this.name && this.value) {
          var paramName = this.name.toLowerCase();
          var paramValue = this.value;
 
          switch (paramName) {
            case "wrapper":
              wrapper = paramValue;
              break;
            case "background":
              navigation = paramValue;
              break;
            case "foreground":
              caption = paramValue;
              break;
          }
        }
      });
 
      // Get widget location
      var pageHost = document.location.host;
 
      // Set default values for original jQuery plugin
      var options = {
        background: background,
        foreground: foreground
      }
 
      // Check if plugin is already loaded
      if (jQuery.fn.Hilight) {
        // Plugin allready loaded no need to load script
        // just call the plugin
        $(wrapper).Hilight(options);
      } else {
        // Plugin not loaded so first load the plugin
        // and then call it
        jQuery.getScript($dnn.baseResourcesUrl +
          "Widgets/User/YourCompany/js/” +
          “jquery.Hilight.js",
          function() {
            $(wrapper).Hilight(options);
          });
      }
 
    })(jQuery);
 }
 // END: render
}
 
YourCompany.Widgets.Hilight.inheritsFrom(
 DotNetNuke.UI.WebControls.Widgets.BaseWidget);
YourCompany.Widgets.Hilight.registerClass(
 "YourCompany.Widgets.Hilight",
 DotNetNuke.UI.WebControls.Widgets.BaseWidget);
DotNetNuke.UI.WebControls.Widgets.renderWidgetType(
 "YourCompany.Widgets.Hilight");
// END: Hilight class
Listing 11: Finished Hilight DotNetNuke Widget

Installing Your Custom Widget

When you are building a widget, the installation process can be manual. All you have to do is create a new subdirectory in the ~/Resources/Widgets/User/ directory. Best practices would suggest that you name the subdirectory after your company. Using the same naming convention used thus far, that would make our new directory ~/Resources/Widgets/User/YourCompany/. Your widget files would go into that directory.
 
As mentioned earlier, it’s very important to get the naming convention correct for the folders and files in the widget framework.
 
In order for our widget to be portable and allow others to use it on their sites, we need to create an installation package. Installation packages for widgets are nearly identical to those created for skins or modules in DotNetNuke. There are only a couple of minor differences, and all within the manifest file. 
 
Extension packaging for DotNetNuke is pretty well-documented, so it is outside the scope of this article to go into any great detail on that topic. However, we will point out the differences in the manifest file, shown in listing 12. All other portions of the manifest file can be copied from an existing installation package for nearly any other extension, including that from the Widget Suite for DotNetNuke.
 
<dotnetnuke type="Package" version="5.0">
 <packages>
    <package name="YourCompany.Hilight"
      type="Widget" version="1.0.0">
      <components>
        <!—
        It is important to identify the type as a
        widget for the installer
        -->
        <component type="Widget">
          <widgetFiles>
            <!-- The name of the widget folder -->
            <basePath>YourCompany</basePath>
           <!—
            The listing of all of the widget files
            included in the zip file
            -->
            <widgetFile>
              <name>
                YourCompany.Widgets.Hilight.js
              </name>
            </widgetFile>
            <widgetFile>
              <path>js</path>
              <name>jquery.Hilight.js</name>
           </widgetFile>
          </widgetFiles>
        </component>
      </components>
    </package>
 </packages>
</dotnetnuke>
Listing 12: Widget Manifest File Example
 
Save the manifest file as CompanyName.dnn and zip all 3 files and install the extension in DotNetNuke the same way you would with any other extension in DotNetNuke. Modules, skins, providers, and even widgets all are installed the same way.
 
Following a successful installation, add the code from listing 13 into your skin or an instance of the Text/HTML Module.
 
<object id="wgtHilight"
codetype="dotnetnuke/client"
codebase="YourCompany.Widgets.Hilight"
declare="declare">
 <param name="wrapper" value=".hilight" />
 <param name="foreground" value="white" />
 <param name="background" value="red" />
</object>
Listing 13: Hilight Widget Code
 
Now you will see the element with the "hilight" class with red background and white text.

Summary

Hopefully, this article has done a good job of walking you through the value of using and building widgets for your DotNetNuke website. You are able to employ user interface, interactive, utilitarian, and even search engine friendly tools solutions on your website without the overhead of a server-side page or user control. Widgets load and execute on the client’s web browser, allowing you to same time and processing power from executing on your server, opening up a whole new range of possibilities for your DotNetNuke website. 
 
If you’re a developer, integrating with and shipping your DotNetNuke extensions with companion widgets can allow you to further leverage multiple content management strategies and distribute the interactivity of your solution to new platforms while still using DotNetNuke as your CMS of choice as a hub for your software solution. You can also make it easy to use and reuse client-side applications and plug-ins very easily, in a portable way. This saves you time in both development and implementation

Resources

There are still very few resources available for building and implementing widgets in your site. People like me have given technical presentations at events like code camps and user group meetings, and they are briefly spoken about in various DotNetNuke books. Here are a few resources that can help you get started using and understanding widgets even more.
 
http://www.dotnetnuke.com/Resources/Wiki/tabid/1409/Page/Widget/Default.aspx, DNN Community Wiki Article on Widgets
 
http://www.kalyani.com/tag/widgets/, Nik Kalyani’s Blog Entries on Widgets
 
http://dnnwidgets.com/, Widget Suite for DotNetNuke
 
http://blog.theaccidentalgeek.com/post/2009/12/29/DotNetNuke-Tips-and-Tricks-15-DotNetNuke-Visibility-Widget.aspx, Visibility Widget by Joe Brinkman
Geef feedback:

CAPTCHA image
Vul de bovenstaande code hieronder in
Verzend Commentaar