The Ice Cream Chronicles

Bourbon Brown Butter Pencan

For Christmas 2011, my mother-in-law gave me a Kitchen Aid ice cream maker attachment for our mixer (http://www.amazon.com/KitchenAid-KICA0WH-Cream-Maker-Attachment/dp/B0002IES80/ref=sr_1_1?ie=UTF8&qid=1356897228&sr=8-1&keywords=kitchen+aid+ice+cream). It was something that I had asked for on a whim, never expecting to get one, but there it was, sitting there amid the pile of torn wrapping paper, staring at me.

This was actually my second ice cream maker. A while ago I had gotten one of the old bucket type ones, where you supply the ice and rock salt which freeze the ice cream. It even had an old-fashioned hand crank. The couple of times I tried making ice cream in it, however, neither turned out very good at all.

I had a vague desire to make unusual ice creams, but it wasn’t a burning need. So the new contraption sat in the box for a few months in the pantry. I would spot it every once in a while, feel guilty, and tell myself that I need to make some ice cream.

Around late spring, I bit the bullet and made my first batch. I scoured the internet looking for recipes, and finally decided on a lemon ice cream. Honesty, it was horrible. I like tart things, but this was too much even for me. It was icy, bitter, and just all around unpleasant. Not a great start.

My father’s birthday was a coming up soon, and I decided that I wanted to try again. This time fresh peach was on the menu. Here’s a tip for all of you would-be ice cream artisans…you have to churn it for more than five minutes, and it needs to actually freeze to be considered ice cream. On the plus side, this batch tasted pretty good, although it was more like a chilled soup than a tasty frozen treat.

Now a little bit about me, so you understand my position. I am not overly competitive. I like to win as much as the next guy, but it isn’t a driving force in my life. However, I hate being a failure at anything. I don’t have to be the best, but just not a failure, and there I was with two failed ice creams under my belt. I would have to keep trying.

A couple of weeks later, at the end of June, the temperature was climbing, and some of our best friends were having a Hawaiian themed birthday party. (They had just gotten back from the islands, and wanted to rub it in share the experience with everyone.) I decided to try to make a pineapple ice cream. Specifically, I wanted to make pineapple floats (a scoop of pineapple soft serve ice cream floating in glass of pineapple juice. Perfect on a hot summer night!)

This time, success!The ice cream was smooth, tangy, and just about perfect. It was the hit of the party, which is saying something, considering my lovely wife Tara (http://teaberrycreative.com/), who is a spectacular cook, had also made something almost equally tasty for the party.

Since then, I have made a different ice cream each month, for various occasions. Some have been more successful than others, but I have learned something from each batch. Tara and I decided that it would be a good thing to share the experiences, so that’s why I’m writing this now. I figure ice cream can fall under the “And More” portion of my blog’s tagline. So keep a look out for new experiments and recipes.

Old Tricks – XSLT files and Smart Forms

It’s funny how you can work with a product for years, and then finally learn about
something that turns into a complete game changer. Take smart forms for example.
Smart forms provide a way to have structured content stored in the CMS.

Structure always sounds good, but why would you want to have structured content
instead of unstructured html content? I think Bill Cava (@billcava) explained
it best in his Ektron Content Types webinar
(http://www.ektron.com/Resources/Webinars/Ektron-Content-Types/)

Read the full post on my Ektron Community Blog

Thank You James and Ken

This huge thank you goes out to James Stout (tweetjaytem @egandalf) and Ken McAndrew (tweetjaytem  @kmac23va). Let me explain why.

Last November, Ektron hosted their annual customer conference, Synergy, in Washington D.C. These are great events that give the customers an opportunity to meet the people responsible for the CMS system that they use, partner companies who can help them realize their web site visions, and other Ektron clients.

When I worked for Canyon County, ID, I had the opportunity to attend the 2009 and 2010 conferences in Orlando, Florida, but when I started working for Ektron, I figured those would be my last ones. It’s expensive for a company to send people to a conference, even one that they are hosting, and sending a brand new developer didn’t make any sense.

After Ektron shut down their PSG group (see When Dreams Change),  I started working for WSOL, one of Ektron’s top partners. When Synergy 2012 was announced, I didn’t expect to go. This is a major marketing event for WSOL, and they send the people that can best represent the company, the Chief Operating Officer Bill Casey, the Director of Design and Development, Chris Osterhout, and the head of Sales, Brian Elrich.

When the keynote speakers were announced, I was very excited to see that Ethan Marcotte (tweetjaytem  @beep) and Luke Wroblowski (tweetjaytem @lukew) were going to be speaking. Ethan is the guy who started the whole “Responsive Web Design” trend, and Luke is the evangelist for designing for Mobile first, and then for the desktop. These are two of my internet heroes, and I really wanted to meet them. So, in traditional geek fashion, I expressed my desire, and regret that I wouldn’t be going, on Twitter. This generated some interesting conversations, and at one point I jokingly suggested that I should get a life size cardboard cut-out of me, and have it standing up at the conference. That got some laughs, and then was forgotten. Or so I thought.

In late October, as the Synergy excitement was really ramping up, James brought it up again. He was going to be one of the technical speakers at Synergy, and he hinted that if I got the cut-out to him, he might have it on stage during his presentation. I thought this would be hilarious, so I started shopping around.

It turns out that it is pretty easy to get a life-size cardboard cut-out made, but not cheap for a gag. But then I found a company that made what they called “head-ka-bobs”, where the y basically take a picture of someone’s head, and put it on a stick. Perfect, and it was reasonably priced. So the #FaceOfJoe was born. (We even started the #FaceOfJoe hashtag on Twitter. It never trended, but I still hold out hope.)

tumblr_md6oq1nhpE1rjftawo1_1280

I had the #FaceOfJoe shipped to Ken McAndrew at C-Span. Ken was also scheduled to speak at Synergy, as since it was in Washington D.C., Ken’s home base, it made sense.

Ken took the #FaceOfJoe to Synergy. Between he and James, they took many pictures with people holding the #FaceOfJoe, got it on stage with many of the speakers, and even got photos  Ethan Marcotte and Luke Wroblowski each holding it.

In addition, they started a Tumblr blog to document the #FaceOfJoe’s adventures throughout Synergy. http://joegoestosynergy.tumblr.com I can’t remember laughing so hard.

So, I wanted to say a big thank you to every one who participated, and for being willing to pose for a picture with a ridiculous card board cut-out of my head. Thank you to Ken and James for hauling the #FaceOfJoe around to all of those sessions. For taking all of the pictures; for approaching people to see if they were willing to have their picture taken; for being such good friends, and good people; and for making me feel like a part of the event, even though I wasn’t there in person. This was a Synergy that I will never forget.

CYOA – Choose Your Own Adventure

A journey through your website

Note: I am not a content strategist or marketer, nor am I trying to pretend to be. These are my opinions based on being a web user for the last 15 years, and a web developer for the last 13.

As a child of the ‘80‘s, and a lifelong Science Fiction/Fantasy reader, books like Journey Under the Sea, and other Choose Your Own Adventure (CYOA) books filled many an afternoon of my young life. I remember being enthralled by the choices that I had, and excited that I could make decisions on where the story would go next. I was in control of the journey.

Excerpt from Journey Under the Sea by R.A. Montgomery 1

Journey Under the Sea

The cable attaching the Seeker to the ship Maray is extended to its limit. You have come to rest on a ledge near the canyon in the ocean floor that ancient myth says leads to the lost city of Atlantis.

You have an experimental diving suit designed to protect you from the intense pressure of the deep. You can also cut the Seeker loose and travel further.

As agreed, you signal the Maray: “All systems GO; it’s awesome down here.”

If you decide to explore the ledge where the Seeker has come to rest, turn to page 6. If you decide to cut loose from the Maray and dive with the Seeker into the canyon in the ocean floor, turn to page 4.

Jump forward a few years to high school, and I am in my first computer programming class, writing a CYOA adventure game in BASIC (this was the ‘80s) for a class project. It was awful. The story was overly simplistic, the options minimal, and the experience dismal, but the idea, I think, was there. Provide a story that gives the reader some control.

Today, I build web pages for a living. It’s interesting how similar the tasks then and now are.

A few days ago, I stumbled across a very interesting article on Christian Swinehart of samizdat.cc (http://samizdat.cc/digital/cyoa), where he does a wonderful analysis of  many of the CYOA books. That article really got me thinking that CYOA books, the stories within them, and the user experience that they create have a lot of similarities to a website.

Ok, that might be a stretch, but let’s think about it for a bit. The books themselves are a really a collection of decisions, with some of the text set up to prompt the reader to make a decision. Do I go to page 6 or page 4? If I want to explore the ledge, then page 6 it is. The point is that it’s the user who has the control of where they go next.

Now look at the typical website. It too is filled with decisions that a user must make. Do I click on this link, try the menu, or run a search? Do I read this article first, then move on to comments, or jump out to Amazon.com and shop for Scooby Snacks? The choice is mine.

The point I am trying to make is that just like the readers of CYOA books, the website’s users make choices on where they are going to go on a sites. We, as content authors, marketers, and developers can provide guidance and suggested paths through a website, but ultimately, the users are going to choose their own path.

If you decide to keep struggling towards the surface, turn to page 51.
If you decide to rest quietly, gain strength, and work out a plan, turn to page 53.
Journey Under the Sea pg. 33

Building an Adventure

I don’t mean that your website should be littered with traps and mazes, but it should be interesting and engaging for your users. If your content is boring, then why would anyone read it? Many companies make excuses for not building great content (see 4 Lame excuses brands use for not creating content ). It’s also very important to keep your content current to give your readers a reason to be on your website, and a reason to come back.

Reaching the Treasure

You need to make your site easy to move through, and navigate successfully. If your goal is to get the user to purchase those Scooby Snacks bites, then don’t make them go through a web page equivalent of the beginning of Raiders of the Lost Ark. Make it easy for them. Have a clear, simple navigation and easy search functionality.

All Roads Lead to Victory

At least, that is what we hope, but the reality is that not every journey will lead to success. And if you have too many roads, how will the user know what to do, or where to go?

Imagine coming up to an intersection with road signs like this,  and trying to make a decision on which way to go. 2

Make the choices clear and easy to understand. Options are good, but too many options can be overwhelming. Don’t send the user down useless paths, instead make it easy for them to get where they want to go. They will appreciate it.

 

Ultimately, a user’s journey through your website is based on the decisions that they make. We don’t know what brought them here, or where they will go, or how they will get there. What we can do is to make sure that the experience that they have is worthwhile.

 

If you decide to try and escape, turn to page 62.
If you try to hitch a ride on the whale, turn to page 83.
If you don’t know what to do, turn to page 86.
Journey Under the Sea page 64

 

1Journey Under the Sea, R.A. Montgomery, first published in1978 by Chooseco, LLC. ISBN  10 1-933390-02-6 and 13 978-1-933390-02-4

2 Image courtesy of DepositPhotos.com

Jaytem gets a facelift

You all may have noticed that the Jaytem site is looking a little bit different now-a-days. I finally convinced my talented wife @teaberryrelish to design a logo for me. Well, actually I have been begging her for a logo for a couple of years now, but I finally gave her an idea that she ran with, and I think it is brilliant.

In addition, the old theme and tagline of “Jump The Map” really didn’t make a lot of sense, so I went with something simpler, and less obtuse.

As for the look and feel, I wish I could say that I designed and built this great theme, but I cheated, and purchased a beautiful Wordpress theme. Why? Honestly, it was easier. I struggle a lot with PHP, and WordPress is loaded with the stuff. The pre-packaged theme provided all of the functionality I wanted, and a whole lot more that I never thought of.

In addition, I am getting some business cards printed up, and I am super excited. Jaytem business card - front

I wanted something that incorporated that beautiful logo, and had some simple information, so I could hand them out to people, and I think this accomplishes that wonderfully. I’m not after business or work, I just wanted something I could hand out at conferences if I am not representing anyone else. If you get a chance, mosey over to Teaberry Creative’s new site, and take a look at her work. She does some pretty awesome stuff.

 

A User Control by Any Other Name

I have a confession to make, when Ektron announced their PageBuilder functionality, with the drag & drop widgets, I wasn’t excited. I was happy building pages the way I had been, and historically, a good bit of my time was spent fixing pages that my content editors had messed up, because they didn’t listen to what I had told them. So why would I be interested in a technology that gave them more control?

Then I watched Jason Arden’s Lunch and Learn webinar, that talked about PageBuilder, and the widgets, and I finally saw the potential. (When I built my first widget, dragged it onto a page, and it actually worked, I think I may have even done a happy dance.)

Fast forward a few months, I had built a widget to handle a specific problem (I don’t remember what it was), and then found that I needed the same functionality, but I couldn’t use PageBuilder in that circumstance. Being the innocent and naive soul that I was back then, I didn’t know that widgets where just dressed up user controls. (Sure, they had the same extension, but what does that mean anyway?) So I copied the code into a standard user control, removed all of the widget specific portions, and had two version with the same functionality. Two versions where I had to make changes, when they were inevitably needed. Not ideal.

I have recently learned that you can use Widgets just like you would a normal user control. Since code re-use is a goal of all back-end developers, this was an exciting revelation for me, and it just takes a few simple changes to your widget code.

NOTE: I am not going to go into depth about how to build widgets, or all of the components of one. James Stout ( @eGandalf) has written some outstanding blog posts, walking you through widget development http://www.ektron.com/blog/egandalf/. )

The examples and screenshots for this post were all built on the 8.5 CMS platform, but you could easily do this on 8.0 as well.

 

Let’s jump in.

For this example, I will be using the HelloWorld widget. This widget is standard in the Ektron 8.0+ CMS installs, and is about as simple as widgets get, so it will be easy to explain the changes.

First, let’s take a look at the default HelloWorld widget code.

HelloWorld.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="HelloWorld.ascx.cs" Inherits="widgets_HelloWorld" %>
    <asp:MultiView ID="ViewSet" runat="server" ActiveViewIndex="0">
        <asp:View ID="View" runat="server">
            <!-- You Need To Do ..............................  -->
            <asp:Label ID="OutputLabel" runat="server"></asp:Label>
            <!-- End To Do ..............................  -->
        </asp:View>
        <asp:View ID="Edit" runat="server">
            <div id="<%=ClientID%>_edit">
                 <!-- You Need To Do ..............................  -->
                 <asp:TextBox ID="HelloTextBox" runat="server" Style="width: 95%"> </asp:TextBox>
                  <!-- End To Do ..............................  -->
                 <asp:Button ID="CancelButton" runat="server" Text="Cancel" OnClick="CancelButton_Click" /> &nbsp;&nbsp;
                <asp:Button ID="SaveButton" runat="server" Text="Save" OnClick="SaveButton_Click" />
            </div>
        </asp:View>
    </asp:MultiView>

Not very complicated, and if you have looked at any of the widget code, this should be pretty familiar. We have the standard <%@ Control declaration statement at the top, and Asp Multiview control to show either the Normal view with an asp:Label for output, or the Edit view, with a simple form for updating and saving the widget properties.

 

In the code behind file, HelloWorld.ascx.cs

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Ektron.Cms.Widget;
using Ektron.Cms;
using Ektron.Cms.API;
using Ektron.Cms.Common;
using Ektron.Cms.PageBuilder;
using System.Configuration;

public partial class widgets_HelloWorld : System.Web.UI.UserControl, IWidget
{
    #region properties
    private string _HelloString;
   [WidgetDataMember("Hello World")]
    public string HelloString { get { return _HelloString; } set { _HelloString = value; } }
    #endregion

    IWidgetHost _host;
    protected void Page_Init(object sender, EventArgs e)
    {
        string sitepath = new CommonApi().SitePath;
        JS.RegisterJSInclude(this, JS.ManagedScript.EktronJS);
        JS.RegisterJSInclude(this, JS.ManagedScript.EktronModalJS);
        Css.RegisterCss(this, Css.ManagedStyleSheet.EktronModalCss);
        _host = Ektron.Cms.Widget.WidgetHost.GetHost(this);
        _host.Title = "Hello World Widget";
        _host.Edit += new EditDelegate(EditEvent);
        _host.Maximize += new MaximizeDelegate(delegate() { Visible = true; });
        _host.Minimize += new MinimizeDelegate(delegate() { Visible = false; });
        _host.Create += new CreateDelegate(delegate() { EditEvent(""); });
        PreRender += new EventHandler(delegate(object PreRenderSender, EventArgs Evt) { SetOutput(); });
        string myPath = string.Empty;
        if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["ek_helpDomainPrefix"]))
        {
            string helpDomain = ConfigurationManager.AppSettings["ek_helpDomainPrefix"];
            if ((helpDomain.IndexOf("[ek_cmsversion]") > 1))
            {
                myPath = helpDomain.Replace("[ek_cmsversion]", new CommonApi().RequestInformationRef.Version);
            }
            else
            {
                myPath = ConfigurationManager.AppSettings["ek_helpDomainPrefix"];
            }
        }
        else
        {
            myPath = sitepath + "Workarea/help";
        }
        _host.HelpFile = myPath + "/Widget Chapter/Hello World/Creating the Hello World Widget.htm";
        ViewSet.SetActiveView(View);
    }

    void EditEvent(string settings)
    {
        HelloTextBox.Text = HelloString;
        ViewSet.SetActiveView(Edit);
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        HelloString = HelloTextBox.Text;
        _host.SaveWidgetDataMembers();
        ViewSet.SetActiveView(View);
    }

    protected void SetOutput()
    {
        OutputLabel.Text = HelloString;
    }

    protected void CancelButton_Click(object sender, EventArgs e)
    {
        ViewSet.SetActiveView(View);
    }
}

In this file, we see the normal using statements at the top; the widget property declarations, in this case just the one for HelloString (I did say this was a simple widget); the Page_Init function, that sets the widget properties, registers some javascript and css  files, and creates the delegates for the IWidget _host interface.

After that, is the EditEvent function, that populates the fields in the Edit view, which allows you to change the text that is going to be displayed on the screen. The SaveButton_Click function, which saves the values from the Edit form to the widget properties. The SetOutput function, which generally is used to build or populate the actual widget View output. And the CancelButton_Click function, which cancels the Edit mode.

In order to also use this widget as a standard user control, we need to make a few modifications.

I created a new user control file in the widgets directory: jaytemHelloWorld.ascx, and added the following code from the default widget.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="jaytemHelloWorld.ascx.cs" Inherits="widgets_jaytemHelloWorld" %>

<%-- Used to initialize a Script Manager is one does not exist --%>
<asp:PlaceHolder ID="phScriptManager" runat="server" />

<asp:MultiView ID="ViewSet" runat="server" ActiveViewIndex="0">
     <asp:View ID="View" runat="server">
          <asp:Label ID="lblOutput" runat="server" />
     </asp:View>
     <asp:View ID="Edit" runat="server">
          <div id="<%=ClientID %>_edit">
               <asp:Label ID="lblHelloText" runat="server" AssociatedControlID="txtHelloTextBox" Text="Text to Display" />
              <asp:TextBox ID="txtHelloTextBox" runat="server" style="width: 95%" />
              <div>
                    <asp:Button ID="CancelButton" runat="server" Text="Cancel" OnClick="CancelButton_Click" />
                    <asp:Button ID="SaveButton" runat="server" Text="Save" OnClick="SaveButton_Click" />
              </div>
          </div>
     </asp:View>
</asp:MultiView>

 

The only real difference between the two is the addition of the Asp PlaceHolder control, just below the @Control definition. This will be used to add and initialize a Script Manager, if we are using this widget as a user control.

And the code behind: jaytemHelloWorld.ascx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Ektron.Cms.Widget;
using Ektron.Cms;
using Ektron.Cms.API;
using Ektron.Cms.Common;
using Ektron.Cms.PageBuilder;

public partial class widgets_jaytemHelloWorld : System.Web.UI.UserControl, IWidget
{
	#region Properties

	private string _HelloString;

	[WidgetDataMember("Hello World")]
	public string HelloString
	{
		get { return _HelloString; }
		set { _HelloString = value; }
	}

	private IWidgetHost _host;

	#endregion

	#region Constructor

	public widgets_jaytemHelloWorld()
	{
		_host = null;
		HelloString = String.Empty;
	}

	#endregion

	#region Page Events

	protected void Page_Init(object sender, EventArgs e)
    {
		string sitepath = new CommonApi().SitePath;

		//Tries to populate host if PageHost exists
		_host = Ektron.Cms.Widget.WidgetHost.GetHost(this);

		//Keeps null reference from occuring when using as a standard user control
		if (_host != null)
		{
			_host.Title = "Jaytem's Hello World Widget";
			_host.Edit += new EditDelegate(EditEvent);
			_host.Maximize += new MaximizeDelegate(delegate() { Visible = true; });
			_host.Minimize += new MinimizeDelegate(delegate() { Visible = false; });
			_host.Create += new CreateDelegate(delegate() { EditEvent(""); });
			_host.ExpandOptions = Expandable.ExpandOnEdit;
		}

		ViewSet.SetActiveView(View);

		//If the Scriptmanager is null, then instantiate and add to placeholder control
		if (ScriptManager.GetCurrent(this.Page) == null)
		{
			ScriptManager sManager = new ScriptManager();
			sManager.ID = "sManager_" + DateTime.Now.Ticks;
			phScriptManager.Controls.AddAt(0, sManager);
		}
	}

	protected void Page_PreRender(object sender, EventArgs e)
	{
		if (ViewSet.GetActiveView() != View)
			return;

		//if HelloString is passed in the properties, use that
		if (!string.IsNullOrEmpty(HelloString))
		{
			lblOutput.Text = HelloString;
		}
	}

	#endregion

	#region Event Handlers

	protected void SaveButton_Click(object sender, EventArgs e)
	{
		HelloString = txtHelloTextBox.Text.Trim();
		_host.SaveWidgetDataMembers();
		ViewSet.SetActiveView(View);
	}

	protected void CancelButton_Click(object sender, EventArgs e)
	{
		ViewSet.SetActiveView(View);
	}

	#endregion

	#region Methods

	void EditEvent(string settings)
	{
		txtHelloTextBox.Text = HelloString;
		ViewSet.SetActiveView(Edit);
	}

	private void SetOutput()
	{
		lblOutput.Text = HelloString;
	}

	#endregion
}

The code is very similar, with a few important differences (Plus I like to organize my code a bit differently).

Just below the Properties region, I have a Constructor. The Constructor allows us to instantiate an instance of the widget user control, and set the properties without needing the PageBuilder functionality. The constructor also sets some default widget property values, which is very important.

I cleaned up the Page_Init function a bit, getting rid of some of the functionality that this widget really didn’t need (although it would be very useful in a more complex widget). I also added a check for the ScriptManager, checking to see if it is null or not (null means that this widget is being used outside of the PageBuilder environment). If the ScriptManager is null, then we need to create a new instance of it, and add it to the page. This is where the Asp:PlaceHolder control that we added to the .ascx page comes in.

After the Page_Init function, we have the Page_PreRender event function. The Page_PreRender event happens after the Page_Load, but before the page is rendered to the screen. When using widgets in the PageBuilder environment, the PreRender event handler is set using a delegate, and referencing the SetOutput function. In this case, we use the event when using this widget as a user control, we have to do it ourselves.

Everything else is exactly the same.

Let’s see it in Action

As a Widget

First, let’s start with using this widget as a widget. I have a very simple PageBuilder template, with a single drop-zone. My new widget is in the widgets directory, and I have added it to the Widgets list, and to the template in the WorkArea Settings.

I creates a new PB page, using my new template, and add the Hello World widgets by dragging and dropping the widgets into the drop-zone.

 

Next, I will edit the new widget, and update the text to be displayed.

I click save, and then Publish the PB page, so we end up with both widgets displaying on the page.

 

 

As a User Control

There are two ways that you can use your new widget as a user control: by adding a control to the .aspx page, and passing in the parameters as attributes; or by adding the user control to the page programmatically.

For this demonstration, I have very simple .aspx page

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="widget_uc.aspx.cs" Inherits="test_widget_uc" %>

<%-- Register the widget on the page, to use as a normal user control --%>
<%@ Register Src="~/widgets/jaytemHelloWorld.ascx" TagName="HelloWorld" TagPrefix="jtm" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
     <head runat="server">
          <title></title>
     </head>
     <body>
          <form id="form1" runat="server">
               <div>
                    <%-- Add the user control to the page --%>
                    <jtm:HelloWorld ID="jtmHW" runat="server" HelloString="Hello World. Broadcasting from the widget user control" />

                    <%-- Add an asp:PlaceHolder control, to add the widget user control to the page programmatically --%>
                    <p>
                         <asp:PlaceHolder ID="phControls" runat="server" />
                    </p>
               </div>
          </form>
     </body>
</html>

You first need to register the widget on the page. This needs to be done for both methods, or it won’t work.  Add a new <%@ Register  declaration, at the top of the page, but below the <% @ Page declaration. Put the path to the widget in the Src attribute, and give it a TagName and TagPrefix values.

Next, add the user control to the page in the markup, setting a new HelloString value. When you run the page, this is what you see:

 

Simple, right?

If you wanted to add the user control programmatically, it’s almost as simple. Here is the code behind file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class test_widget_uc : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
		ASP.widgets_jaytemhelloworld_ascx HelloWorld = new ASP.widgets_jaytemhelloworld_ascx();
		HelloWorld.HelloString = "So Long, and Thanks for all the Fish";
		phControls.Controls.Add(HelloWorld);
    }
}

In the Page_Load Event function, I am instantiating a new instance of the widget user control. Then I am setting the string that I want to output, and adding the control to an asp:PlaceHolder control that I have on the .aspx page. I like using PlaceHolder controls in this instance, because I can control the placement of the new user control on the page.

When you refresh the page, the second user control is added.

 

So there you have it. Having the option to use your widgets as standard user controls opens up some possibilities on your site, and is a great example of code reuse. You don’t have to create a new user control if you already have the functionality in a widget. Just use the widget.

Happy Coding.

What year is it anyway?

Over the last few years, Ektron has focused on a key theme each year, where most of their communications, presentations, and community outreach all focus on that theme. In 2010, it was the ‘Year of the Marketer’; 2011, the ‘Year of the Developer’, and now we are into 2012, and the new theme is clearly the ‘Year of the Designer.’

2010 Year of the Marketer

I was lucky enough to attend the Synergy conference in 2010. This was a great conference, with a focus on the Marketing and Business side of a website. I remember sitting in a session listening to Tom Wentworth ( @twentworth12) and Nicole Rogers ( @nicolekrogers), two dynamic and fun speakers, talk about how, if content is king, then context is queen.

We saw a big push on things like PageBuilder, which allows the non-technical folks to build complex pages on an Ektron site; the Analytics integration, which puts key demographic information of who is using what parts of your website into the hands of those who can make the most of it;  and showing us how Ektron could leverage a visitor’s context, from sources such as their recent browsing history, Facebook, or their physical location, to provide a unique, targeted experience.

Note: These are all very important things, but I am a developer at heart. While I find all of that interesting, not as important as how to build something cool.

2011 Year of the Developer

If you were an Ektron developer, then 2011 was your year!

We saw the release of version 8.5, which brought a slick new interface for the WorkArea; powerful new features and technologies such as the new FAST Search; and a completely redesigned Framework API, that makes building custom functionality to interact with the CMS so much easier.

In the Developer Community, there was the rise of the Ektron Exchange, that finally gave Ektron developers a place to share the widgets and code samples that they had developed over the years. The developer forums got a needed infusion of answers from knowledgeable Ektron folks, such as Andrew Eddy, James Stout, and Bill Cava, to name just a few. ( @andrew_eddy, @egandalf, and @billcava)

Developer Meetups were scheduled all over, where folks could get together and share their experiences and knowledge with other Ektron developers over dinner and drinks. If you were lucky enough to have a  Local User Group (LUGs) meeting somewhere close by, you go to see new examples of what was available today, and more importantly, what was coming in the future.

2012 Year of the Designer

We are now seeing the direction of 2012, which I am dubbing the ‘Year of the Designer’. In 2012, we are finally starting to see that a well designed website is so much more than something nice to look at, it also has to work for the user.

Part of this I am sure is driven by the enormous momentum that we all see with the mobile web, where having a well designed, functional site that works on any device (smartphone, tablet, desktop computer), could very well be the difference between a business’s success or failure.

Ektron has embraced the Mobile First philosophy, made famous by Luke Wroblowski ( @lukewMobile First), and they are busy promoting the relatively new, and fundamentally game-changing web design trend called Responsive Web Design, pioneered by Ethan Marcotte ( @beep, Responsive Web Design). The really great thing about 2012, is that Ektron is going to have both of these incredible individuals speaking at the annual Synergy conference this year. This one is not to be missed.

Note: These are two of my biggest web heroes. They are changing they way that we look at the web.

P.S.: Responsive Web Design is something that I have been interested in for some time. In 2011, I made a short presentation at the Seattle LUG, where I showed what might have been the first Ektron site using RWD (at least I like to think that it was), and that was followed up with a Developer interview with Bill Cava (Developer Webinar – Interview with Joe Mayberry), where I talked about Ethan Marcotte, and the potential that RWD has with the Ektron Platform.

An argument could be made that I had a hand in starting the momentum that led to the Year of the Designer. With that, a trip to D.C. in November, to see Luke and Ethan speak, would be the culmination of my efforts. What do you think? Maybe I should take up a collection.

When Dreams Change

It has been about a year since my life changed. In April of 2011, I saw a job posting on the Ektron web site for a Sales Engineer, and I thought I should go for it.

Now, at that point, I had been using the Ektron CMS platform for Canyon County, Idaho’s public and private websites for over three years, I was actively involved in the developer community, on both Twitter and the Ektron developer forums, and I was starting to be recognized. Because of my involvement in the developer community, I was asked to speak at Ektron’s Seattle Local Users Group meeting, and Bill Cava, Ektron’s Chief Evangelist, asked me to participate in a developer interview webinar (http://www.ektron.com/Resources/Webinars/Interview-With-Joe-Mayberry/)

The more I dealt with the folks at Ektron, the more impressed I was with the company, and the quality of people who worked there. I kept thinking that this would be a great place to work, so when I saw the Sales Engineer posting, I finally thought, “I can do that.” After all, I was already a client, and I could bring an informed perspective to the situation.

Before applying, I decided to reach out to friend I had made on Twitter, who had been in a very similar situation a couple of years earlier, and was now one of the most respected developers at Ektron. I asked for his opinion, and if life at Ektron was as good as I thought it would be. His answer surprised me. Not by what he did or didn’t say, but by the direction it went. He told me that the Sales Engineer job would be a great learning experience, but that he wasn’t sure if it was right for me, and that the group he was in had an opening.

It took a bit, a couple of telephone interviews, and what seemed like more emails than I can count, but they hired me. I was living the dream. I was doing work that I really enjoyed, working remotely, with some truly great people, and I learned. I learned how to push the Ektron CMS platform past anything I had ever thought of. And as we pushed it, I grew as well, and I was good at my job.

That’s when the dream changed.

Friday, March 30, 2012 started out just like any other. I went up to my office, a thermos of tea in hand, excited to build something cool. One of the first things I noticed was an email from Ektron’s CEO Bill Rogers, saying that there was a mandatory meeting in a couple of hours that I needed to call into. Being a remote worker, this wasn’t unheard of. A couple of my colleagues and I talked over instant message about it, wondering what was going on. We were curious, but not worried since we knew the company was doing really well.

When the meeting started, they got right to the point: Ektron was getting out of the services business, and we had lost our jobs, effective immediately. (You can read the official Ektron Corporate Update here: http://www.ektron.com/billrogersblog/Ektron-Corporate-Update/)

My dream had just become a nightmare.

Why did this happen? The company was doing really well, reporting a 35% rise in licensing over the last year, so why were they letting us go? More specifically, why were they letting me go? Hadn’t I been doing a good job?

A lot of people out there have probably disapproved and criticized Ektron and Bill Rogers for what they did, and how it was handled. I am not one of those people.

This wasn’t a personal decision. It was a business decision. Bill had decided to take the company in a new direction, which didn’t include us. He made the decision for what he believes to be for the betterment of his company, and only time will tell if he was right or not. Personally, I think he will be proved right.

I imagine that the decision to let so many of us go was a difficult one, at least I hope it was. Changing so many lives so suddenly should be a hard decision, and not one to do on a whim. A person or company that can do that easily is not one I want to work with.

Getting fired over the phone isn’t ideal, but what is? They had people spread out across the country, in offices and remote locations like me. How else were they supposed to do it? By email? This was probably the most conscientious way that it could have been done, given the circumstances.

So there I was, feeling betrayed, confused and lost; alternating between fear, anger, and disbelief so quickly that a manic-depressive on crack, riding a roller-coaster would have had a hard time keeping up with my emotions.

But the story does have a happy ending and a new beginning.

I quickly reached out on Twitter and Linkedin, letting people know that I had just lost my job, and asking if anyone knew of any positions available. The response was fast and overwhelming. It turns out that .Net developers with Ektron experience are very desirable. I quickly had an interview and a job offer with WSOL that I was happy to accept, and I start work in a few days.

I used to tell people that my job with Ektron was the one that Twitter helped me get, which is true, but I don’t think I would have gotten this new one as quickly as I did without being a presence on the social media platforms, or without the time I spent at Ektron.

I will always appreciate my time at Ektron, and getting to know the people that work there. It is a great company, with a good product, and spectacular people. I am still sad that I won’t be working there anymore, but that part of my life is over, and a new one is just getting started.

An Answer to the Problem – Responsive Web Design

In my earlier post, “What is Responsive Web Design? The Problem…“, I outlined one of the many issues facing web developers today, namely how to deal with all of the different devices, screen sizes, and capabilities now available for users to interact with a web site.

One answer is to use Responsive Web Design.

Responsive Web Design is a concept that was first introduced by Ethan Marcotte on the A List Apart web site on May 25, 2010. His article title simply Responsive Web Design lays out a concept of designing and developing a web page that adapts to it’s environment to provide an elegant and efficient user experience, regardless of whether a user is using a high definition desktop monitor, or a cell phone with 320 x 480 pixel resolution.

Responsive Web Design uses a combination of fluid grids, flexible images, and CSS3 media queries to create a platform agnostic web site, that adapts and reflows as needed,hiding or reveling elements, or changing font sizes, line heights and leading to introduce alternate page layouts as the resolution changes.  to optimize the reading experience on different screen sizes.

While Ethan’s solution is powerful, and elegant, it is not the solution for every situation. Careful consideration needs to be given to each project, to provide the most appropriate solution. This is a topic that Ethan himself addressed in a blog post on his website Unstoppable Robot Ninja, which is a great read for anyone who is serious about web development.

The great news is that people are jumping on the Responsive Web Design bandwagon, and producing some incredible websites.  Here is just a small sampling of some of the websites that I have run across:

And there are so many more. In fact, this concept is catching on so well, that Ethan has written a book Responsive Web Design, which is being released from A Book Apart on June 7. I am very excited to get my hands on this book. I follow several people on Twitter who have gotten a sneak peek, and they all have rave reviews.

I am a firm believer in the power of Responsive Web Design, and over the next several months I will be spending a lot of time researching, investigating, and practicing with the concepts. I will do my best to share what I learn in this blog, so I hope you will continue reading.

Getting Values from Textbox in Nested ListView Controls

A few days ago, I was given a task to build a simple web application to maintain and display the results from an upcoming local election. Since this was supposed to be a very simple election, using a hand counted paper ballot, I didn’t think it would be that difficult.

I decided to use the ListView control that I had recently learned of  (Yes, I am very behind). The ListView control made it very easy to build both the data output, and the input form, by binding a datasource to the parent control with a record for each race being run. I then bound a secondary datasource to a nested ListView control for each record to display the candidates for each race.

Here is a screen capture of the simple input form I built.

Paper Ballot Maintenance Screen

The front-end code example: ListView-front end Code Example

 

There are a lot of different ways to handle this code, but this was a rush job, and needed to get done quickly.

The plan was to have the Elections folks enter the votes received data as they get it from polling locations on election night after the polls close,  and then update the datasource as needed.

This sounded simple, until I tried to get the data from the text boxes in the nested ListView. Then things got complicated. And while I searched and searched on-line for a solution, I didn’t find one that fit my particular circumstances.

I started out looping over the top level ListView, and getting the values from each of the drop-down fields. This went smoothly. But I quickly found that I didn’t have access to the text box fields, as they were in a child object. The solution I finally came up with is the following excerpt from the code behind file: ListView-codebehind Code Example

The trick turned out to be to find out how many items are in the ListView, start a for loop going the same number of times as items in the ListView. At each iteration of the loop, get the information you need, and load it into whatever you need to interact with the data. In my case I am loading it into an object for later processing.

In addition, look for a child ListView control. In this case, I put it into a try/catch, so I could proceed even if one isn’t present. Instantiate a new ListView object in the code behind, and load the child control into it. You now have access to all of the data present in that child ListView control. Repeat the process from above: loop over the ListView object, now looking for your text boxes. Load each one of them into a new TextBox object, and you have the data.

It seems cumbersome, and probably is. Let me know what you think, or if you have a better way of handling this. I am sure that there is a more elegant way to accomplish this, and I would love to know about it.