There are times when you have a requirement of only selecting “Custom Page layouts” when a user wants to create a new page in Sharepoint Portal site.

I won’t go in details of how to adding and deploying new custom page layouts using feature,  but you can refer here for it :

http://blogs.msdn.com/syedi/archive/2008/08/01/custom-site-definition-for-collaboration-portal-template-sharepoint-2007-wow-moss.aspx
http://spreflections.wordpress.com/2008/09/24/deploy-master-page-and-page-layout-as-a-feature/

Once you have a added a custom page layout, you don’t want the user to pick from any sharepoint built-in page layouts.

To achieve that functionality you can mark those layout types to be hidden on the feature activation code. As all the page layouts are item in a list which is source controlled via sharepoint you will need to check out the file and then only update the “Hidden Page” attribute.

here is how you can ahcieve it.


using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["Master Page Gallery"];
foreach (SPListItem item in list.Items)
{
//Note that if your page layout's content type needs to be different
if (item["Associated Content Type"] != null && (item["Associated Content Type"].ToString().IndexOf("Article Page") != -1
|| item["Associated Content Type"].ToString().IndexOf("Welcome") != -1))
{
item.File.CheckOut();
item["Hidden Page"] = "True";
item.Update();
item.File.CheckIn("");
}
}
list.Update();
web.Update();
}

now when the feature is activated, user will only be able to see custom page layouts.

Good luck!

SWFUpload is a very handy tool, if you had to upload multiple files. More info on SWFUpload and implementation details can be found at http://www.swfupload.org/

With SWFUPload once the file is uploaded there is no actual implementation (i have come across ) to delete file once uploaded. I have implemented this using asp.net, but it wont be hard to convert that to different web technologies. In this implementation i have used jquery (http://jquery.com/) to handle delete file-function.

Some of the files are modified  for demostration purpose. You can enhance it accordingly. In this example i havn’t created any custom control to keep things simple, but there are many implementation of SWFUPload as asp.net custom control.

19-02-2009-11-11-561

(fileprogress.js)

19-02-2009-11-02-081

The logic is quite simple to delete the files. Once the files are uploaded setComplete function is invoked & in that, we will need to attach a DIV & an anchor tag for delete link.

(deletefile.ashx)

19-02-2009-11-09-061

Attached are all the zip files created in VS.NET 2008.

  • Handler.ashx is for uploading & checking if file exists
  • deletefile.ashx for file deletion
  • fileprogress.js modified for attaching deletion event
  • handlers.js modifed for checking server response on file exists
  • swfupload.js modified (FILE_ALREADY_EXISTS             : 300)
  • swfupload.queue.js  not modified.

(default.aspx)

19-02-2009-11-18-131

Download source code here

Hello…

Recently i have been told to display our firm’s time entry in sharepointy calendar view.. First of all it sounded very interesting & still it is :)

It nearly took me an hour to get a hang of  SPCalendarView control provided by ms (thanks to http://www.tonstegeman.com/Blog/Lists/Posts/Post.aspx?ID=60). My main challenge was not to display data out for Sharepoint list, but integrate it with one of our core systems.  With SPCalendarView & SPCalendarItem its very easy to display data in a webpart format, but the problem happens, if you intend to use javascript in DisplayFormURL.

It will show you an error :

You must specify a server relative URL at Microsoft.SharePoint.WebControls.SPCalendarItem.set_DisplayFormUrl(String value)

Googled for an hour but with no luck. So i tried to modified the Generated HTML of the Calendar View and hurray it worked!!!. Look at the Render function below which has all the modification. I haven’t use SPCalendarItem’s item.ItemID property, but you can customize it for your purpose.

When the Webpart is getting rendered, i replaced “/replace?ID” with my javascript string. You will also need to replace  — ONCLICK=”GoToLink(this);return false; with a blank string. This will prevent displaying the message “Invalid URL”

Look at the status bar in below mentioned images!.

original1

modified1

If you had to open a new window (which i had to), when the user clicks on a particular item you can achieve it using the following lines.

//while adding a new item, you can improve the logic here, but this was just for testing.
item.DisplayFormUrl = "/replace/window.open("+ Page.Server.UrlEncode("'") + "item.aspx?time_uno=" + row["id"].ToString();

//when the rendering happens!

StringWriter textWriter = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(textWriter);
calView.RenderControl(htmlWriter);
string replaced = htmlWriter.InnerWriter.ToString();
replaced =Page.Server.UrlDecode(replaced);
replaced = replaced.Replace("/replace/", "javascript:");
replaced = replaced.Replace("?ID=", "');");
replaced = replaced.Replace("ONCLICK=\"GoToLink(this);return false;\" target=\"_self\"", "");
replaced = replaced.Replace("onfocus=\"OnLink(this)\"","");
writer.Write(replaced);

So here it goes

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebControls;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using System.Data;
using System.IO;

namespace TimeEntry
{
[Guid("a4e02451-4738-4adf-ab8f-36a27d81c813")]
public class TEViewer : Microsoft.SharePoint.WebPartPages.WebPart
{
/// <summary>
/// Create all your controls here for rendering.
/// Try to avoid using the RenderWebPart() method.
/// </summary>
protected override void CreateChildControls()
{
base.CreateChildControls();

try
{
AddCalendar();
}

catch (Exception ex)
{
Controls.Add(new LiteralControl("<b>Error</b> "));
Controls.Add(new LiteralControl(ex.ToString()));
}
}

private SPCalendarItemCollection GetTimeEntry()
{
SPCalendarItemCollection items = new SPCalendarItemCollection();

Ds = //Your Dataset...
DateTime currentdatetime = DateTime.Now;
foreach (DataRow row in Ds.Tables[0].Rows)
{
SPCalendarItem item = new SPCalendarItem();
//item.ItemID = row["id"].ToString();

item.StartDate = row["StartDate"];
item.EndDate = row["EndDate"];

item.hasEndDate = true;
item.DisplayFormUrl = "/replace";

item.Title = row["Title"]ToString() ;
item.IsAllDayEvent = false;
item.IsRecurrence = false;
item.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
items.Add(item);
}
return items;
}

protected override void Render(HtmlTextWriter writer)
{
StringWriter textWriter = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(textWriter);
calView.RenderControl(htmlWriter);

string replaced = htmlWriter.InnerWriter.ToString().Replace("/replace?ID=", "javascript:alert('Sharepoint hacked!');");
replaced = replaced.Replace("ONCLICK="GoToLink(this);return false;"", "");
writer.Write(replaced);
}

SPCalendarView calView;
private void AddCalendar()
{

calView = new SPCalendarView();
calView.ViewType = GetCalendarType(Page.Request["CalendarPeriod"]);
calView.DataSource = GetTimeEntry();
calView.DataBind();
Controls.Add(calView);

}

private static string GetCalendarType(string type)
{
if (type == null)
type = string.Empty;
switch (type.ToLower())
{
case "day":
return "day";
case "week":
return "week";
case "timeline":
return "timeline";
default:
return "month";
}
}
/// <summary>
/// Ensures that the CreateChildControls() is called before events.
/// Use CreateChildControls() to create your controls.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
if (!_error)
{
try
{
base.OnLoad(e);
this.EnsureChildControls();
// Your code here...
}
catch (Exception ex)
{
HandleException(ex);
}
}
}

/// <summary>
/// Clear all child controls and add an error message for display.
/// </summary>
/// <param name="ex"></param>
private void HandleException(Exception ex)
{
this._error = true;
this.Controls.Clear();
this.Controls.Add(new LiteralControl(ex.Message));
}
}
}