It has been brought to my attention that my previous post to modify IIS to enable users to click on .exe files and download them is flawed as it will disable quite a bit of other functionality in SharePoint. One big one is the inability to use SharePoint designer to navigate to subsites. Big problem there if you have SPD workflows or custom page layouts etc on those subsites.
So in the end, I had to undo the solution as discussed and create a custom web part to add to the document library in question that would modify the div (using Javascript) with the same Javascript link that is used to download the file.
It's not the neatest piece of code since the client needed it in a hurry so I didn't really think about the best way to do things. I just made it work.
The code will prompt you to download anything in the document library. So if the document is a .html file or a .aspx file, it won't open it, it will instead prompt you to download it. You can modify the code to distinguish between files that should be opened vs files that should be downloaded though with a simple if statement.
In addition, the code works for items that have been grouped. If the document library is not grouped, then the code can be simplified. However, the way it is now will work whether the document library is grouped or not.
Here's the javascript part of things:
<script language='javascript'>
function changeDownloadLink(id,NewHtml) {
// check that the element exists
if (document.getElementById(id)) {
// check that the element does not yet contain the string stsnavigate
// if it doesn't then replace the html
if (document.getElementById(id).innerHTML.indexOf(""STSNavigate"") == -1) document.getElementById(id).innerHTML=NewHtml;
}
}
items = new Array();
function saveArray(item) {
items[items.length]=item;
}
function resetLinks() {
// loop through the items array
for (var i=0;i<items.length;i++) {
if (i%2!=0) {
changeDownloadLink(items[(i-1)],items[i]);
//if (i==1) alert(items[(i-1)] + ' - ' + items[i]);
}
}
}
window.setInterval(function()
{
resetLinks();
}, 1000);
</script>
And here is the C# Render method (DocLibName) is the name of the document library that contains all the files that should be downloaded.
try
{
SPWeb mySite = SPContext.Current.Web;
SPList oList = mySite.Lists[DocLibName];
SPListItemCollection listItems = oList.Items;
if (listItems.Count > 0)
{
for (int i = 0; i < listItems.Count; i++)
{
SPListItem item = listItems[i];
writer.Write("<script>changeDownloadLink('" + item["ID"].ToString() + "','<a href=\"#\" onclick=\"STSNavigate(\\'" + mySite.Url + "/_layouts/download.aspx?SourceUrl=" + HttpUtility.UrlEncode(item.File.ServerRelativeUrl) + "\\')\">" + item.DisplayName + "</a>')</script>");
string url = "<a href=\"#\" onclick=\"STSNavigate(\\'" + mySite.Url + "/_layouts/download.aspx?SourceUrl=" + HttpUtility.UrlEncode(item.File.ServerRelativeUrl) + "\\')\">" + item.DisplayName + "</a>";
writer.Write("<script>saveArray('" + item["ID"].ToString() + "');</script>");
writer.Write("<script>saveArray('" + url + "');</script>");
}
}
//writer.Write("All Done");
}
catch (Exception ex)
{
writer.Write(ex.ToString());
}
It's not the prettiest code, but it works and the clients are happy.