Friday, February 1, 2013

HTML5 + SharePoint People Picker: I give up!

The SharePoint 2010 people picker is a piece of crap. Plain and simple. I have not had a chance to check out what 2013 has to offer for a people picker control – honestly I am a little scared to. I just know that the people picker breaks all the time in IE under normal circumstances, and when you try to use an HTML5 master page on your SharePoint site, it gets even worse. There are some ways to try to fix it that people have put out there (see here: http://social.msdn.microsoft.com/Forums/da/sharepoint2010general/thread/8c83010e-d351-48ba-bd1e-1ffb0641ec03) but but I have not come across a 100% solution to fix IE yet that results in a working HTML5 page.

This is the funny part: When the browser is not IE – something superior like Chrome or Firefox – the people picker is functional. It is ugly – showing login names rather than display names – but that is a small price to pay for having it be functional. Plus it has always been ugly. So I thought – ‘Hey, what if I could make the code think it was using a different browser so the people picker can work…’ And here is how I did it:

Add this JavaScript to the bottom of your master page. (If you do not have a custom master page, you are out of luck – since most of the people pickers can be found on layouts pages.)

if (typeof (PreferContentEditableDiv) == "function") {
//force downlevel people picker because HTML5 + IE makes people picker more terrible than usual
PreferContentEditableDiv = _PreferContentEditableDiv;
$("div.ms-inputuserfield").css("display", "none");
$("textarea.ms-inputuserfield").css({"display": "inline", "position":"static"});
}

Thursday, January 31, 2013

jQuery, AJAX, and Aggressive iOS Caching

This was the situation: A jQuery Mobile app was using jQuery AJAX requests to get JSON data from the server. Nothing crazy – except for maybe the server was a SharePoint server. I know – running one of those IS pretty crazy.

The requests from a typical browser worked as expected. No issues. With the ‘cache’ flag turned off, the server logs were showing each request come in when it was expected. Then came the iPad + iPhone testing. Initially all looked great. Except after the first request, subsequent requests never made it back to the server. WTH?

Turns out iOS does not honor the ‘cache’ flag in the jQuery AJAX object. In case you are not familiar with this, here is what a typical jQuery AJAX request looks like:

$.ajax({
url: ws_url,
type: "POST",
data: JSON.stringify(data),
dataType: 'json',
contentType: "application/json; charset=utf-8",
async: true,
cache: false, //to cache or not to cache
success: function (data) {
//yes
},
error: function (jqXHR, exception, errorThrown) {
//no
}
});

Caching is good and all, but most of the time you need to control it, like if you had a refresh button. This is usually done by changing the ‘cache’ flag to false. To account for the iOS family, you must also add the cache-control header and set it to ‘no-cache’ – which looks like this:




$.ajax({
url: ws_url,
type: "POST",
data: JSON.stringify(data),
dataType: 'json',
contentType: "application/json; charset=utf-8",
async: true,
cache: false,
headers: { "cache-control": "no-cache" },
success: function (data) {
//yes
},
error: function (jqXHR, exception, errorThrown) {
//no
}
});

Hope this saves someone some time.

Tuesday, October 9, 2012

SharePoint 2010: Easy Dynamic Resize of Dialogs

Some situations require asynchronously loaded data. When this data is within a SP dialog, the dialog will have ugly scrollbars. You could try to guess at the size of the dialog ahead of time when you open it, but that would be what people call ‘lame’. What you need is to dynamically resize the dialog once the async load is complete.

Holy Crap: When I searched for this I found some long, half-baked solutions that had more holes than a Toyota pickup truck in the Middle East. Some examples: An MSDN forum post and Some Dude’s Blog – both long, and (sorry fellas) – kind of crappy.

Solution turned out to be kind of easy – here is the pattern:

JavaScript:

function AutosizeDialog(){
//resize dialog if we are in one
var dlg = SP.UI.ModalDialog.get_childDialog();
if (dlg != null) {
dlg.autoSize();
}
}


function LoadPageData(){
//PSEUDOCODE jquery ajax
$.ajax({
url: < web service providing the data >,
/* other ajax options */
async: true,
cache: false,
success: function (data) {
/* load data into element(s) */
AutosizeDialog();
},
error: function (err) {
/* be good and handle errors */
}
});
}



Explanation: The function “LoadPageData” is your function that loads data into your page dynamically. Maybe it loads it from a web service using SPServices, or jQuery ajax (exampled above). Maybe it is just via a client function generating HTML dynamically. Or maybe it’s something really cool I don’t even know about. Whatever the case may be, the important part is that after the HTML has been set, a call to the “AutosizeDialog” function is made.  That is where the easy magic happens – all within SharePoint native client methods.



Important note: This is all WITHIN the dialog content. Some examples you see out there try to do resizing from the place where the dialog is created. Usually using some kind of whacked-out timer delay. Avoid this.



Pretty simple after all – no need for any extra junk.



Update #1

So it quickly became obvious that something else is needed after the dialog is resized: The window then should be repositioned so the dialog is nice and centered. Again – no need for any JavaScript craziness, and especially no need for long winded explanation – here is the updated version of AutoSizeDialog:







function AutosizeDialog() {
//resize dialog if we are in one
var dlg = typeof(SP.UI.ModalDialog.get_childDialog) == "function" ? SP.UI.ModalDialog.get_childDialog() : null;
if (dlg != null) {
dlg.autoSize();
var dlgWin = $(".ms-dlgContent", window.parent.document);
dlgWin.css({ top: ($(window.top).height() / 2 - dlgWin.height() / 2) + "px", left: $(window.top).width() / 2 - dlgWin.width() / 2 });
}
}




Just two lines to cover resizing – probably could even be reduced to one. Also added an extra check to for the SP.UI.ModalDialog load state.

Friday, January 13, 2012

SharePoint Saturday Virginia Beach 2012

SharePoint Saturday 2012 Virginia Beach was great, like all of the SPSaturday’s in Virginia Beach before it.

photo

I took this photo at the beginning of the kick off – a few minutes later, the seats in front of me were filled and people were standing along the walls.

Below is my HTML5 presentation. I welcome any and all feedback.

Sunday, October 30, 2011

Custom Timer Jobs

Some great advice here: http://www.codeproject.com/KB/sharepoint/debugging-sharepointjobs.aspx
…especially the part about restarting the timer service to see code changes take effect. So obvious… now! Would have saved me a plethora of time…

HTTP Header Manager Feature for SharePoint 2010

What is it?
This is a Web Application scoped feature that will strip HTTP response headers out of configured content.

WTH?
Ever forced to download your PDF after uploading it to a document library? Tried to embed a Shockwave/Flash file in a SharePoint 2010 page and have it not work? Then you searched for the solution and it was “just downgrade your server’s security level by changing the Web App’s file handling mode from strict to permissive”. Yeah – downgrading server security is always a great solution. Just make sure you add your SSN to the footer of every page. </sarcasm> Wrote a post on all this – you probably missed it… but that’s cool.

What it does is…

  • Adds a HttpModule to the web app it is activated in. I know, I know – performance blah blah. It is a very quick check to the requested file extension, so it should impact your precious pipeline minimally. Got a better way? Let me hear about it.
     
  • Adds a custom config section to the web.config of the web app. The section references an external configSource…
     
  • Adds a config file named ManagedHeaders.config to the root of the web app. This is where the action is – update this file to add new file types to be 'excluded’ from the strict mode handling.


Below is the default ManagedHeaders.config. Once it is in place, change it to be whatever you want. It is pretty self-explanatory – add an extension, then configure the headers to remove from the response. Also possible to add headers, but that is a different blog post… 

<?xml version="1.0" encoding="utf-8" ?>
<ManagedHeaders>
<extensions>
<add extension="html" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="pdf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="swf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="flv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="csv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
</extensions>
</ManagedHeaders>


The Files:
Below are links to a WSP as well as a Visual Studio 2010 project, in case you want to look at what is in the WSP, or make any changes.






Friday, June 24, 2011

Inline file types under SharePoint 2010 WITHOUT security downgrade

So you got your site migrated to 2010 and were crazy enough to include Flash and PDF content. Have your testers tried clicking on links to those files yet? Or worse, looked at a page with embedded objects that link to those file types? If so, you have probably discovered that those files are on the SharePoint 2010 naughty list and are no longer served as inline content. While I suspect that this may be a subtle form of revenge from MS directed at Adobe (cannot help but like this), it would be way better if there was some way we could control it…

If you Google this issue, many people proudly report (in their blogs) the solution to be changing the Browser File Handling mode from ‘Strict’ to ‘Permissive’ for the web application:

Browser File Handling
You can specify whether additional security headers are added to documents that are served to Web browsers. These security headers specify that a browser shows a download prompt for certain types of files (for example, .html), and to use the server's specified Multipurpose Internet Mail Extensions (MIME) type for other types of files.
The Permissive setting specifies that no headers are added. The Strict setting adds headers that force the browser to download certain types of files. The forced download improves security for the server by disallowing the automatic execution of Web content. By default, the setting is Strict.

ref: http://technet.microsoft.com/en-us/library/cc262107.aspx

Am I the only one who has a problem with downgrading a SharePoint security setting like this? Apparently so.

To resolve this, here is what I did so that an application may server PDF and Flash (and any other specific content) inline while remaining in strict mode for all other content currently on the ‘no inline’ list:

1. Create a Feature that deploys a new HttpModule in IIS. Say what you want about how they inspect every request, do it right and the impact is almost undetectable.

2. Within that HttpModule, check the current requested file’s extension.

3. Using a custom configuration section, allow a set of ‘handled’ extensions to be defined, along with a set of HTTP headers to be removed.

4. Deploy your solution and add in sections to remove the X-Download-Options, X-Content-Type-Options, Content-Disposition headers from FLV, PDF, and SWF files

Simple. Here is an example of what one of our config files looks like to allow PDF, SWF, and FLV files to be served inline:

<add extension="pdf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="swf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="flv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />

As you might be able to tell, the solution also allows you to add headers to a specific file type, which would let you add to SharePoint’s inline naughty list if you should some day have a need for it.

If you are reading this and say to yourself ‘Hmmm – this sounds useful, sure wish I had the code for it…’ then you are in luck – just leave a comment and the code shall be posted!! Otherwise, I ain’t going to bother with it – already bothered enough firing up Live Writer to post this post.

[Update!] I finally got around to posting the files! They are at the bottom if this post here.

 
© I caught you a delicious bass.
Back to top