New Beginnings

Today was the start of some new stuff.  I started my new class at University of Phoenix.   Its pretty interesting so far.  I don't want to talk specifics too much but I am interested in it and hope it will be of some benefit for me.

I also woke up this morning at around 5, managed to drag myself out of bed and run around the block a couple of times.  Going around my block is just about exactly one half mile so I ran/walked a mile.  It took me about 18 minutes which obviously isn't great, but its a start and I plan on running about that long every morning, ramping up the distance as I get faster.   I asked Leslie to join me but its unclear if that will happen.  I also learned that taking a shower directly after running is kind of useless as I will continue to sweat after I get out of the shower.  So I will need to cool down a bit first tomorrow.  I also want to take advantage of all these new beginnings and changes of schedule to start fighting more.  I fought this weekend at the Highlands War, but it was the first time in a few months.

SCA Online OP Improvements, Link to Dynamic Forms Module - Part 2

In Part 1, I did all the background programming to put the settings in and display them the correct way in the settings page, but I haven't actually used the settings to create the link yet.  I also was blogging as I was programming which I now know why this is a rarity- It takes a long time and although the side trips down a buggy path may be interesting, its distracting from getting the actual work accomplished.  I finished this up yesterday without blogging about it and it went much faster.  So this is all done now and I probably won't linger too long on any of the problems I had.

The purpose of all the settings was to enable a link to be made from my Online OP module to the Datasprings Dynamic Forms module I have set up to take Award Reccommendations.   The first part was to customize this form a bit more so that it would even recognize this data.  The Dynamic Forms Module allows for data to come in in several ways, cookie, session, and querystring.   I decided to use the querystring to send this info forward.  In the advanced options of the question I found the setting I was looking for.

I set this for the Name and Branch field of the Awards Form and I also set up a hidden field for the internal member id.  I would use this to pass the id forward so it could link to the person in the OP.

Once the fields were set up, I modified the email result so that it could contain a link directly to the person that was being recommended.  The form completion events have 2 events, one to send an email to the crown, the other to send it to the person submitting a recommendation.  Both of these would recieve the link.   Each already had the main email set up so I only had to add the link at the bottom of the existing email text.  The main trick (if you can call it a trick) was to put the $(memid) field into the link target.  $(memid) was the hidden field I had set up to read a querystring I was sending.

Now to set up the Online OP module to provide the link.  The first thing I did was put the link in near the Awards header in the OP Record screen.

 

<h2 class="SCAMemberAwardsHeader">
        Awards Received</h2>
    <asp:Literal ID="litNoAwards" runat="server" Visible="false">No Awards Recorded.<br /></asp:Literal>
    <asp:HyperLink runat="server" ID="hlRecommend" CssClass="RecommendLink" >Recommend this person for an award.</asp:HyperLink>
    <div class="break"></div>
    <asp:Panel ID="pnlAwards" runat="server" Visible="true">
        <asp:DataGrid ID="dgAwards" runat="server" AutoGenerateColumns="False" CssClass="ResultList">

 

I also set up the link so it would float off to the right, under the picture of the person if there is one but inline with the Awards header.  This is from the module.css

 

.RecommendLink
{
    display:block;
    float:right;
    margin:15px 0px 15px 0;
}

 

 Next I had to generate the link.  I checked the settings to see if I should generate the link and then if I should, which tab should I direct to.  The querystring key's are determined by the short name of the fields in the Dynamic Forms module.

 

if(Convert.ToBoolean(Settings["LinkToRec"]))
            {
                hlRecommend.NavigateUrl = Globals.NavigateURL(Convert.ToInt32(Settings["AwardRecTabId"]), "",
                                                              "Recommended=" + h1MemberName.InnerText, "memid=" + memid, "branch=" + Residence);
            }
            else
            {
                hlRecommend.Visible = false;
            }

 

I initially had some trouble with the Friendly Url Provider I was using (iFinity Friendly Url Provider) and the way it was handling some special characters such as commas and single quotes (apostrophes), but this was resolved by using the latest dll provided on the site for DNN 5. 

Writing this blog after the fact is definately the way to go. Its like providng your own code review, which is very handy on a project you work on by yourself.

 

SCA Online OP Improvements, Link to Dynamic Forms Module - Part 1

A lot of coding blogs write about problems they have already solved and while I know its not unique to do so, I want to write down stuff as I do them for this project, rather than summarizing a problem I have already solved. Although this series of blogs involves the SCA, it will be more about the process or working on a DNN (DotNetNuke) module and the programming that goes into it.

If you are not familiar with the SCA Online OP, it is a module I wrote and maintain for the Kingdom of Atenveldt, a branch of the SCA.  The OP part of the module stands for Order of Precedence.  This is basically a ranking system that we use in the SCA loosely based on historical practices of knowing who is ranked above who.  I have taken that practice and put a lot of work around it to not only list the people and what awards they have in the right order, but enable viewing pictures of the people, descriptions of the awards, information about the local groups the people reside in and information about the members that reign over them.  All of this can be found on the Atenveldt Online OP.

Since I will have a lot of free time this memorial day weekend, I am putting some effort into some improvements I have wanted to do to the module for some time.  The first improvement I want to do is to link the OP to the new forms module I just installed for making an award recommendation for a person.  The forms module supports having a field get data out of a querystring, so it should be a simple task of creating a dyamic link that will point from a person's record in the OP to the award recommendation form.  Even though this module will never be in widespread use and will most likely be a single installation on the Atenveldt site, I try to add features that stay flexible and have the possibility of transferring over to anther DNN installation.

Step 1.  Settings.

I figure the module needs to be pointed to from the settings.  I am imaging a checkbox that indicates that we want to have a reference link to the award rec. form, along with a drop down of all the installed Dynamic Forms modules installed in the portal.

I have a settings page already created. So I will add the controls to the form.  Here is what the settings form looks like.

<%@ Control AutoEventWireup="false" CodeFile="SCAOnlineOPSettings.ascx.cs" Inherits="JeffMartin.DNN.Modules.SCAOnlineOP.SCAOnlineOPSettings"
    Language="c#" %>
<%@ Register TagPrefix="dnn" TagName="Label" Src="~/controls/LabelControl.ascx" %>
<table>
    <tr>
        <td valign="top" class="SettingsLabelColumn">
            <dnn:label id="dlBasePortal" runat="server" controlname="ddlPortalList" />
           </td><td valign="top">
            <asp:DropDownList runat="server" ID="ddlPortalList">
            </asp:DropDownList>
        </td>
    </tr>
    <tr>
        <td valign="top" class="SettingsLabelColumn">
            <dnn:Label ID="dlLinktoReccomendationForm" runat="server" ControlName="chkLinkToRec" />
        </td>
        <td valign="top">
            <asp:CheckBox ID="chkLinkToRec" runat="server" />
        </td>
    </tr>
    <tr>
        <td valign="top" class="SettingsLabelColumn">
            <dnn:Label ID="dlReccomendationForm" runat="server" ControlName="ddlDynamicForms" />
        </td>
        <td valign="top">
            <asp:DropDownList runat="server" ID="ddlDynamicForms">
            </asp:DropDownList>
        </td>
    </tr>
</table>
 

 

Now that the form fields are created, I will put some backing logic to them.  First I need to fill the drop down list with all the modules that are the DataSprings Dynamic Forms that I am looking for.  As I am writing this code, I realize that I want to put a message indicating that I can't detect the Dynamic Forms module being installed.   This will be convenient to test as I don't have the dynamic forms module installed yet on my local build installation.   As I look at the code a bit more, I decide to just hide the setting if I can't detect the module existing.  So I put a placeholder module around the two table rows that contain the info needed for setting up the dynamic forms stuff.

 

ModuleController mc = new ModuleController();
ModuleInfo mInfo = mc.GetModuleByDefinition(PortalId, "Dynamic Forms");
if (mInfo == null)
{
    phAwardRecsSettings.Visible = false;
}
else
{
    phAwardRecsSettings.Visible = true;
    ArrayList moduleTabs = mc.GetModuleTabs(mInfo.ModuleID);
    ddlDynamicForms.DataTextField = "ModuleTitle";
    ddlDynamicForms.DataValueField = "TabId";
    ddlDynamicForms.DataSource = moduleTabs;
    ddlDynamicForms.DataBind();
}

 

 You may notice I am programming in C#.  This is just something I would rather do than keep flipping between VB for this and C# at work.  The modules work perfectly fine. 

The next step for me is to try this out.  I don't like going to far without making sure this code works.  This keeps it fresh in my mind if I have to debug it rather than debugging something I did an hour ago if I wait that long before testing it out.  After testing that nothing was different when I didn't have the dynamic forms installed, I installed the dynamic forms module, imported my form from the live website, and tested again... It works!

 New Settings Display Correctly

Now that everything is displaying correctly - I need to actually make the settings save (and be read).  I want to make sure the drop down box shows the correct value when the settings are loaded and the check box is correctly checked or unchecked.  Here are the methods:

public override void LoadSettings()
       {
           try
           {
               if (!Page.IsPostBack)
               {
                   var basePortalId = ((string) Settings["BasePortal"]);
                   if (basePortalId == null)
                       ddlPortalList.SelectedValue = "0";
                   else
                       ddlPortalList.SelectedValue = basePortalId;
 
                   var awardRecTabId = ((string) Settings["AwardRecTabId"]);
                   if (awardRecTabId != null)
                       ddlPortalList.SelectedValue = awardRecTabId;
 
                   bool linkToRec = Convert.ToBoolean(Settings["LinkToRec"]);
                   chkLinkToRec.Checked = linkToRec;
               }
           }
           catch (Exception exc)
           {
               Exceptions.ProcessModuleLoadException(this, exc);
           }
       }
 
       public override void UpdateSettings()
       {
           try
           {
               var objModules = new ModuleController();
               objModules.UpdateModuleSetting(ModuleId, "BasePortal", ddlPortalList.SelectedValue);
               objModules.UpdateModuleSetting(ModuleId, "AwardRecTabId", ddlDynamicForms.SelectedValue);
               objModules.UpdateModuleSetting(ModuleId, "LinkToRec", chkLinkToRec.Checked.ToString());
 
               Response.Redirect(Globals.NavigateURL(), true);
           }
           catch (Exception exc)
           {
               Exceptions.ProcessModuleLoadException(this, exc);
           }
       }

When I go to test, doh... there is a problem.

DNN Critical ErrorLets see what the Event Log has to say about that. 

It turns out after quite a trip down the debugging rabbit hold that the above code doesn't compile in ASP.NET 2.0 (I may upgrade my site shortly).  The 'var' keyword got slipped in there by an overzealous ReSharper reformat.  After changing the settings in ReSharper, fixing the 'var', I found that the LoadSettings() actually gets called BEFORE the Page_Load... this means that I need to bind my controls in the LoadSettings().  Just because I am a bit paranoid about this changing in some future version, I put in a BindControls() method that I can call from Page_Load too.  I also protect for binding twice unnecessarily.  The final code for the settings is below.

using System;
using System.Collections;
using DotNetNuke.Common;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Services.Exceptions;
 
namespace JeffMartin.DNN.Modules.SCAOnlineOP
{
    partial class ScaOnlineOpSettings : ModuleSettingsBase
    {
        #region Web Form Designer generated code
 
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
            this.Load += new System.EventHandler(this.Page_Load);
        }
 
        /// <summary>
        ///        Required method for Designer support - do not modify
        ///        the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }
 
        #endregion
 
        private void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (!Page.IsPostBack)
                {
                    BindControls();
                }
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }
 
        private bool boundOnce;
 
        private void BindControls()
        {
            if (!boundOnce)
            {
                PortalController pc = new PortalController();
                ArrayList Portals = pc.GetPortals();
                ddlPortalList.DataTextField = "PortalName";
                ddlPortalList.DataValueField = "PortalID";
                ddlPortalList.DataSource = Portals;
                ddlPortalList.DataBind();
 
                ModuleController mc = new ModuleController();
                ModuleInfo mInfo = mc.GetModuleByDefinition(PortalId, "Dynamic Forms");
                if (mInfo == null)
                {
                    phAwardRecsSettings.Visible = false;
                }
                else
                {
                    phAwardRecsSettings.Visible = true;
                    ArrayList moduleTabs = mc.GetModuleTabs(mInfo.ModuleID);
                    ddlDynamicForms.DataTextField = "ModuleTitle";
                    ddlDynamicForms.DataValueField = "TabId";
                    ddlDynamicForms.DataSource = moduleTabs;
                    ddlDynamicForms.DataBind();
                }
                boundOnce = true;
            }
        }
 
 
        public override void LoadSettings()
        {
            try
            {
                if (!Page.IsPostBack)
                {
                    BindControls();
                    string basePortalId = ((string) Settings["BasePortal"]);
                    if (basePortalId == null)
                        ddlPortalList.SelectedValue = "0";
                    else
                        ddlPortalList.SelectedValue = basePortalId;
 
                    string awardRecTabId = ((string) Settings["AwardRecTabId"]);
                    if (awardRecTabId != null)
                        ddlPortalList.SelectedValue = awardRecTabId;
 
                    bool linkToRec = Convert.ToBoolean(Settings["LinkToRec"]);
                    chkLinkToRec.Checked = linkToRec;
                }
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }
 
        public override void UpdateSettings()
        {
            try
            {
                ModuleController objModules = new ModuleController();
                objModules.UpdateModuleSetting(ModuleId, "BasePortal", ddlPortalList.SelectedValue);
                objModules.UpdateModuleSetting(ModuleId, "AwardRecTabId", ddlDynamicForms.SelectedValue);
                objModules.UpdateModuleSetting(ModuleId, "LinkToRec", chkLinkToRec.Checked.ToString());
 
                Response.Redirect(Globals.NavigateURL(), true);
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }
    }
}

Now that the settings are in and saved, I actually have to make use of them in the module.   I will save that for Part 2.

What do I want to do with this site?

So I am up early this morning.  I have already taken a shower and gotten dressed and its still only 5:40am.  I have been waking up at 5 all week but this is the first time I got out of bed and did something.  I probably should have gone on a bike ride but I woke up with some ideas about the site and I wanted to write some of them down.

Why do I have this site?  Because I am a web developer and I ought to have a website.  Like many web developers already out there and blogging, I'd like to do some stuff about code or whatever but most of what I do isn't particularly new and I feel like I am more than just a web developer.  I have other interests that I want to delve into here.  Since I have bought my Android, I have been listening to a lot of podcasts. (Another thing I want to blog about at some point soon).  Some of them have been from the twit.tv network.  This is where Leo Laporte has created an internet radio/tv/broadcasting station about tech and the internet.  This has made me aware of a lot of the things that people do on the internet that I wasn't doing 3 months ago.   Twitter, friendfeed, and all this social media stuff that people in the media are talking about because everything else is just bad news about the economy.  Blogging to these guys is so... six years ago.  But I haven't every really gotten off the ground with it.

I want this blog to be useful to people so I intend to have tech stuff that I discover on the job.  I also intend to do some stuff about the SCA.  I think there are enough web developers talking out there to the echo chamber that is the developer community.  I'd like to use some of my powers of web development and technical geekiness in areas that aren't about web development and technical geekiness.  So I guess I am choosing historical recreation geekiness.  The idea I woke up with this morning was to go get a cheap video camera and start collecting interviews with various SCA persona and find about about them.  I really loved the Lions Road podcast while it was going and its too bad it didn't last.  I'd like to create something that will help the SCA bring more people in that will enjoy its good times.  It so easy for people to get caught up playing World of Warcraft, why not do these things in real life with people who are right in front of you rather than over a wire?

So I need to figure out how to have some separate blogs so that the internet can get some focused pages to return in search engine results but still have them consolidated into one feed that is this site.  I have some ideas about this as squarespace supports creating redirects to certain pages.  So I should be able to create a page called JeffMartin.com/sca and have it just be my blog posts about the SCA.

I also know from reading other blogs that in order to be a decent blog you have to just go for it and write on a regular basis.  So here I am writing.  I know not all of it will be interesting to all people, or even some people, but with practice I hope I will be focusing my efforts.