Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Friday, September 18, 2015

Collapsible Current Navigation in SharePoint...and my new job

Big news in the beginning of this week. No, I'm not back to school :) I recently accepted a new job as an internal SharePoin employee for a company which is not yet an enterprise, but not a startup either. It will be very different than all of my past experience at service providers and consultancy engagements, but I am excited as it's a very innovative organization and we met when it's just about time for some SharePoint(ing).

Now to the point... one of my first tasks is to create the organization's navigation structure for an Intranet portal. We will use Managed Navigation after an evaluation and demos of all the possible methods. I will do this on SharePoint Online for the example, but the method is the same for SharePoint 2013 as well.

The decision to use Managed Navigation is not the scope of this post, a very good comparison by Microsoft is published here, which evaluates performance, needs and in fact all pros and cons.

One of the main requirements is for the Current Navigation to become collapsible, imagine a Windows Explorer style...like the following example. Now, if you have users that will be switching from file shares to SharePoint, that type of navigation might come handy. I personally don't really like the fact that it does go very big when you expand a lot of nodes, but there's a solution for that.

If the SharePoint site structure becomes deeply nested e.g. Site Collection -> Site -> Site -> Site ... this will also be a pain to navigate in, and most users would most likely prefer the Search option (I got this feedback after conducting a few user interviews and demoing this type of navigation).



Let's review the options to achieve the closest functionality in the SharePoint Current Navigation.
We assume we'll only have one site collection, which is nowadays common for small to medium sized organizations. Especially if you go the SharePoint Online route.

Option 1: Tree View

The way to enable this is simply going to Site Settings -> Tree View -> Enable Tree View.



The Tree View looks like this in a site collection (left) and respectively in a site (right):


Now, I'll share my view, based on experience around this functionality.

Pros:

- Sites are automatically added, no admin overhead
- OOB solution. No custom master page need, hence sticking to the Office 365 best practices.
- Displays lists and libraries in addition to the sites
- Easy to use, nice icons on the left, indicating the type of each node - that's all OOB again.

Cons:

- NOT security trimmed!
- Displays the Apps (add-ins) as well, no way to hide those. The regular user might not need them.
- Can take a large part of your screen and becomes unusable if you need too much scrolling
- Enabled per site level only, e.g. you need to save your site as a template and create new sites based on that if you need Tree View enabled by default
- NOT consistent accross sites. E.g. does not show the parent navigation when you're in subsites. 
- NO way to customize it OOB, needs custom CSS (not a big deal, you still don't need to modify the master page for that and the OOB view might suit you just fine in some scenarios.)


Option 2: Managed Navigation + custom CSS

The Managed Navigation requires some planning, manual work and a lot more maintenance then the Tree View. The way to enable it will be out of the scope of this post, but just don't forget to enable the Publishing feature on your sites before you switch to this navigation. It's a prerequisite. 

The way it looks in a very quick and simple demo is this:


But it's not collapsible by default!... Even though there are some articles online suggesting the use of fly-out menu I personally didn't feel it's good enough (e.g. a lot of levels will take a lot of space oon the right of the designated navigation menu control)

There's another solution which uses jQuery and provides the "accordion" feeling. But this will generally work if your items that you want to expand don't have a hyperlink. E.g. if in the above screenshot Operations doesn't point anywhere, then it would make sense to expand it with a click and see its children. But in our scenario the 1st level items would be links to actual sites...the solution still works... but in order to expand the children, you'd need to wait for the parent link to load. Not good, could be annoying for users and the link might point you to a site which doesn't inherit the same navigation. 

So... to just quickly review the Managed Navigation against Structured Navigation and the alternative Tree View option... read further.

Pros:

- Consistent across all sites if you inherit navigation in the subsites
- Very good for public sites or extranets, where you don't want it to definitely reflect your site structure.
- Better performance than the structured navigation
- More compact than the Tree View and very good looking when customized

Cons:

- Sites are not automatically added, it requires some maintenance
- Not security trimmed.
- Not collapsible OOB for use in Current Navigation. Needs custom CSS and potentially JavaScript.
- By default it's set to display only 2 levels of hierarchy - e.g. Projects site -> Project X subsite. If you want to display libraries and lists for example, or anything else... you need to touch the master page.

Now on the collapsing functionality... you can achieve that by using some simple css. Take the example a few lines below and save it somewhere on your SharePoint site. For the demo I've used a file, called sideNavBox.css and I've put it in the Style Library.

I got the original idea from Dércia Silva at broculus, but that solution seems to work well only for small navigation structures. I don't see it working with more than 2 levels and it requires you to click on a menu item (e.g. a site) to see its children.By default SharePoint will load the site if there's a valid link behind the navigation menu item. Not too good, you might have clicked on it by mistake, and you might not want to wait the load time (imagine it's a heavily customized site).  It also uses jQuery, while I think this functionality can be achieved by CSS only. 

So I decided to use the :hover pseudo selector instead of the .selected class to address the need for the click issue.

/* Do not show nested ul by default */
#sideNavBox .ms-core-listMenu-verticalBox ul ul {
 display: none; !important
}

/* Show nested ul on hover only */
#sideNavBox .ms-core-listMenu-verticalBox ul li:hover ul {
 display: block; !important
}


Now you need to refer your site to the custom CSS file. Go to Site Settings -> Master Page -> Alternate CSS URL (preferred solution): 



...or if for some reason you can't do the above, then as a last resort insert it in a custom Master Page directly by putting this line in the <head>. (change the path to your CSS). Please have in mind that custom Master Pages  in SharePoint Online should be used if no other customization option exist. The reason behind this is that you''ll end up not getting regular updates on master page functionalities released by Microsoft (they only deploy these to the oslo and seattle master pages).

If you're interested in the way Office 365 Sites branding is going forward, I recommend this great explanatory session by Vesa Juvonen. Then you can decide... to brand... or not to brand :) 

If you do decide to ignore the recommendations, here's the control you need to insert in your master page...

 <SharePoint:CssRegistration Name="Style%20Library/en-us/Themable/sideNavBox.css" runat="server" />

So, with the hovering trick and some more customizations I've added the nav menu looks like this. Currently I am hovering over the PMO link which is a site in a site collection (could be anything) and Project 1/2/3 are sites under PMO (again could be anything you add in the Managed Navigation through the term store management tool)

The extra styling is just for some similarity to the Tree View menu (the icon is a shameless steal from there)...  The "Edit Links" item is hidden and colors/sizes are slightly changed. Some cheeky icons added on the left to make it look more intuitive, too. Pretty  basic for the means of our example today:



Here's the additional CSS I applied:


/* Any style you want for the left-hand nav control*/
#sideNavBox {
background-color: #DBE8F3;
}

/* Making some room for the icons on the left */
.ms-core-sideNavBox-removeLeftMargin {
margin-left: 5px; !important
}

/* Insert the plus icon for the ul */
#sideNavBox  ul {
list-style-image: url('/Style%20Library/Images/Expand_01.gif'); !important
}

/* SP treeview expand icon for the nested ul */
#sideNavBox  ul li ul{
list-style-image: url('/_layouts/15/images/tvclosed.png'); !important
}


/* Hide the Edit Links button in the current nav */

.ms-listMenu-editLink {
 display: none; !important
}

And now to the levels... we have the requirement to display more than the two level of hierarchy on the screenshot above. Now if you get to this, and you definitely want to use Current Navigation (rather than Global Navigation) for this (regardless of the fact if you use Structured or Managed Nav in the background) then you need to edit your Master Page e.g. use a custom Master Page in SPO.

So, in a bit more details:

1. Create a blank master page
2. Open your seattle master page and copy all the code to the new one.
3. Go to the V4QuickLaunchMenu control.

       <SharePoint:AspMenu id="V4QuickLaunchMenu" runat="server" EnableViewState="false" DataSourceId="QuickLaunchSiteMap" UseSimpleRendering="true" Orientation="Vertical" StaticDisplayLevels="3" AdjustForShowStartingNode="true" MaximumDynamicDisplayLevels="0" SkipLinkText="" />

To properly achieve your goals, you might need a bit of clarifications on this above piece of code.

StaticDisplayLevels are the hierarchical items that will show in the navigation control. You would imagine that this solution will work like a charm and display the navigation representing the term store hierarchy. The problem is, if you increase that to 4, for example, you'll get this due to the lack of space in the OOB control. To visualize what I mean I've shown a small part of the term store managed navigation and the way it was represented after I've increased the StaticDisplayLevels.

So the expectation would be to see the same structure as on the left hand-side.
 ... but the reality is different: 

Let's look at the solution for this:

MaximumDynamicDisplayLevels are the hierarchical items that will show outside of the control.
Increasing that number will give you the items, but outside of the Quick Launch menu. Not too bad.
This functionality works OOB in the Global Navigation, so it's a good idea to consider that as well.


So... just a slight tuning here, in order to achieve the same styling as on the regular list items, I've had to apply the below CSS (not needed if you didn't use custom styling for this at all).

/* customize the dynamic ul */
#sideNavBox .ms-core-listMenu-verticalBox .dynamic {
 background-color: #DBE8F3; !important

}


That's it folks, hope you enjoy your new collapsible current navigation. If not, you can always switch to the Global Managed Navigation - it will collapse by default, it kind of uses the space on the screen in a more rational way and could be customized to the same extent. It's the user preference -horizontal or vertical menus... you could even go for the trendy mega menus in the Global Navigation (more suitable for public websites in my personal opinion anyway).

Wednesday, December 3, 2014

How to change the opening behavior of Calendar items in a Calendar Overlay view

Today I've had another interesting requirement to change the behavior of a SharePoint 2010 calendar, which was built using the Calendar Overlay view to address the need of multiple departments to be able to view all events in the organization. Each department was set with their own calendar, so the quickest choice was to use the Calendar Overlay view. That is quite limited, by the way, but that's a whole different story. You can't have more than 10 calendars and more than 9 different colors assigned to the calendars. You can, however easily customize the colors to your own choice. The final results looks like that:




Now, the user story is they find it annoying that whenever they click on a calendar item, it always loads in a new tab and when they click the "Close" button on it, it leaves the overlay view on the screen and that makes one additional tab open in their  browser.

No out-of-the-box way to change that unfortunately, but everything's possible with a little JavaScipt / jQuery - that will do the exact trick - it'll make the events load in a pop-up window in the same tab:

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
_spBodyOnLoadFunctionNames.push('calendarEventLinkIntercept');

function calendarEventLinkIntercept()
{
if (SP.UI.ApplicationPages.CalendarNotify.$4a)
  {
    var OldCalendarNotify = SP.UI.ApplicationPages.CalendarNotify.$4a;
    SP.UI.ApplicationPages.CalendarNotify.$4a = function () 
      {
        OldCalendarNotify();
        bindEventClickHandler();
      }
  }
  if (SP.UI.ApplicationPages.CalendarNotify.$4b)
  {
    var OldCalendarNotify = SP.UI.ApplicationPages.CalendarNotify.$4b;
    SP.UI.ApplicationPages.CalendarNotify.$4b =  function () 
      {
        OldCalendarNotify();
        bindEventClickHandler();

      }  
  }
}

function bindEventClickHandler() {
$('.ms-acal-rootdiv a').click(function(){EditLink2(this,'WPQ2');return false;});
}
</script>

Add that in a Content Editor Web part on your Calendar list overlay page and you're done.
The tricky bit: This only addresses the opening behavior when the user clicks on an item title. If they double click on the calendar field, the event still loads in a new window. I think that's also possible to change, but not worth the effort in researching and developing.

Tuesday, December 2, 2014

JavaScript / jQuery not loading in a site with SSL

This is quite related to the previous post, but decided to split it as some people might just have the generic issue of JavaScript not kicking in on their SharePoint sites... when they use jQuery and SSL :)

The issue might be very simple, and usually the first thing to do when your script is not loading is to see how the Developer Tools look like in your browser. When you use SSL and refer to the jQuery library in a JavaScript, make sure you use the https:// prefix, otherwise your script won't load at all and you'll end up with the error below and maybe an error displayed in the browser saying "Only secure content is displayed", depending on which browser you use and its settings.


You can of course workaround this in the browser itself by doing the following (example for IE) but I strongly recommend doing it the right way in your script in the first instance so you don't have to mess with end-user settings at all. Use this workaround for testing purposes only.

Tools -> Internet Options -> Security, Custom level -> Scroll to: Display mixed content -> Enable -> OK -> Restart IE.

Usually the best practice is to store jQuery locally in the SharePoint farm (in a library for example) and then refer to it in your script. That way you ensure the protocol will be consistent between the site and the location of jQuery.

How to change the Web Part Title URL behavior

With my morning cup of coffee I decided to start with something fairly simple (as a requirement) - it's in fact quite fresh as I had to do it for a client yesterday. It sounded like a 5 minute job, at the end it turned out more interesting. I've done this on 2010 and tested on 2013 as well - same behavior.

The requirement is to make just one specific webpart title URL to open in a new window while keeping all others (if any) loading in the same browser window. I am referring to the "Title URL" property, that is set in the Advanced section when you edit the web part.


There's no out of the box option to configure that, you could remove the URL, or point it to the page itself by changing it to #, but no way to make it open in a new window by adding "_blank" or something.

We can, however use a tiny piece of JavaScript to achieve that (tell SharePoint to do a specific thing when someone clicks on a specific URL) and we have a couple of options doing that thanks to jQuery.

Depending on whether that webpart is reused in many sites or web apps, you need to decide which method is the right one for you, You can do it globally with a full trust solution. That would have a wide impact on all web apps that have the solution deployed.
Let's assume you already have some branding solution in place which has a ccustomizations file in a .js format, you can add that piece of code in there. We are using the onload function here to ensure the site has fully loaded. If you have other JavaScript / jQuery customizations in the site that's the preferred method of calling jQuery to avoid any conflicts. The downside is that it will load only after all images are fully loaded, including some banner ads, etc.

In those example scripts I'm using the Microsoft CDN hosted version of the jQuery library, you can, however download a copy and store it locally on your site. Please make sure you use the https:// prefix in the reference if your site is accessed through SSL.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
window.onload = function() {
    if (window.jQuery) {
        jQuery(document).ready(function () {
                                jQuery('a[href^="http://www.contoso.com (replace with your URL)"]').click(function () {
                                jQuery(this).attr("target", "_blank");
                                });

                });
 </script>

The second way (more granular) is to store the script as a .js file in SharePoint and apply that on the page level by using the Content Editor webpart to call it. Here we're using the statement known as the ready event. This ensures that the code will run as soon as the document is ready for manipulation. Preferred method if we don't experience any conflicts with other customizations when trying to load it that way. Executes straight away without loading all the images first.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
$(document).ready(function(){
  $('a[href^="http://www.contoso.com (replace with your URL)"]').click(function() {
    $(this).attr("target","_blank");
  });
});
 </script>

You can also do that for all web part title URLs, the script will look like this:

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
$(document).ready(function(){
$("h3.ms-WPTitle a").attr("target","_blank");
 });
 </script>

That's it. You can then export/import your CEWP and reuse it on any other page quickly. Don't forget to set its Chrome type to None so you don't actually display it on the web page.