Manage multiple Tv Root Folders in Settings/General.

Start of AddExisting.
This commit is contained in:
Mark McDowall 2011-03-08 23:40:48 -08:00
parent 2e9dd7f1ff
commit 2871723bfe
21 changed files with 381 additions and 90 deletions

View File

@ -66,25 +66,25 @@ namespace NzbDrone.Core.Test
//Assert.AreEqual(title, result, postTitle);
}
[Test]
public void get_unmapped()
{
//Setup
var kernel = new MockingKernel();
//[Test]
//public void get_unmapped()
//{
// //Setup
// var kernel = new MockingKernel();
kernel.Bind<ISeriesProvider>().To<SeriesProvider>();
kernel.Bind<IDiskProvider>().ToConstant(MockLib.GetStandardDisk(0, 0));
kernel.Bind<IConfigProvider>().ToConstant(MockLib.StandardConfig);
// kernel.Bind<ISeriesProvider>().To<SeriesProvider>();
// kernel.Bind<IDiskProvider>().ToConstant(MockLib.GetStandardDisk(0, 0));
// kernel.Bind<IConfigProvider>().ToConstant(MockLib.StandardConfig);
var seriesController = kernel.Get<ISeriesProvider>();
// var seriesController = kernel.Get<ISeriesProvider>();
//Act
var unmappedFolder = seriesController.GetUnmappedFolders();
// //Act
// var unmappedFolder = seriesController.GetUnmappedFolders();
//Assert
Assert.AreElementsEqualIgnoringOrder(MockLib.StandardSeries, unmappedFolder.Values);
}
// //Assert
// Assert.AreElementsEqualIgnoringOrder(MockLib.StandardSeries, unmappedFolder.Values);
//}
}

View File

@ -62,6 +62,7 @@ namespace NzbDrone.Core
_kernel.Bind<IHttpProvider>().To<HttpProvider>();
_kernel.Bind<IHistoryProvider>().To<HistoryProvider>();
_kernel.Bind<IQualityProvider>().To<QualityProvider>();
_kernel.Bind<IRootDirProvider>().To<RootDirProvider>();
_kernel.Bind<IExtenalNotificationProvider>().To<ExternalNotificationProvider>();
_kernel.Bind<IXbmcProvider>().To<XbmcProvider>();
_kernel.Bind<IConfigProvider>().To<ConfigProvider>().InSingletonScope();

View File

@ -183,6 +183,7 @@
<Compile Include="Providers\IPostProcessingProvider.cs" />
<Compile Include="Providers\IQualityProvider.cs" />
<Compile Include="Providers\IRenameProvider.cs" />
<Compile Include="Providers\IRootDirProvider.cs" />
<Compile Include="Providers\IRssSyncProvider.cs" />
<Compile Include="Providers\IRssProvider.cs" />
<Compile Include="Providers\ITimerProvider.cs" />
@ -190,6 +191,7 @@
<Compile Include="Providers\PostProcessingProvider.cs" />
<Compile Include="Providers\QualityProvider.cs" />
<Compile Include="Providers\RenameProvider.cs" />
<Compile Include="Providers\RootDirProvider.cs" />
<Compile Include="Providers\RssSyncProvider.cs" />
<Compile Include="Providers\RssProvider.cs" />
<Compile Include="Providers\TimerProvider.cs" />
@ -229,6 +231,7 @@
<Compile Include="Repository\Indexer.cs" />
<Compile Include="Repository\Config.cs" />
<Compile Include="Repository\Quality\QualityProfile.cs" />
<Compile Include="Repository\RootDir.cs" />
<Compile Include="Repository\Season.cs" />
<Compile Include="Repository\Quality\QualityTypes.cs" />
<Compile Include="Repository\Series.cs" />

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers
{
public interface IRootDirProvider
{
List<RootDir> GetAll();
void Add(RootDir rootDir);
void Remove(int rootDirId);
void Update(RootDir rootDir);
}
}

View File

@ -18,13 +18,12 @@ namespace NzbDrone.Core.Providers
/// <param name="id">The TVDB ID of the series</param>
/// <returns>Whether or not the show is monitored</returns>
bool IsMonitored(long id);
TvdbSeries MapPathToSeries(string path);
void AddSeries(string path, TvdbSeries series);
Dictionary<Guid, String> GetUnmappedFolders();
Series FindSeries(string cleanTitle);
bool QualityWanted(int seriesId, QualityTypes quality);
void UpdateSeries(Series series);
void DeleteSeries(int seriesId);
bool SeriesPathExists(string cleanPath);
}
}

View File

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.Providers
{
public interface ISyncProvider
{
void SyncUnmappedFolders();
void BeginSyncUnmappedFolders();
bool BeginSyncUnmappedFolders(List<string> paths);
List<String> GetUnmappedFolders(string path);
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Core.Repository;
using SubSonic.Repository;
namespace NzbDrone.Core.Providers
{
public class RootDirProvider : IRootDirProvider
{
private readonly IRepository _sonioRepo;
public RootDirProvider(IRepository sonicRepo)
{
_sonioRepo = sonicRepo;
}
#region IRootDirProvider
public List<RootDir> GetAll()
{
return _sonioRepo.All<RootDir>().ToList();
}
public void Add(RootDir rootDir)
{
_sonioRepo.Add(rootDir);
}
public void Remove(int rootDirId)
{
_sonioRepo.Delete<RootDir>(rootDirId);
}
public void Update(RootDir rootDir)
{
_sonioRepo.Update(rootDir);
}
#endregion
}
}

View File

@ -65,26 +65,6 @@ namespace NzbDrone.Core.Providers
return profile.Allowed.Contains(quality);
}
public Dictionary<Guid, String> GetUnmappedFolders()
{
Logger.Debug("Generating list of unmapped folders");
if (String.IsNullOrEmpty(_config.SeriesRoot))
throw new InvalidOperationException("TV Series folder is not configured yet.");
var results = new Dictionary<Guid, String>();
foreach (string seriesFolder in _diskProvider.GetDirectories(_config.SeriesRoot))
{
var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName);
if (!_sonioRepo.Exists<Series>(s => s.Path == cleanPath))
{
results.Add(Guid.NewGuid(), cleanPath);
}
}
Logger.Debug("{0} unmapped folders detected.", results.Count);
return results;
}
public TvdbSeries MapPathToSeries(string path)
{
var seriesPath = new DirectoryInfo(path);
@ -149,6 +129,14 @@ namespace NzbDrone.Core.Providers
_sonioRepo.Delete<Series>(seriesId);
}
public bool SeriesPathExists(string cleanPath)
{
if (_sonioRepo.Exists<Series>(s => s.Path == cleanPath))
return true;
return false;
}
#endregion
#region Static Helpers

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using NLog;
using NzbDrone.Core.Model.Notification;
@ -16,21 +15,54 @@ namespace NzbDrone.Core.Providers
private readonly IEpisodeProvider _episodeProvider;
private readonly IMediaFileProvider _mediaFileProvider;
private readonly INotificationProvider _notificationProvider;
private readonly IDiskProvider _diskProvider;
private ProgressNotification _seriesSyncNotification;
private Thread _seriesSyncThread;
private List<string> _syncList;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public SyncProvider(ISeriesProvider seriesProvider, IEpisodeProvider episodeProvider, IMediaFileProvider mediaFileProvider, INotificationProvider notificationProvider)
public SyncProvider(ISeriesProvider seriesProvider, IEpisodeProvider episodeProvider,
IMediaFileProvider mediaFileProvider, INotificationProvider notificationProvider,
IDiskProvider diskProvider)
{
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
_mediaFileProvider = mediaFileProvider;
_notificationProvider = notificationProvider;
_diskProvider = diskProvider;
}
public void BeginSyncUnmappedFolders()
#region ISyncProvider Members
public List<String> GetUnmappedFolders(string path)
{
Logger.Debug("Generating list of unmapped folders");
if (String.IsNullOrEmpty(path))
throw new InvalidOperationException("Invalid path provided");
if (!_diskProvider.FolderExists(path))
{
Logger.Debug("Path supplied does not exist: {0}", path);
}
var results = new List<String>();
foreach (string seriesFolder in _diskProvider.GetDirectories(path))
{
var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName);
if (!_seriesProvider.SeriesPathExists(cleanPath))
results.Add(cleanPath);
}
Logger.Debug("{0} unmapped folders detected.", results.Count);
return results;
}
#endregion
public bool BeginSyncUnmappedFolders(List<string> paths)
{
Logger.Debug("User has request series folder scan");
if (_seriesSyncThread == null || !_seriesSyncThread.IsAlive)
@ -42,15 +74,22 @@ namespace NzbDrone.Core.Providers
Priority = ThreadPriority.Lowest
};
_syncList = paths;
_seriesSyncThread.Start();
}
else
{
Logger.Warn("Series folder scan already in progress. Ignoring request.");
}
//return false if sync was already running, then we can tell the user to try again later
return false;
}
public void SyncUnmappedFolders()
//return true if sync has started
return true;
}
private void SyncUnmappedFolders()
{
Logger.Info("Starting Series folder scan");
@ -60,15 +99,20 @@ namespace NzbDrone.Core.Providers
{
_notificationProvider.Register(_seriesSyncNotification);
_seriesSyncNotification.CurrentStatus = "Analysing Folder";
var unmappedFolders = _seriesProvider.GetUnmappedFolders();
_seriesSyncNotification.ProgressMax = unmappedFolders.Count;
_seriesSyncNotification.ProgressMax = _syncList.Count;
foreach (string seriesFolder in unmappedFolders.Values)
foreach (var seriesFolder in _syncList)
{
try
{
_seriesSyncNotification.CurrentStatus = String.Format("Searching For: {0}", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(new DirectoryInfo(seriesFolder).Name));
if (_seriesProvider.SeriesPathExists(Parser.NormalizePath(seriesFolder)))
{
Logger.Debug("Folder '{0}' is mapped in the database. Skipping.'", seriesFolder);
continue;
}
Logger.Debug("Folder '{0}' isn't mapped in the database. Trying to map it.'", seriesFolder);
var mappedSeries = _seriesProvider.MapPathToSeries(seriesFolder);
@ -86,7 +130,6 @@ namespace NzbDrone.Core.Providers
_episodeProvider.RefreshEpisodeInfo(mappedSeries.Id);
_seriesSyncNotification.CurrentStatus = String.Format("{0}: finding episodes on disk...", mappedSeries.SeriesName);
_mediaFileProvider.Scan(_seriesProvider.GetSeries(mappedSeries.Id));
}
else
{

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SubSonic.SqlGeneration.Schema;
namespace NzbDrone.Core.Repository
{
public class RootDir
{
[SubSonicPrimaryKey(true)]
public int RootDirId { get; set; }
public string Path { get; set; }
public bool Default { get; set; }
}
}

View File

@ -22,6 +22,7 @@ namespace NzbDrone.Web.Controllers
private readonly IQualityProvider _qualityProvider;
private readonly IMediaFileProvider _mediaFileProvider;
private readonly IRenameProvider _renameProvider;
private readonly IRootDirProvider _rootDirProvider;
//
// GET: /Series/
@ -29,7 +30,7 @@ namespace NzbDrone.Web.Controllers
public SeriesController(ISyncProvider syncProvider, ISeriesProvider seriesProvider,
IEpisodeProvider episodeProvider, IRssSyncProvider rssSyncProvider,
IQualityProvider qualityProvider, IMediaFileProvider mediaFileProvider,
IRenameProvider renameProvider)
IRenameProvider renameProvider, IRootDirProvider rootDirProvider)
{
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
@ -38,6 +39,7 @@ namespace NzbDrone.Web.Controllers
_qualityProvider = qualityProvider;
_mediaFileProvider = mediaFileProvider;
_renameProvider = renameProvider;
_rootDirProvider = rootDirProvider;
}
public ActionResult Index()
@ -51,9 +53,15 @@ namespace NzbDrone.Web.Controllers
return View(new AddSeriesModel());
}
public ActionResult Sync()
public ActionResult AddExisting()
{
_syncProvider.BeginSyncUnmappedFolders();
return View();
}
public ActionResult Sync(List<String> paths)
{
//Todo: Make this do something...
_syncProvider.BeginSyncUnmappedFolders(paths);
return RedirectToAction("Index");
}
@ -63,9 +71,9 @@ namespace NzbDrone.Web.Controllers
return RedirectToAction("Index");
}
public ActionResult UnMapped()
public ActionResult UnMapped(string path)
{
return View(_seriesProvider.GetUnmappedFolders().Select(c => new MappingModel() { Id = 1, Path = c.Value }).ToList());
return View(_syncProvider.GetUnmappedFolders(path).Select(c => new MappingModel() { Id = 1, Path = c }).ToList());
}
public ActionResult LoadEpisodes(int seriesId)
@ -103,6 +111,24 @@ namespace NzbDrone.Web.Controllers
Total = data.Count()
});
}
[GridAction]
public ActionResult _AjaxUnmappedFoldersGrid()
{
var unmappedList = new List<String>();
foreach (var folder in _rootDirProvider.GetAll())
unmappedList.AddRange(_syncProvider.GetUnmappedFolders(folder.Path));
var seriesPaths = unmappedList.Select(c => new AddExistingSeriesModel
{
IsWanted = true,
Path = c
});
return View(new GridModel(seriesPaths));
}
private IEnumerable<Episode> GetData(GridCommand command)
{

View File

@ -9,6 +9,7 @@ using NzbDrone.Core;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Web.Models;
@ -20,15 +21,19 @@ namespace NzbDrone.Web.Controllers
private IConfigProvider _configProvider;
private IIndexerProvider _indexerProvider;
private IQualityProvider _qualityProvider;
private IRootDirProvider _rootDirProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private string _settingsSaved = "Settings Saved.";
private string _settingsFailed = "Error Saving Settings, please fix any errors";
public SettingsController(IConfigProvider configProvider, IIndexerProvider indexerProvider, IQualityProvider qualityProvider)
public SettingsController(IConfigProvider configProvider, IIndexerProvider indexerProvider,
IQualityProvider qualityProvider, IRootDirProvider rootDirProvider)
{
_configProvider = configProvider;
_indexerProvider = indexerProvider;
_qualityProvider = qualityProvider;
_rootDirProvider = rootDirProvider;
}
public ActionResult Index(string viewName)
@ -37,21 +42,18 @@ namespace NzbDrone.Web.Controllers
ViewData["viewName"] = viewName;
else
ViewData["viewName"] = "General";
return RedirectToAction("General");
return View("Index", new SettingsModel
{
TvFolder = _configProvider.SeriesRoot
});
return View("Index");
}
public ActionResult General()
{
ViewData["viewName"] = "General";
return View("Index", new SettingsModel
{
TvFolder = _configProvider.SeriesRoot,
Quality = Convert.ToInt32(_configProvider.GetValue("Quality", "1", true)),
Directories = new List<RootDir>()
});
}
@ -185,6 +187,11 @@ namespace NzbDrone.Web.Controllers
return View("UserProfileSection", new QualityProfile { Name = "New Profile", UserProfile = true });
}
public ViewResult AddRootDir()
{
return View("RootDir", new RootDir { Default = false });
}
public ActionResult SubMenu()
{
return PartialView();
@ -202,9 +209,30 @@ namespace NzbDrone.Web.Controllers
[HttpPost]
public ActionResult SaveGeneral(SettingsModel data)
{
if (ModelState.IsValid)
if (data.Directories.Count > 0)
{
_configProvider.SeriesRoot = data.TvFolder;
//If the Javascript was beaten we need to return an error
if (!data.Directories.Exists(d => d.Default))
return Content(_settingsFailed);
var currentRootDirs = _rootDirProvider.GetAll();
foreach (var currentRootDir in currentRootDirs)
{
var closureRootDir = currentRootDir;
if (!data.Directories.Exists(d => d.RootDirId == closureRootDir.RootDirId))
_rootDirProvider.Remove(closureRootDir.RootDirId);
}
foreach (var dir in data.Directories)
{
if (dir.RootDirId == 0)
_rootDirProvider.Add(dir);
else
_rootDirProvider.Update(dir);
}
return Content(_settingsSaved);
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace NzbDrone.Web.Models
{
public class AddExistingSeriesModel
{
public bool IsWanted { get; set; }
public string Path { get; set; }
}
}

View File

@ -10,22 +10,7 @@ namespace NzbDrone.Web.Models
public class SettingsModel
{
[DataType(DataType.Text)]
[Required(ErrorMessage = "Please enter a valid TV path")]
[DisplayName("TV Folder")]
public String TvFolder
{
get;
set;
}
[DataType(DataType.Text)]
[DisplayName("Initial Quality")]
public int Quality
{
get;
set;
}
[DisplayName("TV Series Root Folder(s)")]
public List<RootDir> Directories { get; set; }
}
}

View File

@ -86,6 +86,7 @@
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
<Compile Include="Models\AccountModels.cs" />
<Compile Include="Models\AddExistingSeriesModel.cs" />
<Compile Include="Models\AddSeriesModel.cs" />
<Compile Include="Models\DownloadSettingsModel.cs" />
<Compile Include="Models\EpisodeSortingModel.cs" />
@ -271,6 +272,7 @@
<Content Include="Scripts\Notification.js" />
<Content Include="Views\Home\Test.aspx" />
<Content Include="Views\Log\Index.aspx" />
<Content Include="Views\Series\AddExisting.aspx" />
<Content Include="Views\Series\Details.aspx" />
<Content Include="Views\Series\Edit.aspx" />
<Content Include="Views\Series\EpisodeDetail.ascx" />
@ -278,6 +280,7 @@
<Content Include="Views\Series\SubMenu.ascx" />
<Content Include="Views\Series\Unmapped.aspx" />
<Content Include="Views\Series\Add.aspx" />
<Content Include="Views\Settings\RootDir.ascx" />
<Content Include="Views\Settings\Notifications.ascx" />
<Content Include="Views\Settings\Downloads.ascx" />
<Content Include="Views\Settings\EpisodeSorting.ascx" />

View File

@ -15,4 +15,8 @@
//Add Existing
//Ask user for existing TV Root Folder...
//Get list of unmapped folders and allow the user to check off the ones they want to add...
//
</asp:Content>

View File

@ -0,0 +1,35 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Import Namespace="Telerik.Web.Mvc.UI" %>
<%@ Import Namespace="NzbDrone.Web.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Add Existing Series
</asp:Content>
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
<%
Html.RenderPartial("SubMenu");
%>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
//Get AJAX listing of unmapped directories
<%
Html.Telerik().Grid<AddExistingSeriesModel>().Name("Unmapped Series Folders")
.Columns(columns =>
{
columns.Bound(c => c.IsWanted).Width(0).Title("Is Wanted?");
columns.Bound(c => c.Path);
})
//.DetailView(detailView => detailView.Template(e => Html.RenderPartial("EpisodeDetail", e)))
//.DetailView(detailView => detailView.ClientTemplate("<div><#= Overview #></div>"))
//.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.EpisodeNumber).Descending()).Enabled(true))
.Footer(false)
.DataBinding(d => d.Ajax().Select("_AjaxUnmappedFoldersGrid", "Series"))
//.EnableCustomBinding(true)
//.ClientEvents(e => e.OnDetailViewExpand("episodeDetailExpanded")) //Causes issues displaying the episode detail multiple times...
.Render();
%>`
</asp:Content>

View File

@ -5,7 +5,7 @@
<% Html.Telerik().Menu().Name("telerikGrid").Items(items =>
{
items.Add().Text("View Unmapped Folders").Action("Unmapped", "Series");
items.Add().Text("Sync With Disk").Action("Sync", "Series");
items.Add().Text("Sync With Disk").Action("Sync", "Series", new { paths = "test" });
items.Add().Text("Start RSS Sync").Action("RssSync", "Series");
items.Add().Text("Rename All").Action("RenameAll", "Series");
items.Add().Text("Add Series").Action("Add", "Series");

View File

@ -27,15 +27,21 @@
<% using (Html.BeginForm("SaveGeneral", "Settings", FormMethod.Post, new { id = "form", name = "form" }))
{%>
<%: Html.ValidationSummary(true, "Unable to save your settings. Please correct the errors and try again.") %>
<fieldset>
<fieldset>
<legend>General</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.TvFolder) %>
<div style="padding-top: 10px;">
<div style="padding-left: 7px; margin-bottom: 5px;">
<a id="addItem" style="text-decoration:none;" href="<%: Url.Action("AddRootDir", "Settings") %>">
<img src="../../Content/Images/Plus.png" alt="Add New Profile" />
<h4 style="margin-left: 3px; display: inline; color: Black;">Add New Root Directory</h4></a>
</div>
<div id="root-dirs">
<%foreach (var item in Model.Directories) { %>
<% Html.RenderPartial("RootDir", item); %>
<% } %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.TvFolder) %>
<%= Html.ValidationMessageFor(model => model.TvFolder) %>
</div>
<p>
@ -44,3 +50,35 @@
</fieldset>
<% } Html.EndForm();%>
<div id="result"></div>
<script type="text/javascript">
$("#addItem").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#root-dirs").append(html); }
});
return false;
});
$("a.deleteRow").live("click", function () {
$(this).parents("div.rootDirSection:first").remove();
return false;
});
$(".defaultCheckbox").live("change", function () {
var checked = $(this).attr('checked');
if (checked) {
var thisOne = this;
$(".defaultCheckbox").attr('checked', false);
$(this).attr('checked', true);
}
//Don't let the user uncheck a checkbox (Like a radio button)
else {
$(this).attr('checked', true);
}
});
</script>

View File

@ -0,0 +1,36 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NzbDrone.Core.Repository.RootDir>" %>
<%@ Import Namespace="NzbDrone.Web.Helpers" %>
<% using (Html.BeginCollectionItem("Directories"))
{ %>
<%
var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_');
//string sortable1 = String.Format("{0}_sortable1", idClean);
%>
<style type="text/css">
.root_dir_text { width:300px; }
</style>
<div class="rootDirSection">
<fieldset style="width:350px; height:16px; margin:0px; margin-top: 0px; border-color:#CCCCCD; -khtml-border-radius:8px; border-radius:8px; -moz-border-radius:8px; -webkit-border-radius:8px;">
<div>
<%: Html.CheckBoxFor(m => m.Default, new { @class = "defaultCheckbox" }) %>
<%: Html.TextBoxFor(m => m.Path, new { @class="root_dir_text" }) %>
<a href="#" class="deleteRow"><img src="../../Content/Images/X.png" alt="Delete"/></a>
</div>
<div>
<%: Html.ValidationMessageFor(m => m.Path) %>
</div>
<div class="hiddenProfileDetails">
<%= Html.TextBoxFor(x => x.RootDirId, new { @style = "display:none" })%>
</div>
</fieldset>
</div>
<% } %>

View File

@ -12,6 +12,8 @@
string sortable2 = String.Format("{0}_sortable2", idClean);
string allowedStringName = String.Format("{0}_AllowedString", idClean);
string connectedSortable = String.Format("connected{0}", idClean);
string title = String.Format("{0}_Title", idClean);
string nameBox = String.Format("{0}_Name", idClean);
%>
<style type="text/css">
@ -24,7 +26,6 @@
.sortable1 li.ui-state-highlight, .sortable2 li.ui-state-highlight { background: #fbf5d0; border-color: #065EFE; }
.removeDiv { float: left; display:block; }
.ui-state-highlight { height: 1.5em; line-height: 1.2em; }
</style>
<script type="text/javascript">
@ -53,7 +54,7 @@
<fieldset style="width:275px; margin:5px; margin-top: 0px; border-color:#CCCCCD">
<div id="qualityHeader" style="padding-bottom: 5px; margin: 0px;">
<h2 style="display:inline; padding-right: 4px; margin-left: 4px;"><%= Html.DisplayTextFor(m => m.Name) %></h2>
<h2 style="display:inline; padding-right: 4px; margin-left: 4px;" id="<%= title %>"><%= Html.DisplayTextFor(m => m.Name) %></h2>
<a href="#" class="deleteRow"><img src="../../Content/Images/X.png" alt="Delete" /></a>
</div>
@ -115,4 +116,12 @@
</div>
</fieldset>
</div>
<script type="text/javascript">
$("#<%: nameBox %>").keyup(function () {
var value = $(this).val();
$("#<%= title %>").text(value);
}).keyup();
</script>
<% } %>