Commits

Lee Kelleher  committed 2ba7c23

Imported from svn by Bitbucket

  • Participants

Comments (0)

Files changed (21)

File Our.Umbraco.Tree.RobotsTxt.csproj

+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}</ProjectGuid>
+    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Our.Umbraco.Tree.RobotsTxt</RootNamespace>
+    <AssemblyName>Our.Umbraco.Tree.RobotsTxt</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkSubset>
+    </TargetFrameworkSubset>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="businesslogic, Version=1.0.3441.18044, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>_externals\businesslogic.dll</HintPath>
+    </Reference>
+    <Reference Include="cms, Version=1.0.3441.17655, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>_externals\cms.dll</HintPath>
+    </Reference>
+    <Reference Include="controls, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>_externals\controls.dll</HintPath>
+    </Reference>
+    <Reference Include="interfaces, Version=1.0.3438.34252, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>_externals\interfaces.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Web" />
+    <Reference Include="System.Xml" />
+    <Reference Include="umbraco, Version=1.0.3441.17657, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>_externals\umbraco.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RobotsTxtTree.cs" />
+    <Compile Include="umbraco\robots-txt\editRobotsTxtFile.aspx.cs">
+      <DependentUpon>editRobotsTxtFile.aspx</DependentUpon>
+      <SubType>ASPXCodeBehind</SubType>
+    </Compile>
+    <Compile Include="umbraco\robots-txt\editRobotsTxtFile.aspx.designer.cs">
+      <DependentUpon>editRobotsTxtFile.aspx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="package\package.xml" />
+    <EmbeddedResource Include="robots.txt" />
+    <Content Include="umbraco\robots-txt\robot.png" />
+    <Content Include="umbraco\robots-txt\editRobotsTxtFile.aspx" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="umbraco\robots-txt\disallow.gif" />
+    <Content Include="umbraco\robots-txt\lines-comment.gif" />
+    <Content Include="umbraco\robots-txt\lines-uncomment.gif" />
+    <Content Include="umbraco\robots-txt\user-agent.gif" />
+    <Content Include="web.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <UseIIS>False</UseIIS>
+          <AutoAssignPort>True</AutoAssignPort>
+          <DevelopmentServerPort>1066</DevelopmentServerPort>
+          <DevelopmentServerVPath>/</DevelopmentServerVPath>
+          <IISUrl>
+          </IISUrl>
+          <NTLMAuthentication>False</NTLMAuthentication>
+          <UseCustomServer>True</UseCustomServer>
+          <CustomServerUrl>http://localhost/</CustomServerUrl>
+          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+  <PropertyGroup>
+    <PostBuildEvent>XCOPY "$(ProjectDir)bin\$(ProjectName)*.*" "C:\Inetpub\wwwroot\umbraco45\bin\" /y
+XCOPY "$(ProjectDir)umbraco\robots-txt\*.*" "C:\Inetpub\wwwroot\umbraco45\umbraco\robots-txt\" /y
+</PostBuildEvent>
+  </PropertyGroup>
+</Project>

File Our.Umbraco.Tree.RobotsTxt.sln

+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Our.Umbraco.Tree.RobotsTxt", "Our.Umbraco.Tree.RobotsTxt.csproj", "{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1286BAAC-76C2-4D9A-ABBD-2CD8320D3C8B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

File Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Our.Umbraco.Tree.RobotsTxt")]
+[assembly: AssemblyDescription("A Robots.txt Editor for Umbraco")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Vertino Ltd")]
+[assembly: AssemblyProduct("Our.Umbraco.Tree.RobotsTxt")]
+[assembly: AssemblyCopyright("Copyright © Lee Kelleher 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("2.0.1")]
+[assembly: AssemblyFileVersion("2.0.1")]

File RobotsTxtTree.cs

+namespace Our.Umbraco.Tree.RobotsTxt
+{
+	using System;
+	using System.Collections.Generic;
+	using System.Text;
+	using System.Web;
+	using System.Xml;
+
+	using umbraco.cms.presentation.Trees;
+	using umbraco.interfaces;
+
+	public class RobotsTxtTree : BaseTree
+	{
+		public RobotsTxtTree(string applicaton)
+			: base(applicaton)
+		{
+		}
+
+		/// <summary>
+		/// Renders the specified tree.
+		/// </summary>
+		/// <param name="tree">The application tree.</param>
+		public override void Render(ref XmlTree tree)
+		{
+			// nothing happens here (yet)
+		}
+
+		/// <summary>
+		/// Renders the JS.
+		/// </summary>
+		/// <param name="javascript">The javascript.</param>
+		public override void RenderJS(ref StringBuilder javascript)
+		{
+			javascript.Append(@"
+				function openRobotsTxtEditor() { parent.right.document.location.href = 'robots-txt/editRobotsTxtFile.aspx'; }
+			");
+		}
+
+		/// <summary>
+		/// Creates the root node.
+		/// </summary>
+		/// <param name="rootNode">The root node.</param>
+		protected override void CreateRootNode(ref XmlTreeNode rootNode)
+		{
+			rootNode.Action = "javascript:openRobotsTxtEditor();";
+			rootNode.Text = "Robots.txt";
+			rootNode.Icon = "../../robots-txt/robot.png";
+			rootNode.OpenIcon = rootNode.Icon;
+			rootNode.NodeID = "initRobotsTxt";
+			rootNode.NodeType = String.Concat(rootNode.NodeID, this.TreeAlias);
+			rootNode.Menu = new List<IAction>();
+			rootNode.HasChildren = false;
+			rootNode.Source = String.Empty;
+		}
+	}
+}

File _externals/businesslogic.dll

Binary file added.

File _externals/cms.dll

Binary file added.

File _externals/controls.dll

Binary file added.

File _externals/interfaces.dll

Binary file added.

File _externals/umbraco.dll

Binary file added.

File package/package.xml

+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<umbPackage>
+	<files>
+		<file>
+			<guid>Our.Umbraco.Tree.RobotsTxt.dll</guid>
+			<orgPath>/bin</orgPath>
+			<orgName>Our.Umbraco.Tree.RobotsTxt.dll</orgName>
+		</file>
+		<file>
+			<guid>disallow.gif</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>disallow.gif</orgName>
+		</file>
+		<file>
+			<guid>editRobotsTxtFile.aspx</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>editRobotsTxtFile.aspx</orgName>
+		</file>
+		<file>
+			<guid>lines-comment.gif</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>lines-comment.gif</orgName>
+		</file>
+		<file>
+			<guid>lines-uncomment.gif</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>lines-uncomment.gif</orgName>
+		</file>
+		<file>
+			<guid>robot.png</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>robot.png</orgName>
+		</file>
+		<file>
+			<guid>user-agent.gif</guid>
+			<orgPath>/umbraco/robots-txt</orgPath>
+			<orgName>user-agent.gif</orgName>
+		</file>
+	</files>
+	<info>
+		<package>
+			<name>Robots.txt Editor</name>
+			<version>3.0</version>
+			<license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license>
+			<url>http://our.umbraco.org/projects/developer-tools/robotstxt-editor</url>
+			<requirements>
+				<major>4</major>
+				<minor>5</minor>
+				<patch>0</patch>
+			</requirements>
+		</package>
+		<author>
+			<name>Lee Kelleher</name>
+			<website>http://leekelleher.com</website>
+		</author>
+		<readme>
+			<![CDATA[Adds a tree node to the developer section, which allows access to your Robots.txt file from the root of your website. If you do not have an existing Robots.txt, then one will be created for you.
+
+The editor contains basic validation for the Robots.txt protocol.]]>
+		</readme>
+	</info>
+	<DocumentTypes />
+	<Templates />
+	<Stylesheets />
+	<Macros />
+	<DictionaryItems />
+	<Languages />
+	<DataTypes />
+	<Actions>
+		<Action runat="install" alias="addApplicationTree" silent="false" initialize="true" sortOrder="6" applicationAlias="developer" treeAlias="robotsTxt" treeTitle="Robots.txt" iconOpened="../../robots-txt/robot.png" iconClosed="../../robots-txt/robot.png" assemblyName="Our.Umbraco.Tree.RobotsTxt" treeHandlerType="RobotsTxtTree" action="" />
+	</Actions>
+</umbPackage>
+# robots.txt for Umbraco
+User-agent: *
+Disallow: /aspnet_client/
+Disallow: /bin/
+Disallow: /config/
+Disallow: /css/
+Disallow: /data/
+Disallow: /install/
+Disallow: /masterpages/
+Disallow: /python/
+Disallow: /scripts/
+Disallow: /umbraco/
+Disallow: /umbraco_client/
+Disallow: /usercontrols/
+Disallow: /xslt/

File umbraco/robots-txt/disallow.gif

Added
New image

File umbraco/robots-txt/editRobotsTxtFile.aspx

+<%@ Page Language="C#" MasterPageFile="../masterpages/umbracoPage.Master" AutoEventWireup="true" CodeBehind="editRobotsTxtFile.aspx.cs" Inherits="Our.Umbraco.Tree.RobotsTxt.EditRobotsTxtFile" ValidateRequest="False" %>
+<%@ Register TagPrefix="umb" Namespace="umbraco.uicontrols" Assembly="controls" %>
+
+<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
+	<script type="text/javascript">
+		function robotsTxtInsertRule(rule, defstr) {
+			var value = prompt('Please enter a value for the rule', defstr);
+			if (value != null && value != '') {
+				UmbEditor.Insert('\n' + rule, value, '<%= editorSource.ClientID %>');
+			}
+		}
+		function robotsTxtCommentOutRules() {
+			var editor = (!UmbEditor.IsSimpleEditor) ? UmbEditor._editor : jQuery("#<%= editorSource.ClientID %>");
+			var snippet = (!UmbEditor.IsSimpleEditor) ? editor.selection() : editor.getSelection().text;
+			if (snippet == '') {
+				alert('Please select the text to comment out');
+			}
+			else {
+				editor.replaceSelection(snippet.replace(/\n/g, '\n# '));
+			}
+		}
+		function robotsTxtUncommentRules() {
+			var editor = (!UmbEditor.IsSimpleEditor) ? UmbEditor._editor : jQuery("#<%= editorSource.ClientID %>");
+			var snippet = (!UmbEditor.IsSimpleEditor) ? editor.selection() : editor.getSelection().text;
+			if (snippet == '') {
+				alert('Please select the text to uncomment');
+			}
+			else {
+				editor.replaceSelection(snippet.replace(/\n# /g, '\n'));
+			}
+		}
+	</script>
+</asp:Content>
+
+<asp:Content ID="Content2" ContentPlaceHolderID="body" runat="server">
+	<umb:UmbracoPanel ID="UmbracoPanel1" runat="server" Text="Robots.txt Editor" hasMenu="true">
+		
+		<umb:Pane ID="Pane1" runat="server" Text="robots.txt">
+		
+			<umb:Feedback runat="server" ID="Feedback1" Visible="false" />
+			
+			<umb:PropertyPanel ID="PropertyPanel1" runat="server" Text="Skip testing (ignores errors)">
+				<asp:CheckBox ID="SkipTesting" runat="server"></asp:CheckBox>
+			</umb:PropertyPanel>
+			
+			<umb:PropertyPanel ID="PropertyPanel2" runat="server">
+				<umb:CodeArea ID="editorSource" runat="server" AutoResize="true" OffSetX="47" OffSetY="47" />
+			</umb:PropertyPanel>
+			
+		</umb:Pane>
+		
+	</umb:UmbracoPanel>
+</asp:Content>
+
+<asp:Content ID="Content3" ContentPlaceHolderID="footer" runat="server"></asp:Content>

File umbraco/robots-txt/editRobotsTxtFile.aspx.cs

+namespace Our.Umbraco.Tree.RobotsTxt
+{
+	using System;
+	using System.Collections.Generic;
+	using System.IO;
+	using System.Reflection;
+	using System.Text;
+	using System.Web;
+	using System.Web.UI;
+	using System.Web.UI.WebControls;
+
+	using umbraco;
+	using umbraco.BasePages;
+	using umbraco.BusinessLogic;
+	using umbraco.uicontrols;
+
+	/// <summary>
+	/// The Robots.txt Editor page class.
+	/// </summary>
+	public partial class EditRobotsTxtFile : UmbracoEnsuredPage
+	{
+		/// <summary>
+		/// Saves the contents of the Robots.txt to disk.
+		/// </summary>
+		/// <param name="contents">The contents of the Robots.txt file.</param>
+		/// <returns>Whether the save was successful.</returns>
+		public bool SaveRobotsTxt(string contents)
+		{
+			try
+			{
+				string filePath = Server.MapPath("~/robots.txt");
+
+				using (StreamWriter writer = File.CreateText(filePath))
+				{
+					writer.Write(contents);
+				}
+
+				return true;
+			}
+			catch
+			{
+				return false;
+			}
+		}
+
+		/// <summary>
+		/// A very basic Robots.txt validation.
+		/// </summary>
+		/// <param name="contents">The contents of the Robots.txt file.</param>
+		/// <returns>A list of Pair objects, containing the line number and detail of the error.</returns>
+		public List<Pair> ValidateRobotsTxt(string contents)
+		{
+			List<string> lines = new List<string>(contents.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
+			List<Pair> errors = new List<Pair>();
+
+			for (int i = 0; i < lines.Count; i++)
+			{
+				string line = lines[i].Trim().ToUpper();
+
+				// check if the line is invalid
+				if ((!line.StartsWith("#")) && (!line.StartsWith("USER-AGENT")) && (!line.StartsWith("DISALLOW")) && (!line.StartsWith("ALLOW")) && (!line.StartsWith("SITEMAP")) && (!line.StartsWith("CRAWL-DELAY")) && (!line.StartsWith("REQUEST-RATE")) && (!line.StartsWith("VISIT-TIME")))
+				{
+					// invalid command
+					errors.Add(new Pair(i, line));
+				}
+			}
+
+			return errors;
+		}
+
+		/// <summary>
+		/// Raises the <see cref="E:Init"/> event.
+		/// </summary>
+		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+		protected override void OnInit(EventArgs e)
+		{
+			base.OnInit(e);
+
+			if (this.UmbracoPanel1.hasMenu)
+			{
+				// add the save button
+				ImageButton menuSave = this.UmbracoPanel1.Menu.NewImageButton();
+				menuSave.AlternateText = "Save Robots.txt";
+				menuSave.ImageUrl = String.Concat(GlobalSettings.Path, "/images/editor/save.gif");
+				menuSave.Click += new ImageClickEventHandler(this.MenuSave_Click);
+
+				this.UmbracoPanel1.Menu.InsertSplitter();
+
+				// add a User-Agent button
+				MenuIconI menuIcon = this.UmbracoPanel1.Menu.NewIcon();
+				menuIcon.ImageURL = String.Concat(GlobalSettings.Path, "/robots-txt/user-agent.gif");
+				menuIcon.OnClickCommand = "robotsTxtInsertRule('User-agent: ', '*');";
+				menuIcon.AltText = "Insert User-Agent rule";
+
+				// add a Disallow button
+				menuIcon = this.UmbracoPanel1.Menu.NewIcon();
+				menuIcon.ImageURL = String.Concat(GlobalSettings.Path, "/robots-txt/disallow.gif");
+				menuIcon.OnClickCommand = "robotsTxtInsertRule('Disallow: ', '/');";
+				menuIcon.AltText = "Insert Disallow rule";
+
+				// add a Comment Out button
+				menuIcon = this.UmbracoPanel1.Menu.NewIcon();
+				menuIcon.ImageURL = String.Concat(GlobalSettings.Path, "/robots-txt/lines-comment.gif");
+				menuIcon.OnClickCommand = "robotsTxtCommentOutRules();";
+				menuIcon.AltText = "Comment out rules";
+
+				// add an Uncomment button
+				menuIcon = this.UmbracoPanel1.Menu.NewIcon();
+				menuIcon.ImageURL = String.Concat(GlobalSettings.Path, "/robots-txt/lines-uncomment.gif");
+				menuIcon.OnClickCommand = "robotsTxtUncommentRules();";
+				menuIcon.AltText = "Uncomment rules";
+			}
+		}
+
+		/// <summary>
+		/// Handles the Load event of the Page control.
+		/// </summary>
+		/// <param name="sender">The source of the event.</param>
+		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+		protected void Page_Load(object sender, EventArgs e)
+		{
+			string filePath = Server.MapPath("~/robots.txt");
+			string fileContents = string.Empty;
+
+			if (!IsPostBack)
+			{
+				// HACK: Brute-forces an Umbraco appTree install
+				if (Request.QueryString["action"] == "install")
+				{
+					ApplicationTree appTree = ApplicationTree.getByAlias("robotsTxt");
+					if (appTree == null)
+					{
+						ApplicationTree.MakeNew(false, true, 6, "developer", "robotsTxt", "Robots.txt", "../../robots-txt/robot.png", "../../robots-txt/robot.png", "Our.Umbraco.Tree.RobotsTxt", "RobotsTxtTree", String.Empty);
+					}
+				}
+
+				// check if the robots.txt exists
+				if (!File.Exists(filePath))
+				{
+					// if not, then use the embedded robots.txt
+					Assembly assembly = Assembly.GetExecutingAssembly();
+					if (assembly != null)
+					{
+						using (StreamReader robotsTxt = new StreamReader(assembly.GetManifestResourceStream("Our.Umbraco.Tree.RobotsTxt.robots.txt")))
+						{
+							fileContents = robotsTxt.ReadToEnd();
+						}
+					}
+				}
+				else
+				{
+					// otherwise read the contents
+					using (StreamReader reader = File.OpenText(filePath))
+					{
+						fileContents = reader.ReadToEnd();
+					}
+				}
+
+				if (!String.IsNullOrEmpty(fileContents))
+				{
+					this.editorSource.Text = fileContents;
+				}
+			}
+		}
+
+		/// <summary>
+		/// Handles the Click event of the menuSave control.
+		/// </summary>
+		/// <param name="sender">The source of the event.</param>
+		/// <param name="e">The <see cref="System.Web.UI.ImageClickEventArgs"/> instance containing the event data.</param>
+		protected void MenuSave_Click(object sender, ImageClickEventArgs e)
+		{
+			List<Pair> errors = new List<Pair>();
+
+			if (!this.SkipTesting.Checked)
+			{
+				errors = this.ValidateRobotsTxt(this.editorSource.Text);
+			}
+
+			if (errors.Count > 0)
+			{
+				StringBuilder sb = new StringBuilder(ui.Text("errors", "xsltErrorText").Replace("XSLT", "robots.txt"));
+				string format = ui.Text("errorHandling", "errorRegExp", new string[] { "{0}", "line {1}" }, null);
+
+				sb.AppendLine("<ul>");
+
+				foreach (Pair error in errors)
+				{
+					sb.AppendLine("<li>").AppendFormat(format, error.Second, error.First).AppendLine("</li>");
+				}
+
+				sb.AppendLine("</ul>");
+
+				// display the error message
+				this.Feedback1.Text = sb.ToString();
+				this.Feedback1.type = umbraco.uicontrols.Feedback.feedbacktype.error;
+				this.Feedback1.Visible = true;
+			}
+			else
+			{
+				// save the file if there are no errors
+				if (this.SaveRobotsTxt(this.editorSource.Text))
+				{
+					ClientTools.ShowSpeechBubble(BasePage.speechBubbleIcon.save, ui.Text("speechBubbles", "fileSavedHeader"), ui.Text("speechBubbles", "fileSavedText"));
+				}
+				else
+				{
+					ClientTools.ShowSpeechBubble(BasePage.speechBubbleIcon.error, ui.Text("speechBubbles", "fileErrorHeader"), ui.Text("speechBubbles", "fileErrorText"));
+				}
+			}
+		}
+	}
+}

File umbraco/robots-txt/editRobotsTxtFile.aspx.designer.cs

+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.4927
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Our.Umbraco.Tree.RobotsTxt {
+
+
+	public partial class EditRobotsTxtFile
+	{
+        
+        /// <summary>
+        /// UmbracoPanel1 control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.UmbracoPanel UmbracoPanel1;
+        
+        /// <summary>
+        /// Pane1 control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.Pane Pane1;
+        
+        /// <summary>
+        /// Feedback1 control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.Feedback Feedback1;
+        
+        /// <summary>
+        /// PropertyPanel1 control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.PropertyPanel PropertyPanel1;
+        
+        /// <summary>
+        /// SkipTesting control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::System.Web.UI.WebControls.CheckBox SkipTesting;
+        
+        /// <summary>
+        /// PropertyPanel2 control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.PropertyPanel PropertyPanel2;
+        
+        /// <summary>
+        /// editorSource control.
+        /// </summary>
+        /// <remarks>
+        /// Auto-generated field.
+        /// To modify move field declaration from designer file to code-behind file.
+        /// </remarks>
+        protected global::umbraco.uicontrols.CodeArea editorSource;
+    }
+}

File umbraco/robots-txt/firefox-robot.png

Added
New image

File umbraco/robots-txt/lines-comment.gif

Added
New image

File umbraco/robots-txt/lines-uncomment.gif

Added
New image

File umbraco/robots-txt/robot.png

Added
New image

File umbraco/robots-txt/user-agent.gif

Added
New image
+<?xml version="1.0"?>
+<configuration>
+	<configSections>
+		<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+			<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+				<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+				<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+					<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
+					<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+					<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+					<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
+				</sectionGroup>
+			</sectionGroup>
+		</sectionGroup>
+	</configSections>
+	<appSettings/>
+	<connectionStrings/>
+	<system.web>
+		<compilation debug="false">
+			<assemblies>
+				<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+				<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+				<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+				<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
+			</assemblies>
+		</compilation>
+		<authentication mode="Windows"/>
+		<pages>
+			<controls>
+				<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+				<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+			</controls>
+		</pages>
+		<httpHandlers>
+			<remove verb="*" path="*.asmx"/>
+			<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+			<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+			<add verb="GET,HEAD" path="ScriptResource.axd" validate="false" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+		</httpHandlers>
+		<httpModules>
+			<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+		</httpModules>
+	</system.web>
+	<system.codedom>
+		<compilers>
+			<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4">
+				<providerOption name="CompilerVersion" value="v3.5"/>
+				<providerOption name="WarnAsError" value="false"/>
+			</compiler>
+		</compilers>
+	</system.codedom>
+	<system.webServer>
+		<validation validateIntegratedModeConfiguration="false"/>
+		<modules>
+			<remove name="ScriptModule"/>
+			<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+		</modules>
+		<handlers>
+			<remove name="WebServiceHandlerFactory-Integrated"/>
+			<remove name="ScriptHandlerFactory"/>
+			<remove name="ScriptHandlerFactoryAppServices"/>
+			<remove name="ScriptResource"/>
+			<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+			<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+			<add name="ScriptResource" verb="GET,HEAD" path="ScriptResource.axd" preCondition="integratedMode" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
+		</handlers>
+	</system.webServer>
+	<runtime>
+		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+			<dependentAssembly>
+				<assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
+				<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
+				<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
+			</dependentAssembly>
+		</assemblyBinding>
+	</runtime>
+</configuration>