Open PDF files from a Document Library in a New Window


Update: 10th June 2012

A few people have posted comments about the script not working for SharePoint 2010. This code was built for SharePoint 2007. However I have been through the code and an updated version can be found below.

Apologies that it has taken a while to respond.

The SharePoint 2010 Code version works slightly differently and uses the jQuery Live method and JavaScript OnMouseOver event to update the PDF’s a tags.

Introduction

One of our clients wanted a way to ensure that Adobe PDF’s did not open in the current browser window.

By default a PDF opened into Adobe Acrobat will open in the current browser window.

This presents a usability problem as user’s lose the reference to the site they were in also other applications, such as Word and Excel, do not behave in this way.

How Acrobat opens a document is controlled within the Acrobat client. Unfortunately to change this through a mechanism such as Group Policy is not a simple task and hence did not meet their timescales.

Just so you know, Acrobat’s PDF browser behaviour is adjusted here :-

  • Open Acrobat Reader (C:\Program Files (x86)\Adobe\Reader 10.0\Reader\acrord32.exe)
  • Click Edit->;;Preferences
  • Choose Internet (down the left-hand side)
  • Unselect “Display PDF in Browser”
  • Click OK

acrobat-browsersetting

;

Unfortunately this was not possible for the client, so I started to look at alternative solutions. First thing is that the client wanted something that was quick (the fix was required in a day) as they had committed to launching the internal site quickly. The requirement was for a single page and therefore the solution did not need to scale.

The idea that I came up with was to use jQuery to find the PDF hyperlinks on the page and then add a target attribute with a value of “_new”.

This was pretty straightforward and using a content editor web part the JavaScript was quickly added to the page to prove the approach.

simpleopeninnewwindowjscode

;

Of course its never as simple as that and when this approach was tried then it worked well for a standard document library but the page had views that were grouping content by certain columns and the jQuery could not find the ; link to bind to.

When the grouping function is used on a view then the content within a group is lazy loaded using JavaScript functions within the init.js SharePoint library. So therefore the jQuery will not find the ; tags because they don’t exist yet.

One option I thought of was to try and run the code as late as possible. So I starting to look into how SharePoint JavaScript function were called. One thing I had noticed was how the content within a group was loaded in after the document had loaded.

Looking at the SharePoint JavaScript files I found init.js. SharePoint seems to add functions to an array called ‘_spBodyOnLoadFunctionNames’ using the function _spBodyOnLoadFunctionNames.push(). This array is passed into a function called “ProcessDefaultOnLoad()” within init.js. These functions are then called one at a time by looping through the array.

So another line within the $(document).ready() function was added :-

_spBodyOnLoadFunctionName.push(refreshPDFLinks());

However, this still didn’t work.

The grouping function when it expands a node updates the html to display these links to the various documents, so I wanted to find a way to bind to an event which would be called when changes to the html were made. After some more research I couldn’t find a way to throw an event which would work in IE and Firefox.

I then thought we’ll why don’t we delay the call to look for the PDF links by a second or two. The important thing was that the delay was an asynchronous call that did not block the other scripts from running.

In the end the setTimeout() JavaScript function was used. This function was bound to all the expanders for the document library. Fortunately with jQuery the binding was pretty straightforward with the line:-

$(documentLibExpGroup).bind('click', function(){
refreshPDFLinkTimeOut = setTimeout("refreshPDFLinks()",1500);
});

This approach works though it is not great for the following reasons :-

  • it is not scalable and need to be added to each page that the functionality is required for.
  • the timeout needs to be long enough to load the PDFs but not so long so that the link is not updated in time.

Anyway with those caveats in mind here is:-

The SharePoint 2007 Source Code.

<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.4.min.js">
</script>
<script language"javascript" type="text/javascript">
/* PDF Link to new window function */
$(document).ready(function () {

    var refreshPDFLinkTimeOut=null;
    //bind function to document library expand events
    bindToDocumentLibraryEvents();
    //_spBodyOnLoadFunctionNames.push(&quot;refreshPDFLinks&quot;);
    refreshPDFLinks();
});

function bindToDocumentLibraryEvents() {

    var documentLibExpGroup=$("a[onclick*='ExpCollGroup']");
    $(documentLibExpGroup).bind('click', function(){
        refreshPDFLinkTimeOut = setTimeout("refreshPDFLinks()",2000);
    });
    alert"Bound to " + documentLibExpGroup.length + " Document Lib Group Switch");
    return true;
}

function refreshPDFLinks() {
    fixPDFUrls();
    //var pdfTags = getPDFUrls();
    //updatePDFUrls(pdfTags);
    //alert(&quot;Found &quot; + pdfTags.length + &quot; PDF Links&quot;);
    return true;
}

function getPDFUrls() {
    var pdfUrlTags = $"a[onclick*='DispEx'][onfocus*='OnLink'][href*='pdf']");

    var fixTags = new Array();
    for (var i = 0; i <;; pdfUrlTags.length; i++) {
            fixTags.push($(pdfUrlTags[i]));
    }

    return fixTags;
}

function fixPDFUrls() {
    var pdfUrlTags = $("a[onclick*='DispEx'][onfocus*='OnLink'][href*='pdf']");
    alert("Found " + pdfUrlTags.length + " PDF Links");
    $(pdfUrlTags).live('click', function() {updatePDFUrls(this);});
    return true;
}

function updatePDFUrls(pdfUrlTags) {
    for (var i = 0; i <;; pdfUrlTags.length; i++) {
        $(pdfUrlTags[i]).attr('target','_new');
    }

    return true;
}

function updatePdfTargetUrl(e) {
    $(e).attr('target','_new');
    return false;
}

/* PDF Link to new window function */
</script>

The SharePoint 2010 Source Code

<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.7.1.min.js">
</script>;
<script type="text/javascript" language="javascript">
/*

/* PDF Link to new window function */
$(document).ready(function () {

    var refreshPDFLinkTimeOut=null;
    //bind function to document library expand events
    bindToDocumentLibraryGroupByEvents();
    refreshPDFLinks();
});

function bindToDocumentLibraryGroupByEvents() {

    var documentLibExpGroup=$("a[onclick*='ExpCollGroup']");
    $(documentLibExpGroup).live('mouseover', function(event){
        refreshPDFLinkTimeOut = setTimeout("refreshPDFLinks()",2000);
    });
    //alert("Bound to " + documentLibExpGroup.length + " Document Lib Group Switch");
    return true;
}

function refreshPDFLinks() {
	fixPDFUrls();
    return true;
}

function fixPDFUrls() {
    var pdfUrlTags = $"a[onclick*='DispEx'][onfocus*='OnLink'][href*='pdf']");
    $(pdfUrlTags).live('mouseover', function (event) { updatePdfTargetUrl($(this)); });
    return true;
}

//updates the tag, adding the _new property to the target to open new window
// and disabling the SharePoint DispEx onclick function to stop the pdf from being opened in the current browser window.
function updatePdfTargetUrl(e) {
    $(e).attr('target', '_new');
    $(e).prop('onclick', null).attr('onclick',null);
	return false;
}

/* PDF Link to new window function */
</script>

Usage

To use this piece of JavaScript do the following:-

  • Download the Source code JavaScript file
  • Browse to the SharePoint page that you wish to add the PDF functionality to.
  • Edit the SharePoint Page
  • Add a Content Editor Web Part to the page
  • Edit the Content Editor Web part and open its source view
  • Open the source code file, copy the contents of the javascript
  • Paste the contents in the Content Editor Web part’s source.
  • Save the Web part and the Page
  • Test out the functionality.
  • If nothing happens then check that the jQuery library can be accessed as it uses the Microsoft AJAX site to get the appropriate version.

Links