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 is very handy when using the SVN browser view:
- A shortcut for TortoiseSVN checkout.
- While developers will most likely have a SVN client installed, the same can not always be said for project managers and document writers 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).
Let's start...
I will assume the default install location for VisualSVN Server: 'c:\Program Files\VisualSVN Server'.
Add these tho images to the 'htdocs' folder:
and
.
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 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 refresh 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 Apache config file 'conf\httpd.conf'. Look for the 'SVNParentPath' attribute in the '<Location /svn/>' section and just under it, add 'SVNAutoversioning on'. Restart 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.
Download the code from CodeProject: http://www.codeproject.com/KB/applications/CustomVisualSVNServerXSLT.aspx