Click here to Skip to main content
Click here to Skip to main content

Customise the VisualSVN Server browser view

, 17 Oct 2008
Rate this:
Please Sign up or sign in to vote.
How to... customise the VisualSVN Server browser view.

CustomVisualSVNServerXSLT.JPG

Introduction

VisualSVN Server is a basic package of Subversion with the Apache web server and a visual management console (MMC). The VisualSVN Server browser view is very basic, but it is easy to customise via the provided XSLT stylesheet. Just keep in mind that the files are auto generated and can be overwritten by the VisualSVN server management console. Always backup any files before editing them. There are two things that I think would be very handy when using the SVN browser view:

  1. A shortcut for TortoiseSVN checkout.
  2. While developers will most likely have an SVN client installed, the same can not always be said for project managers and document writersn and to explain the concepts of how the versioning works can be a pain. The solution to this is auto versioning and the ability to open repository directories with Windows Explorer (web folder).

Updates

Update (18 Oct 2008)

Problems when accessing WebDav (Web Distributed Authoring and Versioning) from Vista.

vistadav.jpg

If you are experiencing problems accessing WebDav (Web Distributed Authoring and Versioning) from Vista, please try the following updates:

Update (22 Oct 2008)

After applying the above updates and rebooting, try to add a new "Network Place" to initialize the connection to the WebDAV folder.

Note (22 Oct 2008): The ability to open repository directories with Windows Explorer will not always work when displayed within a SharePoint IFrame WebPart.

Using the code

I will assume the default install location for VisualSVN Server as 'c:\Program Files\VisualSVN Server'. Add these two images to the 'htdocs' folder: Checkout with TortoiseSVN and Open Folder with Windows Explorer. In the 'htdocs' folder, you should find 'svnindex.xsl'. This is the stylesheet that renders the WebDAV XML in your browser. Open the file in your favourite text editor and find the '<xsl:template match="dir">...<xsl:template>' section. Replace the following bit:

<xsl:element name="a">
   <xsl:attribute name="href">
      <xsl:value-of select="@href"/>
   </xsl:attribute>
   <img src="/dir.png"/>
   <xsl:text> </xsl:text>
   <xsl:value-of select="@name"/>
   <xsl:text>/</xsl:text>
</xsl:element>

with:

<table border="0" style="width:99%"><tr><td>
<xsl:element name="a">
 <xsl:attribute name="href">
     <xsl:value-of select="@href"/>
 </xsl:attribute>
 <img src="/dir.png"/>
 <xsl:text> </xsl:text>
 <xsl:value-of select="@name"/>
 <xsl:text>/</xsl:text>
</xsl:element>
</td><td nowrap="nowrap" style="width:1%">
 <xsl:element name="a">
   <xsl:attribute name="href">
     javascript:void(0);
   </xsl:attribute>
   <xsl:attribute name="onclick">
     javascript:document.location.href='tsvn:'+document.location.href.substr(0, 
       document.location.href.lastIndexOf('/'))+ 
       '/<xsl:value-of select="@href"/>';
   </xsl:attribute>
   <xsl:attribute name="title">
     Checkout with TortoiseSVN
   </xsl:attribute>
   <img alt="Checkout with TortoiseSVN" src="/tsvn.png"/>
 </xsl:element>
</td><td nowrap="nowrap" style="width:1%">
 <xsl:element name="a">
   <xsl:attribute name="href">
     javascript:void(0);
   </xsl:attribute>
   <xsl:attribute name="onclick">
     javascript:NavigateHttpFolderIfSupported(document.location.href.substr(0, 
       document.location.href.lastIndexOf('/'))+
       '/<xsl:value-of select="@href"/>', '_blank');
   </xsl:attribute>
   <xsl:attribute name="title">
     Open Folder with Windows Explorer
   </xsl:attribute>
   <img alt="Open Folder with Windows Explorer" src="/explorer.png"/>
 </xsl:element>
</td></tr></table>

Add a new text file to the 'htdocs' folder, name it 'dav.js', and paste the following into it:

/* 
The bits from the SharePoint init.js and core.js needed 
for the 'Open Folder with Windows Explorer' functionality.
*/
function BrowserIs () 
{
    var agt=navigator.userAgent.toLowerCase();
    this.osver=1.0;
    if (agt)
    {
        var stOSVer=agt.substring(agt.indexOf("windows ")+11);
        this.osver=parseFloat(stOSVer);
    }
    this.major=parseInt(navigator.appVersion);
    this.nav=((agt.indexOf('mozilla')!=-1)&&
       ((agt.indexOf('spoofer')==-1) && (agt.indexOf('compatible')==-1)));
    this.nav6=this.nav && (this.major==5);
    this.nav6up=this.nav && (this.major >=5);
    this.nav7up=false;
    if (this.nav6up)
    {
        var navIdx=agt.indexOf("netscape/");
        if (navIdx >=0 )
            this.nav7up=parseInt(agt.substring(navIdx+9)) >=7;
    }
    this.ie=(agt.indexOf("msie")!=-1);
    this.aol=this.ie && agt.indexOf(" aol ")!=-1;
    if (this.ie)
        {
        var stIEVer=agt.substring(agt.indexOf("msie ")+5);
        this.iever=parseInt(stIEVer);
        this.verIEFull=parseFloat(stIEVer);
        }
    else
        this.iever=0;
    this.ie4up=this.ie && (this.major >=4);
    this.ie5up=this.ie && (this.iever >=5);
    this.ie55up=this.ie && (this.verIEFull >=5.5);
    this.ie6up=this.ie && (this.iever >=6);
    this.winnt=((agt.indexOf("winnt")!=-1)||(agt.indexOf("windows nt")!=-1));
    this.win32=((this.major >=4) && (navigator.platform=="Win32")) ||
        (agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1);
    this.mac=(agt.indexOf("mac")!=-1);
    this.w3c=this.nav6up;
    this.safari=(agt.indexOf("safari")!=-1);
    this.safari125up=false;
    if (this.safari && this.major >=5)
    {
        var navIdx=agt.indexOf("safari/");
        if (navIdx >=0)
            this.safari125up=parseInt(agt.substring(navIdx+7)) >=125;
    }
}
var browseris=new BrowserIs();

var L_WebFoldersError_Text = "Your client does not support opening " + 
                             "this list with Windows Explorer.";
var L_WebFoldersRequired_Text="Please wait while Explorer View is loaded. " + 
    "If Explorer View does not appear, your browser may not support it.";

function SupportsNavigateHttpFolder()
{
    return (browseris.ie5up && browseris.win32);
}

var httpFolderTarget=null;
var httpFolderSource=null;
var httpFolderDiv=null;
function NavigateHttpFolderCore()
{
    if (httpFolderDiv==null)
    {
        httpFolderDiv=document.createElement('DIV');
        document.body.appendChild(httpFolderDiv);
        httpFolderDiv.onreadystatechange=NavigateHttpFolderCore;
        httpFolderDiv.addBehavior('#default#httpFolder');
    }
    if (httpFolderDiv.readyState=="complete")
    {
        httpFolderDiv.onreadystatechange=null;
        try
        {
            var targetFrame=document.frames.item(httpFolderTarget);
            if (targetFrame !=null)
            {
                targetFrame.document.body.innerText=L_WebFoldersRequired_Text;
            }
        }
        catch (e) {}
        var isOk=false;
        try
        {
            var ret="";
            ret=httpFolderDiv.navigateFrame(httpFolderSource,
                httpFolderTarget);
            if (ret=="OK")
                isOk=true;
        }
        catch (e) { }
        if (!isOk &&
            0==httpFolderSource.search("http://[a-zA-Z0-9\-\.]+(:80)?/"))
        {
            var sUrl=httpFolderSource
                .replace(/http:\/\/([a-zA-Z0-9\-\.]+)(:80)?[\/]/, "//$1/")
                .replace(/[\/]/g, "\\");
            var targetFrame=document.frames.item(httpFolderTarget);
            if (targetFrame !=null)
            {
                try
                {
                        targetFrame.onload=null;
                        targetFrame.document.location.href=sUrl;
                        isOk=true;
                }
                catch (e) { }
            }
        }
        if (!isOk)
        {
            alert(L_WebFoldersError_Text);
        }
    }
}

function NavigateHttpFolder(urlSrc, frameTarget)
{
    if ('/'==urlSrc.charAt(0))
    {
        urlSrc=document.location.protocol+"//"+document.location.host+urlSrc;
    }
    httpFolderSource=urlSrc;
    httpFolderTarget=frameTarget;
    NavigateHttpFolderCore();
}

function NavigateHttpFolderIfSupported(urlSrc, frameTarget)
{
    if (SupportsNavigateHttpFolder())
    {
        NavigateHttpFolder(urlSrc, frameTarget);
    }
    else
    {
        alert(L_WebFoldersError_Text);
        window.history.back();
    }
}

When refreshing the browser now, you'll have the following:

Notice the new icons on the right of the folders. When the tortoise image is clicked, the TortoiseSVN checkout window should appear with the repository URL filled in:

If you are using Internet Explorer, the repository window will open with Windows Explorer when the explore image is clicked:

To enable auto versioning, we need to make a change to the Apache config file 'conf\httpd.conf'. Look for the 'SVNParentPath' attribute in the '<Location /svn/>' section, and just under it, add 'SVNAutoversioning on'. Restart the VisualSVN Server for the configuration change to take effect. Of course, this is now only the beginning. You can change the skin by editing 'htdocs\svnindex.css' and add your company logo etc.

History

  • 28 June 2008
    • Original article posted.
  • 14 July 2008
    • Updated links to JS files and images in svnindex.xsl.
  • 18/22 October 2008
    • Added some connection troubleshooting info.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Riaan Lehmkuhl
Software Developer adhdForge
South Africa South Africa
Me, a disorder of the brain that results in a disruption in a person's thinking, mood, and ability to relate to others.
Follow on   Twitter

Comments and Discussions

 
QuestionNo action when clicking on either icon PinmemberMember 40952652-Jul-08 5:42 
AnswerRe: No action when clicking on either icon PinmemberRiaan Lehmkuhl14-Jul-08 7:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140709.1 | Last Updated 17 Oct 2008
Article Copyright 2008 by Riaan Lehmkuhl
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid