📜 ⬆️ ⬇️

Coloring Calendar List

Introduction


Recently, there was a task to make a colorized by the value of the field in the list of the calendar.
At the same time, the task was a little complicated by the fact that it was necessary not only to color the sheet, but also to apply different styles to the blocks on the calendar.



Implementation


The first thought was to try to paint from the object model.
but ... as it turned out, only the elements displayed on the monthly calendar are able to be painted 0_0
By the way, these elements have one more feature, it will be described in more detail below.
')
To begin with, a WebPart was created to display the legend.

public class StyledCalendar : System.Web.UI.WebControls.WebParts.WebPart
{

#region [ Properties ]

[Personalizable, Browsable( false )]
public string FieldID
{
get ;
set ;
}

[Personalizable, Browsable( false )]
public string ListID
{
get ;
set ;
}

[Personalizable, Browsable( false )]
public List <ItemData> Colored
{
get ;
set ;http://habrahabr.ru/edit/topic/60813/#
}

#endregion
// .............
}

* This source code was highlighted with Source Code Highlighter .


To it was created a class to ensure the selection of a list for coloring,

image

[ Serializable ]
public class ItemData
{
public string CSS { get ; set ;}
public string JavaScript { get ; set ; }
public string ItemGUID { get ; set ; }
public string ItemText { get ; set ; }
}

public class StyledCalendarEditorPart : EditorPart, IPostBackEventHandler
{
private DropDownList _ddlFields;
private DropDownList _ddlValues;
private DropDownList _ddlCalendars;

//

protected override void CreateChildControls()
{
Panel groupPanel = new Panel();
_ddlFields = new DropDownList();
_ddlValues = new DropDownList();
_ddlCalendars = new DropDownList();

_txtStyleName = new TextBox();
_txtStyleName.ID = "txtStyleName" ;

_btnChange = new Button();
_btnChange.Text = "Change Style" ;
_btnChange.OnClientClick = "openStyleWindow()" ;

_ddlValues.Attributes.Add( "onchange" , "onFieldValueChange(this, '" + _txtStyleName.ClientID + "')" );

_ddlCalendars.SelectedIndexChanged += new EventHandler(_ddlCalendars_SelectedIndexChanged);
_ddlCalendars.AutoPostBack = true ;

if (_list != String .Empty )
_ddlCalendars.Text = _list;

_ddlFields.SelectedIndexChanged += new EventHandler(_ddlFields_SelectedIndexChanged);
_ddlFields.AutoPostBack = true ;

if (_field!= String .Empty)
_ddlFields.Text = _field;

groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Calendars on page:<br>" ));
groupPanel.Controls.Add(_ddlCalendars);

groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Choice Fields:<br>" ));
groupPanel.Controls.Add(_ddlFields);

groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Field Value:<br>" ));
groupPanel.Controls.Add(_ddlValues);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add(_btnChange);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Template Preview:<br>" ));

_lbPreview = new Label();
_lbPreview.Text = MakePreview();
groupPanel.Controls.Add(_lbPreview);

groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Style Name:<br>" ));
groupPanel.Controls.Add(_txtStyleName);

this .Controls.Add(groupPanel);
}

//

}

* This source code was highlighted with Source Code Highlighter .


A js file was added to the project, which opened the window

image

The contents of the window - the file SetStyle.aspx put in LAYOUTS

Actually you can go to the organization of coloring.

Empirically (reflector) it was found where the templates for the list come from
TEMPLATES \ CONTROLTEMPLATES \ DefaultTemplates.aspx

In it you can find something like:

< SharePoint:RenderingTemplate ID ="CalendarViewMonthItemMultiDayTemplate" runat ="server" >
< Template >
< div class ="<%# DataBinder.Eval(Container," DivClass "," ")%>" dir ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . Direction "," "))%>" >
< table border ="0" width ="100%" cellspacing = 0 cellpadding = 0 dir ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . Direction "," "))%>" >
< tr >
< td class ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>"
onmouseover ="this.className='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>sel';"
onmouseout ="this.className='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>';"
href ="<%# SPHttpUtility.HtmlUrlAttributeEncode(DataBinder.Eval(Container," DataItem . DisplayFormUrl "," "))%>?ID=<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . ItemID "," "))%>"
ONCLICK ="GoToLink(this);return false;" target ="_self"
>
< a onfocus ="OnLink(this)"
href ="<%# SPHttpUtility.HtmlUrlAttributeEncode(DataBinder.Eval(Container," DataItem . DisplayFormUrl "," "))%>?ID=<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . ItemID "," "))%>"
ONCLICK ="GoToLink(this);return false;" target ="_self"
tabindex =&# 60 ;%# DataBinder . Eval ( Container , "TabIndex" )%&# 62 ;
>
< b > <% # SPHttpUtility.HtmlEncode(DataBinder.Eval(Container, "DataItem.Title" , "{0:G}" )) %> </ b >
</ a >
</ td >
</ tr >
</ table >
</ div >
</ Template >
</ SharePoint:RenderingTemplate >

* This source code was highlighted with Source Code Highlighter .


And so for each type of calendar item.

You do not need to change this file. You can create your own file with any name in the folder CONTROLTEMPLATES. Sharepoint searches for a template by ID, but checks the type of the controller-template, so you cannot inherit from the template itself - it is sealed: ((

Content:

< SharePoint:renderingtemplate id ="CalendarViewWeekItemTemplate" runat ="server" >
< Template >
item'a
</ Template >
</ SharePoint:renderingtemplate >

* This source code was highlighted with Source Code Highlighter .


Initially, there was a thought to add Binding, but apart from the reserved fields, no zl list could be reached :(
Then Templated Control was written, into which a part of the table was inserted.

Unfortunately, the source code of this case did not remain as this mechanism did not work on
items associated with the monthly calendar, in particular on CalendarViewMonthItemMultiDayTemplate

Judging by the debugger when the binding came, almost all the fields of the controller were null.
Everything worked in other controllers 0_o

Then the concept was changed - a new non-template control was made which rigidly generated the html code in the Template, while receiving data from the list via the Sharepoint object model.

As a result, the template code is reduced to:

< SharePoint:renderingtemplate id ="CalendarViewWeekItemTemplate" runat ="server" >
< Template >

< myCompany:MyCompanyCalendarViewDayItemCtrl ID ="myCompanyCalendarViewDayItemCtrl1" runat ="server" >
</ myCompany:MyCompanyCalendarViewDayItemCtrl >


</ Template >
</ SharePoint:renderingtemplate >

* This source code was highlighted with Source Code Highlighter .


Class implementation:

public class RenderItemData
{
public string ItemName { get ; set ; }

public string ItemStyle { get ; set ; }
public string ItemDisplayFormUrl { get ; set ; }
public string ItemId { get ; set ; }
public string ItemTitle { get ; set ; }

public string ItemDefaultBackground { get ; set ; }
public string ItemDirection { get ; set ; }

}

[ToolboxData( "<{0}:MyCompanyCalendarViewMonthItemCtrl runat=server></{0}:MyCompanyCalendarViewMonthItemCtrl>" )]
public class MyCompanyCalendarView : WebControl
{

public static Dictionary< string , RenderItemData> _dict;

RenderItemData _item;
private string _dispType;

[Bindable( true )]
[Category( "Appearance" )]
[Localizable( true )]
protected string DisplayType
{
get
{
return _dispType;
}
set
{
_dispType = value ;
}
}

public MyCompanyCalendarView()
{
if (_dict == null )
{
_dict = new Dictionary< string , RenderItemData>();
}

}

protected override void OnLoad( EventArgs e)
{

WebPartManager wp = WebPartManager.GetCurrentWebPartManager( this . Page );

StyledCalendar cal = null ;

foreach (WebPart part in wp.WebParts)
{
cal = part as StyledCalendar;
if (cal != null )
{
break ;
}
}

if (cal == null )
{
return ;
}

SPCalendarItem calItem = (SPCalendarItem)((Microsoft.SharePoint.WebControls.SPCalendarItemContainer)( this .Parent)).DataItem;

_item = new RenderItemData();

_item.ItemTitle = calItem.Title;
_item.ItemId = calItem.ItemID;
_item.ItemDisplayFormUrl = calItem.DisplayFormUrl;
_item.ItemDefaultBackground = calItem.BackgroundColorClassName;
_item.ItemDirection = calItem.Direction;

using (SPWeb web = SPContext.Current.Web)
{
SPList list = web.Lists[ new Guid (cal.ListID)];

string fieldValue = String .Empty;
string [] recId = calItem.ItemID.Split( new char [] { '.' });

foreach (SPListItem listItem in list.Items)
{
if (recId.Length > 1)
{
if (listItem.ID.ToString() == recId[0])
{
fieldValue = listItem[ new Guid (cal.FieldID)].ToString();
break ;
}
}
else
if (listItem.ID.ToString() == calItem.ItemID)
{
fieldValue = listItem[ new Guid (cal.FieldID)].ToString();
break ;
}

}

_item.ItemName = fieldValue;

foreach (ItemData data in cal.Colored)
{
if (data.ItemText == _item.ItemName)
{
_item.ItemStyle = data.CSS;
}

}

// Item - .

if (_dict.ContainsKey(calItem.DisplayFormUrl + _item.ItemId.ToString()))
{
_dict.Remove(calItem.DisplayFormUrl + _item.ItemId.ToString());
}

_dict.Add(calItem.DisplayFormUrl + _item.ItemId.ToString(), _item);

}

base .OnLoad(e);
}

// Item'
// - , ,
protected virtual string GetInnerTemplate(RenderItemData renderData, SPCalendarItem calendarItem, SPCalendarItemContainer container)
{
StringBuilder sb = new StringBuilder ();
string background = calendarItem.BackgroundColorClassName;
string bgsel = calendarItem.BackgroundColorClassName + "sel" ;

if (renderData != null && String .IsNullOrEmpty(renderData.ItemStyle) == false )
{
background += "_m" ;
bgsel += "_m" ;

}

sb.AppendFormat( "<td class='{0}'" , background);
sb.AppendFormat( "onmouseover=\"this.className='{0}';\"" , bgsel);
sb.AppendFormat( "onmouseout=\"this.className='{0}';\"" , background);
sb.AppendFormat( "href='{0}?ID={1}'" , calendarItem.DisplayFormUrl, calendarItem.ItemID);
sb.AppendFormat( "ONCLICK='GoToLink(this);return false;' target='_self'" );
sb.AppendFormat( ">" );
sb.AppendFormat( "<a onfocus='OnLink(this)'" );

if (renderData != null && ! String .IsNullOrEmpty(renderData.ItemStyle))
{
sb.AppendFormat( " {0} " , renderData.ItemStyle);
}

sb.AppendFormat( "href='{0}?ID={1}'" , calendarItem.DisplayFormUrl, calendarItem.ItemID);
sb.AppendFormat( "ONCLICK='GoToLink(this);return false;' target='_self'" );
sb.AppendFormat( "tabindex={0}" , container.TabIndex);
sb.AppendFormat( ">" );
sb.AppendFormat( "<b>{0:G}</b>" , calendarItem.Title);
sb.AppendFormat( "</a>" );
sb.AppendFormat( "</td>" );

return sb.ToString();
}



protected override void Render(HtmlTextWriter writer)
{
CreateChildControls();

SPCalendarItemContainer cont = Parent as SPCalendarItemContainer;
SPCalendarItem item = cont.DataItem as SPCalendarItem;
RenderItemData renderData = null ;
_dict.TryGetValue(item.DisplayFormUrl + item.ItemID, out renderData);


string background = item.BackgroundColorClassName;
string bgsel = item.BackgroundColorClassName + "sel" ;
string suffix = String .Empty;

if (renderData != null && String .IsNullOrEmpty(renderData.ItemStyle) == false )
{
suffix = "_m" ;
}

background += suffix;
bgsel += suffix;

StringBuilder sb = new StringBuilder ();

if (renderData != null && ! String .IsNullOrEmpty(renderData.ItemStyle))
{
sb.AppendFormat( "<div {0} dir='{1}'>" , renderData.ItemStyle, item.Direction);
}
else
{
sb.AppendFormat( "<div class='{0}' dir='{1}'>" , cont.DivClass, item.Direction);
}

string tableStyle = "" ;

switch (item.CalendarType)
{
case 0:
String .Format( "class='ms-cal-tdayitem{0}'" , suffix);
break ;
case 1: // Week Item
tableStyle = String .Format( "class='ms-cal-tweekitem{0}'" , suffix);
break ;
case 2:
tableStyle = String .Format( "class='ms-cal-tmonthitem{0}'" , suffix);
break ;
default :
tableStyle = string .Empty;
break ;
}

sb.AppendFormat( "<table border='0' width='100%' cellspacing=0 cellpadding=0 dir='{0}' {1}>" , item.Direction, tableStyle);
sb.AppendFormat( "<tr>" );

sb.Append(GetInnerTemplate(renderData, item, cont));

sb.AppendFormat( "</tr>" );
sb.AppendFormat( "</table>" );
sb.AppendFormat( "</div>" );

writer.Write(sb.ToString());

base .Render(writer);
}

}


* This source code was highlighted with Source Code Highlighter .


In addition, several descendants were inherited for different types of Item.
the descendant controls themselves are inserted into the template.

Depla




What happened in the end:

image

What gives such an approach?



On codeplex there is a project , where a similar calendar is implemented via javascript connection to the page.

Minuses:



What gives such an approach:



This work was carried out jointly with a friend who unfortunately does not have an account on Habré, but very much wants to get into it, I will be grateful for the invite provided to him :)

Thanks for attention!

Source: https://habr.com/ru/post/60813/


All Articles