Friday, October 14, 2011

SharePoint Search Box Trick For Handling Search Input Enter Key.


Some of SharePoint developer who face issues with SharePoint search box that the enter key should be hit twice to do search, this strange behavior appears in both (Firefox and Chrome browsers), if you follow the event and method executed to do search you will find script rendered by SharePoint that is responsible for doing search as follow: 


 function SearchEnsureSOD() {  
       EnsureScript('search.js', typeof (GoSearch));  
     }  
     _spBodyOnLoadFunctionNames.push('SearchEnsureSOD');  
     function S6F789EBA_Submit() {  
       if (document.getElementById('ctl00_SearchBox_ctl03').value == '0') {  
         document.getElementById('ctl00_SearchBox_S6F789EBA_InputKeywords').value = '';  
       }  
       SearchEnsureSOD();  
       GoSearch('ctl00_SearchBox_ctl03', 'ctl00_SearchBox_S6F789EBA_InputKeywords', null, true, false, null, null, null, null, null, '\u002fSearch\u002fPages\u002fResults.aspx', '\u0647\u0630\u0627 \u0627\u0644\u0645\u0648\u0642\u0639', '\u0647\u0630\u0647 \u0627\u0644\u0642\u0627\u0626\u0645\u0629', '\u0647\u0630\u0627 \u0627\u0644\u0645\u062C\u0644\u062F', '\u0627\u0644\u0645\u0648\u0627\u0642\u0639 \u0630\u0627\u062A \u0627\u0644\u0635\u0644\u0629', '\u002fSearch\u002fPages\u002fResults.aspx', '', '\u0627\u0644\u0631\u062C\u0627\u0621 \u0625\u062F\u062E\u0627\u0644 \u0643\u0644\u0645\u0629 \u0628\u062D\u062B \u0648\u0627\u062D\u062F\u0629 \u0623\u0648 \u0623\u0643\u062B\u0631.'); if (document.getElementById('ctl00_SearchBox_ctl03').value == '0') {  
         document.getElementById('ctl00_SearchBox_S6F789EBA_InputKeywords').value = '\u0623\u062F\u062E\u0644 \u0646\u0635 \u0627\u0644\u0628\u062D\u062B ...';  
       }  
     }  


so that code ensure loading of java script file called "search.js" that is responsible for search handling by calling 


 _spBodyOnLoadFunctionNames.push('SearchEnsureSOD');  


i think that calling not performed well by neither Firefox nor Chrome "this calling will push SearchEnsureSOD method to onload event handled by SharePoint" if this method not performed as expected so the script will not be loaded so when enter key be hit it will call "S6F789EBA_Submit()" and for the first time the "SearchEnsureSOD will executed" and no redirect to search page will not be performed
and the next hi will fire search normally.

to handle this simply, we will ensure loading of "Search.js" at ready event by this we make sure that search java script file loaded successfully.

 $(document).ready(function () {  
    SearchEnsureSOD();  
 });  

by this Enter key will perform normally "Try and Have Fun"

Thursday, October 6, 2011

Bottom to Up Image Transition Effect
Today i will introduce very simple code snippet for applying image transition effect by using jQuery and CSS, now let us go to directly to HTML

 <div class="wrapper">  
     <div class="facesDiv">  
       <img src="images/03.png" width="128" height="100" originalheight="100" hoverheight="128"  
         hoverimage="images/03_hover.png" class="face" style="left: 0;" alt="face" />  
       <img src="images/02.png" width="128" height="100" originalheight="100" hoverheight="128"  
         hoverimage="images/02_hover.png" class="face" style="left: 128px;" alt="face" />  
       <img src="images/01.png" width="128" height="100" originalheight="100" hoverheight="128"  
         hoverimage="images/01_hover.png" class="face" style="left: 256px;" alt="face" />  
     </div>  
   </div>  

only 3 images as sample with known HEIGHT and WIDTH, give them the same class to be handled by jQuery and CSS such "face" also specify three nonstandard attributes to be handled by jQuery code as the following

  1. originalheight: this is the original image height.
  2. hoverheight: the maximum height after hover action.
  3. hoverimage: the image to be replaced after hover action.
also let us take a look on the JavaScript

 <script type="text/javascript">  
     $(document).ready(function () {  
       var navHeight = 0;  
       var tmpimage = '';  
       $('img.face').mouseenter(function () {  
         tmpimage = $(this).attr('src');  
         navHeight = $(this).attr('hoverheight') - $(this).attr('originalheight');  
         $(this).attr('src', $(this).attr('hoverimage'));  
         $(this).animate(  
         {  
           top: "-=" + navHeight,  
           height: "+=" + navHeight,  
           duration: 1000  
         });  
       }).mouseleave(function () {  
         $(this).attr('src', tmpimage);  
         $(this).animate(  
         {  
           top: "+=" + navHeight,  
           height: "-=" + navHeight,  
           duration: 1000  
         });  
       });  
     });  
   </script>  

and finally the CSS

 body  
 {  
   padding: 0px;  
   margin: 0px;  
 }  
 .wrapper  
 {  
   width: 384px;  
   height: 500px;  
   margin: auto;  
   text-align: center;  
 }  
 .facesDiv  
 {  
   position: relative;  
   height: 100px;  
   top: 200px;  
   margin: 0;  
   padding: 0;  
 }  
 .face  
 {  
   position: absolute;  
   float: left;  
   bottom: 0;  
 }  

for a complete sample, you can download the file  here

Friday, September 23, 2011

Simple ASP.net Auto Complete Composite Server Control

Today i will introduce new ASP.net composite server control "Auto Complete"
using  jQuery Auto Complete with few plugin modification that will support the main functionality of our control.

Let us go fast in control properties, the new control contains several properties most of them belongs to plugin itself and others will handle the control.

Properties belongs to plugin:
  1. MinimumChars: get or set the minimum characters to fire the autocomplete action * default = 1 *
  2. MaximumRows: get or set the maximum rows to be returned by the plugin * default = 5 *
  3. AutoFill: get or set autoFill property for the auto complete plugin "if true plugin will set input text with the first item" * default is false * 
  4. MustMatch: get or set mustMatch property for the auto complete plugin* default is false * 
  5. MatchContains:get or set matchContains property for the auto complete plugin* default is false * 
  6. SelectFirst: get or set selectFirst property for the auto complete plugin * default is true * 
  7. Scroll: get or set scroll property for the auto complete plugin * default is true *
  8. ScrollHeight: get or set scrollHeight property for the auto complete plugin * default is 180px *
  9. Delay: get or set delay property for the auto complete plugin* default is 400 mili seconds *
Properties belongs to control:
  1. TextBoxCssClass: get or set text box control css class
  2. PostURL: the url to post the jquery ajax call ** this url should url to an aspx page that will contain the method **
  3. MethodName: method name to be called ** this method should write response of type "text/xml" and has parameter called "searchKey" as string**
  4. MethodNameRequestKey: get or set requet key for method name "it is the query string key for method name if you need to specify your request such you post several posts to the same page"
  5. SelectedText (updated): get or set the text selected by user
  6. SelectedValue (updated): get or set the value selected by user
  7. XMLElementKey: get or set xmlelement key such as "user, employee and etc"
  8. XMLElementTextAttribute (updated): get or set xml element text attribute such as "name, department and etc"
  9. XMLElementValueAttribute (new): get or set xml element value attribute such as "id"
  10. IsRequired (new): provide option if user need to make the control required or not "default is false"
  11. IsSymbolsDisabled (new): provide option if user need to make the control disable symbols (special characters) or not "default is true"
  12. ValidationGroup (new): get or set the validation related group
  13. ErrorMessage (new): get or set required validator error message
  14. LettersErrorMessage (new): get or set the special characters error message
  15. LettersValidationExpression (new): get or set the special characters validation expression
  16. ErrorMessageDisplay (new):  get or set validation message display layout (value of enumeration {Inline, Breakline} ) "default is inline"

Now i will show you the main two methods in the control:

 protected override void CreateChildControls()  
     {  
       Controls.Clear();  
       // setting ids  
       txtAutoComplete.ID = "txtAutoComplete";  
       hdfValue.ID = "hdfValue";  
       // check if user provide cssclass for text input  
       if (!string.IsNullOrEmpty(TextBoxCssClass))  
       {  
         txtAutoComplete.CssClass = TextBoxCssClass + " autocompleteinput";  
       }  
       else  
         txtAutoComplete.CssClass = "autocompleteinput";  
       #region Required Field Validators  
       // text input RFV  
       rfvTextInput.Display = ValidatorDisplay.Dynamic;  
       rfvTextInput.ControlToValidate = "txtAutoComplete";  
       rfvTextInput.ErrorMessage = ErrorMessage;  
       // text input REXV  
       rexvTextInput.Display = ValidatorDisplay.Dynamic;  
       rexvTextInput.ControlToValidate = "txtAutoComplete";  
       rexvTextInput.ErrorMessage = LettersErrorMessage;  
       rexvTextInput.ValidationExpression = LettersValidationExpression;  
       // check if user need this instance required or not  
       if (!IsRequired)  
       {  
         rfvTextInput.Enabled = false;  
       }  
       // check if user need prevent user from entering special characters  
       if (!IsSymbolsDisabled)  
       {  
         rexvTextInput.Enabled = false;  
       }  
       if (!string.IsNullOrEmpty(ValidationGroup))  
       {  
         txtAutoComplete.ValidationGroup = ValidationGroup;  
         rfvTextInput.ValidationGroup = ValidationGroup;  
         rexvTextInput.ValidationGroup = ValidationGroup;  
       }  
       #endregion  
       #region User Interface  
       // adding the text box        
       Controls.Add(txtAutoComplete);  
       if (ErrorMessageDisplay == ErrorMessageDisplayLayout.BreakLine)  
         Controls.Add(new LiteralControl("<br />"));  
       // add validators  
       Controls.Add(rfvTextInput);  
       Controls.Add(rexvTextInput);  
       // adding the hidden field  
       Controls.Add(hdfValue);  
       #endregion  
       // register client script  
       RegisterPluginScript();  
     }  


Note: txtAutoComplete is an instance of TextBox declared  within the control

The other method is RegisterPluginScript() that will register the formatted script that will initialize the autocomplete instance.

 private void RegisterPluginScript()  
     {  
       try  
       {  
         if (string.IsNullOrEmpty(XMLElementKey) || string.IsNullOrEmpty(XMLElementTextAttribute))  
           return;  
         // if user never specify XMLElementValueAttribute --> control will assign the same text element attribute for value element attribute  
         if (string.IsNullOrEmpty(XMLElementValueAttribute))  
           XMLElementValueAttribute = XMLElementTextAttribute;  
         string key = "AutoComplete" + this.ID;  
         if (Page.ClientScript.IsClientScriptBlockRegistered(GetType(), key))  
           return;  
         StringBuilder scriptValue = new StringBuilder();  
         scriptValue.Append("<script type=\"text/javascript\">");  
         scriptValue.Append("$(document).ready(function () {");  
         if (!string.IsNullOrEmpty(MethodNameRequestKey) && !string.IsNullOrEmpty(MethodName))  
           scriptValue.AppendFormat("$('input#{0}').autocomplete('{1}?{2}={3}&',", this.txtAutoComplete.ClientID, PostURL, MethodNameRequestKey, MethodName);  
         else  
           scriptValue.AppendFormat("$('input#{0}').autocomplete('{1}?',", this.txtAutoComplete.ClientID, PostURL);  
         scriptValue.Append("{parse: function (xml) {");  
         scriptValue.Append("var rows = new Array();");  
         scriptValue.AppendFormat("$(xml).find('{0}').each(function (i) ", XMLElementKey);  
         scriptValue.Append("{rows[i] = {");  
         scriptValue.AppendFormat("data: $(this), value: $(this).attr('{0}'), result: $(this).attr('{1}')", XMLElementValueAttribute, XMLElementTextAttribute);  
         scriptValue.Append("};});");  
         scriptValue.Append("return rows;");  
         scriptValue.Append("},");  
         scriptValue.Append("formatItem: function (row, i, n) {");  
         scriptValue.AppendFormat("return row.attr('{0}');", XMLElementTextAttribute);  
         scriptValue.Append("},");  
         scriptValue.AppendFormat("minChars: {0},", MinimumChars.ToString());  
         scriptValue.AppendFormat("max: {0},", MaximumRows.ToString());  
         scriptValue.AppendFormat("autoFill: {0},", AutoFill.ToString().ToLower());  
         scriptValue.AppendFormat("mustMatch: {0},", MustMatch.ToString().ToLower());  
         scriptValue.AppendFormat("matchContains: {0},", MatchContains.ToString().ToLower());  
         scriptValue.AppendFormat("selectFirst: {0},", SelectFirst.ToString().ToLower());  
         scriptValue.AppendFormat("scroll: {0},", Scroll.ToString().ToLower());  
         scriptValue.AppendFormat("scrollHeight: {0},", ScrollHeight.ToString());  
         scriptValue.AppendFormat("delay: {0}", Delay.ToString());  
         scriptValue.Append("});");  
         scriptValue.AppendFormat("$('input#{0}').result(function (event, data, value) ", this.txtAutoComplete.ClientID);  
         scriptValue.Append("{");  
         scriptValue.AppendFormat("var hidden = $('input#{0}');", this.hdfValue.ClientID);  
         scriptValue.Append("hidden.val(value);");  
         scriptValue.Append("}); });");  
         scriptValue.Append("</script>");  
         Page.ClientScript.RegisterStartupScript(GetType(), key, scriptValue.ToString());  
       }  
       catch { }  
     }  

Note: not allowed to forget passing "XMLElementKey and XMLElementTextAttribute" if you forgotten them or one of them the control will not complete it is functionality since those are the main functionality key for the plugin data also you will note that data will be formatted for the plugin from XML data to array to be handled by the plugin. 

Prerequisites:
  1. jQuery plugin registered
  2. jquery.autocomplete registered "new modified one you can get all files you will need here as zip file called AutoCompleteFiles.zip contains three files (plugin, CSS file for results "don not change classes names" and image for loading)"
  3. ASPX page that will handle the posts by the plugin "will be discussed soon"
Implementation:
  1. Registering control in web.config file
     <add tagPrefix="dev" namespace="CustomControls" assembly="CustomControls" />  
    
  2. Adding the control to your ASPX page
     <dev:AutoComplete runat="server" ID="acEmployeeName" MaximumRows="10" MinimumChars="1" MatchContains="true"  
             MethodName="SearchUsers" PostURL="http://localhost/SiteName/Pages/AjaxHelper.aspx"  
             MethodNameRequestKey="op" TabIndex="3" XMLElementKey="User" XMLElementTextAttribute="Name" XMLElementValueAttribute="ID" />  
    
  3. The ASPX page that will handle the ajax calls posted by the plugin will have the folloing implementation
     protected void Page_Load(object sender, EventArgs e)  
         {  
           if (Request["op"] != null && Request["op"] == "SearchUsers")  
           {  
             if (Request["searchKey"] != null)  
               SearchUsers(Request["searchKey"]);  
           }  
         }  
         private void SearchUsers(string searchKey)  
         {  
           StringBuilder usersString = new StringBuilder();  
           // sample data --> data can be retrieved from any source and format the xml with and values you want
           string[] users = new string[] { "Ahmed", "Mohamed", "Fakhry", "Khalil", "Mansor" };  
           // build the XML   
           usersString.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");  
           usersString.Append("<Users>");  
    
          for (int i = 0; i < users.Length; i++)
                    if (users[i].ToLower().Contains(searchKey.ToLower()))
                        usersString.AppendFormat("", users[i], i.ToString());
    
           usersString.Append("</Users>");  
           Response.ClearContent();  
           Response.ContentType = "text/xml";  
           Response.Write(usersString.ToString());  
           Response.End();  
         }  
    
As noted the page will write an XML responce that will be reformatted by the control according to "XMLElementKeyXMLElementTextAttribute XMLElementValueAttribute" properties provided --> here 
  • XMLElementKey: User 
  • XMLElementTextAttribute: Name
  • XMLElementValueAttribute: ID
Note: If XMLElementValueAttribute same as XMLElementTextAttribute you can specify  XMLElementTextAttribute only and the control will consider value attribute as the same as the text attribute.

Note: To request the text you get the property called "SelectedText" and for value you will get the property called "SelectedValue"


Note: new updates added as the following
  1. Each item will have text and value.
  2. If the user never specify new property "XMLElementValueAttribute" the control will specify the text property to the value property.


Finally i hope for all good luck and i wish that article helpful

Note: you can find the complete source code here that is called "CustomControls.zip"

Thursday, September 8, 2011

Simple ASP.net Time Picker Composite Server Control

Today i will introduce commonly used server control for ASP.net, let us describe the control in details.

This control support localization for all possible value you need to localize such as
  1. HoursText
  2. MinutesText
  3. AMText
  4. PMText
  5. LayoutDirection
  6. TextAlign
Available properties in the control
  1. AMPM: provide option if user need time control render as AP-PM mode or not
  2. IsRequired: provide option if user need to make the control required or not
  3. ValidationGroup: option to make user provide "ValidationGroup" sub-controls
  4. DropDownListCssClass: option to provide "CssClass" for Drop Down Lists
  5. Time: "The Default Property" get or set the time value for the control the return value is string and the format depends on the "AMPM" property
  6. ShortTimeString: get the 24 hour-format time as string "hh:mm" as "23:30"
  7. LongTimeString: get the 12 hour-format time as string "hh:mmtt" as "01:30pm" 
  8. HoursText: the first item text for hours drop down list
  9. MinutesText: the first item text for minutes drop down list 
  10. AMText: the AM item text for AMPM drop down list 
  11. PMText: the PM item text for AMPM drop down list  
  12. LayoutDirection: the layout direction for drop down lists "ltr||rtl"
  13. TextAlign: the text align for drop down lists "left||right"
  14. SetCurrentTimeDefault: set the current time as default time selected by time picker
Note: also the control support Arabic numeral automatically

now with the main methods and overrides for rendering the control:


Note: you will find that the class inherits from class "WebControl" and this the main class that will be implemented and also implement the interface called "INamingContainer" and note that you not find any implementation for the interface methods and it used only for creating unique id for newly added control.


Control Collection and Create Child Controls Overrides

 public override ControlCollection Controls  
     {  
       get  
       {  
         EnsureChildControls();  
         return base.Controls;  
       }  
     }  

 protected override void CreateChildControls()  
     {  
       Controls.Clear();  
       #region Drop Down Lists  
       // setting ids  
       ddlHours.ID = "ddlHours";  
       ddlMinutes.ID = "ddlMinutes";  
       ddlAMPM.ID = "ddlAMPM";  
       // text align for drop down lists "left||right"        
       ddlHours.Attributes["style"] = "text-align:" + TextAlign.ToString();  
       ddlMinutes.Attributes["style"] = "text-align:" + TextAlign.ToString();  
       ddlAMPM.Attributes["style"] = "text-align:" + TextAlign.ToString();  
       // check if user provide cssclass for drop down lists  
       if (!string.IsNullOrEmpty(DropDownListCssClass))  
       {  
         ddlHours.CssClass = DropDownListCssClass;  
         ddlMinutes.CssClass = DropDownListCssClass;  
         ddlAMPM.CssClass = DropDownListCssClass;  
       }  
       #endregion  
       #region Required Field Validators  
       // hours RFV  
       rfvHours.Display = ValidatorDisplay.Dynamic;  
       rfvHours.ControlToValidate = "ddlHours";  
       rfvHours.ErrorMessage = "*";  
       rfvHours.InitialValue = "-1";  
       // minutes RFV  
       rfvMinutes.Display = ValidatorDisplay.Dynamic;  
       rfvMinutes.ControlToValidate = "ddlMinutes";  
       rfvMinutes.ErrorMessage = "*";  
       rfvMinutes.InitialValue = "-1";  
       // check if user need this instance required or not  
       if (!IsRequired)  
       {  
         rfvHours.Enabled = false;  
         rfvMinutes.Enabled = false;  
       }  
       else  
         if (!string.IsNullOrEmpty(ValidationGroup))  
         {  
           ddlHours.ValidationGroup = ValidationGroup;  
           rfvHours.ValidationGroup = ValidationGroup;  
           ddlMinutes.ValidationGroup = ValidationGroup;  
           rfvMinutes.ValidationGroup = ValidationGroup;  
         }  
       #endregion  
       #region User Interface  
       Controls.Add(new LiteralControl("<table border=\"0\" cellpadding=\"5\" cellspacing=\"0\" dir=\"" + LayoutDirection.ToString() + "\"><tr><td>"));  
       Controls.Add(ddlHours);  
       Controls.Add(rfvHours);  
       Controls.Add(new LiteralControl("</td><td>"));  
       Controls.Add(ddlMinutes);  
       Controls.Add(rfvMinutes);  
       Controls.Add(new LiteralControl("</td><td>"));  
       Controls.Add(ddlAMPM);  
       Controls.Add(new LiteralControl("</td></tr></table>"));  
       #endregion  
       string _time = string.Empty;  
       // time parts variable for 12 and 24 hour format  
       string[] timeParts = null;  
       if (string.IsNullOrEmpty(Time))  
       {  
         if (SetCurrentTimeDefault)  
         {  
           if (AMPM)  
           {  
             _time = DateTime.Now.ToString("hh:mmtt");  
             // 12hour-format time  
             timeParts = new string[3];  
             timeParts[0] = _time.Split(':')[0].ToString();  
             timeParts[1] = _time.Split(':')[1].Substring(0, 2);  
             timeParts[2] = _time.Split(':')[1].Substring(2, 2);  
           }  
           else  
           {  
             _time = DateTime.Now.ToString("hh:mm");  
             // 24hour-format time  
             timeParts = new string[2];  
             timeParts = _time.Split(':');  
           }  
         }  
         // load time drob down lists  
         LoadTime();  
         if (timeParts != null)  
         {  
           if (AMPM)  
           {  
             ddlHours.SelectedValue = timeParts[0];  
             ddlMinutes.SelectedValue = timeParts[1];  
             ddlAMPM.SelectedValue = timeParts[2];  
           }  
           else  
           {  
             ddlHours.SelectedValue = timeParts[0];  
             ddlMinutes.SelectedValue = timeParts[1];  
           }  
         }  
         // check if user need ampm option or not  
         if (!AMPM)  
           ddlAMPM.Visible = false;  
       }  
     }  




and the main method called LoadTime (to initialize all drop down lists with items)
 private void LoadTime()  
     {  
       try  
       {  
         // fill hours drop down list  
         ddlHours.Items.Clear();  
         if (!AMPM)  
           for (int i = 00; i < 24; i++)  
           {  
             if (HttpContext.Current.Session.LCID == 1025) // arabic  
               ddlHours.Items.Add(new ListItem(i.ToString().Length < 2 ? ConvertToArabicNumeral("0" + i.ToString()) : ConvertToArabicNumeral(i.ToString()), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
             else  
               ddlHours.Items.Add(new ListItem(i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString(), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
           }  
         else  
           for (int i = 01; i <= 12; i++)  
           {  
             if (HttpContext.Current.Session.LCID == 1025) // arabic  
               ddlHours.Items.Add(new ListItem(i.ToString().Length < 2 ? ConvertToArabicNumeral("0" + i.ToString()) : ConvertToArabicNumeral(i.ToString()), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
             else  
               ddlHours.Items.Add(new ListItem(i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString(), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
           }  
         // add first item to hours drop down list          
         ddlHours.Items.Insert(0, new ListItem(HoursText, "-1"));  
         // fill minutes drop down list  
         ddlMinutes.Items.Clear();  
         for (int i = 00; i < 60; i++)  
         {  
           if (HttpContext.Current.Session.LCID == 1025) // arabic  
             ddlMinutes.Items.Add(new ListItem(i.ToString().Length < 2 ? ConvertToArabicNumeral("0" + i.ToString()) : ConvertToArabicNumeral(i.ToString()), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
           else  
             ddlMinutes.Items.Add(new ListItem(i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString(), i.ToString().Length < 2 ? "0" + i.ToString() : i.ToString()));  
         }  
         // add first item to hours drop down list          
         ddlMinutes.Items.Insert(0, new ListItem(MinutesText, "-1"));  
         #region AMPM DropDownList  
         ddlAMPM.Items.Insert(0, new ListItem(AMText, "AM")); // first item  
         ddlAMPM.Items.Insert(1, new ListItem(PMText, "PM")); // second item  
         #endregion  
       }  
       catch (Exception ex)  
       {  
         throw new Exception(ex.Message);  
       }  
     }  

and the time validation method the support 12 hour-format and 24 hour-format

 private bool ValidateTime(string time, out bool IsAMPM)  
     {  
       IsAMPM = false;  
       bool validTime = false;  
       // validate 12hour-format time string  
       Regex rg12 = new Regex("^([1-9]|1[0-2]|0[1-9]){1}(:[0-5][0-9][aApP][mM]){1}$");  
       if (rg12.IsMatch(time))  
       {  
         validTime = true;  
         IsAMPM = true;  
         return validTime;  
       }  
       // validate 24hour-format time string  
       Regex rg24 = new Regex("^([0-1][0-9]|[2][0-3]):([0-5][0-9])$");  
       if (rg24.IsMatch(time))  
       {  
         validTime = true;  
         return validTime;  
       }  
       return validTime;  
     }  

and the last method for handling Arabic numeral

 // convert from english numeral to arabic numeral  
     protected string ConvertToArabicNumeral(string englishNumber)  
     {  
       string arabicNumebr = englishNumber;  
       try  
       {  
         foreach (char enn in englishNumber)  
         {  
           switch (enn)  
           {  
             case '0':  
               arabicNumebr = arabicNumebr.Replace('0', 'Ù ');  
               break;  
             case '1':  
               arabicNumebr = arabicNumebr.Replace('1', 'Ù¡');  
               break;  
             case '2':  
               arabicNumebr = arabicNumebr.Replace('2', 'Ù¢');  
               break;  
             case '3':  
               arabicNumebr = arabicNumebr.Replace('3', 'Ù£');  
               break;  
             case '4':  
               arabicNumebr = arabicNumebr.Replace('4', 'Ù¤');  
               break;  
             case '5':  
               arabicNumebr = arabicNumebr.Replace('5', 'Ù¥');  
               break;  
             case '6':  
               arabicNumebr = arabicNumebr.Replace('6', 'Ù¦');  
               break;  
             case '7':  
               arabicNumebr = arabicNumebr.Replace('7', 'Ù§');  
               break;  
             case '8':  
               arabicNumebr = arabicNumebr.Replace('8', 'Ù¨');  
               break;  
             case '9':  
               arabicNumebr = arabicNumebr.Replace('9', 'Ù©');  
               break;  
           }  
         }  
         return arabicNumebr;  
       }  
       catch  
       {  
         return englishNumber;  
       }  
     }  

now with the registering, using and screen shots of the rendered control

Registering the control through web.config file

 <add tagPrefix="uc1" namespace="CustomControls" assembly="CustomControls" />  

Localized English version (AP-PM 12 hour-format)

 <dev:TimePicker runat="server" ID="tpExpectedReturnTime" AMPM="true" IsRequired="true"  
         ValidationGroup="LeaveForm" TabIndex="10" meta:resourcekey="tpExpectedReturnTimeResource" />  

Localized English Version (24 hour-format)

 <dev:TimePicker runat="server" ID="tpLeaveTime" AMPM="false" IsRequired="true" ValidationGroup="LeaveForm"  
         TabIndex="9" meta:resourcekey="tpLeaveTimeResource" />  

Localized Arabic Sample (AP-PM 12 hour-format)


Note: Newly added method "Reset" that will reset time control (all drop down lists)

Finally i hope for all good luck and i wish that article helpful

Note: you can find the complete source code here that is called "CustomControls.zip"

Wednesday, August 31, 2011

Very Simple and Easy to Apply jQuery Tabs

I hope for all perfect mode with jQuery magic so this post will be very light and interesting for jQuery beginners to apply, "so this post mainly for training purpose and at the end of post you will find the plugin itself to make every thing tabs with few changes"

all what you want three anchor elements and three div elements with the following structure and styles

1- HTML Source

 <div id="tabs">  
     <a href="javascript:void(0);" class="tab selected">  
       First Tab  
     </a>  
     <a href="div02" class="tab">  
       Second Tab  
     </a>  
     <a href="div03" class="tab">  
       Third Tab  
     </a>  
   </div>    
   <div id="div01" class="tabdiv">  
     <b>First Tab </b>  
   </div>  
   <div id="div02" class="tabdiv" style="display: none;">  
     <b>Second Tab </b>  
   </div>  
   <div id="div03" class="tabdiv" style="display: none;">  
     <b>Third Tab</b>  
   </div>  

2- Script Source

 <script type="text/javascript">  
     $(document).ready(function () {  
       // declare an temporary variable for href value 'by default the first tab is selected'  
       var tempHref = 'div01';  
       $('a.tab').click(function () {  
         if ($(this).hasClass('selected'))  
           return;  
         // re-assign the href value for the anchor element that had 'selected' class  
         $('a.selected').attr('href', tempHref);  
         $('a.selected').removeClass('selected');  
         // we will save the clicked anchor element href value // the id of the crossponding div  
         tempHref = $(this).attr('href');  
         $(this).attr('href', 'javascript:void(0);');  
         $(this).addClass('selected');  
         // hide all div  
         $('div.tabdiv').hide();  
         $('#' + tempHref).show();  
       });  
     });  
   </script>

3- CSS Source

 .tab:link, .tab:visited, .tab:hover  
 {  
   width: 100px; /* width can be auto*/  
   height: 25px;  
   text-align: center;  
   color: Gray;  
   background-color: White;  
   border: 1px solid Gray;  
   text-decoration: none;  
   margin: 3px 3px 3px 0px;  
   padding: 3px;  
 }  
 .selected:link, .selected:visited, .selected:hover  
 {  
   color: Gray;  
   font-size: 15px;  
   font-weight: bold;  
   border-bottom: 0;  
   padding: 3px 3px 1px 3px;  
 }  
 .tabdiv  
 {  
   width: 500px; /* width can be auto*/  
   height: 250px;  
   border: 1px solid Gray;  
   float: left; /* for english and for arabic it should be right floated */  
   text-align: left; /* for english and for arabic it should be right aligned */  
   padding: 5px;  
 }  

New Added Plugin for Any Thing Tabs

to apply the new plugin just do the following
  • Add reference for the plugin "you can get it from Tabs-1.0.js"
  • Replace the Script Source with the following script

 <script type="text/javascript">  
     $(document).ready(function () {  
       $('a.tab').tabs({  
         defaultTabID: 'div01',  
         tabClass: 'tabdiv',  
         selectedClass: 'selected'  
       });  
     });  
   </script>  

  • defaultTabID: is the default tab that should be selected at first
  • tabClass: is the common class for each corresponding div elements
  • selectedClass: is the class to be assigned by the plugin to the selected tab
Have fun and you can get a complete sample here

Note: Styles may be not standard with all versions of all browser so you can customize them as you want

Sunday, June 12, 2011

Customizing Simple jQuery Tree View (Multi-Level) to add accordion effect to first level

Firstly you should show the original Simple jQuery Tree site jQuery Simple TreeView Plugin

after you briefly review the options for the plugin as

  1. open:  "&#9660;", // HTML string to display for the opened handle
  2. close: "&#9658;", // HTML string to display for the closed handle
  3. slide: false, // Boolean flag to indicate if node should slide open/close
  4. speed: 'normal', // Speed of the slide. Can be a string: 'slow', 'fast', or a number of milliseconds: 1000
  5. collapsed: false, // Boolean to indicate if the tree should be collapsed on build
  6. collapse: null, // A node to collapse on build. Can be a string with indexes: '0.1.2' or a jQuery ul: $("#tree ul:eq(1)")
  7. expand: null // A node to expand on build. Can be a string with indexes: '0.1.2' or a jQuery ul: $("#tree ul:eq(1)")
and basic installation as


    $(document).ready(function() {
         $("ul#sitemap").simpletreeview();
    });


now we will describe the customized method that will add accordion effect to the first level of the tree


  1. function toggle($ul, method, callback)
  2.     // this method customized by Ahmed Gouda to support accordion effect
  3.     // only for first level and also highlighting anchor elements
  4.     // Set callback to empty function if undefined
  5.     if (callback === undefined) callback = function() { };
  6.     var $handle = $ul.parent("li").children("span.handle");
  7.     var $anchor = $ul.parent("li").children("a");
  8.     if ($ul.is(':hidden') && $ul.hasClass('SecondLevelUL')) {
  9.         $('ul.SecondLevelUL').each(function(){
  10.         $(this).parent("li").children("span.handle").html(settings.close);
  11.           $(this).parent("li").children("a").css('font-weight', 'normal');
  12.             $(this).slideUp(settings.speed, callback);
  13.         });
  14.        }
  15.     if (method == "open") {
  16.         $handle.html(settings.open);
  17.         $anchor.css('font-weight', 'bold');
  18.         if (settings.slide) { $ul.slideDown(settings.speed, callback); }
  19.         else { $ul.show(); callback(); }
  20.     }
  21.     else if (method == "close") {
  22.         $handle.html(settings.close);
  23.         $anchor.css('font-weight', 'normal');
  24.         if (settings.slide) { $ul.slideUp(settings.speed, callback); }
  25.         else { $ul.hide(); callback(); }
  26.     }
  27.     else {
  28.         $handle.html($ul.is(':hidden') ? settings.open : settings.close);
  29.         if ($ul.is(':hidden'))
  30.             $anchor.css('font-weight', 'bold');
  31.         else
  32.             $anchor.css('font-weight', 'normal');
  33.         if (settings.slide) { $ul.slideToggle(settings.speed, callback); }
  34.         else { $ul.toggle(); callback(); }
  35.     }
  36. }
and here the sample implementation

  1. <script type="text/javascript">
  2.     $(document).ready(function() {
  3.         var sitemap = $("#sitemap").simpletreeview({
  4.             open: '<span style="color: #900;">&darr;</span>',
  5.             close: '<span style="color: #090;">&rarr;</span>',
  6.             slide: true,
  7.             speed: 'fast',
  8.             collapsed: true,
  9.             expand: '0'
  10.         });
  11.         $('a.expand').click(function() {
  12.             sitemap.expand($(this).attr('rel'));
  13.         });
  14.         $('a.collapse').click(function() {
  15.             sitemap.collapse($(this).attr('rel'));
  16.         });
  17.     });                      
  18. </script>
and you can find complete sample from here



keep commenting.