In this post, I have written the code to create the custom org chart using REST API in sharepoint 2013.
Below is the code of "OrgChart.js"
=============================
In summary , you need to follow below steps to create org chart
1. Create "EasyTree.js"
2. Create "OrgChart.js"
3. Create "orgChart.css"
4. Replace all dynamic variables in OrgChart.js
5. Create div in HTML with class CSS
OrgChart.Js file uses the PeopleManager REST API of sharepoint 2013.
I have used "easyTree.js" file that builds the tree architecture allows expand and collapse functionality.
Below is the code of "EasyTree.js"
===================================================================
(function ($) {
$.fn.EasyTree = function (options) {
var defaults = {
selectable: true,
deletable: false,
editable: false,
addable: false,
i18n: {
deleteNull: 'Select a node to delete',
deleteConfirmation: 'Delete this node?',
confirmButtonLabel: 'Okay',
editNull: 'Select a node to edit',
editMultiple: 'Only one node can be edited at one time',
addMultiple: 'Select a node to add a new node',
collapseTip: 'collapse',
expandTip: 'expand',
selectTip: 'select',
unselectTip: 'unselet',
editTip: 'edit',
addTip: 'add',
deleteTip: 'delete',
cancelButtonLabel: 'cancle'
}
};
var warningAlert = $('<div class="alert alert-warning alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><strong></strong><span class="alert-content"></span> </div> ');
var dangerAlert = $('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><strong></strong><span class="alert-content"></span> </div> ');
var createInput = $('<div class="input-group"><input type="text" class="form-control"><span class="input-group-btn"><button type="button" class="btn btn-default btn-success confirm"></button> </span><span class="input-group-btn"><button type="button" class="btn btn-default cancel"></button> </span> </div> ');
options = $.extend(defaults, options);
this.each(function () {
var easyTree = $(this);
$.each($(easyTree).find('ul > li'), function() {
var text;
if($(this).is('li:has(ul)')) {
var children = $(this).find(' > ul');
$(children).remove();
text = $(this).html();
if(!$(this).find(' > span > span').hasClass("glyphicon"))
{
$(this).html('<span><span class="glyphicon"></span><a href="javascript: void(0);"></a> </span>');
$(this).find(' > span > span').addClass('glyphicon-folder-open');
$(this).find(' > span > a').html(text);
$(this).append(children);
}
}
else {
text = $(this).html();
if(!$(this).find(' > span > span').hasClass("glyphicon"))
{
$(this).html('<span><span class="glyphicon"></span><a href="javascript: void(0);"></a> </span>');
$(this).find(' > span > span').addClass('glyphicon-file');
$(this).find(' > span > a').html(text);
}
}
});
$(easyTree).find('li:has(ul)').addClass('parent_li').find(' > span').attr('title', options.i18n.collapseTip);
// add easy tree toolbar dom
if (options.deletable || options.editable || options.addable) {
$(easyTree).prepend('<div class="easy-tree-toolbar"></div> ');
}
// addable
if (options.addable) {
$(easyTree).find('.easy-tree-toolbar').append('<div class="create"><button class="btn btn-default btn-sm btn-success"><span class="glyphicon glyphicon-plus"></span></button></div> ');
$(easyTree).find('.easy-tree-toolbar .create > button').attr('title', options.i18n.addTip).click(function () {
var createBlock = $(easyTree).find('.easy-tree-toolbar .create');
$(createBlock).append(createInput);
$(createInput).find('input').focus();
$(createInput).find('.confirm').text(options.i18n.confirmButtonLabel);
$(createInput).find('.confirm').click(function () {
if ($(createInput).find('input').val() === '')
return;
var selected = getSelectedItems();
var item = $('<li><span><span class="glyphicon glyphicon-file"></span><a href="javascript: void(0);">' + $(createInput).find('input').val() + '</a> </span></li>');
$(item).find(' > span > span').attr('title', options.i18n.collapseTip);
$(item).find(' > span > a').attr('title', options.i18n.selectTip);
if (selected.length <= 0) {
$(easyTree).find(' > ul').append($(item));
} else if (selected.length > 1) {
$(easyTree).prepend(warningAlert);
$(easyTree).find('.alert .alert-content').text(options.i18n.addMultiple);
} else {
if ($(selected).hasClass('parent_li')) {
$(selected).find(' > ul').append(item);
} else {
$(selected).addClass('parent_li').find(' > span > span').addClass('glyphicon-folder-open').removeClass('glyphicon-file');
$(selected).append($('<ul></ul>')).find(' > ul').append(item);
}
}
$(createInput).find('input').val('');
if (options.selectable) {
$(item).find(' > span > a').attr('title', options.i18n.selectTip);
$(item).find(' > span > a').click(function (e) {
var li = $(this).parent().parent();
if (li.hasClass('li_selected')) {
$(this).attr('title', options.i18n.selectTip);
$(li).removeClass('li_selected');
}
else {
$(easyTree).find('li.li_selected').removeClass('li_selected');
$(this).attr('title', options.i18n.unselectTip);
$(li).addClass('li_selected');
}
if (options.deletable || options.editable || options.addable) {
var selected = getSelectedItems();
if (options.editable) {
if (selected.length <= 0 || selected.length > 1)
$(easyTree).find('.easy-tree-toolbar .edit > button').addClass('disabled');
else
$(easyTree).find('.easy-tree-toolbar .edit > button').removeClass('disabled');
}
if (options.deletable) {
if (selected.length <= 0 || selected.length > 1)
$(easyTree).find('.easy-tree-toolbar .remove > button').addClass('disabled');
else
$(easyTree).find('.easy-tree-toolbar .remove > button').removeClass('disabled');
}
}
e.stopPropagation();
});
}
$(createInput).remove();
});
$(createInput).find('.cancel').text(options.i18n.cancelButtonLabel);
$(createInput).find('.cancel').click(function () {
$(createInput).remove();
});
});
}
// editable
if (options.editable) {
$(easyTree).find('.easy-tree-toolbar').append('<div class="edit"><button class="btn btn-default btn-sm btn-primary disabled"><span class="glyphicon glyphicon-edit"></span></button></div> ');
$(easyTree).find('.easy-tree-toolbar .edit > button').attr('title', options.i18n.editTip).click(function () {
$(easyTree).find('input.easy-tree-editor').remove();
$(easyTree).find('li > span > a:hidden').show();
var selected = getSelectedItems();
if (selected.length <= 0) {
$(easyTree).prepend(warningAlert);
$(easyTree).find('.alert .alert-content').html(options.i18n.editNull);
}
else if (selected.length > 1) {
$(easyTree).prepend(warningAlert);
$(easyTree).find('.alert .alert-content').html(options.i18n.editMultiple);
}
else {
var value = $(selected).find(' > span > a').text();
$(selected).find(' > span > a').hide();
$(selected).find(' > span').append('<input type="text" class="easy-tree-editor">');
var editor = $(selected).find(' > span > input.easy-tree-editor');
$(editor).val(value);
$(editor).focus();
$(editor).keydown(function (e) {
if (e.which == 13) {
if ($(editor).val() !== '') {
$(selected).find(' > span > a').text($(editor).val());
$(editor).remove();
$(selected).find(' > span > a').show();
}
}
});
}
});
}
// deletable
if (options.deletable) {
$(easyTree).find('.easy-tree-toolbar').append('<div class="remove"><button class="btn btn-default btn-sm btn-danger disabled"><span class="glyphicon glyphicon-remove"></span></button></div> ');
$(easyTree).find('.easy-tree-toolbar .remove > button').attr('title', options.i18n.deleteTip).click(function () {
var selected = getSelectedItems();
if (selected.length <= 0) {
$(easyTree).prepend(warningAlert);
$(easyTree).find('.alert .alert-content').html(options.i18n.deleteNull);
} else {
$(easyTree).prepend(dangerAlert);
$(easyTree).find('.alert .alert-content').html(options.i18n.deleteConfirmation)
.append('<a style="margin-left: 10px;" class="btn btn-default btn-danger confirm"></a>')
.find('.confirm').html(options.i18n.confirmButtonLabel);
$(easyTree).find('.alert .alert-content .confirm').on('click', function () {
$(selected).find(' ul ').remove();
if($(selected).parent('ul').find(' > li').length <= 1) {
$(selected).parents('li').removeClass('parent_li').find(' > span > span').removeClass('glyphicon-folder-open').addClass('glyphicon-file');
$(selected).parent('ul').remove();
}
$(selected).remove();
$(dangerAlert).remove();
});
}
});
}
// collapse or expand
$(easyTree).delegate('li.parent_li > span', 'click', function (e) {
var children = $(this).parent('li.parent_li').find(' > ul > li');
if (children.is(':visible')) {
children.hide('fast');
$(this).attr('title', options.i18n.expandTip)
.find(' > span.glyphicon')
.addClass('glyphicon-folder-close')
.removeClass('glyphicon-folder-open');
} else {
children.show('fast');
$(this).attr('title', options.i18n.collapseTip)
.find(' > span.glyphicon')
.addClass('glyphicon-folder-open')
.removeClass('glyphicon-folder-close');
}
e.stopPropagation();
});
// selectable, only single select
if (options.selectable) {
$(easyTree).find('li > span > a').attr('title', options.i18n.selectTip);
$(easyTree).find('li > span > a').click(function (e) {
// var htmlTest = "<ul><li><img src='images/profile-icon-lrg.png'>Smith<br>Staff</li><li><img src='images/profile-icon-lrg.png'>LTaylor<br>Staff</li></ul>";
var li = $(this).parent().parent();
var userEmail=li.find('p').text();
LoadFurtherUserData(li,userEmail);
// alert(li.find('p').text());
// li.append(htmlTest);
if (li.hasClass('li_selected')) {
$(this).attr('title', options.i18n.selectTip);
$(li).removeClass('li_selected');
}
else {
$(easyTree).find('li.li_selected').removeClass('li_selected');
$(this).attr('title', options.i18n.unselectTip);
$(li).addClass('li_selected');
}
if (options.deletable || options.editable || options.addable) {
var selected = getSelectedItems();
if (options.editable) {
if (selected.length <= 0 || selected.length > 1)
$(easyTree).find('.easy-tree-toolbar .edit > button').addClass('disabled');
else
$(easyTree).find('.easy-tree-toolbar .edit > button').removeClass('disabled');
}
if (options.deletable) {
if (selected.length <= 0 || selected.length > 1)
$(easyTree).find('.easy-tree-toolbar .remove > button').addClass('disabled');
else
$(easyTree).find('.easy-tree-toolbar .remove > button').removeClass('disabled');
}
}
e.stopPropagation();
});
}
// Get selected items
var getSelectedItems = function () {
return $(easyTree).find('li.li_selected');
};
});
};
})(jQuery);
Below is the code of "OrgChart.js"
==========================================================
I have used a custom "orgchart.js" which used REST API to search the user profile details for the people.
=========================================================
var _userProfileData;
var userDetails= [];
var jobTitle='';
var displayName=''
var
picPath="https://{siteURL}/sites/intranet/_layouts/15/userphoto.aspx?size=S&accountname=";
var
defaultImage="https:// {siteURL}/sites/tatesit/Style%20Library/Images/profile-icon-lrg.png";
function UserProfileDataLoader(data,serviceName) {
var
firstName=data.split('@')[0];
var
emailPart=data.split('@')[1];
var requestHeaders
= { "accept": "application/json; odata=verbose" };
$.ajax({
url:
"https:// {siteURL}/sites/intranet/_api/sp.userprofiles.peoplemanager/getpropertiesfor%28@v%29?@v=%27i%3A0%23.f%7Cmembership%7C"+firstName+"%40"+emailPart+"%27",
contentType:
"application/json;odata=verbose",
method:
"GET",
headers:
requestHeaders,
success: function (data)
{
_userProfileData.orgData
= data;
if(serviceName=="SpecificEmailPersonalDetail")
{
_userProfileData.jobTitle=data.d.Title;
_userProfileData.displayName=data.d.DisplayName;
}
},
async: false,
error:
function (err) {
alert("error: " + JSON.stringify(err));
}
});
}
function RedirectToMyProfile(email)
{
var firstName=email.split('@')[0];
var
emailPart=email.split('@')[1];
var url="https://{tenancyName}-my.sharepoint.com/PersonImmersive.aspx?accountname=i%3A0%23.f%7Cmembership%7C"+firstName+"%40"+emailPart+"";
var win = window.open(url, '_blank');
win.focus()
//alert(window.open(path));
}
function LoadSpecificUserDetails(email)
{
UserProfileDataLoader(email,"SpecificEmailPersonalDetail");
}
function RenderMainUserData() {
var response=
_userProfileData.orgData; //Main Data results for the Department head
var
email=response.d.Email;
var
displayName=response.d.DisplayName;
var
JobTitle=response.d.Title;
var
department=response.d.UserProfileProperties.results[11].Value;
var htmlContent =
'<ul>';
var picName='';
//step1 Read the
Manager info of the User
$.each(response.d.ExtendedManagers.results,
function (i)
{
email=response.d.ExtendedManagers.results[i].split('|')[2]
LoadSpecificUserDetails(email);
//
picName=picPath+email.replace('.','_').replace('@','_').replace('.','_')+"_MThumb.jpg";
picName=picPath+email;
htmlContent+='<li><img
onclick=javascript:RedirectToMyProfile("'+email+'") src="'+picName+'"
alt="julia"
/>'+_userProfileData.displayName+'<br>'+_userProfileData.jobTitle+'';
});
//step2 Read the
unser details for which ORG chart is displayed
//picName=picPath+response.d.Email.replace('.','_').replace('@','_').replace('.','_')+"_MThumb.jpg";
picName=picPath+response.d.Email;
htmlContent+='<ul><li class="li_selected"><img
onclick=javascript:RedirectToMyProfile("'+response.d.Email+'")
src="'+picName+'">'+displayName+'<br>'+JobTitle+'';
//step3 Read the Users who directly reports to the
specified User
htmlContent+='<ul>'
$.each(response.d.DirectReports.results,
function (i)
{
email=response.d.DirectReports.results[i].split('|')[2]
LoadSpecificUserDetails(email);
// picName=picPath+email.replace('.','_').replace('@','_').replace('.','_')+"_MThumb.jpg";
picName=picPath+email;
htmlContent+='<li><img
onclick=javascript:RedirectToMyProfile("'+email+'")
src="'+picName+'">'+_userProfileData.displayName+'<br>'+_userProfileData.jobTitle+'
<br><p class="hide">'+email+'</></li>';
});
htmlContent+='</ul></li></ul>';
//Step 4 Read
Extended Reporters
//
$.each(response.d.ExtendedReports.results, function (i) {
//
email=response.d.ExtendedReports.results[i].split('|')[2]
//
LoadSpecifiUserDetails(email);
//htmlContent+='<div>'+_userProfileData.displayName+'</div><div
class=ExtendedReporters>'+_userProfileData.jobTitle+'</div>';//Reads
the users who reports to intended user. i.e Rebecca
//});
htmlContent+='</li></ul>';
$(".easy-tree").html(htmlContent);
_userProfileData.orgData='';
}
var UserProfileData= function () {
this.orgData =
'';
this.userSpecificDetails =[];
this.jobTitle='';
this.displayName='';
}
function
LoadFurtherUserData(selectedLi, userEmail)
{
var count =
(userEmail.match(/@/g) || []).length;
if(count==1)
{
UserProfileDataLoader(userEmail,"main")
var response=
_userProfileData.orgData;
var
htmlFurthereUsers="<ul>";
var itemCount=0;
$.each(response.d.DirectReports.results,
function (i)
{
itemCount=1;
email=response.d.DirectReports.results[i].split('|')[2]
LoadSpecificUserDetails(email);
picName=picPath+email;
htmlFurthereUsers+='<li><img
onclick=javascript:RedirectToMyProfile("'+email+'")
src="'+picName+'">'+_userProfileData.displayName+'<br>'+_userProfileData.jobTitle+'
<br><p class="hide">'+email+'</></li>';
});
htmlFurthereUsers+="</ul>";
if(itemCount==1)
{
selectedLi.append(htmlFurthereUsers);
_userProfileData.orgData='';
selectedLi.EasyTree({
addable: false,
editable: false,
deletable: false
});
selectedLi.addClass('parent_li')
}
}
// alert(userEmail);
}
$(document).ready(function ()
{
_userProfileData=
new UserProfileData();
if(sessionStorage.getItem('DataMain')==null)
{
UserProfileDataLoader("rebecca.watson@domain.com","main");
sessionStorage.setItem('DataMain', JSON.stringify(_userProfileData.orgData));
}
else
{
_userProfileData.orgData=
JSON.parse(sessionStorage.getItem('DataMain'));
}
RenderMainUserData();
//console.log(_userProfileData.orgData);
$('.easy-tree').EasyTree({
addable: true,
editable: true,
deletable: true
});
});
========================================================
HTML will contain a div with class name "easy-tree"
like <div class="easy-div"></div>
CSS file:
===========================================================
/** Easy Tree style */
.glyphicon-folder-open::before {
/* content: "‹";*/
content:url(images/down.png);
left: 63px;
margin: 5px;
position: absolute;
top: 47px;
width: 2%;}
.glyphicon-folder-close::before, .glyphicon-file::before {
/* content: "›";*/
content:url(images/up.png);
left: 63px;
margin: 5px;
position: absolute;
top: 47px;
width: 2%;
}
.ms-WPBorder {
border: 0 solid #c6c6c6;
}
.hide{
display:none;
}
.easy-tree {
min-height: 20px;
margin-bottom: 20px;
color: #fff;
border: none;
border-top: none;
padding-bottom: 15px;
}
.easy-tree ul {
margin-left: 2px;
margin-top: -3px;
padding: 0 0 0 30px !important;
}
.easy-tree li {
list-style-type: none;
margin: 0;
padding: 10px 5px 0 5px;
position: relative
}
.easy-tree li::before, .easy-tree li::after {
content: '';
left: -32px;
position: absolute;
right: auto
}
.easy-tree li::before {
border-left: 1px solid #01b6b1;
bottom: 50px;
height: 100%;
top: 0;
width: 1px
}
.easy-tree li::after {
border-top: 1px solid #01b6b1;
height: 20px;
top: 41px;
width: 47px;
}
.ms-WPBorder {
overflow: visible !important;
}
.easy-tree li > div{display:block!important;}
.easy-tree li > span {
display: inline-block;
padding: 5px;
text-decoration: none;
width: 100%;
}
.easy-tree li.parent_li > span {
cursor: pointer
}
.easy-tree > ul > li::before, .easy-tree > ul > li::after {
border: 0
}
.easy-tree li:last-child::before {
height: 42px
}
.easy-tree li.parent_li > span:hover, .easy-tree li.parent_li > span:hover + ul li span {
/* background: #fff;*/
/* color: #fff;*/
}
.glyphicon {
color: red;
}
.easy-tree li.parent_li > span:hover + ul li.li_selected span {
/* background: #fff;
color: #7a7a7a;*/
}
.easy-tree li > span > a {
color: #818181;
float: left;
font-family: trebuchet ms;
font-size: 11pt;
font-weight: bold;
padding: 0;
text-align: left;
text-decoration: none;
width: 96%;
}.easy-tree li > span > a > img {
border-radius: 50%;
float: left;
height: 50px;
margin-right: 10px;
width: 50px;
}
.easy-tree li > span > span.glyphicon-folder-close, .easy-tree li > span > span.glyphicon-folder-open {
margin-right: 5px;
}
.easy-tree li.li_selected > span, .easy-tree li.li_selected > span > a {
background: #01b6b1;
color: #fff;
}
.li_selected a{
color:#fff;
}
/*.easy-tree li.li_selected > span:hover {
background: #fafafa;
color: #ff6c60;
}*/
.easy-tree .easy-tree-toolbar {
background-color: #fff;display:none;
}
.easy-tree .easy-tree-toolbar > div {
display: inline-block;
}
.easy-tree .easy-tree-toolbar > div > button {
border-radius: 0;
margin: 20px 5px;
}
.easy-tree .easy-tree-toolbar .create .input-group {
top: -15px;
margin-left: 5px;
margin-right: 5px;
}
.easy-tree .easy-tree-toolbar .create .input-group input {
border-radius: 0;
}
.easy-tree .easy-tree-toolbar .create .input-group button {
border-radius: 0;
}
Note:
in above js file you have to replace the {SiteURL} and {domain} and {tenency} with you actual URL of the site.
In summary , you need to follow below steps to create org chart
1. Create "EasyTree.js"
2. Create "OrgChart.js"
3. Create "orgChart.css"
4. Replace all dynamic variables in OrgChart.js
5. Create div in HTML with class CSS
OrgChart.Js file uses the PeopleManager REST API of sharepoint 2013.
Thanks,
Sarvesh
No comments:
Post a Comment