• Using jQuery to add a new item to the breadcrumbs at the top of a SharePoint 2010 site.

    I wanted to add a bread crumb item to a sub site that pointed back to the home page. This is the jQuery code I used to insert it. This code also aadds the little arrow divider

    
    var NavItem ='<a id="ctl00_PlaceHolderSiteName_onetidProjectPropertyTitle" href="/">Home</a>'
    
    NavItem = NavItem + '<span id="onetidPageTitleSeparator" class="s4-nothome s4-bcsep s4-titlesep"><span><span style="height:11px;width:11px;position:relative;display:inline-block;overflow:hidden;"><img src="/_layouts/images/fgimg.png" alt=":" style="border-width:0px;position:absolute;left:-0px !important;top:-585px !important;" /></span></span> </span>'
    
    $(".s4-titletext h1").prepend(NavItem)
    
    

  • Event calendar I used in my SharePoint 2010 intranet

    This is more of a note for myself, but I thought I would post it anyway, since it my be useful to someone. I used the following event calendar on the front page of my intranet. Small, clean, worked well:

    Event-Calendar-Listing-Web-Part-SharePoint-2010


  • PowerShell 3 – Invoke-WebRequest and Invoke-RestMethod, unable to set the Accept header?

    With both of these commands, when I try to add an Accept header (I want to receive my CRM 2011 data in JSON format, so I need Accept=application/json) I receive the error:

    “This header must be modified using the appropriate property or method.”

    I think this is a bug. This link shows the bug, and I agree that the workaround does not apply


  • PowerShell 3: Invoke-WebRequest vs Invoke-RestMethod and a SharePoint 2010 list with more than 1000 entries

    When using Invoke-RestMethod with a SharePoint 2010 list and ListData.svc, it returns an “System.Xml.XmlElement#http://www.w3.org/2005/Atom#entry” object. Not sure why, but the end result is that you can’t get access to the “rel=next” url, or am I doing something wrong?

    $Results=Invoke-RestMethod -uri $ListUrl -UseDefaultCredentials
    $Results | gm 
    TypeName: System.Xml.XmlElement#http://www.w3.org/2005/Atom#entry
    

    I had to use Invoke-WebRequest and then take the Content and put it in an XML variable, only then could I get to the next page of items.

    $MailingLabels = Invoke-WebRequest -Uri $ListUrl -UseDefaultCredentials
    $Next =  ($MailingLabelsXML.feed.link | ?{$_.rel -eq "next"}).href
    

    Thoughts?


  • SharePoint 2010 modal dialog (showModalDialog) without an existing page

    I was retrieving Activity data from a Microsoft CRM 2011 REST query. I wanted to have a popup with more information. I decided to use the built in showModalDialog. The problem was that all the examples I found showed how to popup an existing page. I wanted the modal to contain data that didn’t exist anywhere. The solution was to use the following code, specifically create a divElement and set the innerHTML to html that contained the data I want to show. I threw in some typical SharePoint css classes to keep the same look and feel as the rest of the site.

        displayActivityModalDialog = function () {
            var divElem = document.createElement('div');
            var htmlOutput = '<div class="ms-bodyareacell"><table>'
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Type:</td><td class="ms-formbody">' + this.ActivityType + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Subject:</td><td class="ms-formbody">' + this.Subject + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Date:</td><td class="ms-formbody">' + this.ScheduledStart + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Regarding:</td><td class="ms-formbody">' + this.Regarding + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Organizer:</td><td class="ms-formbody">' + this.Organizer + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Description:</td><td class="ms-formbody">' + this.Description + '</td></tr>';
            htmlOutput += '<tr><td width="190" class="ms-formlabel">Other Attendees:</td><td class="ms-formbody">' + this.RequiredAttendee + '</td></tr>';
            htmlOutput += '</table></div>'
    
            divElem.innerHTML = htmlOutput;
            var options = SP.UI.$create_DialogOptions();
            options.html = divElem;
            options.title = "Activity details";
            options.showClose = true;
            options.showMaximized = false;
            SP.UI.ModalDialog.showModalDialog(options);
        }
    

    Now I can put anything in a showModalDialog!


  • SharePoint 2010, CSOM and External Lists – must use LoadQuery

    I was working on some JavaScript code to pull data from an External List that was pointing to a Microsoft CRM 2011 database. The code was being used to populate a jQuery autocomplete like this post. In that post you can see on line 10, I use the “load” method. This worked, but if I started a new query before the previous one ended, a javascript error was thrown. I am sorry I don’t recall the error – I am blogging this a month or so after I figured it out.

    It took me a while, but I found one reference to figure out the issue. It is on page 143 of Scott Hillier’s book “Professional Business Connectivity Services in SharePoint 2010” (I found it via the google query “loadquery external list”)

    The work around was that you have to use LoadQuery with External lists, Load is not supported. Not sure where this is documented, but it took me quite a while to figure that one out.

    Hope that helps some one?


  • Using Nivo slider, knockout.js and SharePoint CSOM to create an announcements Slider

    I wanted to create a slider that contains images and items from an announcements in my SharePoint 2010 home page. I started writing my own slider, but realized I was just re-creating the wheel. I ended up finding Nivo Slider. It seemed well supported and clean, so I went with that as my jQuery slider. Let’s dive into the code:

    First, here is the HTML code I put on the home page. I just added a CEWP and linked it to a text file in a document library. This is the contents of the text file:

    <div class="slider-wrapper theme-default">
        <div id="slider" class="nivoSlider">
            <img src="/PhotoLibrary/cityscape1.jpg" title="#htmlcaption" />
            <img src="/PhotoLibrary/cityscape2.jpg" title="#htmlcaption" />
            <img src="/PhotoLibrary/cityscape3.jpg" title="#htmlcaption" />
            <img src="/PhotoLibrary/cityscape4.jpg" title="#htmlcaption" />
        </div>
        <div id="htmlcaption" class="nivo-html-caption">
    	<span data-bind="html: sliderCurrentTitle" style="font-weight:bold;text-decoration:underline;"></span>
    	<span data-bind="html: sliderCurrentSummary" ></span>
        </div>
    </div>
    

    This interesting parts are lines 9 & 10. I set these two spans to Knockout observable arrays. When the slide changes, I am going to update the contents of these values

    And here is the JavaScript document.ready code. Explanation of the code is below the block.

    $(document).ready(function () {
        $('#slider').nivoSlider({
            effect: 'sliceDownRight',
            pauseTime: 4000,
            beforeChange: function () {
                VM.sliderNextItem()
            }
        });
    ko.applyBindings(VM);
    VM.sliderRetrieveAnnouncments();
    var VM = new viewModel();
    })
    

    Lines 2-8: are the settings for the Nivo Slider.
    Line 6: This is the most important part of this part of the code. This calls the function for get the next announcement when the slide changes.
    Line 10: This line calls the function that initially loads all the announcements into a JavaScript object.

    Here is the code to my Knockout View Model (explanations below):

    function viewModel() {
        var self = this;
        self.sliderAnnouncement = function (title, summary) {
            this.title = title;
            this.summary = summary;
        }
        self.sliderAllAnnouncments = ko.observableArray();
        self.sliderCurrentTitle = ko.observable();
        self.sliderCurrentSummary = ko.observable()
        self.sliderCurrentItemIndex = 0
        self.sliderNextItem = function () {
            self.sliderCurrentTitle(self.sliderAllAnnouncments()[self.sliderCurrentItemIndex].title)
            self.sliderCurrentSummary(self.sliderAllAnnouncments()[self.sliderCurrentItemIndex].summary)
            self.sliderCurrentItemIndex++
            if (self.sliderCurrentItemIndex > self.sliderAllAnnouncments().length - 1) {
                self.sliderCurrentItemIndex = 0
            }
        }
        self.sliderRetrieveAnnouncments = function () {
            var clientContext = SP.ClientContext.get_current();
            var oList = clientContext.get_web().get_lists().getByTitle('Announcements');
            var camlQuery = new SP.CamlQuery();
            camlQuery.set_viewXml("<View><Query><Where><And><IsNotNull><FieldRef Name='Title' /></IsNotNull><Gt><FieldRef Name='Expires' /><Value Type='DateTime'><Today/></Value></Gt></And></Where><OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy></Query></View>");
            var collListItem = oList.getItems(camlQuery);
            clientContext.load(collListItem);
            clientContext.executeQueryAsync(
    	    	Function.createDelegate(this, function () {
    	    	    var listItemInfo = '';
    	    	    var listItemEnumerator = collListItem.getEnumerator();
    	    	    while (listItemEnumerator.moveNext()) {
    	    	        var oListItem = listItemEnumerator.get_current();
    	    	        listItemInfo +=
    					'\n' + oListItem.get_item('Title') +
    			    	'\n' + oListItem.get_item('Summary');
    	    	        self.sliderAllAnnouncments.push(new self.sliderAnnouncement(oListItem.get_item('Title'), oListItem.get_item('Summary')));
    	    	    }
    	    	    self.sliderNextItem()
    	    	}),
    	    	Function.createDelegate(this, function () { alert('There was an error - sliderRetrieveAnnouncments') }));
        }
    }
    

    Lines 3-6 this is the announcement object that I will use to hold the info of a single announcement
    Lines 7-9: this is the observable items that are displayed on the slider that contain the announcement’s title and summary
    Line 10: this is the index of the current announcement that is being displayed. All I am doing is incrementing it with the NextItem function
    Lines 11-18: This is fired when the slide changes (a builtin hook of the Nivo slider). Once it has changed the item, it increments for the next slide.
    Lines 19-40: This is the CSOM query to retrieve all the items from the announcement list that have not expired.
    Line 23: This is CAML query to get the items that have not expired.
    Line 26: This line makes the query.
    Lines 30-36: This code loops through the successful returned items.
    Line 35: This line puts each of the items into observable array that is used to house all the announcements.

    I hope this is helpful to some one. I have been pretty happy with the outcome.

    Update: I saw this slider in action at SharePoint conference: http://corporatenewsapp.codeplex.com/
    Looked pretty sweet. May have to try to backport to SharePoint 2010.


  • Problems with SharePoint 2010 menus and javascript using a Cisco WebVPN (ASA)

    We noticed that the SharePoint 2010 menus were not working with our Cisco ASA’s WebVPN. If the top level menu had children, they would not show on hover. Then we started noticing that all jQuery based functions stopped working. It seemed that much of the Javascript used with SharePoint 2010 would not work with our ASA. The fix was to add this to the web.config for the SharePoint site:

     <system.web.extensions>
         <scripting>
               <scriptResourceHandler enableCompression="false" enableCaching="true" />
         </scripting>
    </system.web.extensions>
    

    Obviously you are adding the scriptResourceHandler to an exiting scripting section and not replacing what is already there.