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>

10 comments:

  1. this is great! Thank you very much. Exactly what I was looking for.

    ReplyDelete
  2. Thanks for the code insight.

    We use SharePoint 2010 on Office 365.

    However, since i'm new to designer, it seems that the page code is made of unodifiables blocks.

    How can I edit it freely ?

    Thanks
    Guillaume

    ReplyDelete
    Replies
    1. Nevermind, just found how to do it.
      Must edit the page in "Advanced Mode", found withing the context menu of the view.

      Works great.

      Delete
  3. Add the following line:

    name = name.toLowerCase();

    AFTER:
    ------------------------------------
    name = name.replace(/'/g, '%27');
    ------------------------------------

    So it matches when images are uploaded with uppercase extensions.

    ReplyDelete
  4. Another solution:
    http://www.sparqube.com/SharePoint-Picture-Column/
    Allow to upload and display images in sharePoint lists.
    Free open source solution: http://sparqubepicturelite.codeplex.com/

    ReplyDelete
  5. Hi Shirin,
    This may be a little too late, but here's a pretty elegant solution that I just wrote. It basically checks for the attachment table, then—instead of parsing the code with regular expressions—simply modifies the DOM since the link is already there.

    <script type="text/javascript">
    //Function to avoid global namespace collision.
    (function(){
    var aT=document.getElementById('idAttachmentsTable'),aA=aT.getElementsByTagName('A'),a,img;
    if(aT){
    for(var i=0,l=aA.length;i<l;i++){
    a=aA[i];
    if(!(new RegExp('\.jpg|\.jpeg|\.png|\.gif|\.bmp|\.tif|\.tiff','i').test(a.href)))continue;//Test for image extensions, ignoring case.
    img=document.createElement('img');
    img.style.width='450px';//Optional: to constrain the width of the image to the default SP form width, resizing proportionally.
    img.style.border='0';//Optional: to remove the standard hyperlinked border around the image.
    img.src=a.href;
    a.appendChild(document.createElement('br'));//Optional: to add a line break before the image.
    a.appendChild(img);
    }
    }
    })();
    </script>

    ReplyDelete
    Replies
    1. Here it is simply minimized:

      (function(){
      var b=document.getElementById('idAttachmentsTable');
      if(b){
      var c=b.getElementsByTagName('A'),a,d;
      for(var i=0,l=c.length;i<l;i++){
      a=c[i];
      if(!(new RegExp('\.jpg|\.jpeg|\.png|\.gif|\.bmp|\.tif|\.tiff','i').test(a.href)))continue;
      d=document.createElement('img');
      d.style.width='450px';
      d.style.border='0';
      d.src=a.href;
      a.appendChild(document.createElement('br'));
      a.appendChild(d)
      }
      }
      })();

      Delete
    2. style.width='450px' can be style.maxWidth='450px' if the image width is smaller than that. I also forgot to mention to add the code inside the PlaceHolderMain closing content tag, as you mentioned above.

      Delete
  6. Has anyone tried this with SharePoint Online? I can't get it to work at all - no error, nothing - any thoughts?

    ReplyDelete