Wednesday, August 15, 2012

Show All Sites I Have Access to in SharePoint with Filtering using JQuery and Javascript

Suppose you want your users to see all the SharePoint sites that they have access to on one page, instead of having to drill down to each subsite to find their content. Instead of creating a site directory, I want to show them all the sites that they can access and allow them to filter based on the site name, site path and site description.

Laura Rogers has a blog post that goes through a step by step process of using the Search Core Results web part, which can be found here: http://sharepoint911.com/blogs/laura/Lists/Posts/Post.aspx?ID=90

However, I want to do this by using some scripting. By default, it will show all the sites the current user has access to (with a scroll bar on the right hand side if it is an extensive list). The search textbox will automatically filter the entire set of sites (with no post backs) on the site title, path and description. The end result will be similar to below:


First, we will want to use the SharePoint search service and get all the sites and webs using jquery/ajax. The query we will use gets only the indexed items that are of contentclass type "STS_SITE" or "STS_WEB:

SELECT Title, Rank, Size, Description, Path FROM Scope() WHERE "scope" = 'All Sites' AND (contentclass = 'STS_Site' OR contentclass = 'STS_Web') ORDER BY "Rank" DESC"
Next, we will call the query using the search service, where the url being passed in is the url to the search.asmx path.

 $.ajax({ 
url: "http://mydomain/_vti_bin/search.asmx" ,  
type: "POST",   
dataType: "xml",       
data: soapEnv,      
async:true,
complete: processResult,   
contentType: "text/xml; charset=\"utf-8\""
 });   
The processResult function will be executed to iterate through the results and create our table once the ajax call has been made.

Finally, we will use the dataTable js plugin to allow scrolling and filtering on the sites list
$('#mySitesTable').dataTable( {
"sScrollY": "300px",
"bPaginate": false,
"bSort": false
} );

Simply add this script to a SharePoint page and reference the jquery library, which you can grab from http://docs.jquery.com/Downloading_jQuery and the jquery.dataTables.min.js, which you can download from http://datatables.net/:

<div id="errorMsg"></div>
<div id="showQueryResults" style="display: none">false</div>
<div id="searchResults"></div>
<div id="testoutput" style="display: none"></div>

<script src="/assets/js/jquery/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="/assets/js/jquery/plugins/dataTables/jquery.dataTables.min.js" type="text/javascript"></script>

<style>
 div.table_Wrapper { border:10px solid blue; }
 .dataTables_filter 
 {
  width: 50%;
  float: right;
  text-align: right;
 }
 .dataTables_info
 {
  width: 100%;
  font-weight:bold;
  float: left;
  border: 2px solid #ddd;
  background-color: Gainsboro;
  color: #999;
  text-align: right;

 }
 
</style>


<script type="text/javascript">

var searchURL = "http://mydomain/_vti_bin/search.asmx";
var arraySearchResults = new Array();
var arrayListToSearch = new Array();
var displayQueryResults = false;
var searchCap = 5000;
 
//used to display the output of the query; 
//if you would like to see the query result, make set the innerHTML of showQueryResults to true
if( document.getElementById("showQueryResults").innerHTML == "true")
{
 displayQueryResults = true;       
}

RunSearch(); 

   
function RunSearch()
{
 arraySearchResults = new Array();
 

 var myQuery = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>";
 myQuery += "<Query>"; 
 myQuery += "<SupportedFormats><Format>urn:Microsoft.Search.Response.Document.Document</Format></SupportedFormats>";  
 myQuery += "<Range><Count>" + searchCap + "</Count></Range>";  
 myQuery += "<Context>";
 myQuery += "<QueryText language='en-US' type='MSSQLFT'>";
 myQuery += "SELECT Title, Rank, Description, Path FROM Scope() WHERE \"scope\" = 'All Sites' AND (contentclass = 'STS_Site' OR contentclass = 'STS_Web') ORDER BY \"Rank\" DESC";
 myQuery += "</QueryText>";
 myQuery += "</Context>"; 
 myQuery += "</Query>";
 myQuery += "</QueryPacket>";   

  
 var soapEnv = "<?xml version=\"1.0\"?>"+
 "<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>" + 
 "<soap:Body>" +
 "<Query xmlns='urn:Microsoft.Search'>"+
 "<queryXml>" + escapeHTML(myQuery) + "</queryXml>"+   
 "</Query>"+    
 "</soap:Body>"+ 
 "</soap:Envelope>";


 $.ajax({  
  url: searchURL,   
  type: "POST",    
  dataType: "xml",        
  data: soapEnv,       
  async:true,

  complete: processResult,    
  contentType: "text/xml; charset=\"utf-8\""

 });         
 }
 
  

function processResult(xData, Status)
{
 if (Status == "error") 
 {
  DisplayErrorMesssage(Status, xData);
  return;
 }

// alert($(xData.responseXML).text());
 
   var queryResult = $(xData.responseXML).find("QueryResult").text();
   $("#testoutput").text(queryResult);
 
   if( displayQueryResults )
   {
       document.getElementById("testoutput").style.display = "";
   }
   else
   {
       document.getElementById("testoutput").style.display = "none";
   }
 
   $(xData.responseXML).find("QueryResult").each(function() {  
    var xml = $("<xml>" + $(this).text() + "</xml>");  
    xml.find("Document").each(function() 
    {  
  var curPath = $("Action>LinkUrl", $(this)).text();  
  curPath = curPath.toLowerCase();

  var curTitle = "";  
  var curDesc = "";
 
 
  $(this).find("Property").each(function() 
  {  
   if ($("Name", $(this)).text() == "TITLE") 
   {  
    curTitle = $("Value", $(this)).text(); 
   }  
   if ($("Name", $(this)).text() == "DESCRIPTION") 
   {  
    curDesc = $("Value", $(this)).text(); 
   }  
  });  
  
  arraySearchResults.push([curTitle, curPath, curDesc]);
    
    });  

  });
 
 PrintOutput();
}
 
 

function PrintOutput()
{ 
 arraySearchResults.sort(sortSearchResults);

 var output = "";

 output += '<table id="mySitesTable" cellpadding="0" cellspacing="0" border="0" class="display">';
 output += "<thead><tr><th align='left'><font color='steelblue' size='2pt'><u><b>Sites that I have access to</b></u></font><br/><br/></th></tr></thead>"; 
 output += "<tbody>";

 
 for( var x = 0; x < arraySearchResults.length; x++ )
 {
  var title = arraySearchResults[x][0];
  var path = arraySearchResults[x][1];
  var desc = arraySearchResults[x][2];
  
  output += PrintRow(path, title, desc);
 } 
 
 output += "</tbody></table>";
 
 document.getElementById("searchResults").innerHTML = output;
 
  
 $('#mySitesTable').dataTable( {
  "sScrollY": "300px",
  "bPaginate": false,
  "bSort": false
 } );
}
 
function PrintRow(path, title, desc)
{
 var output = "";

 if( desc != null && desc != "" )
  output += '<tr><td><a href="' +  path +  '" target="_blank">' + title   + '</a><br/><font color="green">' + path + '</font><br/>'+desc+'<br/><br/></td></tr>';
 else
  output += '<tr><td><a href="' +  path +  '" target="_blank">' + title   + '</a><br/><font color="green">'+path+'</font><br/><br/></td></tr>';

 return output; 
}
 
 
function DisplayErrorMesssage( Status, xData)
{
 document.getElementById("errorMsg").innerHTML = "Error occurred. " + Status ;

 if( xData.responseXML != null )
 {
  document.getElementById("errorMsg").innerHTML += $(xData.responseXML).text();
 }
}
 
 
function sortSearchResults(a, b){

 var aTitle = a[0]; 
 var bTitle = b[0];
  
  
 var x = aTitle.toLowerCase(), y = bTitle.toLowerCase();   
 
 return x < y ? -1 : x > y ? 1 : 0;   
}


function escapeHTML (str) 
{  
 return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');   
}     
 </script>



7 comments:

  1. Pretty Cool. I like! One thing I would is what type of Permission they have to the site for example Read, Contribute or Full Permission.

    ReplyDelete
    Replies
    1. Thanks! Unfortunately, the search only brings back the sites that you have at least read access to. It doesn't bring back the permission details.

      Stay tuned though, because I have another web part that I've built in Visual Studio using C# that will allow you to search all of the sites, even if you do not have access to the site. I've done this by utilizing elevated privileges...

      Another web part that I have developed and I'm planning on putting on codeplex is one that shows the entire web application, site collections and sites directory in a treeview. It will grey out the sites you do not have access to and if you have access to it, it will show you what type of access you do have.

      I plan to put those 2 web parts up in codeplex shortly!

      Delete
    2. Thanks for sharing this solution. Can you please provide links to the two web part solutions you have developed mentioned above. It sounds very interesting.
      BTW, is the above and the new intended for SP2010 or MOSS 2007?
      Thanks,
      Anant

      Delete
  2. great script! did you have an opportunity to complete the solution using C#?

    thanks,
    Jason

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Please anyone can give this demonstrate using step by step.
    I am not getting what step i have to follow first,

    Regards,
    Arun

    ReplyDelete
  5. Is there a particular way this should be added into a page? It doesn't seem to be working as-is (with the address and js source paths changed of course). I'm not sure if there are other steps I need to take in order to make this function?

    Thank you!
    Caitlin

    ReplyDelete