zaterdag 31 maart 2012

Custom Cancel button, Go Back to the web-page you came from ...

Nice to have against the Close or Save button is a beautifull Cancel button. 
A request of a customer this week was to have a link on there intranet 
to a sharepoint custom new page, but without the Sharepoint header and menu. 

So people could add items in a list, but nothing else more. 

On the page the Sharepoint Close/Cancel button returns automatically back to 
the Sharepoint List. But what the customer wanted was that the requester 
returned back to the page where they came from or, 
if the page was openend in a new window, to close the window.

To do this, replace the Sharepoint Close/Cancel button with our own custum buttom.
add a little script in a content Editor webpart to execute the return function (goback).



<input type="button" value="Cancel" name="CancelButton" class="ms-ButtonHeightWidth" onclick="goback();" />

// in content editor webpart:
function goback() {
    // Jumps back
            //history.back();
            if (history.length >0)
            {
                        history.back();
            }
            else
            {
                        window.close();
            }
}

 

vrijdag 30 maart 2012

Customizing the Search Results Page (XSLT) – Add highlighting


Thanks to Tobias Zimmergren I found out how to add Word Highlighting your Search Result Page.

 
Customizing the Search result page xslt by adding Highlighting

What you have to do is to adapt the XSL code in the XSLT Editor of the Core Search Result 
webpart and locate the the following section (It already exist):


<xsl:template name="Hithightlighting">
 

And since this template exists from the beginning, all you really have to do is to customize 
the style attribute and add a color property of the <b> tag 
(I replaced it with a <strong> tag instead, for sake of standards)

Then you can simply specify the styles for each highlighted word like following:
 <xsl:template match="c0">
 <strong style="color:blue;"><xsl:value-of select="."/></strong>
 </xsl:template>
 

It’s simple as that. I hope this helped some of you to get started 
on some basic Search Core Results XSLT customizations. 


For customizing the result itself you can take also a look 
at the blog of customize the search result using Sharepoint Designer.

dinsdag 27 maart 2012

Full screen width SharePoint Rich Text Editor


It can be frustrating in SharePoint when the "Rich Text Editor" on the edit page 
of Wiki's, Blogs, Edit pages is set to fixed column width by default Sharepoint.  

We get frequently the question to enlarge the width of the editor. This because
it's easier to fill in text in a fullscreen-width editor!
 
Here's the CSS to make it happen (warning, this syntax applies to ALL rich text editors!). 

The first does all normal forms and wikis:

<style> 
#onetIDListForm, #onetIDListForm .ms-formbody, #onetIDListForm iframe[title="Rich Text Editor"]{
 width:100% !important;
}
</style> 
 
And this does the same for Blogs!
<style> 
.ms-formbody span span div iframe, .ms-formbody span span table.ms-long{
 width:100%; text-align:left;
}

</style>
 


You just to need to put the code in a Content Editor Webpart on your page.

I hope that your customers enyoi the full width Rich Text Editors like ours...

zondag 11 maart 2012

How to open a custom page in Modal Sharepoint Popup Window.


Last week we wanted to open a custom made sharepoint page 
in a Modal Sharepoint Popup window. 
But this without enabling the option to open all windows in a modal popup. 

This is easy to do. 
Here is a JavaScript that will allow you to open any page in the modal popupwindow of Sharepoint. 
 

//Handle the DialogCallback callback
function DialogCallback(dialogResult, returnValue){
    window.location = window.location;
}

//Open the Dialog
function OpenEditDialog(link){
    var options = {
        url:URL_TO_YOUR_PAGE + '&IsDlg=1',
        width: 700,
        height: 700,
        dialogReturnValueCallback: DialogCallback};
    SP.UI.ModalDialog.showModalDialog(options);
}
 

Notice that the IsDlg=1 query string parameter is appended 
within the OpenEditDialog function. 
The presence of “IsDlg” dynamically loads the "/_layouts/styles/dlgframe.css” file 
which applies “display:none” to all items using the “s4-notdlg” css class. 
This effectively hides items of this class in a dialog box. 
For example, v4.master uses the “s4-notdlg” class for the Ribbon control 
to hide the ribbon within dialogs.

 

dinsdag 6 maart 2012

Copy, Duplicate or Pre-populate Sharepoint Fields


New demand arrived to duplicate items in a custom list. Out of the box, Sharepoint hasn't provided
that functionality.
So, lets develop it our selfs...

Wat you need to do is to provide a custom link on you existing item that provides a parameter,
for example DID (Duplicate ID). Create a custom newform.aspx where you add a new datawebpart that
takes your parameter as filter. Add the fields that you want to duplicate to your page en put them 
in a table that you set hidden.
Once done, you add a content webpart Editor to your page and some next script to your page : 

_spBodyOnLoadFunctionNames.push('SPCC_Dup_fill_AllDefaultValues()');
ExecuteOrDelayUntilScriptLoaded(SPCC_Dup_fill_TaxonomyValues, "scriptforwebtaggingui.js");

// only change this function...
function SPCC_Dup_fill_AllDefaultValues(){          
 // Pre-populate peoplepicker field
 // fillPeoplePicker (ID of Sharepoint Form PeoplePicker_userfield, Name of Sharepoint Form PeoplePicker_userfield, ID of DIV readonly field)
 SPCC_Dup_fill_PeoplePicker("FIELDID_UserField","FIELDNAME$UserField", "REFERENCE_DIV_ID");
 // Pre-populate text Field
 // fillInputField( ID of Sharepoint Form Text Field, ID of DIV readonly field)
 SPCC_Dup_fill_InputField("FIELDID_TextField","REFERENCE_DIV_ID");
 // Pre-populate Lookup/Select Field
 // Fill_Lookup_Select_FromFieldName(Form FieldName, ID of DIV readonly field, type [Lookup, DropDownChoice ] )
 SPCC_Dup_fill_Lookup_Select_FromFieldName("FIELDID_DropDownChoice","REFERENCE_DIV_ID", 'DropDownChoice');
 // Pre-Populate Hyperlink
 // FillHyperlinkField(Form FieldName Url, Form FieldName Description, ID of DIV readonly field);
    SPCC_Dup_fill_HyperlinkField("FIELDID_UrlFieldUrl","FIELDID_UrlFieldDescription", "REFERENCE_DIV_ID");
 // Pre-Populate CheckBox Yes No
 SPCC_Dup_fill_CheckboxFieldYN("FIELDID_BooleanField", "REFERENCE_DIV_ID");
 // Pre-Populate Date Time field.  
 SPCC_Dup_fill_DateTimeField("FIELDID_DateTimeField_DateTimeFieldDate", "REFERENCE_DIV_ID", "mm/dd/yyyy");
 // Pre-Populate RadioButtonlist
 SPCC_Dup_fill_RadioButtonList("FIELDNAME$RadioButtons", "REFERENCE_DIV_ID");
 // Pre-Populate CheckButtonList
 SPCC_Dup_fill_CheckButtonList("FIELDID","REFERENCE_DIV_ID");
 // Pre-Populate Dropdown
 SPCC_Dup_fill_CustomSelect("FIELDID_DropDownChoice","REFERENCE_DIV_ID");
    // Pre-Populate MultiSelect
 SPCC_Dup_fill_MultiSelect("FIELDID_SelectCandidate", "REFERENCE_DIV_ID");        
    // Pre-Populate MetaDataField
 // see SPCC_Dup_fill_TaxonomyValues function
 // Pre-populate Mutli line text Field
 SPCC_Dup_fill_MultiTextField("FIELDID_TextField_inplacerte","REFERENCE_DIV_ID");
}

function SPCC_Dup_fill_TaxonomyValues(){
 // Pre-Populate MetaDataField
 SPCC_Dup_fill_MetaDataFied("FIELDID_ctl02", "REFERENCE_DIV_ID");
}
 

I have written an function for the different types of Sharepoint Fields... if I have missed one, 
don't hesitate to let me know...

Now the important block, the different functions...

two function I use often to get the Field Objects for manipulating the values or innerHTML methods:
// Direct call for getting the element Object by the ID-property of the element
function SPCC_Dup_getTagFromIdentifier(identifier) {  return document.getElementById(identifier); }
// Call for getting the element Object by the TagName and filter them by identifier or the ID-property
function SPCC_Dup_getTagFromIdentifierAndTitle(tagName, identifier, myid){
 var len = identifier.length;
 var tags = document.getElementsByTagName(tagName);
 for (var i=0; i< tags.length; i++)
 {
  var tempString = tags[i].id;
  if( (tags[i].id == myid) && ( (identifier == '') || (tempString.indexOf(identifier) == tempString.length - len)) )
  { return tags[i]; }
 }
 return null;
} 
 

One of the difficult fields to fill in by script was the PeoplePicker. 
This because when you take al look at the source of the generated Sharepoint HTML,
you see that the field exists of different span, div and input fields. 
Also, in the view state of your element you get HTML tags with a link and 
as display the name of the user that you have to put in the PeoplePicker field. 
So first step is to get only the username. 
Second step is to retrieve the element object of the peoplepicker field 
that ends with _upLevelDiv. 
Third step is to put your username in that DIV and at last but not least 
to validate the user. 

function SPCC_Dup_fill_PeoplePicker(myPeoplePicker_ID, myPeoplePicker_Name, newPP_ID){
// STEP 1: Retreive only username of the view PeoplePicker field
 var ppf = document.getElementById(newPP_ID);
 var myppfValue = ppf.innerHTML;
 var ibegin = myppfValue.indexOf('">') + 2;
 var myppfValueUpperCase = myppfValue.toUpperCase();
 var myPPValue = myppfValue.substr(ibegin, myppfValueUpperCase.indexOf('>/A<', ibegin ) - ibegin);
// STEP 2 : get the PeoplePicker field Object to fill in.
 var myPeoplePicker_UpperLevel_ID = myPeoplePicker_ID + '_upLevelDiv';
 var assingedToInput = SPCC_Dup_getTagFromIdentifier(myPeoplePicker_UpperLevel_ID);
// STEP 3 : put the username in the PeoplePicker Field object 
 assingedToInput.innerHTML = myPPValue ;
// LAST STEP : refresh and validate picker control
 if(!ValidatePickerControl(myPeoplePicker_ID))
 {
    ShowValidationError();
 }
 var arg = getUplevel(myPeoplePicker_ID);
 var ctx = myPeoplePicker_ID;
 EntityEditorSetWaitCursor(ctx);
 WebForm_DoCallback(myPeoplePicker_Name,arg,EntityEditorHandleCheckNameResult,ctx,EntityEditorHandleCheckNameError,true);
}
 

One of the easy ones is the normal InputFields. With this field you only have to read and set the values...
function SPCC_Dup_fill_InputField(SPFF_ID, newTF_ID)
{
 var sptf = document.getElementById(newTF_ID);
 var spff = document.getElementById(SPFF_ID);
 spff.value = sptf.innerHTML;
}
 

An other hard one is the Multiline textfield. I have passed half a day for understanding how 
this field is being generated by Sharepoint !!! Not easy to understand, because you only see a
hidden input field and some DIV's that are empty. 

First step I have done is to remove from the view field the surrounded DIV-tag. 
Afterwards convert it as full HTML format, and at least put it in the sharepoint Element and
call a sharepoint function to validate it. This is needed because otherwise your text is removed again.

function SPCC_Dup_fill_MultiTextField(SPFF_ID, newTF_ID){
// STEP 1 : get the content to fill in and remove the parent DIV-tag
            var sptf = document.getElementById(newTF_ID);
            var convertRTE = sptf.innerHTML;
            var ibegin = convertRTE.indexOf('">') + 5;
            convertRTE= convertRTE.substr(ibegin , convertRTE.indexOf('</div>',ibegin)-ibegin);
// STEP 2 : convert the content to full qualified HTML body format
            convertRTE= convertRTE.replace(/</g, "<");
            convertRTE= convertRTE.replace(/>/g, ">");
// STEP 3 : fill in the you multiline textfield with your bodycontent and validate it.
            var spff = document.getElementById(SPFF_ID);
            spff.UseInlineStyle = 'True';
            spff.innerHTML = convertRTE;
            RTE.RichTextEditor.transferContentsToInputField(SPFF_ID);
}
 

An other funny one is the Lookup or Select Fields. 
This because Sharepoint can generate two different type of fields. Or it is an select/option list
or just even an input tag. This depending if there are less or more than 20 elements in the list.
So you need to check the type of field Sharepoint has created, and depending on it populate the
select-tag or input-tag.

function SPCC_Dup_fill_Lookup_Select_FromFieldName(fieldName, newTF_ID, type){
 var value = document.getElementById(newTF_ID).innerHTML;
 if (value == undefined) return;
 var theSelect = SPCC_Dup_getTagFromIdentifierAndTitle("select", type,fieldName);
// if theSelect is null, it means that the target list has more than
 // 20 items, and the Lookup is being rendered with an input element
 if (theSelect == null) {
  var theInput = SPCC_Dup_getTagFromIdentifierAndTitle("input","",fieldName);
  ShowDropdown(theInput.id); //this function is provided by SharePoint
  var opt=document.getElementById(theInput.opt);
  SPCC_Dup_setSelectedOption(opt, value);
  OptLoseFocus(opt); //this function is provided by SharePoint
 } else {
  SPCC_Dup_setSelectedOption(theSelect, value);
 }
}
 
function SPCC_Dup_setSelectedOption(select, value)
{
 var opts = select.options;
 var l = opts.length;
 if (select == null) return;
 for (var i=0; i < l; i++) {
  if (opts[i].value == value) {
   select.selectedIndex = i;
   return true;
  }
 }          
 return false;
}
 

A Hyperlink field gives you in view an array with the link and the description of the link.
so to fill it in your newform you need to fill in two input fields. 
function SPCC_Dup_fill_HyperlinkField(SPFFUrl_ID, SPFFDesc_ID, newTF_ID){
 var sptf = document.getElementById(newTF_ID);
 var spffurl = document.getElementById(SPFFUrl_ID);
 var spffdesc = document.getElementById(SPFFDesc_ID);
 var mySplitResult = sptf.innerHTML.split(", ");
 if(mySplitResult.length > 1)
 {
  spffurl.value = mySplitResult[0];
  spffdesc.value = mySplitResult[1];
 }
 else
 {          
  spffurl.value = mySplitResult[0];
 }
}           
 

Sharepoint provided also a YES_NO field, behind the screen it is just a checkbox. 
function SPCC_Dup_fill_CheckboxFieldYN(SPFF_ID, newTF_ID){
 var sptf = document.getElementById(newTF_ID);
 var spff = document.getElementById(SPFF_ID);
 if (sptf.innerHTML.toUpperCase()=="TRUE"||sptf.innerHTML=="1"){
  spff.checked=true;
    }
    if (sptf.innerHTML.toUpperCase()=="FALSE"||sptf.innerHTML=="0"){
        spff.checked=false;
    }
}
 

Two elements that acts amost the same are the radiobutton list and the checkbutton list. 
Here you need to loop the array of items in your fields and check them if needed.

function SPCC_Dup_fill_RadioButtonList(SPFF_Name, newTF_ID){
 var sptf = document.getElementById(newTF_ID);
 var spff = document.getElementsByName(SPFF_Name);
 if (spff != null)
 {
  for (i=0; i < spff.length;i++)
  {
   if (spff[i].parentNode.innerHTML.indexOf(sptf.innerHTML) >= 0)
    {spff[i].checked = true;}
   else
    {spff[i].checked = false;}
  }                      
 }
}
                       
function SPCC_Dup_fill_CheckButtonList(SPFF_ID, newTF_ID){
 var sptf = document.getElementById(newTF_ID);
 var split_sptf = sptf.innerHTML.split(", ");
 var tags = document.getElementsByTagName('input');
 var identifier =  SPFF_ID.substr(0,SPFF_ID.length -5);
 var found = 0;
 for (var i=0; i< tags.length; i++)
 {   found = 0 ;
  var tempString = tags[i].id;
  if(tempString.indexOf(identifier) >= 0)
  {
   var spff= tags[i];
   for (j=0; j < split_sptf.length; j++)
   {
    if (spff.parentNode.innerHTML.indexOf(split_sptf[j]) >= 0)
    { spff.checked = true; found++;}
    else
       {   if (found == 0){spff.checked = false;}}
   }
  }                      
 }
}
 

The Date Time field of sharepoint is not so easy to fill in. 
This because you get from your field a totaly other format as what you need to fill in sharepoint.
The new fields exists of three blocks of fields. The date-field, the Hour-field and the minutes-field.
So you need to convert your datetime result into three different blocks. 
Also it is possible to fill in the hours as format HH: or HH AM/PM. 
We have put our general site settings for time to 24h option.
So here an example function, but depending your site settings 
it may have to be changed or be completed !
function SPCC_Dup_fill_DateTimeField(setDateFieldId,theDate, sDateFormat){
 // expecting format yyyy-MM-ddTHH:mm:ssZ
    var odate = SPCC_Dup_getTagFromIdentifier(theDate);
    var setDate = SPCC_Dup_getTagFromIdentifier(setDateFieldId);
    var setHours = SPCC_Dup_getTagFromIdentifier(setDateFieldId + "Hours");
    var setMinutes = SPCC_Dup_getTagFromIdentifier(setDateFieldId + "Minutes");
    if (odate != null)
    {
   var ddate = odate.innerHTML;
   if (ddate.length > 0)
   {
  var dDay = ddate.substring(8,10);
  var dMonth = ddate.substring(5,7);
  var dYear= ddate.substring(0,4);
  var dHours= ddate.substring(11,13);
  var dMinutes= ddate.substring(14,16);

  if (setDate != null)
  {
    if (sDateFormat.toLowerCase() == 'dd/mm/yyyy')
    {           setDate.value = dDay + '/' + dMonth + '/' + dYear;}
    if (sDateFormat.toLowerCase() == 'mm/dd/yyyy')
    {           setDate.value = dMonth + '/' + dDay + '/' + dYear;}
    if (sDateFormat.toLowerCase() == 'yyyy/mm/dd')
    {           setDate.value = dYear+ '/' + dMonth + '/' + dDay;}
  }
  if (setHours != null)
  {
    var iHours = parseInt(dHours) + 1;
    if ( iHours <10) {dHours = '0' + iHours;} else {dHours = iHours;}
    setHours.value = dHours +':';
  }
  if (setMinutes != null)
  {
    setMinutes.value = dMinutes;
  }
   }
 }
}

For a Select field, you have the option to choose of an normal selectbox, 
or one where you may fill in a custom text. This means that in case of pre-populate
you need to check if you value exist in the Dropdown field, if not to fill in the
custom inputfield. 

function SPCC_Dup_fill_CustomSelect(fieldID, newTF_ID){
 var value = document.getElementById(newTF_ID).innerHTML;
 if (value == undefined) return;
 var theSelect = document.getElementById(fieldID);
 if (SPCC_Dup_setSelectedOption(theSelect, value) == false)
 {   // value does not exist in the DropDown box. zo fill in the custum field.
  var myNewID = fieldID.replace("DropDownChoice", "ctl01");
  var theInput = document.getElementById(myNewID);
  theInput.value = value;
  var myNewButtonID = fieldID.replace("DropDownChoice", "FillInButton");
  SetChoiceOption(myNewButtonID);
 }
}

A interesting field for prepopulating is also the Multi Select field.
This because you get an array of fields in your result, but in the newform
you receive two multi select boxes. One with the available items and 
one with the selected items.
For making me easy, I created the script to select first the items in the
candidates list and call the sharepoint function to populate them in the selected box.
So I don't have to remove them myself in the candidate list and transfer them manualy in 
the selected items box. 

function SPCC_Dup_fill_MultiSelect(fieldID, newTF_ID){          
 var value = document.getElementById(newTF_ID).innerHTML;
 var fieldbuttonID = eval(fieldID.replace("SelectCandidate", "MultiLookupPicker_m"));
 var split_value = value.split("</a>");
 var theSelect = document.getElementById(fieldID);
 var i = 0;
 for (i=0; i< theSelect.options.length; i++)
 {
  var valuefound = false;
  for(var j=0;j< split_value.length;j++)
  {
   var ibegin = split_value[j].indexOf(">") + 4;
   var myMLPValue = split_value[j].substr(ibegin, split_value[j].length);
   if(theSelect.options[i].text == myMLPValue)
   {
    theSelect.options[i].selected = true;
    valuefound = true;
   }
   else
   {
    if(!valuefound)
    {
     theSelect.options[i].selected = false;
    }
   }
  }
 }
 GipAddSelectedItems(fieldbuttonID);
}

Last function I hope is the MetaData Field (or better known as Termstore or taxonomy-field).
What I thought to be difficult ended very easy to do. 
You just need to fill in a DIV that has your fieldID followed by editableRegion.
put the values in that DIV and call a Sharepoint function 
with as parameter the master Parent of your TermStore field. 
And at least call the validation function to justify your filled in records.
  
function SPCC_Dup_fill_MetaDataFied(fieldID, referenceFieldID){
 var value = document.getElementById(referenceFieldID).innerHTML;
 if (value != '')
 {
  var resetDefault = document.getElementById(fieldID.substr(0,fieldID.length-1) + "1");
  resetDefault.value = "";
  var targetvalue = document.getElementById(fieldID);
  var mydiv = document.getElementById(fieldID);
  var editableRegion = document.getElementById(fieldID + "editableRegion");
  editableRegion.innerHTML = value;  
  var taxonomyParent = editableRegion.parentNode.parentNode.parentNode;  
  var taxonomyObject = new Microsoft.SharePoint.Taxonomy.ControlObject(taxonomyParent);
  taxonomyObject.validateAll();
 }
}

I hope I have handled all different types of fields. 
It has costed me some hours of development, but I hope the functions I have written 
may help you and others. 
I also prefered not to use the JQuery library, this for learning reasons. 
It makes you understand better how Sharepoints generates his fields 
and how there behaviour are.


Spread the words around and forward my blog so many others can save some time on finding solutions.