The application primarily uses a single page to process the functionality of displaying information to the user, Default.aspx. This page is the container for all the controls and skin elements the application needs to effectively serve its purpose of displaying the content to the portal user. You could refer to Default.apsx as a placeholder for the other information because its content is basic. If you view the source of the page from your IDE, it includes a placeholder for the content to be loaded and some error handling for the application. As you can see in Listing 16-1, there is a lot more that will be injected in the page than it would appear from looking at the code for the page.
Listing 16-1: Default.aspx Source Code
<%@ Page Language="vb" AutoEventWireup="false" Explicit="True" Inherits="DotNetNuke.Framework.DefaultPage" CodeFile="Default.aspx.vb" %> <%@ Register TagPrefix="dnn" Namespace="DotNetNuke.Common.Controls" Assembly=" DotNetNuke" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head runat="server"> <title><%= Title %></title> <%= Comment %> <meta name="DESCRIPTION" content=<%= Description %>> <meta name="KEYWORDS" content=<%= KeyWords %>> <meta name="COPYRIGHT" content=<%= Copyright %>> <meta name="GENERATOR" content=<%= Generator %>> <meta name="AUTHOR" content=<%= Author %>> <meta name="RESOURCE-TYPE" content=" DOCUMENT"> <meta name="DISTRIBUTION" content=" GLOBAL"> <meta name="ROBOTS" content="INDEX, FOLLOW"> <meta name="REVISIT-AFTER" content="1 DAYS"> <meta name="RATING" content="GENERAL"> <meta http-equiv="PAGE-ENTER" content="RevealTrans(Duration=0,Transition=1)"> <style runat="server"></style> <asp:placeholder runat="server"></asp:placeholder> <asp:placeholder runat="server"></asp:placeholder> <script src="/books/3/435/1/html/2/<%= Page.ResolveUrl("js/dnncore.js") %>"></script> <asp:placeholder runat="server"></asp:placeholder> </head> <body runat="server" onscroll="__dnn_bodyscroll()" bottommargin="0" leftmargin="0" topmargin="0" rightmargin="0" marginwidth="0" marginheight="0"> <noscript></noscript> <dnn:Form runat="server" ENCTYPE="multipart/form-data" style="" height: 100%;"> <asp:Label runat="server" Css Visible="False"></asp:Label> <asp:PlaceHolder runat="server" /> <input runat="server" name="ScrollTop" type="hidden"> <input runat="server" name="__dnnVariable" type="hidden"> </dnn:Form> </body> </html>
So how does all this work? When a URL is requested and the user enters the application, the request is inspected and the proper skin is determined from the database tables. As you can see in Listing 16-2, the Page_Init goes through a series of logical steps until it finally has a skin value to load. The first step is to determine if the skin to be loaded is an applied preview. You can see an applied preview from several areas where skin selection is possible, such as Page Settings, by clicking the preview link next to the skin selection drop-down list. Doing this opens a new browser window that loads a portal page with the selected skin applied. This is done by adding the SkinSrc query string parameter to the URL. When a page is loaded containing the SkinSrc parameter, its corresponding value, which is the skin name converted for use in the URL, is applied to the page. If this parameter does not exist, the next step is to check the user's cookie for this site to see if it has a skin value set in it.
Listing 16-2: Default.aspx.vb Init_Page Directives
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init ' set global page settings InitializePage() ' load skin control Dim ctlSkin As UserControl = Nothing ' skin preview If (Not Request.QueryString("SkinSrc") Is Nothing) Then PortalSettings.ActiveTab.SkinSrc = SkinController.FormatSkinSrc (QueryStringDecode(Request.QueryString("SkinSrc")) & ".ascx", PortalSettings) ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc) End If ' load user skin (based on cookie) If ctlSkin Is Nothing Then If Not Request.Cookies("_SkinSrc" & PortalSettings.PortalId. ToString) Is Nothing Then If Request.Cookies("_SkinSrc" & PortalSettings.PortalId.ToString).Value <> "" Then PortalSettings.ActiveTab.SkinSrc = SkinController.FormatSkinSrc(Request.Cookies("_SkinSrc" & PortalSettings.PortalId.ToString).Value & ".ascx", PortalSettings) ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc) End If End If End If ' load assigned skin If ctlSkin Is Nothing Then If IsAdminSkin(PortalSettings.ActiveTab.IsAdminTab) Then Dim objSkin As UI.Skins.SkinInfo objSkin = SkinController.GetSkin(SkinInfo.RootSkin, PortalSettings.PortalId, SkinType.Admin) If Not objSkin Is Nothing Then PortalSettings.ActiveTab.SkinSrc = objSkin.SkinSrc Else PortalSettings.ActiveTab.SkinSrc = "" End If End If If PortalSettings.ActiveTab.SkinSrc <> "" Then PortalSettings.ActiveTab.SkinSrc = SkinController.FormatSkinSrc(PortalSettings.ActiveTab.SkinSrc, PortalSettings) ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc) End If End If ' error loading skin - load default If ctlSkin Is Nothing Then ' could not load skin control - load default skin If IsAdminSkin(PortalSettings.ActiveTab.IsAdminTab) Then PortalSettings.ActiveTab.SkinSrc = Common.Globals.HostPath & SkinInfo.RootSkin & glbDefaultSkinFolder & glbDefaultAdminSkin Else PortalSettings.ActiveTab.SkinSrc = Common.Globals.HostPath & SkinInfo.RootSkin & glbDefaultSkinFolder & glbDefaultSkin End If ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc) End If ' set skin path PortalSettings.ActiveTab.SkinPath = SkinController.FormatSkinPath(PortalSettings.ActiveTab.SkinSrc) ' set skin id to an explicit short name to reduce page payload and make it standards compliant ctlSkin.ID = "dnn" ' add CSS links ManageStyleSheets(False) ' add Favicon ManageFavicon() ' add skin to page SkinPlaceHolder.Controls.Add(ctlSkin) ' add CSS links ManageStyleSheets(True) ' ClientCallback Logic DotNetNuke.UI.Utilities.ClientAPI.HandleClientAPICallbackEvent(Me) End Sub
If the application still does not have a value for the skin to load, and the majority of the time it won't, the application will try to assign a value based on a set of substeps. First, it will look to see if the current page loading is an Admin page. If it is, it will look to the database to get the assigned skin based on the admin skin set in the Site Settings. If no skin was set in the Site Settings, it will then check for a value for the Host Settings admin skin.
In the case where the loading page is not an Admin page, the skin will then be assigned based on the active page's settings. This will check to see if a value exists for this particular page in the database. If it does not, it will then go through a process similar to the Admin page process just discussed. The difference is that instead of checking for the assigned admin skin, it will now check for the assigned portal skin. Also similar to the Admin page skin assignment process, the application will first check for an assignment at the site level, and if no results are found, it will then check for an assignment at the Host level.
Finally, if a skin value has still not been assigned, the application will load the default skin included with every DotNetNuke distribution as the default. It's also important to note that if a skin is found but it has an error that prohibits the framework from rendering it, the default skin with an error message at the top of the rendered page will be loaded.
Once the application is at this point, the ctlSkin variable will have a value. With the ctlSkin variable now populated, the application can move on to creating links in the rendered page for the skin's Cascading Style Sheets. The function responsible for handling this is the ManageStyleSheets function, shown in Listing 16-3. This function is actually called twice from within Page_Init:
The first time it creates a link for the default.css file, located in the Portals/_default/ folder. It then attempts to load a link to the skin.css file if it exists for the current skin package. Finally, the application attempts to load a link to the CSS filename corresponding to the name of the current ASCX skin file being loaded if one exists.
The second time this function is called it simply loads the portal.css file located in the Portals/PortalId folder. By default, unless the portal.css in the Portals/_default folder was hanged prior to the portal being created, the portal.css file is a skeleton file with only the names of the styles commonly used throughout the DotNetNuke user interface.
Listing 16-3: Default.aspx.vb ManageStyleSheets Function
Private Sub ManageStyleSheets(ByVal PortalCSS As Boolean) ' initialize reference paths to load the cascading style sheets Dim objCSS As Control = Me.FindControl("CSS") Dim objLink As HtmlGenericControl Dim ID As String Dim objCSSCache As Hashtable = CType(DataCache.GetCache("CSS"), Hashtable) If objCSSCache Is Nothing Then objCSSCache = New Hashtable End If If Not objCSS Is Nothing Then If PortalCSS = False Then ' default style sheet (required) ID = CreateValidID(Common.Globals.HostPath) objLink = New HtmlGenericControl("LINK") objLink.ID = ID objLink.Attributes("rel") = "stylesheet" objLink.Attributes("type") = "text/css" objLink.Attributes("href") = Common.Globals.HostPath & "default.css" objCSS.Controls.Add(objLink) ' skin package style sheet ID = CreateValidID(PortalSettings.ActiveTab.SkinPath) If objCSSCache.ContainsKey(ID) = False Then If File.Exists(Server.MapPath(PortalSettings.ActiveTab. SkinPath) & "skin.css") Then objCSSCache(ID) = PortalSettings.ActiveTab.SkinPath & "skin.css" Else objCSSCache(ID) = "" End If If Not Common.Globals.PerformanceSetting = Common.Globals.PerformanceSettings.NoCaching Then DataCache.SetCache("CSS", objCSSCache) End If End If If objCSSCache(ID).ToString <> "" Then objLink = New HtmlGenericControl("LINK") objLink.ID = ID objLink.Attributes("rel") = "stylesheet" objLink.Attributes("type") = "text/css" objLink.Attributes("href") = objCSSCache(ID).ToString objCSS.Controls.Add(objLink) End If ' skin file style sheet ID = CreateValidID(Replace(PortalSettings.ActiveTab.SkinSrc, ".ascx", ".css")) If objCSSCache.ContainsKey(ID) = False Then If File.Exists(Server.MapPath(Replace (PortalSettings.ActiveTab.SkinSrc, ".ascx", ".css"))) Then objCSSCache(ID) = Replace (PortalSettings.ActiveTab.SkinSrc, ".ascx", ".css") Else objCSSCache(ID) = "" End If If Not Common.Globals.PerformanceSetting = Common.Globals.PerformanceSettings.NoCaching Then DataCache.SetCache("CSS", objCSSCache) End If End If If objCSSCache(ID).ToString <> "" Then objLink = New HtmlGenericControl("LINK") objLink.ID = ID objLink.Attributes("rel") = "stylesheet" objLink.Attributes("type") = "text/css" objLink.Attributes("href") = objCSSCache(ID).ToString objCSS.Controls.Add(objLink) End If Else ' portal style sheet ID = CreateValidID(PortalSettings.HomeDirectory) objLink = New HtmlGenericControl("LINK") objLink.ID = ID objLink.Attributes("rel") = "stylesheet" objLink.Attributes("type") = "text/css" objLink.Attributes("href") = PortalSettings.HomeDirectory & "portal.css" objCSS.Controls.Add(objLink) End If End If End Sub
Note | If you would like an introduction to the default CSS styles used throughout the framework, please review default.css , which contains all the styles with the default values that are applied at run-time. Those default values can also be seen in Table 16-2 later in this chapter. |
Note | One final note about the loading of skins is that there is a performance hit with these DB calls and enabling the portal to use this dynamic skinning solution, as there is with any application that can change its appearance on-the-fly. Even though there is a performance hit, this is one of the killer features DotNetNuke contains and is worth the additional overhead the process requires. |