Fix: Content Editor Web Part Rich Text Editor Popup fails to display


 

Introduction

This problem has been bugging me for the past 3 days and so I thought I’d be kind and document it just in case it has been causing someone else problems.

So the issue is with the SharePoint 2007 Content Editor Web Part and when you edit the web part and click the button to show the Rich Text Editor you get a JavaScript error.

There does seem to be another post on MSDN (http://social.msdn.microsoft.com/Forums/en-NZ/sharepointcustomization/thread/90e14ff3-7003-44fd-9b4c-d9e654f7d8e1 that was showing the same issue and although the fix was related, the fixes that were specified in this post didn’t help me.

 

Issue

So as I have already mentioned when using the SharePoint 2007 Content Editor Web Part’s Rich Text Editor Dialog you get the following JavaScript error:-

Invalid Argument in HtmlEditor.js at line 5740, character position 2

On further investigation it is this line in the HtmlEditor.js file that is causing the problem.

elem=document.getElementByid(containerId);

Actually if you follow the JavaScript code then the issue seems to be down to the piece of JavaScript where the web parts are registered on the page. At the bottom of each SharePoint page is a section of JavaScript that looks something like this:-

 1: <script LANGUAGE='Javascript'>


 

 2: <!--


 

 3: WPSC.Init(document);


 

 4: var varPartWPQ1 = WPSC.WebPartPage.Parts.Register('WPQ1','[GUID]',document.all.item('WebPartWPQ1'));


 

 5: WPSC.WebPartPage.WebURL = 'http:\u002f\u002fsharepointurl';


 

 6: WPSC.WebPartPage.WebServerRelativeURL = '\u002f';


 

 7: //-->


 

 8: </script>

It seems that the JavaScript which creates the varPartWPQ1 variable does not work properly as the varPartWPQ1 is created without populating its ID property. This ID property is the value that is assigned to containerId in the line:-

elem=document.getElementByid(containerId);

 

The Solution

After a lot of trial and error I found that it was to do with the master page and a <meta> tag within the master page’s <head> tag.

The tag causing the problem is this one:-

 1: <meta http-equiv="X-UA-Compatible" content="IE=8" />

Removing this line and redeploying the master page fixed the JavaScript error.

This meta tag tells IE to run in IE 8 Standards mode which seems to cause a problem with the browser when its trying to get a document item using the function document.all.item([itemid]).

For more information on the <meta> tag please see the following article on Defining Document Compatability (http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx)

 

Further Information

The reason for this happening was actually that the master page was being ported back from a SharePoint 2010 master page to a SharePoint 2007 master page.

This tag was left in from the SharePoint 2010 master page.

I really do hope this helps someone as it drove me mad for a while.

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