Click here to Skip to main content
15,886,362 members
Articles / Web Development / HTML

Calendar UI Extender Control

Rate me:
Please Sign up or sign in to vote.
4.00/5 (3 votes)
10 Oct 20075 min read 77.2K   1.2K   45  
An AJAX calendar extender control that implements a highly customizable UI and a WYSIWYG designer preview
/*
 **************************************************************
 * AjaxCalendarToolkit 
 **************************************************************
 * Author: Rohit Gadagkar (rohit.gadagkar@gmail.com)
 * Copyright � 2007 Rohit Gadagkar
 * License:
 * Free without any restrictions whatsoever 
 * 
 * Created: 7/10/2007 
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
 * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 **************************************************************  
*/

using System;
using System.Collections.Generic;
using System.Text;
using AjaxCalendarToolkit.Properties;

namespace AjaxCalendarToolkit.UI
{
    internal class DateExpressionBuilder
    {
        static readonly string[] daysOfWeek1Letter;
        static readonly string[] daysOfWeek3Letter;
        static readonly string[] dateSuffixes;

        private DateDisplaySpec _dateDisplaySpec;
        private DateDisplayOrder _dateDisplayOrder;
        private string _yearPrefix;
        private string _yearSuffix;
        private string _monthPrefix;
        private string _monthSuffix;
        private string _datePrefix;
        private string _dateSuffix;
        private string _dayOfWeekPrefix;
        private string _dayOfWeekSuffix;
        private bool _overridePrefixSuffixBehaviourUsingDefault;
        
        static class Defaults
        {
            internal const string YearPrefix = " ";
            internal const string YearSuffix = " ";
            internal const string MonthSuffix = " ";
            internal const string MonthPrefix = " ";
            internal const string DateSuffix = " ";
            internal const string DatePrefix = " ";
            internal const string DayOfWeekSuffix = ", ";
            internal const string DayOfWeekPrefix = " ";
            internal const string NumericSeperator = "/";
            internal const string WordSeperator = " ";  
        }

        /// <summary>
        /// Defines the prefix, suffix behaviour of DateExpressionBuilder.
        /// If set to true, the user need not specify prefix and suffix strings for the date
        /// components. Default values will be used if required, depending on the bits 
        /// specified in the DateDisplaySpec. 
        /// </summary>
        /// <remarks>
        /// This property is true by default. If DateDisplaySpecs for all date component(s) 
        /// are numeric, the default delimiter is "/". If not, the default delimiter is a 
        /// whitespace. This class does a sanity check before applying prefix and suffix strings.
        /// 
        /// Note -
        /// If user has specified one of the prefix or suffix properties (example DateSuffix)
        /// and OverridePrefixSuffixBehaviourUsingDefault is true (the default), the user
        /// specified prefix and suffixes will not be used. The default behaviour will be used
        /// instead.
        /// </remarks>
        public bool OverridePrefixSuffixBehaviourUsingDefault
        {
            get { return _overridePrefixSuffixBehaviourUsingDefault; }
            set { _overridePrefixSuffixBehaviourUsingDefault = value; }
        }

        string GetPropertyValue(bool isPropertyEmpty, string propertyValue)
        {
            return isPropertyEmpty? String.Empty : propertyValue;
        }

        bool IsPropertyValueEmpty(
                                DateDisplaySpec propertyFlag,
                                DateDisplaySpec[] validFlags)
        {
            DoSmartFormat();
            bool res1 = (_dateDisplaySpec & propertyFlag) != 0;
            if (res1)
            {
                bool res2 = false;
                foreach (DateDisplaySpec flag in validFlags)
                    res2 |= ((_dateDisplaySpec & flag) != 0);
                return !res2;
            }
            return true;
        }

        public string DayOfWeekSuffix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.DayOfWeekSuffix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.DayOfWeekFullWord,
                            DateDisplaySpec.DayOfWeek3LetterAbbreviation,
                            DateDisplaySpec.DayOfWeekNumeric}),
                    _dayOfWeekSuffix);                
            }
            set { _dayOfWeekSuffix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.DayOfWeekSuffix);
            }
        }

        public string DayOfWeekPrefix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.DayOfWeekPrefix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.DayOfWeekFullWord,
                            DateDisplaySpec.DayOfWeek3LetterAbbreviation,
                            DateDisplaySpec.DayOfWeekNumeric}),
                    _dayOfWeekPrefix);                
            }
            set { _dayOfWeekPrefix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.DayOfWeekPrefix);
            }
        }

        public string DateSuffix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.DateSuffix|DateDisplaySpec.DateSuffix2Letter,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Date2Digit,
                            DateDisplaySpec.DateAnyDigits}),
                    _dateSuffix);  
            }
            set { _dateSuffix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.DateSuffix);
            }
        }

        public bool AutoGenerateTwoLetterDateSuffix
        {
            get {
                return ((_dateDisplaySpec & DateDisplaySpec.DateSuffix2Letter) != 0);
            }
            set {
                SetDateFlagOnOff(value, DateDisplaySpec.DateSuffix2Letter);
            }
        }

        public string DatePrefix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.DatePrefix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Date2Digit,
                            DateDisplaySpec.DateAnyDigits}),
                    _datePrefix);  
            }
            set { _datePrefix = value; 
                SetDateFlagOnOff(value, DateDisplaySpec.DatePrefix);
            }
        }

        public string MonthSuffix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.MonthSuffix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Month3LetterAbbreviation,
                            DateDisplaySpec.MonthFullWord,
                            DateDisplaySpec.MonthNumeric2Digits,
                            DateDisplaySpec.MonthNumericAnyDigits}),
                    _monthSuffix);  
            }
            set { _monthSuffix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.MonthSuffix);
            }
        }

        public string MonthPrefix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.MonthPrefix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Month3LetterAbbreviation,
                            DateDisplaySpec.MonthFullWord,
                            DateDisplaySpec.MonthNumeric2Digits,
                            DateDisplaySpec.MonthNumericAnyDigits}),
                    _monthPrefix);  
            }
            set { _monthPrefix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.MonthPrefix);
            }
        }

        public string YearSuffix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.YearSuffix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Year2Digits,
                            DateDisplaySpec.Year4Digits}),
                    _yearSuffix);  
            }
            set { _yearSuffix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.YearSuffix);
            }
        }

        public string YearPrefix
        {
            get {
                return GetPropertyValue(
                    IsPropertyValueEmpty(
                        DateDisplaySpec.YearPrefix,
                        new DateDisplaySpec[] {
                            DateDisplaySpec.Year2Digits,
                            DateDisplaySpec.Year4Digits}),
                    _yearPrefix);
            }
            set { _yearPrefix = value;
                SetDateFlagOnOff(value, DateDisplaySpec.YearPrefix);
            }
        }


        public DateDisplayOrder DateDisplayOrder
        {
            get { return _dateDisplayOrder; }
            set { _dateDisplayOrder = value; DoSmartFormat(); }
        }

        public DateDisplaySpec DateDisplaySpec
        {
            get { return _dateDisplaySpec; }
            set { _dateDisplaySpec = value; DoSmartFormat(); }
        }
        
        static DateExpressionBuilder()
        {
            daysOfWeek1Letter = Resources.DaysOfWeek1Letter.Split(
                new string[] { Resources.ArrayDelimiter }, StringSplitOptions.None);
            daysOfWeek3Letter = Resources.DaysOfWeek3Letter.Split(
                new string[] { Resources.ArrayDelimiter }, StringSplitOptions.None);
            dateSuffixes = Resources.DateSuffixes.Split(
                new string[] { Resources.ArrayDelimiter }, StringSplitOptions.None);
        }

        public DateExpressionBuilder(DateDisplaySpec specs, DateDisplayOrder displayOrder,
            bool overridePrefixSuffixBehaviourUsingDefault)
        {
            _dateDisplaySpec = specs; _dateDisplayOrder = displayOrder;
            _overridePrefixSuffixBehaviourUsingDefault = overridePrefixSuffixBehaviourUsingDefault;
        }

        public DateExpressionBuilder(DateDisplaySpec specs, DateDisplayOrder displayOrder)
            : this(specs, displayOrder, true)
        {}

        public DateExpressionBuilder(DateDisplaySpec specs)
            : this(specs, DateDisplayOrder.DayOfWeek_Month_Date_Year)
        { }

        public DateExpressionBuilder()
            : this(
            DateDisplaySpec.Year4Digits | DateDisplaySpec.MonthFullWord |
            DateDisplaySpec.DateAnyDigits | DateDisplaySpec.DayOfWeekFullWord |
            DateDisplaySpec.DayOfWeekSuffix | DateDisplaySpec.MonthSuffix |
            DateDisplaySpec.DateSuffix | DateDisplaySpec.DateSuffix2Letter)
        {}

        public string FormatDate(DateTime date)
        {
            DoSmartFormat();
            return date.ToString(ConstructFullFormatString(date));
        }

        internal bool DayOfWeekBitIsSet
        {
            get {
                return (_dateDisplaySpec & DateDisplaySpec.DayOfWeek3LetterAbbreviation) != 0
                || (_dateDisplaySpec & DateDisplaySpec.DayOfWeekFullWord) != 0
                || (_dateDisplaySpec & DateDisplaySpec.DayOfWeekNumeric) != 0;                
            }
        }

        internal bool MonthBitIsSet
        {
            get {
                return (_dateDisplaySpec & DateDisplaySpec.Month3LetterAbbreviation) != 0
                || (_dateDisplaySpec & DateDisplaySpec.MonthFullWord) != 0
                || (_dateDisplaySpec & DateDisplaySpec.MonthNumeric2Digits) != 0
                || (_dateDisplaySpec & DateDisplaySpec.MonthNumericAnyDigits) != 0;
            }
        }

        internal bool DateBitIsSet
        {
            get {
                return (_dateDisplaySpec & DateDisplaySpec.Date2Digit) != 0
                || (_dateDisplaySpec & DateDisplaySpec.DateAnyDigits) != 0;
            }
        }

        internal bool YearBitIsSet
        {
            get {
                return (_dateDisplaySpec & DateDisplaySpec.Year2Digits) != 0
                || (_dateDisplaySpec & DateDisplaySpec.Year4Digits) != 0;
            }
        }

        internal bool AllNumericBits
        {
            get { 
                bool dow = ((DayOfWeekBitIsSet && 
                    (_dateDisplaySpec & DateDisplaySpec.DayOfWeekNumeric)!=0))
                || (!DayOfWeekBitIsSet);
                bool m = (MonthBitIsSet &&
                    ((_dateDisplaySpec & DateDisplaySpec.MonthNumeric2Digits) != 0
                || (_dateDisplaySpec & DateDisplaySpec.MonthNumericAnyDigits) != 0))
                || !MonthBitIsSet;
                bool dt = DateBitIsSet;
                bool yr = YearBitIsSet;
                return dow && m && dt && yr;
            }
        }

        internal void SetDateFlagOnOff(string stringPropertyValue, DateDisplaySpec dateFlag)
        {
            SetDateFlag(String.IsNullOrEmpty(stringPropertyValue), dateFlag);
        }

        internal void SetDateFlagOnOff(bool boolPropertyValue, DateDisplaySpec dateFlag)
        {
            SetDateFlag(boolPropertyValue, dateFlag);
        }

        internal void SetDateFlag(bool turnOffFlagBit, DateDisplaySpec dateFlag)
        {
            if (turnOffFlagBit && (_dateDisplaySpec & dateFlag) != 0)
                _dateDisplaySpec ^= dateFlag;
            else if (!turnOffFlagBit) _dateDisplaySpec |= dateFlag;
        }

        /// <summary>
        /// This method verifies and sets up valid values for default behaviour
        /// Default prefix suffix behaviour is to 
        ///     1) put " " character as suffix (seperator)
        ///     2) put "/" character as suffix when all date component specs are numeric
        ///     3) default behaviour suffixes override any user supplied values through the
        ///        prefix and suffix date component properties.
        /// If UseDefaultPrefixSuffixBehaviour is set to false, the user is expected to 
        /// provide each of the date spec suffixes, which will be used as seperators in the
        /// output.
        /// </summary>
        internal void DoSmartFormat()
        {
            if (_overridePrefixSuffixBehaviourUsingDefault)
            {
                DayOfWeekPrefix = String.Empty; DatePrefix = String.Empty;
                MonthPrefix = String.Empty; YearPrefix = String.Empty;
                _dateDisplaySpec |= (DateDisplaySpec.DateSuffix | DateDisplaySpec.DateSuffix2Letter 
                    |DateDisplaySpec.MonthSuffix);
                if (AllNumericBits) {
                    if (DateBitIsSet) DateSuffix = Defaults.NumericSeperator;
                    if (MonthBitIsSet) MonthSuffix = Defaults.NumericSeperator;
                }
                switch (_dateDisplayOrder)
                {
                    case DateDisplayOrder.DayOfWeek_Date_Month_Year:
                    case DateDisplayOrder.DayOfWeek_Month_Date_Year:
                        _dateDisplaySpec |= DateDisplaySpec.DayOfWeekSuffix;
                        
                        DayOfWeekSuffix = DayOfWeekBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (DayOfWeekBitIsSet && !MonthBitIsSet && !DateBitIsSet & !YearBitIsSet)
                            DayOfWeekSuffix = String.Empty;
                        
                        MonthSuffix = MonthBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (MonthBitIsSet && (
                            (_dateDisplayOrder == DateDisplayOrder.DayOfWeek_Month_Date_Year 
                            && !DateBitIsSet && !YearBitIsSet)
                            || (_dateDisplayOrder == DateDisplayOrder.DayOfWeek_Date_Month_Year
                            && !YearBitIsSet)))
                            MonthSuffix = String.Empty;

                        DateSuffix = DateBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (DateBitIsSet && (
                            (_dateDisplayOrder == DateDisplayOrder.DayOfWeek_Month_Date_Year 
                            && !YearBitIsSet)
                            || (_dateDisplayOrder == DateDisplayOrder.DayOfWeek_Date_Month_Year
                            && !YearBitIsSet && !MonthBitIsSet)))
                            DateSuffix = String.Empty;

                        if (YearBitIsSet) {
                            YearSuffix = String.Empty;
                            if (_dateDisplayOrder == DateDisplayOrder.DayOfWeek_Month_Date_Year
                                && DateBitIsSet) 
                                YearPrefix = Defaults.WordSeperator;
                            
                        }
                        if (MonthBitIsSet && DateBitIsSet &&
                            DateDisplayOrder == DateDisplayOrder.DayOfWeek_Date_Month_Year)
                            MonthPrefix = Defaults.WordSeperator;                        
                        
                        break;
                    case DateDisplayOrder.Year_Month_Date_DayOfWeek:
                        _dateDisplaySpec |= DateDisplaySpec.YearSuffix;
                        
                        YearSuffix = YearBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (YearBitIsSet && !MonthBitIsSet && !DateBitIsSet & !DayOfWeekBitIsSet)
                            YearSuffix = String.Empty;

                        MonthSuffix = MonthBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (MonthBitIsSet && !DateBitIsSet && !DayOfWeekBitIsSet)
                            MonthSuffix = String.Empty;

                        DateSuffix = DateBitIsSet
                        ? (AllNumericBits ? Defaults.NumericSeperator : Defaults.WordSeperator)
                        : String.Empty;
                        if (DateBitIsSet && !DayOfWeekBitIsSet)
                            DateSuffix = String.Empty;

                        if (DayOfWeekBitIsSet) {
                            DayOfWeekSuffix = String.Empty;
                            if (DateBitIsSet) DayOfWeekPrefix = Defaults.WordSeperator;
                        }
                        break;
                }
            }            
        }

        //todo: Construct methods will include prefix and suffix in return values
        internal string ConstructDayOfWeekFormat(DateTime d)
        {
            if (!DayOfWeekBitIsSet) return String.Empty;
            string format = "'{0}'{1}'{2}'", val = null;
            if ((_dateDisplaySpec & DateDisplaySpec.DayOfWeek3LetterAbbreviation) != 0)
                val = "ddd";
            else if ((_dateDisplaySpec & DateDisplaySpec.DayOfWeekFullWord) != 0)
                val = "dddd";
            else if ((_dateDisplaySpec & DateDisplaySpec.DayOfWeekNumeric) != 0)
                val = "%d";
            return String.Format(format, DayOfWeekPrefix, val, DayOfWeekSuffix);
        }

        internal string ConstructMonthFormat(DateTime d)
        {
            if (!MonthBitIsSet) return String.Empty;
            string format = "'{0}'{1}'{2}'", val = null;
            if ((_dateDisplaySpec & DateDisplaySpec.Month3LetterAbbreviation) != 0)
                val = "MMM";
            else if ((_dateDisplaySpec & DateDisplaySpec.MonthFullWord) != 0)
                val = "MMMM";
            else if ((_dateDisplaySpec & DateDisplaySpec.MonthNumeric2Digits) != 0)
                val = "MM";
            else if ((_dateDisplaySpec & DateDisplaySpec.MonthNumericAnyDigits) != 0)
                val = "%M";
            return String.Format(format, MonthPrefix, val, MonthSuffix);
        }

        internal string ConstructDateFormat(DateTime d)
        {
            //todo: for the date suffix, if 2letter bit is there return dynamic suffix from resouces 
            if (!DateBitIsSet) return String.Empty;
            string format = "'{0}'{1}'{2}'", val = null;
            if ((_dateDisplaySpec & DateDisplaySpec.Date2Digit) != 0)
                val = "dd";
            else if ((_dateDisplaySpec & DateDisplaySpec.DateAnyDigits) != 0)
                val = "%d";
            return String.Format(format, DatePrefix, val,
                AutoGenerateTwoLetterDateSuffix ? GetDateSuffix(d) : DateSuffix);            
        }

        internal string ConstructYearFormat(DateTime d)
        {
            if (!YearBitIsSet) return String.Empty;
            string format = "'{0}'{1}'{2}'", val = null;
            if ((_dateDisplaySpec & DateDisplaySpec.Year2Digits) != 0)
                val = "yy";
            else if ((_dateDisplaySpec & DateDisplaySpec.Year4Digits) != 0)
                val = "yyyy";
            return String.Format(format, YearPrefix, val, YearSuffix);
        }

        internal string ConstructFullFormatString(DateTime d)
        {
            string format = "{0}{1}{2}{3}";
            switch (_dateDisplayOrder)
            {
                case DateDisplayOrder.DayOfWeek_Date_Month_Year:
                case DateDisplayOrder.DayOfWeek_Month_Date_Year:
                    format = String.Format(format,
                        ConstructDayOfWeekFormat(d),
                        _dateDisplayOrder == DateDisplayOrder.DayOfWeek_Date_Month_Year
                        ? ConstructDateFormat(d) : ConstructMonthFormat(d),
                        _dateDisplayOrder == DateDisplayOrder.DayOfWeek_Date_Month_Year
                        ? ConstructMonthFormat(d) : ConstructDateFormat(d),
                        ConstructYearFormat(d));
                    break;
                case DateDisplayOrder.Year_Month_Date_DayOfWeek:
                    format = String.Format(format,
                        ConstructYearFormat(d),
                        ConstructMonthFormat(d),
                        ConstructDateFormat(d),
                        ConstructDayOfWeekFormat(d));
                    break;
            }
            return format;
        }

        string GetDateSuffix(DateTime d)
        {
            int unitDigit = d.Day % 10;
            if (d.Day >= 11 && d.Day <= 13) unitDigit = 0;
            return unitDigit < dateSuffixes.Length ? dateSuffixes[unitDigit] : String.Empty;
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I am a tech lead working for Cap Gemini. Although I primarily work with the Microsoft technology stack (including .NET and legacy technologies) I like to keep myself informed about developments in the Java world.

Comments and Discussions