However, there have been a few bumps on the road while making such significant changes in the framework, and I’d like to make sure everyone is aware of them and provide an opportunity for discussion in the comments.
First, let’s start with the history of jQuery and jQuery UI usage in DNN, and then we’ll talk about where we are now. Please, bear with me as we take a detailed historical journey.
DotNetNuke 5.0 introduced a new API method to allow for registration of jQuery. This has been the standard way to register jQuery in the core as well as third party modules ever since.
However, some module developers, wanting to still support older versions of DotNetNuke (e.g. 4.x), bypassed the public API and checked the internal flag (HttpContext.Current.Items("jquery_registered")) that denotes whether jQuery has been registered. This wasn’t/isn’t the only technique to support backwards compatibility though, Bruce Chapman has a nice bit of code on his blog that supports the same functionality without sneaking around the public API.
The only real important thing to note is that DotNetNuke 6 introduced jQuery UI into the core framework. At this time, jQuery UI was placed in-between the body and the form.
DotNetNuke 6.1 introduced the new Client Resource Management API. The API allows for specific placement of JS files, using a registration provider. In 6.1, the available options were:
- PageHeaderProvider (appended to the head)
- DnnBodyProvider (top of the form)
- DnnFormBottomProvider (bottom of the form)
jQuery was the only script to use PageHeaderProvider, the rest would use DnnBodyProvider, save for one (a search related script) that would use DnnFormBottomProvider. This was done to try to replicate, as much as possible, what was there previously with respect to order.
Also of important note, the ability to take advantage of the HttpContext key workaround to find out if jQuery was already loaded was removed in DotnetNuke 6.1.0, as the internals of our jQuery registration system changed to use our new Client Resource Management API, and we no longer needed to use this HttpContext key for tracking. The unfortunate side effect of this is that now those modules that were using this technique would load jQuery again. Sometimes this will cause issues, sometimes it will not. It all depends on if anything is extending jQuery in-between the first and second registration. More on that later.
The were two specific issues with 6.1.0 that were fixed in DotNetNuke 6.1.1. The first was that the contents of a DotNetNuke Page’s header and Styles skin objects were not being placed in the right order in the page head. This caused issues with ordering when one of these two techniques was being used.
The fix for this issue was to create a new registration provider “DnnPageHeaderProvider” and use this instead of the “regular” PageHeaderProvider, the difference between the two is small but important: The DotNetNuke version inserts the contents at a specific location, whereas the other dynamically appends its contents to the end of the head. Usage of the DotNetNuke version ensures that things are loaded in the expected order.
The second was that jQuery UI was being loaded “too low” in the document. If someone were writing code that depended on jQuery, the possibility existed for them to register their code prior to jQuery being loaded. The decision was to move jQuery UI to the head – to treat it the same way as jQuery. This would improve the overall situation for those that want to take advantage of jQuery UI, by ensuring that it is loaded prior to virtually any consuming code.
The Current Situation
In DotNetNuke 6.1 or 6.1.1, if a module is relying on the internal implementation of the jQuery registration API to avoid loading jQuery more than once, it is not working. jQuery is being loaded twice.
If the second version of jQuery is loaded *after* jQuery UI, which in 6.1.1, it probably is, then jQuery UI will not be available. Here’s why:
- jQuery is loaded by the DotNetNuke framework. The jQuery object is defined.
- jQuery UI is loaded by the DotNetNuke framework. The jQuery object is extended with jQuery UI specific functionality.
- jQuery is loaded again, and the jQuery object is redefined. And, effectively, jQuery UI was “wiped out”.
This may cause the Manage buttons to stop working, as they rely on jQuery UI’s draggable functionality. Also, other module functionality may be broken as well if it depends on jQuery UI.
Next steps/Action Items
The long term answer here is that module developers need to use the public API directly, or use a method such as Bruce Chapman uses that handles using the API without being dependent on a particular version of DNN.
In the short term, if you are locked into a situation where you cannot change the module, and you cannot move back to a previous version of DotNetNuke, the only stop-gap measure that will work is to load jQuery UI again somewhere on the page. This should probably be avoided at all costs, as you will not only have two copies of jQuery on the page, but now two copies of jQuery UI – but if you absolutely have to fix this issue in-place, I would suggest putting a text/html module on the page and placing a jQuery UI script reference in the header or footer. Here is the snippet:
Managing JS dependencies is undoubtedly tricky business. I hope that this tour of jQuery & jQuery UI in DotNetNuke history is helpful in understanding the "what?” and the “why?” of the implementation, and how we arrived at seeing these issues in DNN 6.1 and 6.1.1.
Although there have been some significant short term challenges, I believe these challenges will help us, as a whole community, get it right. The average DotNetNuke site contains code from a wide variety of developers. In order to be truly successful, all developers need to settle on a common practice.