Thursday, 22 November 2012

Fix for SharePoint 2010 scrolling problems for Chrome, iOS4 & Android



Fix for SharePoint 2010 scrolling problems for Chrome, iOS4 & Android


The other day a public facing website that had been built upon the SharePoint 2010 platform was experiencing some scrolling issues. After a date with Google and a few furrowed brows, I crafted a hybrid solution of my own that worked best for my particular scenario.

The Problem

Scrolling did not work when visiting the site using:
  • Google Chrome
  • An iPad or iPhone that was running iOS4
  • Google Android phones

The Solution

I was able to identify that the source of these scrolling issues was due to the manner in which the static placement of the SharePoint 2010 “Ribbon” was implemented. Essentially the default browser scrolling behaviour has been overridden and replaced with a JavaScript solution that has a few problems. While I appreciate the improved authoring experience that the static ribbon provides for content authors, it serves no purpose for anonymous visitors to the site.
Below is what I did to hide the ribbon control, and override the JavaScript scroll bar if you are an anonymous visitor.
Let’s just jump right in, shall we?
Psst…If you don’t care about the “why?” and just want the final solution go ahead and download my updated v4.master.

Step 1: Right above the closing head tag you want to place the following LoginView snippet.

Why? Because we want to override the body.v4master { overflow: hidden; } default SharePoint declaration but only for anonymous users.
01<asp:LoginView id="LoginView" runat="server">
02     <AnonymousTemplate>
03          <style type="text/css">
04               body.v4master { overflow:auto; }
05          </style>
06     </AnonymousTemplate>
07</asp:LoginView>

Step 2: Remove that pesky scroll=”no” on the body tag.

Why? Because if we don’t then we will not be able to scroll on IE7.
Look for this:
01<body scroll="no" onload="if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();"class="v4master">
And replace with this:
01<body onload="if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();"class="v4master">

Step 3: Hide the Ribbon Control so it only appear when the user has the ability to add or remove personal Web Parts on a Web Part Page.

Why? I do not want the ribbon control to load unless the user is logged in. I tried using the AnonymousTemplate logic above but it created some other issues which will be a follow up post.
Security Trimmed Control, Permissions … What? Yeah I thought the same thing the first time I discovered this control. You can read more about the different built-in permissions available in SharePoint Foundation over here: SPBasePermissions Enumeration. It’s worth your time to take a look.
Look for the id=”s4-ribbonrow” and include the SharePoint:SPSecurityTrimmedControl above it:
01<Sharepoint:SPSecurityTrimmedControl runat="server" Permissions="AddDelPrivateWebParts">
02     <div id="s4-ribbonrow" class="s4-pr s4-ribbonrowhidetitle">
03          <div id="s4-ribboncont">
Now to close the tag look for the closing #s4-ribbonrow div tag, and add the closing SharePoint:SPSecurityTrimmedControl tag.
01                    <Triggers>
02                         <asp:PostBackTrigger ControlID="WebPartAdder" />
03                    </Triggers>
04               </asp:UpdatePanel>
05          </div>
06     </div>
07</SharePoint:SPSecurityTrimmedControl>

Step 4: Only display the the #s4-workspace div if the user is logged in.

Why? Because through JavaScript SharePoint adds an inline height and width to this div that is then referenced in their scrollbar JavaScript code. In my solution I did not need, or want it, for Anonymous visitors.
NOTE: The opening and close #s4-workspace divs will now appear yellow because the MasterPage will not be able to see that they are in fact matching tags. Do not worry though because once the page renders for the visitor, everything will work just fine.
Search for div that has id=”s4-workspace” and replace it with the code below.
01<asp:LoginView runat="server">
02     <LoggedInTemplate>
03          <div id="s4-workspace">
04     </LoggedInTemplate>
05</asp:LoginView>
Search for the closing #s4-workspace div and replace it with the code below.
01<asp:LoginView runat="server">
02     <LoggedInTemplate>
03          </div>
04     </LoggedInTemplate>
05</asp:LoginView>

Step 5: Download my updated v4.master with all the changes described above.

Caveats

While this solution worked for my scenario, I obviously can not promise it will work for you. I did notice one issue of a double scroll bar if a content author accessed the the site using IE7. This particular authoring scenario was not a requirement and the client agreed it was an acceptable trade off.

Friday, 16 November 2012

jQuery Selectors


jQuery - Selectors

Following table lists down few basic selectors and explains them with examples.
SelectorDescription
NameSelects all elements which match with the given elementName.
#IDSelects a single element which matches with the givenID
.ClassSelects all elements which match with the given Class.
Universal (*)Selects all elements available in a DOM.
Multiple Elements E, F, GSelects the combined results of all the specified selectors E, F or G.
Similar to above syntax and examples, following examples would give you understanding on using different type of other useful selectors:
  • $('*'): This selector selects all elements in the document.
  • $("p > *"): This selector selects all elements that are children of a paragraph element.
  • $("#specialID"): This selector function gets the element with id="specialID".
  • $(".specialClass"): This selector gets all the elements that have the class ofspecialClass.
  • $("li:not(.myclass)"): Selects all elements matched by <li> that do not have class="myclass".
  • $("a#specialID.specialClass"): This selector matches links with an id of specialID and a class of specialClass.
  • $("p a.specialClass"): This selector matches links with a class of specialClass declared within <p> elements.
  • $("ul li:first"): This selector gets only the first <li> element of the <ul>.
  • $("#container p"): Selects all elements matched by <p> that are descendants of an element that has an id of container.
  • $("li > ul"): Selects all elements matched by <ul> that are children of an element matched by <li>
  • $("strong + em"): Selects all elements matched by <em> that immediately follow a sibling element matched by <strong>.
  • $("p ~ ul"): Selects all elements matched by <ul> that follow a sibling element matched by <p>.
  • $("code, em, strong"): Selects all elements matched by <code> or <em> or <strong>.
  • $("p strong, .myclass"): Selects all elements matched by <strong> that are descendants of an element matched by <p> as well as all elements that have a class ofmyclass.
  • $(":empty"): Selects all elements that have no children.
  • $("p:empty"): Selects all elements matched by <p> that have no children.
  • $("div[p]"): Selects all elements matched by <div> that contain an element matched by <p>.
  • $("p[.myclass]"): Selects all elements matched by <p> that contain an element with a class of myclass.
  • $("a[@rel]"): Selects all elements matched by <a> that have a rel attribute.
  • $("input[@name=myname]"): Selects all elements matched by <input> that have a name value exactly equal to myname.
  • $("input[@name^=myname]"): Selects all elements matched by <input> that have a name value beginning with myname.
  • $("a[@rel$=self]"): Selects all elements matched by <p> that have a class value ending with bar
  • $("a[@href*=domain.com]"): Selects all elements matched by <a> that have an href value containing domain.com.
  • $("li:even"): Selects all elements matched by <li> that have an even index value.
  • $("tr:odd"): Selects all elements matched by <tr> that have an odd index value.
  • $("li:first"): Selects the first <li> element.
  • $("li:last"): Selects the last <li> element.
  • $("li:visible"): Selects all elements matched by <li> that are visible.
  • $("li:hidden"): Selects all elements matched by <li> that are hidden.
  • $(":radio"): Selects all radio buttons in the form.
  • $(":checked"): Selects all checked boxex in the form.
  • $(":input"): Selects only form elements (input, select, textarea, button).
  • $(":text"): Selects only text elements (input[type=text]).
  • $("li:eq(2)"): Selects the third <li> element
  • $("li:eq(4)"): Selects the fifth <li> element
  • $("li:lt(2)"): Selects all elements matched by <li> element before the third one; in other words, the first two <li> elements.
  • $("p:lt(3)"): selects all elements matched by <p> elements before the fourth one; in other words the first three <p> elements.
  • $("li:gt(1)"): Selects all elements matched by <li> after the second one.
  • $("p:gt(2)"): Selects all elements matched by <p> after the third one.
  • $("div/p"): Selects all elements matched by <p> that are children of an element matched by <div>.
  • $("div//code"): Selects all elements matched by <code>that are descendants of an element matched by <div>.
  • $("//p//a"): Selects all elements matched by <a> that are descendants of an element matched by <p>
  • $("li:first-child"): Selects all elements matched by <li> that are the first child of their parent.
  • $("li:last-child"): Selects all elements matched by <li> that are the last child of their parent.
  • $(":parent"): Selects all elements that are the parent of another element, including text.
  • $("li:contains(second)"): Selects all elements matched by <li> that contain the text second.