Here is the final product. Subsites are only loaded when a user clicks on the '+'
ENJOY!
In Visual Studio create a Farm Solution. Make it a Visual Web Part.
Create a Class titled. SitesList. add these getters and setters.
class SitesList
{
public int SiteCollid { get; set; } /// a counter to give the css class for uniqueness
public string SiteUrl { get; set; }
public bool isRoot { get; set; }
public string Title { get; set; }
}
Add this block of code to override the CreateClientControls, within the VisualWebPart.ascx.cs
.
I had many issues with calling Methods I created within the CreateChildControls. So, this code is a bit of a large block.
The purpose of this code is to get all Top level sites a user has access to, it will build the controls.
Then we will have sp.js get each subsite when a user wants to expand the SiteCollection.
protected override void CreateChildControls()
{
base.CreateChildControls();
List<SitesList> list = new List<SitesList>();
Guid app1Id = new Guid();
int counter = 0;
string userName = Microsoft.SharePoint.SPContext.Current.Web.CurrentUser.LoginName;
using (SPSite newsite = new SPSite("https://DomainWebApp.XX.com")) /// Feel free to use current context we know that the webapp will never change
{ app1Id = newsite.WebApplication.Id; }
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPServiceCollection services = SPFarm.Local.Services;
foreach (SPService eachService in services)
{
if (eachService is SPWebService)
{
SPWebService webService = (SPWebService)eachService;
foreach (SPWebApplication webApp in webService.WebApplications)
{
if (webApp.Id == app1Id)
{
SPSiteCollection siteColl = webApp.Sites;
foreach (SPSite site in siteColl)
{
SPBasePermissions permissionToCheck = SPBasePermissions.ViewPages;
using (SPSite spSite = new SPSite(site.RootWeb.Url))
{
try
{
using (SPWeb indiWeb = spSite.OpenWeb(spSite.RootWeb.ServerRelativeUrl))
{
if (indiWeb.DoesUserHavePermissions(userName, permissionToCheck))
{
list.Add(new SitesList()
{
SiteCollid = counter,
SiteUrl = indiWeb.Url,
Title = indiWeb.Title,
isRoot = true
});
}
}
}
catch (Exception ex)
{
///Feel free to add your own exception throws.
throw;
}
finally
{
counter++;
}
}
}
}
}
}
}
});
list.Sort((x, y) => (x.Title).CompareTo(y.Title)); //inplace sort
foreach (SitesList s in list)
{
HyperLink hyp1 = new HyperLink();
hyp1.CssClass = "AccessSitesLinks " + s.isRoot.ToString() + " " + s.SiteCollid.ToString();
hyp1.Text = s.Title;
hyp1.NavigateUrl = s.SiteUrl;
this.Controls.Add(hyp1);
}
}
Ensure these using statements.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Web.UI.WebControls;
using System.Linq;
Create These folders CSS
JS
in the Style Library of the sites that will contain the WebPart.
Create this CSS File and place it in the CSS Folder
.ContainingBox2{
padding: 2px 15%;
}
.AccessSitesLinks.True {
padding: 2px 2%;
font-size: 1.2em;
width: 40%;
}
.AccessSitesLinks {
text-decoration: none !Important;
font-family: "Segoe UI","Segoe",Tahoma,Helvetica,Arial,sans-serif;
color: #444;
font-size: 1em;
width: 30%;
margin: 2px;
}
.SubSitesAccess {
padding: 2px 2%;
font-size: 1.2em;
width: 40%;
text-decoration: none !Important;
font-family: "Segoe UI","Segoe",Tahoma,Helvetica,Arial,sans-serif;
color: #444;
font-size: 1.2em;
width: 40%;
margin: 2px;
}
Create this Javascript file. and place it in the JS folder.
$(document).ready(function(){
var webCollection = null;
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', buildRootTree);
});
function buildRootTree(){
var urlString = "";
var siteRoot = $('.AccessSitesLinks.True');
var arr = siteRoot.map(function(_, o) {
return {
t: $(o).text(),
h: $(o).attr('href'),
c: $(o).attr('class')
};
}).get();
siteRoot.each(function(i, o) {
console.log(arr[i].c);
$(o).text('+');
$(o).wrap("<div class='ContainingBox "+ arr[i].c + "'></div>");
$(o).parent().append("<a href='" + arr[i].h + "' class='" + arr[i].c + "'>" + arr[i].t + "</a>")
$(o).parent().data('urlString', $(this).attr('href'));
$(o).removeAttr('href');
});
$('.ContainingBox').click(function() {
if(!$(this).attr('boolcheck')) {
$(this).attr('boolcheck', 'Exists');
buildNode($(this).data('urlString'), $(this));
}
else{
$('.ContainingBox2', this).toggle();
}
});
}
function buildNode(urlString, domElement){
console.log(urlString);
var clientContext = new SP.ClientContext(urlString);
console.log("clientContext");
var web = clientContext.get_web();
console.log("get_web");
this.webCollection = web.getSubwebsForCurrentUser(null);
console.log("bout to load");
clientContext.load(this.webCollection);
clientContext.executeQueryAsync(Function.createDelegate(this, function(){ onQuerySucceeded(domElement)}), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(domElement) {
var webEnumerator = this.webCollection.getEnumerator();
while (webEnumerator.moveNext()){
var web = webEnumerator.get_current();
console.log(web.get_title());
console.log(domElement);
domElement.append("<a href='" + web.get_url() + "' class='SubSitesAccess'" + ">" + web.get_title() + "</a>");
}
domElement.children('.SubSitesAccess').wrap("<div class='ContainingBox2'></div>");
}
function onQueryFailed(sender, args) {
}
Create a Script editor on the page where you have put your webparts and edit the snipet to include. Make sure the file you name matches the one in the code below. We used "MyFavorites".
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
SP.SOD.executeOrDelayUntilScriptLoaded(LoadMyScript, 'sp.js');
function LoadMyScript() {
var currWebUrl = _spPageContextInfo.webServerRelativeUrl; // use siteServerRelativeUrl for site-collection
//Dynamic loading of scripts
var jq = document.createElement('script');
jq.src = currWebUrl + "/Style%20Library/JS/MyFavorites.js"; ///Be sure to use the name of your JS file you created
var css = document.createElement('link');
css.href = currWebUrl + "/Style%20Library/CSS/MyFavorites.css"; ///Be sure to use the name of your CSS file you created
css.type = "text/css";
css.rel = "stylesheet";
document.getElementsByTagName('head')[0].appendChild(jq);
document.getElementsByTagName('head')[0].appendChild(css);
}
</script>