Date-aware Theme v2

Tuesday, 07 April 2009 04:16 PM
by Coose

Well, my original Date-aware theme header images was kinda crappy:

  • Required modifications to the BlogEngine.NET theme
  • Only changed a header image
  • Was not implemented as a BlogEngine.NET extension
  • Was not configurable in the BlogEngine.NET control panel
  • …we can go on and on here…it was not a very good solution.

 

So, here is my attempt at version 2. It's quite a bit simpler.

Copy the attached TimelyStyle.cs file into the Extensions folder of the BlogEngine.NET web site.  Now go to the BlogEngine.NET control panel and configure.

Let's examine the code:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5: using BlogEngine.Core;
   6: using BlogEngine.Core.Web.Controls;
   7: using System.Web.UI;
   8: using System.Web.UI.HtmlControls;
   9: using System.Text;
  10: using System.Globalization;
  11: using System.Data;
  12: using System.Text.RegularExpressions;
  13:  
  14: [Extension("Timely Style", "1.0", "<a href=\"http://www.funkymule.com\">Funky Mule</a>")]
  15: public class TimelyStyle
  16: {
  17:     private class ElementImageInfo
  18:     {
  19:         public DateTime StartDate { get; set; }
  20:         public DateTime EndDate { get; set; }
  21:         public string Style { get; set; }
  22:         public string Value { get; set; }
  23:     }
  24:  
  25:     private ExtensionSettings Settings { get; set; }
  26:  
  27:     public TimelyStyle()
  28:     {
  29:         Post.Serving += new EventHandler<ServingEventArgs>(Post_Serving);
  30:         BlogEngine.Core.Page.Serving += new EventHandler<ServingEventArgs>(Post_Serving);
  31:         
  32:         InitSettings();
  33:     }
  34:  
  35:     private void InitSettings()
  36:     {
  37:         ExtensionSettings s = new ExtensionSettings(this);     
  38:         s.AddParameter("Name", "Name", 50, true, true, ParameterType.String);
  39:         s.AddParameter("BeginDate", "Starting on", 50, true, false, ParameterType.String);
  40:         s.AddParameter("EndDate", "Ending on", 50, true, false, ParameterType.String);
  41:         s.AddParameter("ElementId", "Element Id", 255, true, false, ParameterType.String);
  42:         s.AddParameter("Style", "Style", 255, true, false, ParameterType.String);
  43:         s.AddParameter("Value", "Value", 255, true, false, ParameterType.String);
  44:         s.AddParameter("RepeatYearly", "Repeat Yearly", 10, false, false, ParameterType.String);
  45:  
  46:         Settings = ExtensionManager.InitSettings(GetType().Name, s);
  47:     }
  48:  
  49:     void Post_Serving(object sender, ServingEventArgs e)
  50:     {
  51:         if (e.Location != ServingLocation.SinglePage && e.Location != ServingLocation.SinglePost) return;
  52:         
  53:         Dictionary<string, ElementImageInfo> infos = new Dictionary<string,ElementImageInfo>(StringComparer.OrdinalIgnoreCase);
  54:         
  55:         DataTable table = Settings.GetDataTable();
  56:         foreach (DataRow row in table.Rows)
  57:         {
  58:             DateTime startDate, endDate, refDate;
  59:             bool repeat = false;
  60:             bool.TryParse((string)row["RepeatYearly"], out repeat);
  61:             
  62:             // if unable to parse the date, ignore the record.
  63:             if (!DateTime.TryParse((string)row["BeginDate"], out startDate)) continue;
  64:             refDate = new DateTime(repeat ? startDate.Year : DateTime.UtcNow.Year, DateTime.UtcNow.Month,
  65:                 DateTime.UtcNow.Day, DateTime.UtcNow.Hour, DateTime.UtcNow.Minute, DateTime.UtcNow.Second);
  66:             if (startDate > refDate) continue;
  67:             
  68:             if (!DateTime.TryParse((string)row["EndDate"], out endDate)) continue;
  69:             refDate = new DateTime(repeat ? endDate.Year : DateTime.UtcNow.Year, DateTime.UtcNow.Month,
  70:                 DateTime.UtcNow.Day, DateTime.UtcNow.Hour, DateTime.UtcNow.Minute, DateTime.UtcNow.Second);
  71:             if (endDate < refDate) continue;
  72:             
  73:             // do i already have an entry for the specified element id?
  74:             ElementImageInfo existing = new ElementImageInfo();
  75:             if (infos.TryGetValue((string)row["ElementId"], out existing))
  76:             {
  77:                 // we have overlap...so
  78:                 // use whichever one has the LATEST begin date.
  79:                 if (existing.StartDate > startDate) continue;
  80:             }
  81:             
  82:             infos[(string)row["ElementId"]] = new ElementImageInfo() 
  83:                 { StartDate = startDate, EndDate = endDate, Style = MakeCamelCased((string)row["Style"]), Value = (string)row["Value"] };
  84:         }
  85:         
  86:         StringBuilder script = new StringBuilder();
  87:         foreach (KeyValuePair<string, ElementImageInfo> info in infos)
  88:         {
  89:             script.AppendFormat(CultureInfo.InvariantCulture, 
  90:                 "document.getElementById('{0}').style['{1}'] = '{2}';",
  91:                 info.Key, info.Value.Style, info.Value.Value.Replace("'", "\'"));
  92:             script.AppendLine();
  93:         }
  94:  
  95:         ((System.Web.UI.Page)HttpContext.Current.Handler).ClientScript.RegisterStartupScript(GetType(), 
  96:             "TimelyStyle", script.ToString(), true);
  97:     }
  98:     
  99:     private string MakeCamelCased(string input)
 100:     {
 101:         char[] cinput = input.ToCharArray();
 102:         Regex.Matches(input, "(?<=[^a-zA-Z0-9]).").Cast<Match>().Where(m => m.Success == true).ToList()
 103:             .ForEach(m => cinput[m.Index] = char.ToUpperInvariant(cinput[m.Index]));
 104:         return Regex.Replace(new string(cinput), "[^a-zA-Z0-9]", string.Empty);
 105:     }
 106: }

Declare the class, an internal helper class, sink the Serving events in the constructor, and call InitSettings.

Create a repeating array of settings.  "Name" is an arbitrary name.  "BeginDate" is obvious, "EndDate" is obvious.  "ElementId" is the HTML ID of the element that the style will be modified on.  "Style" is the style property name (i.e. backgroundColor, backgroundImage, etc).  "Value" is the value to set for the style.  "RepeatYearly" is true to ignore the year portion of the date so that a setting will be repeated each year.

The Post_Serving method finds all configured items whose BeginDate and EndDate match DateTime.UtcNow.  The element specified by ElementId has it's style property of Style set to Value.

The final method will "camelize" attribute styles into camel cased javascript styles.  I.e. background-color will be converted to backgroundColor.

So personally, I use it like this:

Timely Style Configuration

Which shows that between 12 March and 15 April of every year, the #header element of my page will change it's backgroundImage style to url('Images/HamBdayHdr.jpg') for my sons birthday.

And between 6 April 2009 and 15 April 2009, the same #header element will change it's backgroundImage (or background-image) style property to url(Images/EasterHeader.jpg).

This is performed by injecting startup script to the bottom of the page:

<script type="text/javascript">
//<![CDATA[ document.getElementById('header').style['backgroundImage'] = 'url(Images/EasterHeader.jpg)';
//]]> </script>

You can use any style attribute, and set it to any acceptable javascript value.

Enjoy…or don't…what the hell do I care.

Download the source code here.

Comment on this
Development

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading