Monday, July 9, 2012

Display SharePoint List Item Attachments as Images

Suppose you want a visual display of the images that you attach to a SharePoint list. Clicking on each attachment to open it can be a hassle instead of just having it automatically display the images on load.


By default, the attachments are listed as links:




If you view the properties of a SharePoint list item, you will see that the link to each attachment is calculated by: 

[Site Url]/Attachments/[Item ID]/[Attachment Name]

So, if we can grab the item id of the list item, and then determine the attachment names, we will be able to use those properties to display the image with an img tag.

First thing's first. If you view the source of that default SharePoint item view page, you will see that the attachments are store din the element: idAttachmentsTable. We want to grab all of the attachment names in that element. To do so, we will iterate through the span elements and parse out the attachments:  


 

<script type="text/javascript">
spanTag = document.getElementById("idAttachmentsTable").getElementsByTagName("span");
var attachmentArray = new Array();
for (var i = 0; i < spanTag.length; i++) 
{
  filename = spanTag[i].innerHTML;
  var index  = filename.indexOf('>')+1;
  var lastindex = filename.lastIndexOf('<');

  var name = filename.substring(index, lastindex);

  name = name.replace(/ /g, '%20');
  name = name.replace(/'/g, '%27');

  for( var x = 0; x < imgExtensions.length; x++ )
  {
   if( name.indexOf(imgExtensions[x]) >=0 )
   {
    attachmentArray.push([name]);
    break;
   }
  }
}
</script>

Now that we have the names of the attachments, we want to grab the current item id of our list item, which we can simply grab from the source url.

Call to get the item ID:

var paramID = getParameterByName("ID");

Function to grab the parameter from the source url:
function getParameterByName(name) 
{   
 name = name.replace(/[\[]/, "
\\\[").replace(/[\]]/, "\\\]");  
 var regexS = "[\\?&]" + name + "=([^&#]*)"; 
 var regex = new RegExp(regexS);  
 var results = regex.exec(window.location.href); 
 if(results == null) 
  return "";
 else   
  return decodeURIComponent(results[1].replace(/\+/g, " "));
}

Now, we will use the paramID and the attachment names to create our img tags and append it to the Attachments element:

var ctrl = document.getElementById("idAttachmentsTable");
 var attachmentString = "";
 for( i = 0; i < attachmentArray.length; i++)
 {
  attachmentString += 
  " <img src='" + listAttachmentUrl + paramID + "/"+ attachmentArray[i] + "' width='400px' border='2'>";
 }
 ctrl.parentNode.innerHTML += attachmentString;


After adding our script:





To use this script, you will need to use SharePoint designer to edit the "View" page of the list. Navigate to the end of the PlaceHolderMain content placeholder, and right before the closing "</asp:Content>" tag, place the script below in it's entirety. Make sure to modify the listAttachmentUrl to reflect your site and list names:

<script language="javascript" type="text/javascript"> 
var listAttachmentUrl = '/mysite/Lists/mylist/Attachments/';
var imgExtensions = new Array(".jpg",".jpeg", ".png", ".bmp", ".tif", ".tiff");
LoadAllAttachments();

function LoadAllAttachments()
{
 spanTag = document.getElementById("idAttachmentsTable").getElementsByTagName("span");
 var attachmentArray = new Array();
 for (var i = 0; i < spanTag.length; i++) 
 {
  filename = spanTag[i].innerHTML;
  var index  = filename.indexOf('>')+1;
  var lastindex = filename.lastIndexOf('<');

  var name = filename.substring(index, lastindex);

  name = name.replace(/ /g, '%20');
  name = name.replace(/'/g, '%27');
  for( var x = 0; x < imgExtensions.length; x++ )
  {
   if( name.indexOf(imgExtensions[x]) >=0 )
   {
    attachmentArray.push([name]);
    break;
   }
  }
 }

 var paramID = getParameterByName("ID");
 var ctrl = document.getElementById("idAttachmentsTable");
 var attachmentString = "";
 for( i = 0; i < attachmentArray.length; i++)
 {
  attachmentString += 
  " <img src='" + listAttachmentUrl + paramID + "/"+ attachmentArray[i] + "' width='400px' border='2'>";
 }
 ctrl.parentNode.innerHTML += attachmentString;
}

function getParameterByName(name) 
{   
 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");   
 var regexS = "[\\?&]" + name + "=([^&#]*)";  
 var regex = new RegExp(regexS);   
 var results = regex.exec(window.location.href);  
 if(results == null)  
  return ""; 
 else    
  return decodeURIComponent(results[1].replace(/\+/g, " "));} 
</script>

Friday, July 6, 2012

SharePoint Color Coded list based on a Field in the Row

SharePoint doesn't provide an out of the box way of color coding lists. But, thank goodness, we can use a little scripting to edit the styling of our lists!

Mike Smith provided a great script that allows you to color the background of the row if the cell's value matches the value it's looking for. But, what if another field in the same row has one of the other values and throws off your color coding?

Case in point: color coding is thrown off because the Description field
can have the same value that is being used to color code on
  

Well, this script below will search only the cell index of the row that you would like to base your color coding on. In our case, we would like to search only on the Status field/column. To get started:

1. Add a content editor web part directly underneath the list
2. Open the source editor and place the script below into it
3. Modify the columnIndexToSearch and the columnSpan variables to match the cell/field index to search for and the number of cells in each row respectively.

Note: In this case, the attachment field counts as a cell. Since we are searching only on the Status, our columnIndexToSearch is 2 (0 = Attachment field and 1 = Title field). The total number of columns we are displaying on our list is 5. If you add or remove columns in the view, the color coding will get thrown off. So, make sure to update these variables if you do make updates to the list view.

Final Result: Color coded based on the Status column only
   







<script type="text/javascript">


var listView = getElementsByClass("ms-listviewtable"); //get the list on the page
var tRows = listView[0].childNodes[0].childNodes;

var columnIndexToSearch = 2; //the index of the column that should be searched
var columnSpan = 5; //number of columns visible on the list

var j = 0;
var i = 0; 
var cellcounter = 0; //used to keep track of the cells searched on the row

for( j = 0; j < tRows.length; j++)
{
 if( tRows[j].className == "" || tRows[j].className == "ms-alternating")
 {
  var x = tRows[j].childNodes; // find all of the TRs
  for (i = 0; i < x.length; i++) 
  { 
   if( cellcounter == columnIndexToSearch) 
   {
    if (x[i].innerHTML.indexOf("In Progress") >= 0)
    { 
     x[i].parentNode.style.backgroundColor='lightgreen'; 
    }

    else if (x[i].innerHTML.indexOf("Completed") >= 0)
    { 
     x[i].parentNode.style.backgroundColor='lightblue'; 
    }

    else if (x[i].innerHTML.indexOf("Deferred") >= 0)
    { 
     x[i].parentNode.style.backgroundColor='lightgrey'; 
    }

    else if (x[i].innerHTML.indexOf("Waiting on someone else") >= 0)
    { 
     x[i].parentNode.style.backgroundColor='orange'; 
    }
  }

   cellcounter++;
   if( cellcounter >= columnSpan)
   {
    cellcounter = 0;
   }
  } 
 }
}

function getElementsByClass(searchClass, node, tag) 
{
 var classElements = new Array();
 if ( node == null )
  node = document;
 if ( tag == null )
  tag = '*';
 var els = node.getElementsByTagName(tag);
 var elsLen = els.length;
 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
 for (i = 0, j = 0; i < elsLen; i++) 
 {
  if ( pattern.test(els[i].className) ) 
  {
   classElements[j] = els[i];
   j++;
  }
 }
 return classElements;
}


</script>



SharePoint Calendar Jump to Next or Previous Month

I had a SharePoint calendar and I wanted a way to jump to the Next or Previous month from the left hand navigation/quick launch menu. 

I couldn't hardcode this url into the navigation, because it would change every month. I needed a dynamic way to do this. To address this, I created a new blank SharePoint page in my site, called "MonthRedirector". I added a script that would determine the current month, and then either skip to the next or previous month based on the query string parameters passed in.


1. Create a blank SharePoint page, call it MonthRedirector
2. Add a content editor web part to the page and paste in the script below or (View Code)

Make sure to set the "Chrome Type" to be "none" and modify the site url in the script to reflect your site's url

3. Add 2 new links to the Navigation menu, 1 for the previous month and 1 for the next month:

[siteurl]/Pages/MonthRedirector.aspx?Jump=Prev&Calendar=[Your calendar name]

[siteurl]/Pages/MonthRedirector.aspx?Jump=Next&Calendar=[Your calendar name]


Now, when a user clicks on the links on the left hand navigation, it will automatically direct them to the previous month or the next month on the calendar!


 
<style>
#sidebar,#sidebar-footer {display : none !important;}
</style>

<script type="text/javascript">
var siteURL = "http://mySiteUrl";
//if you do not wish to hardcode the name, use something
//like SPServices to grab the current site url
//var siteURL = $().SPServices.SPGetCurrentSite();

var curDate = new Date();
var paramfilterJump = getParameterByName("Jump");
var paramCalendarName = getParameterByName("Calendar");

if( paramCalendarName != null && paramCalendarName !="" && paramfilterJump != null 
 && paramfilterJump != "" && paramfilterJump == "Next")
{
 var fullDateString =  PadDigits(curDate.getMonth() + 2, 2)  + "%2F" + PadDigits(curDate.getDate(), 2) + "%2F" +  curDate.getFullYear();  
 var redirectURL = siteURL + "/Lists/" + paramCalendarName + "/calendar.aspx?CalendarDate=" + fullDateString; 
 window.location.href = redirectURL;
}
else if( paramCalendarName != null && paramCalendarName != "" && paramfilterJump != null 
 && paramfilterJump != "" && paramfilterJump == "Prev")
{
 var fullDateString =  PadDigits(curDate.getMonth(), 2)  + "%2F" + PadDigits(curDate.getDate(), 2) + "%2F" +  curDate.getFullYear();  
 var redirectURL = siteURL + "/Lists/" + paramCalendarName + "/calendar.aspx?CalendarDate=" + fullDateString; 
 window.location.href = redirectURL;
}

function PadDigits(n, totalDigits) 
{ 
 n = n.toString(); 
 var pd = ''; 
 if (totalDigits > n.length) 
 { 
  for (i=0; i < (totalDigits-n.length); i++) 
  { 
   pd += '0'; 
  } 
 } 
 return pd + n.toString(); 
} 

function getParameterByName(name) {   name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");   var regexS = "[\\?&]" + name + "=([^&#]*)";   var regex = new RegExp(regexS);   var results = regex.exec(window.location.href);   if(results == null)     return "";   else     return decodeURIComponent(results[1].replace(/\+/g, " ")); } 

</script>