Thursday, December 23, 2010

Hooking into ASP Client Side Validation

The Problem: The ASP Validators are hard to style. The Validators only render a <span> with the error information. What if you want to display the complete div around the control to be red when an error occures? This is likely not possible with the standard asp validators.

What you can do is o write a decorator in javascript. The function which displays the errormessages is the "ValidatorUpdateDisplay" method.


1:  /**  
2:   * @requires JQuery 1.4.x  
3:   */  
4:  var Biggy = {};  
5:    
6:  Biggy.Validator = {  
7:   /**  
8:   * Decorator for the ms validator update function  
9:   *  
10:   * @param {orig_fn} Function  
11:   * The function to decorate  
12:   * @return Function  
13:   * The decorated fucntion  
14:   */  
15:   UpdateDisplayDecorator : function(orig_fn) {  
16:    return function(){  
17:   var originalfunc = orig_fn.apply(this, arguments);  
18:   Biggy.Validator.UpdateParentDisplay( arguments[0] );  
19:   return originalfunc;  
20:    };  
21:   },  
22:    
23:   /**  
24:   * This method is used to update the class of parent dom elements  
25:   * when the validator function raised an error  
26:   *  
27:   * @param {val} Object  
28:   * The DOM <span> object created by the validator  
29:   */  
30:   UpdateParentDisplay : function( val ) {   
31:   if (!val.isvalid){  
32:    $(val).css("visibility", "visible").show().parent().show();  
33:   }else{  
34:    $(val).css("visibility", "hidden").hide().parent().hide();  
35:   }  
36:     
37:   }  
38:  }  
39:    
40:  // Create decorated function  
41:  ValidatorUpdateDisplay = Biggy.Validator.UpdateDisplayDecorator(ValidatorUpdateDisplay);  

Now every time a validator shows a error message the "UpdateParentDisplay" function will also be called. Within this function you get the dom object of the validator as parameter and can now do anything you want.

Sunday, November 28, 2010

SharePoint 2010 Timer Job UpdateProgress

SharePoint 2010 has updated some of its timer job features (see http://pathikhrawal.wordpress.com/2010/08/21/enhancement-in-timer-jobs-in-sharepoint-2010/). Now SPJobDefinition offers an UpdateProgress Method, to show the status of the timer job in a status bar.


UpdateProgress
To check the status of a timer job go to "Central Administration > Monitoring > Check Job Status".

Check Job Status link in the CA


The following code snipplet  is an example of how you could use this method. The job reads a rss feed and uploads some pdf files into a document library. The progress bar is updated by each uploaded file. The snipplet is not complete, because of copyright. I commented out some regions but you can see how you could use the updateprogress function.





public class PressListTimerJob : SPJobDefinition
{
  /// <summary>
  /// We must persist the to have in the execute function
  /// </summary>
  [Persisted]
  private String mRootSiteUrl = String.Empty;        




  public PressListTimerJob() : base() { }


  public PressListTimerJob(string jobName, SPWebApplication webApp, string featureName)
: base(jobName, webApp, null, SPJobLockType.Job)
  {
  using (SPSite rootSite = webApp.Sites[0])
  {
mRootSiteUrl = rootSite.Url;
  }
  }


  public override void Execute(Guid targetInstanceId)
  {            
LoadData();
  }


  private void LoadData()
  {
try
  {
      SaveData();
  }
  catch (Exception ex)
  {
// LOG Exception ...
  }
  }


/// <summary>
/// Writes the data into the SharePoint list
/// </summary>
/// <param name="data">The data to write into the list</param>
  private void SaveData()
  {
  try
  {
  // GET SITE & WEB
using (SPSite site = new SPSite(mRootSiteUrl))
{
using (SPWeb web = site.OpenWeb())
{
// Get list                        
SPFolder pressList = web.Folders[mListName];
Boolean allowupdate = web.AllowUnsafeUpdates;
web.AllowUnsafeUpdates = true;                                               
// Get Rss Items
XmlNodeList items = mData.SelectNodes("//item");
WebClient client = new WebClient();


// Create proxy if needed
if (!String.IsNullOrEmpty(mProxyUrl))
client.Proxy = new WebProxy(mProxyUrl);


#region >> Upload files into library                       


int itemCount = items.Count;
int itemCountPercent = itemCount / 100;


if (itemCount > 0)
{
int itemsUploded = 0;
foreach (XmlNode item in items)
{                               
// Get link
if (!String.IsNullOrEmpty(link))
{
// Download pdf file

// If pdf has content upload to library
if (pdfFile.Length > 0)
{
// Upload file
++itemsUploded;
this.UpdateProgress(itemCountPercent * itemsUploded);
}
}
  }
          }
web.AllowUnsafeUpdates = allowupdate;                        
  }
  }
  }
   catch (Exception ex)
  {
  // Log Exceptions
  }
  }
}

Monday, November 15, 2010

Play a video from a asset library in SharePoint with the built-in Silverlight Media Player

The Problem:
You want to place a link into your SharePoint site which opens the Silverlight player in a lightbox and plays a video from a asset library.

Solution:

1) Place the link within an other HTML element like a div, li or span and give this element an id. The link can be somewhere in this container, also in a deeper level

- the link to the video must be serverrelative
- the link can have a title. This can be used as Video title

<div id="mediaplayer">
   <a href="/site/listname/myvideo.wmv">Video</a>
 ..
 ..
</div>


Video link




2.) Place a script tag for the mediaplayer library and a custom script tag for our custom js. You must place it after or in the onload event, because when you use getElementById the element must exist in the DOM.


<div id="mediaplayer">
   <a href="/site/listname/myvideo.wmv">Open Video</a>
 ..
 ..
</div>
<script type="text/javascript" src="/_layouts/mediaplayer.js"></script>
<script type="text/javascript">
  _spBodyOnLoadFunctionNames.push('mediaPlayer.createOverlayPlayer');
  mediaPlayer.attachToMediaLinks( document.getElementById('mediaplayer'), ['wmv', 'avi', 'mp3']);  
</script>


Silverlight player



The "spBodyOnLoadFunctionNames.push('mediaPlayer.createOverlayPlayer'); " creates the overlay

The methode "mediaPlayer.attachToMediaLinks " needs 4 arguments.
(1) The DOM object which surrounds the links
(2) The extensions to pay attention to. It searches the <a> Tag for this extensions
(3) templateSource. A Template for the player
(4) Use Title. When true the title attribute of the a tag is used as player title


Update 17.02.2011: Modifications for Firefox
A reader has commented that the code above does not function in Firefox, and was right.
So I opened the assest library in Firefox and tried to play the video there. No chance.

After digging deeper into the code of the mediaplayer.js I think now that the problems occurs between the communication of Silverlight and JavaScript, but not sure when. When Silverlight Objects are initialized they create a Wrapper Object for their object DOM Nodes. In MediaPlayer.js the HTML for the object Tag is created automatically by the createMediaPlayer function. Firefox could not always create these DOM Wrappers (but sometimes??) when the object tag is created automatically. So the easiest way to create the player in Firefox is to add the object tag manually:

<div id="mediaplayer">
  <a href="/site/listname/myvideo.wmv">Open Video</a>
...
</div>
<div>  
      <object height="1" width="1" id="Silverlight_Shared_MediaPlayer" data="data:application/x-silverlight," type="application/x-silverlight" style="position: fixed; top: 0pt; left: 0pt; z-index: 50;">  
           <param value="#80808080" name="background">  
           <param value="true" name="enableHtmlAccess">  
           <param value="/_layouts/clientbin/mediaplayer.xap" name="source">  
           <param value="isOverlayPlayer=true" name="initParams">  
           <param value="true" name="windowless">  
      </object>  
 </div>  
 <script type="text/javascript" src="/_layouts/MediaPlayer.js"></script>       
 <script type="text/javascript">  
      mediaPlayer.attachToMediaLinks(document.getElementById('mediaplayer'), ['wmv', 'avi', 'mp3']);  
 </script>  

Friday, November 5, 2010

Setting the default page layout in onet.xml (SharePoint 2010)

In SharePoint 2010 you have the option to choose a default page layout when you create a page.

Setting the default page
When you create a new page, a dialog pops up where you enter the name of the site.



You can configure your onet.xml and define the default page by the defaultpagelayout property in the publishing feature.



Or you can set it programmatically as described in SharePoint Blues.

There are also several other properties offered by the Publishing feature you can set:

  • ChromeMasterUrl
  • WelcomePageUrl
  • PagesListUrl
  • AvailableWebTemplates
  • AvailablePageLayouts
  • NewPageUrlToken
  • AlternateCssUrl
  • SimplePublishing
  • VersioningOnPages / Documents / Images
  • EnableModerationOnPages / Documents / Images
  • EnableApprovalWorkflowOnPages / Documents / Images
  • RequireCheckoutOnPages / Documents / Images
  • EnableSchedulingOnPages /Documents / Images
  • AllowSpacesInNewPageName

Each property needs a different value. You can find a good listing of the properties and values to use on blog post of Carsten Keutmann.

If SimplePublishing is set to false, all the properties concerning versioning, moderation, workflowapproval, checkout and scheduling are set to true. Otherwise all are set to false. But you can override them when you use p.e. "SimplePublishing" = true and set VersioningOnDocuments = true;

Interesting is also the new "AllowSpacesInNewPageName" property. It does what he says. If set to false, the checkbox for "Convert spaces to '-' " in the site property settings is checked and spaces are converted to '-'.

Convert Spaces to '-'
In code-behind the web property "__AllowSpacesInNewPageName" is set to true.

If the Publishing Feature gets activated, a web property called "__PublishingFeatureActivated" is set to true.

Wednesday, November 3, 2010

ContentTypeBinding Error - Object reference not set to an instance of an object

An error occurred binding content type '0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900...' to list '/ct2/Pages' on web 'http://pilatus/ct2'.  Exception 'Object reference not set to an instance of an object.'.

This exception occures when you try to bind an empty or non-existent content type to a list. An empty content type is a content type with no fields.

Example of an empty content type.
<ContentType ID="0x010100C568DB52D9D0A14.."   
  Name="Basic Page"
  Group="Custom.Pages"
  Description="Basic Page">
     <!-- here must be some fields -->
    <DocumentTemplate TargetName="/_layouts/CreatePage.aspx" />  </ContentType>

Tuesday, November 2, 2010

MatchPoint Condition - Show only data from last months

If you have a MatchPoint Composite oder DataGrid WebPart and you want to show data from a list which is from current month, from the last months or coming months you can use following condition(s). The field you check should be DateTime field.

MP Configuration

The condition checks if the content of the Date field is lower than the 1st of the current month. If you want the last day of the month, you can use AddMonth(1).AddDays(-1)

How to hide the SharePoint Ribbon in Non-Edit Mode

If you’ve ever developed a page for SharePoint 2007 you certainly used the EditModePanel control to control content visibility. This control now has changed in SP 2010 and ignores the Page Editmode. But there is a possibility to do this with no custom code.


  1.  Locate the position of the class "s4-ribbonrow" and add a display style. (Or overwrite the class in your css). This will hide the panel in DisplayMode.
    <div class="s4-pr s4-ribbonrowhidetitle" id="s4-ribbonrow" style="display: none;">

  2. Add following code after the ribbon div. This will show the ribbon in EditMode.
    <publishingwebcontrols:authoringcontainer displayaudience="AuthorsOnly" runat="server"><publishingwebcontrols:editmodepanel pagedisplaymode="Edit" runat="server"><script type="text/javascript">  document.getElementById("s4-ribbonrow").style.display = "block";</script></publishingwebcontrols:editmodepanel></publishingwebcontrols:authoringcontainer>


Publishing WebControls must be the namespace "Microsoft.SharePoint.Publishing.WebControls".


Further Links

Wednesday, October 20, 2010

Check if a SharePoint page is in edit mode

Everyone who ever created a MasterPage for SharePoint certainly used the EditModePanel control, to show some controls only in "edit" mode. I use the EditModePanel control to load some javascript and css when the page is in edit mode. This is useful when I want to correct webparts, which are to small a.s.o.


<PublishingWebControls:EditModePanel runat="server" id="EditModePanelJSNone">
<script type="text/javascript">
/* <![CDATA[ */
   Editmode = true;
/* ]]> */
</script>
</PublishingWebControls:EditModePanel>


Now I realized that this control doesn't function when it is used with personalized pages. A personalized page saves a snapshot of the page either in edit or display mode.

So I had to check per javascript if a page is in edit mode. Since each of my pages have a webpart zone and a webpartzone has a edit banner in edit mode, I check if this banner exists, by searching after a image that only exits in webpart edit banner.

In the js code below, I check if the page is in edit mode, cut all webpart titles and load an additional stylesheet. A global variable "EditMode" is set so that other methods can use it. I'm using jquery 1.4.

Starting point is the NA.Init function which is a self-executing one. It starts when th js file is loaded and calls the $(document).ready() function, which then calls the NA.cutWebPartTitle function.

/**
 * @namespace The namespace.
 */
var NA = NA || {};


/* 
 * Starting method. This method is started directly when the
 * page is loaded.
 */
NA.Init = function(window, document){


$(window).load( function() {
// Call the _spBodyOnLoadWrapper of SharePoint
// If you remove this, the asp menu does not function
if (typeof(_spBodyOnLoadWrapper) != 'undefined') {
_spBodyOnLoadWrapper();
}
});

$(document).ready( function() {
var $ctx = $("#na-content");
NA.cutWebPartTitle($ctx);
});
}(this, this.document);




/**
 * Cuts the title of webparts in edit mode.
 *
 * @static
 * @namespace NA
 */
NA.cutWebPartTitle = function($ctx){

if (typeof EditMode == "undefined"){
EditMode = false;
$('img', $ctx).each(function(){
if ($(this).attr('src') == '/_layouts/images/wpqaicon.gif'){
EditMode = true;
return;
}
});
}

if (EditMode === true){
                // cut webpart titles to 3
$("h3.ms-WPTitle", "#mgb-content").each( function() {
var objSpan = $(this).find("span:first");
var strTitle = objSpan.text();
objSpan.text( strTitle.substr(0,3) + "..");
});
                // load stylesheet
$.get('/_layouts/MyProject.SharePoint/css/na-edit.css', function(cssStyle) {
$('body').append('<style type="text/css">' + cssStyle + '</style>');
        });
}
}; 

Tuesday, October 5, 2010

JediScript - Objektorientiertes JavaScript

Ich arbeite momentan an einem Whitepaper, in der ich meine Erkenntnisse mit objektorientierten JavaScript zusammenfasse. Es ist eine Zusammenfassung von den grundlegenden Prinzipien bis hinzu Konzepten in produktiven Umgebungen.

Heute stelle ich eine Vorschau von 20 Seiten zur Verfügung. In meiner freien zeit versuche ich das Dokument zu vervollständigen.

Inhalt in diesen 20 Seiten sind:

  • Einleitung
  • Wieso OO
  • Typen in JS
  • Michale JSON - Who is it
  • Unterschied defined & null
  • Funky functions
  • Die magischen Klammern
  • Do you know what this is?
  • delete
  • private und public Properties
  • Namespaces
  • Die Var-polizei
  • Closures

Friday, September 17, 2010

Include Javascript and CSS Compression in Visual Studio

For a frontend developer it is a must to compress his javascript and css files, before deploying a website to a productive environment. In this post I'll demonstrate how you can automate this process in Visual Studio.

First of all download the YUI Compressor for .Net. (3.5)

Extract the zip file and copy the to files into a folder in your visual studio solution. I have a folder called "Libraries" for third part dll files.

YUI Dlls


Create a file "MSBuildCompress.xml" in a folder you want. I put this file in my "_Tools" folder.

Custom Compress Msbuild Task


Put the following xml in your newly created xml file.

<?xml version="1.0" encoding="utf-8"?>
<!-- Author Baris Bikmaz -->
<!-- MSBUILD Task to compress css and js files with the yui compressor -->
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
    <UsingTask
        TaskName="CompressorTask"
        AssemblyFile="../Libraries/Yui/Yahoo.Yui.Compressor.dll" />


    <PropertyGroup>
        <CssOutputFile Condition=" '$(CssOutputFile)'=='' ">$(OutputFolder)\css\main.css</CssOutputFile>
<CssDebugFile>$(OutputFolder)\css\main.debug.css</CssDebugFile>
        <JavaScriptOutputFile Condition=" '$(JavaScriptOutputFile)'=='' ">$(OutputFolder)\js\main.js</JavaScriptOutputFile>
    </PropertyGroup>
    
    <Target Name="CompressAndMergeFiles">
        <ItemGroup>
            <JavaScriptFiles Include="$(OutputFolder)\js\*.*" Exclude="$(OutputFolder)\js\main.*js"/>
            <CssFiles Include="$(OutputFolder)\css\*.*" Exclude="$(OutputFolder)\css\main.*css" />
        </ItemGroup>

<Message Text="========== Compressing Css and Js Files in $(OutputFolder) ==========" Importance="high" />

        <CompressorTask
            CssFiles="@(CssFiles)"
            DeleteCssFiles="false"
            CssOutputFile="$(CssOutputFile)"
            CssCompressionType="YuiStockCompression"
            JavaScriptFiles="@(JavaScriptFiles)"
            ObfuscateJavaScript="True"
            PreserveAllSemicolons="False"
            DisableOptimizations="Nope"
            EncodingType="Default"
            DeleteJavaScriptFiles="false"
            LineBreakPosition="-1"
            JavaScriptOutputFile="$(JavaScriptOutputFile)"
            LoggingType="ALittleBit"
            ThreadCulture="en-au"
            IsEvalIgnored="false"
            />

<Message Text="========== Creating debug file ==========" Importance="high" />
<ReadLinesFromFile File="%(CssFiles.Identity)">
<Output TaskParameter="Lines" ItemName="lines"/>
</ReadLinesFromFile>
<WriteLinesToFile File="$(CssDebugFile)" Lines="@(Lines)" Overwrite="true" />
    </Target>
</Project>

1. Check here that the path to the yui library is correct:


<UsingTask TaskName="CompressorTask"
 AssemblyFile="../Libraries/Yui/Yahoo.Yui.Compressor.dll" />

2. The propertygroup defines the files and their location which are generated by the compressor


<PropertyGroup>
 <CssOutputFile Condition=" '$(CssOutputFile)'=='' ">$(OutputFolder)\css\main.css</CssOutputFile>
 <CssDebugFile>$(OutputFolder)\css\main.debug.css</CssDebugFile>
 <JavaScriptOutputFile Condition=" '$(JavaScriptOutputFile)'=='' ">$(OutputFolder)\js\main.js</JavaScriptOutputFile>
</PropertyGroup>


3. The ItemGroup defines the files which should be compressed by the YUI compressor. I exclude all the files which will be generated because all css files, compressed and uncompressed are in the same folder. You can change this if you want.


<ItemGroup>
  <JavaScriptFiles Include="$(OutputFolder)\js\*.*" Exclude="$(OutputFolder)\js\main.*"/>
  <CssFiles Include="$(OutputFolder)\css\*.*" Exclude="$(OutputFolder)\css\main.*" />
</ItemGroup>

4. The CompressorTask does the compression. The files to compress and the the output files are given ase arguments.

<CompressorTask
            CssFiles="@(CssFiles)"
            DeleteCssFiles="false"
            CssOutputFile="$(CssOutputFile)"
            CssCompressionType="YuiStockCompression"
            JavaScriptFiles="@(JavaScriptFiles)"
            ObfuscateJavaScript="True"
            PreserveAllSemicolons="False"
            DisableOptimizations="Nope"
            EncodingType="Default"
            DeleteJavaScriptFiles="false"
            LineBreakPosition="-1"
            JavaScriptOutputFile="$(JavaScriptOutputFile)"
            LoggingType="ALittleBit"
            ThreadCulture="en-au"
            IsEvalIgnored="false"
            />

5. The last step merges the css files and creates a main.debug.css which is not compressed. This is useful in debug enviroments, where the frontend developer want to examine the css with firebug to find the location of a style.

<ReadLinesFromFile File="%(CssFiles.Identity)">
<Output TaskParameter="Lines" ItemName="lines"/>
</ReadLinesFromFile>
<WriteLinesToFile File="$(CssDebugFile)" Lines="@(Lines)" Overwrite="true" />


6.) Now put some css and js in to your css and js folder. When you look at the ItemGroups XML Node you will see that my css and js are under the same folder, like in the image below.


7. Now test the configuration. Open a dos console and type the command:


"c:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" "C:\MyProject\_Tools\MSBuildCompress.xml" /p:OutputFolder="C:\MyProject\MasterTemplate\12\Template\Layouts\MyProject"

The parameter "OutputFolder" is used in the .xml file to define the folder where the css and js folders are. I have following structure in my project. If you have another stucture you have to adapt the xml file.
If the command is successfull, you can copy it. The next step is to put this command into visual studio.

Open the properties of the project that contains the js and css files. Click on build Events and put the following text into the text field (Pre-Build Event)

Pre-build event