Overhauled Settings/Quality

CSS for Settings uses classes for aligning instead of label/input directly.
This commit is contained in:
Mark McDowall 2011-07-01 02:10:42 -07:00
parent 63e303af3b
commit 859c5246d9
7 changed files with 293 additions and 193 deletions

View File

@ -0,0 +1,116 @@
#bottom
{
margin-top: -25px;
margin-left: 15px;
}
#addItem
{
text-decoration: none;
font-size:16px;
color: black;
font-weight:bold;
}
#profileHeader
{
margin-bottom: 5px;
}
/* QualityProfileItem */
.quality-selectee
{
border-color: #065EFE;
border-style: solid;
border-width: 1px;
width: 75px;
padding: 1px;
padding-left: 3px;
padding-right: 3px;
margin: 2px;
float: left;
cursor: default;
}
.quality-selecting
{
background: #85AEF9;
}
.quality-selected
{
background: #065EFE;
color: white;
}
.profileSection
{
float: left;
height: 157px;
width: 270px;
margin: 2px;
border:solid 1px #CCCCCD;
display: inline-block;
overflow: hidden;
}
.profileOptions label
{
margin-top: 10px;
margin-left: 7px;
margin-right: 25px;
float: left;
font-weight: bold;
width: 50px;
}
.profileOptions input, .profileOptions select
{
font-size:12px;
padding:4px 2px;
border:solid 1px #aacfe4;
width:170px;
margin-right: 2px;
}
.profileOptions select
{
width:176px;
}
.qualitySelector
{
padding-left: 5px;
}
.deleteProfile
{
position: absolute;
top: 0px;
right: 0px;
}
.titleText
{
font-size: 1.5em;
line-height: 1;
margin-bottom: 1em;
display:inline;
position: absolute;
top: -1px;
left: 2px;
padding-bottom: 0px;
white-space:nowrap;
}
.qualityHeader
{
background: #d7e6f2; /* Old browsers */
background: -moz-linear-gradient(left, #d7e6f2 0%, #57a9c6 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, right top, color-stop(0%,#d7e6f2), color-stop(100%,#57a9c6)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(left, #d7e6f2 0%,#57a9c6 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(left, #d7e6f2 0%,#57a9c6 100%); /* Opera11.10+ */
background: -ms-linear-gradient(left, #d7e6f2 0%,#57a9c6 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d7e6f2', endColorstr='#57a9c6',GradientType=1 ); /* IE6-9 */
background: linear-gradient(left, #d7e6f2 0%,#57a9c6 100%); /* W3C */
min-height: 23px;
position: relative;
}

View File

@ -36,7 +36,7 @@ p, h1, form, button{border:0; margin:0; padding:0;}
padding-bottom:10px; padding-bottom:10px;
} }
#stylized label #stylized .labelClass
{ {
display:block; display:block;
font-weight:bold; font-weight:bold;
@ -55,7 +55,7 @@ p, h1, form, button{border:0; margin:0; padding:0;}
width:340px; width:340px;
} }
#stylized input, select #stylized .inputClass
{ {
float:left; float:left;
font-size:12px; font-size:12px;
@ -65,6 +65,11 @@ p, h1, form, button{border:0; margin:0; padding:0;}
margin:2px 0 20px 10px; margin:2px 0 20px 10px;
} }
#stylized .selectClass
{
width: 206px;
}
#stylized button #stylized button
{ {
clear:both; clear:both;

View File

@ -125,6 +125,12 @@ namespace NzbDrone.Web.Controllers
ViewData["Qualities"] = qualityTypes; ViewData["Qualities"] = qualityTypes;
var profiles = _qualityProvider.GetAllProfiles().ToList(); var profiles = _qualityProvider.GetAllProfiles().ToList();
foreach (var qualityProfile in profiles)
{
qualityProfile.AllowedString = string.Join(",", qualityProfile.Allowed);
}
var defaultQualityQualityProfileId = Convert.ToInt32(_configProvider.DefaultQualityProfile); var defaultQualityQualityProfileId = Convert.ToInt32(_configProvider.DefaultQualityProfile);
var qualityProfileSelectList = new SelectList(profiles, "QualityProfileId", "Name"); var qualityProfileSelectList = new SelectList(profiles, "QualityProfileId", "Name");
@ -201,11 +207,12 @@ namespace NzbDrone.Web.Controllers
{ {
Name = "New Profile", Name = "New Profile",
Allowed = new List<QualityTypes> { QualityTypes.Unknown }, Allowed = new List<QualityTypes> { QualityTypes.Unknown },
Cutoff = QualityTypes.Unknown, Cutoff = QualityTypes.Unknown
}; };
var id = _qualityProvider.Add(qualityProfile); var id = _qualityProvider.Add(qualityProfile);
qualityProfile.QualityProfileId = id; qualityProfile.QualityProfileId = id;
qualityProfile.AllowedString = "Unknown";
ViewData["ProfileId"] = id; ViewData["ProfileId"] = id;

View File

@ -493,6 +493,7 @@
<Content Include="Content\Blueprint\ie.css" /> <Content Include="Content\Blueprint\ie.css" />
<Content Include="Content\Blueprint\screen.css" /> <Content Include="Content\Blueprint\screen.css" />
<Content Include="Content\Blueprint\liquid.css" /> <Content Include="Content\Blueprint\liquid.css" />
<Content Include="Content\QualitySettings.css" />
<Content Include="Content\Images\ajax-loader.gif" /> <Content Include="Content\Images\ajax-loader.gif" />
<Content Include="Content\ie.css" /> <Content Include="Content\ie.css" />
<Content Include="Content\Images\arrow.png" /> <Content Include="Content\Images\arrow.png" />

View File

@ -3,61 +3,14 @@
@section HeaderContent{ @section HeaderContent{
<link rel="stylesheet" type="text/css" href="../../Content/Settings.css" /> <link rel="stylesheet" type="text/css" href="../../Content/Settings.css" />
} <link href="../../Content/QualitySettings.css" rel="stylesheet" type="text/css" />
@section TitleContent{
Settings
}
@section ActionMenu{
@{Html.RenderPartial("SubMenu");}
}
@section MainContent{
@using (Html.BeginForm("SaveQuality", "Settings", FormMethod.Post, new { id = "form", name = "form" }))
{
<fieldset style="position: relative;">
<legend>Quality</legend>
<div id="top">
<div class="config-section">
<div class="config-group">
<div class="config-title">@Html.LabelFor(m => m.DefaultQualityProfileId)</div>
<div class="config-value">@Html.DropDownListFor(m => m.DefaultQualityProfileId, Model.QualityProfileSelectList)</div>
</div>
<div class="config-group2">
<div class="config-validation">@Html.ValidationMessageFor(m => m.DefaultQualityProfileId)</div>
<div class="config-description">@Html.DescriptionFor(m => m.DefaultQualityProfileId)</div>
</div>
</div>
</div>
<div id="bottom" style="float: left; padding-bottom: 55px;">
<div style="padding-left: 7px; margin-bottom: 5px;">
<a id="addItem" style="text-decoration:none;" href="@Url.Action("AddProfile", "Settings")">
<img src="../../Content/Images/Plus.png" alt="Add New Profile" width="20px" height="20px" />
<h4 style="margin-left: 3px; display: inline; color: Black;">
Add New Profile</h4>
</a>
</div>
<div id="profiles">
@foreach (var item in Model.Profiles)
{
Html.RenderAction("GetQualityProfileView", item);
}
</div>
</div>
<input type="submit" id="save_button" value="Save" style="position: absolute;
bottom: 0px; display: block; padding-left: 5px;" />
</fieldset>
}
<div id="result" class="hiddenResult">
</div>
}
@section Scripts{
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-1.6.1.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
function renameOption(text, value) {
$("#DefaultQualityProfileId option[value='" + value + "']").html(text);
}
function addOption(text, value) { function addOption(text, value) {
var myCombo = $('#DefaultQualityProfileId'); var myCombo = $('#DefaultQualityProfileId');
@ -70,11 +23,59 @@
function removeOption(value) { function removeOption(value) {
$("#DefaultQualityProfileId option[value='" + value + "']").remove(); $("#DefaultQualityProfileId option[value='" + value + "']").remove();
} }
</script>
}
function renameOption(text, value) { @section TitleContent{
$("#DefaultQualityProfileId option[value='" + value + "']").html(text); Settings
} }
@section ActionMenu{
@{Html.RenderPartial("SubMenu");}
}
@section MainContent{
<div id="stylized">
@using (Html.BeginForm("SaveQuality", "Settings", FormMethod.Post, new { id = "form", name = "form" }))
{
<div id="top" class="settingsForm clearfix">
<h1>Quality</h1>
<p></p>
<label class="labelClass">@Html.LabelFor(m => m.DefaultQualityProfileId)
<span class="small">@Html.DescriptionFor(m => m.DefaultQualityProfileId)</span>
</label>
@Html.DropDownListFor(m => m.DefaultQualityProfileId, Model.QualityProfileSelectList, new { @class = "inputClass" })
</div>
<div id="bottom" class="clearfix">
<div id="profileContainer">
<div id="profileHeader">
<a id="addItem" href="@Url.Action("AddProfile", "Settings")">
<img src="../../Content/Images/Plus.png" alt="Add New Profile" width="20px" height="20px" /> Add New Profile</a>
</div>
<div id="profiles" class="clearfix">
@foreach (var item in Model.Profiles)
{
Html.RenderAction("GetQualityProfileView", item);
}
</div>
</div>
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
</div>
}
</div>
<div id="result" class="hiddenResult"></div>
}
@section Scripts{
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
<script type="text/javascript">
$("#addItem").click(function () { $("#addItem").click(function () {
$.ajax({ $.ajax({
url: this.href, url: this.href,
@ -136,5 +137,53 @@
$("#form :input").attr("disabled", false); $("#form :input").attr("disabled", false);
$('#saveAjax').hide(); $('#saveAjax').hide();
} }
function getProfileId(obj) {
var parentProfileSection = $(obj).parents('.profileSection');
return parentProfileSection.children('.qualityProfileId').val();
}
function getCleanId(obj) {
var parentProfileSection = $(obj).parents('.profileSection');
return parentProfileSection.children('.cleanId').val();
}
$(".profileName_textbox").live('keyup', function () {
var value = $(this).val();
var profileId = getProfileId(this);
$("#title_" + profileId).text(value);
renameOption(value, profileId);
}).keyup();
$('.quality-selectee').live('click', function () {
var profileId = getProfileId(this);
var cleanId = getCleanId(this);
var cutoff = '#' + cleanId + '_Cutoff';
var allowedString = '#' + cleanId + '_AllowedString';
$(cutoff + ' option').each(function () { if ($(this).text().indexOf('Unknown') > -1) $(cutoff + ' option').remove(':contains("' + $(this).text() + '")'); });
if ($(this).hasClass('quality-selected')) {
$(this).removeClass('quality-selected');
var toRemove = this.firstChild.data;
$(cutoff + ' option').each(function () {
if ($(this).text().indexOf(toRemove) > -1)
$(cutoff + ' option').remove(':contains("' + $(this).text() + '")');
});
}
else {
$(this).addClass('quality-selected');
$('<option>' + this.firstChild.data + '</option>').appendTo(cutoff);
}
var result = "";
$("#selectable_" + profileId + " .quality-selected").each(function () {
result += this.firstChild.data + ",";
});
$(allowedString).empty().val(result);
});
</script> </script>
} }

View File

@ -5,127 +5,49 @@
@{ @{
Layout = null; Layout = null;
} }
<style>
.quality-selectee
{
width: 75px;
padding: 1px;
padding-left: 3px;
padding-right: 3px;
margin: 2px;
float: left;
cursor: default;
}
.quality-selecting
{
background: #85AEF9;
}
.quality-selected
{
background: #065EFE;
color: white;
}
</style>
@using (Html.BeginCollectionItem("Profiles")) @using (Html.BeginCollectionItem("Profiles"))
{ {
var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_'); var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_');
string selectable = String.Format("{0}_selectable", idClean); <div class="profileSection" id="profile_@(Model.QualityProfileId)">
string allowedStringName = String.Format("{0}_AllowedString", idClean); <div class="qualityHeader">
string title = String.Format("{0}_Title", idClean); <span class="titleText" id="title_@(Model.QualityProfileId)">
string nameBox = String.Format("{0}_Name", idClean); @Model.Name
string cutoff = String.Format("{0}_Cutoff", idClean); </span>
<a href="#" id="@Model.QualityProfileId" class="deleteProfile" onclick=" deleteProfile('@(Model.QualityProfileId)'); return false;">
<img src="../../Content/Images/X.png" alt="Delete" width="22px" height="22px" /></a>
</div>
<div class="profileOptions">
@Html.LabelFor(x => x.Name)
@Html.TextBoxFor(x => x.Name, new {@class = "profileName_textbox"})
<div class="profileSectionEditor" id="profile_@(ViewData["ProfileId"])" style="float: left; height: 175px; width: 285px; margin-bottom: -14px;"> @Html.LabelFor(x => x.Cutoff)
<fieldset style="width: 264px; margin: 5px; margin-top: 0px; border-color: #CCCCCD"> @Html.DropDownListFor(m => m.Cutoff, new SelectList(Model.Allowed, Model.Cutoff))
<div class="header"> </div>
<div id="qualityHeader" style="padding-bottom: 5px; margin: 0px;"> <div id = "selectable_@(Model.QualityProfileId)" class="qualitySelector">
<h2 style="display:inline; padding-right: 4px; margin-left: 4px;" id="@title"> @{ var qualitiesList = (List<QualityTypes>) ViewData["Qualities"]; }
@{Html.DisplayTextFor(m => m.Name);} @for (int i = 0; i < qualitiesList.Count(); i++)
</h2> {
<a href="#" id="@Model.QualityProfileId" class="deleteRow" onclick="deleteProfile('@ViewData["ProfileId"]'); return false;" style="float:right; padding-top:8px; padding-right: 5px;"> if (qualitiesList[i].ToString() == "Unknown")
<img src="../../Content/Images/X.png" alt="Delete" width="20px" height="20px" /></a> {
</div> continue;
<div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;"> }
<div class="config-title">@Html.LabelFor(x => x.Name)</div>
<div class="config-value">@Html.TextBoxFor(x => x.Name, new { maxlength = 15, style="width: 150px" })</div> if (Model.Allowed != null)
<div class="config-validation">@Html.ValidationMessageFor(x => x.Name)</div> {
</div> if (Model.Allowed.Contains(qualitiesList[i]))
<div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;">
<div class="config-title">@Html.LabelFor(x => x.Cutoff)</div>
<div class="config-value">@Html.DropDownListFor(m => m.Cutoff, new SelectList(Model.Allowed, Model.Cutoff))</div>
<div class="config-validation">@Html.ValidationMessageFor(x => x.Cutoff)</div>
</div>
</div>
<div class="selectableDiv" style="margin-top: 30px;">
<div id="@selectable">
@{var qualitiesList = (List<QualityTypes>)ViewData["Qualities"];}
@for (int i = 0; i < qualitiesList.Count(); i++)
{ {
if (qualitiesList[i].ToString() == "Unknown") <div class="quality-selectee quality-selected">@qualitiesList[i].ToString()</div>
{ continue;
continue;
}
if (Model.Allowed != null)
{
if (Model.Allowed.Contains(qualitiesList[i]))
{
<fieldset class="quality-selectee quality-selected">@qualitiesList[i].ToString()</fieldset>
continue;
}
}
<fieldset class="quality-selectee">@qualitiesList[i].ToString()</fieldset>
} }
</div> }
</div>
<div class="hiddenProfileDetails"> <div class="quality-selectee">@qualitiesList[i].ToString()</div>
@Html.HiddenFor(x => x.QualityProfileId) }
@Html.HiddenFor(m => m.AllowedString) </div>
</div> @Html.HiddenFor(x => x.QualityProfileId, new {@class = "qualityProfileId"})
</fieldset> @Html.HiddenFor(m => m.AllowedString)
@Html.Hidden("cleanId", idClean, new {@class = "cleanId"})
</div> </div>
<script type="text/javascript">
$(document).ready(function () {
addOption('@Model.Name', '@ViewData["ProfileId"]');
var result = "";
$("#@selectable .quality-selected").each(function () {
result += this.firstChild.data + ",";
});
$("#@allowedStringName").empty().val(result);
$('#@selectable .quality-selectee').disableSelection();
$('#@cutoff option').each(function () { if ($(this).text().indexOf('Unknown') > -1) $('#@cutoff option').remove(':contains("' + $(this).text() + '")'); });
});
$("#@nameBox").keyup(function () {
var value = $(this).val();
$("#@title").text(value);
renameOption(value, '@ViewData["ProfileId"]');
}).keyup();
$('#@selectable .quality-selectee').click(function () {
if ($(this).hasClass('quality-selected')) {
$(this).removeClass('quality-selected');
var toRemove = this.firstChild.data;
$('#@cutoff option').each(function () { if ($(this).text().indexOf(toRemove) > -1) $('#@cutoff option').remove(':contains("' + $(this).text() + '")'); });
}
else {
$(this).addClass('quality-selected');
$('<option>' + this.firstChild.data + '</option>').appendTo('#@cutoff');
}
var result = "";
$("#@selectable .quality-selected").each(function () {
result += this.firstChild.data + ",";
});
$("#@allowedStringName").empty().val(result);
});
</script>
} }

View File

@ -21,50 +21,50 @@
<h1>SABnzbd</h1> <h1>SABnzbd</h1>
<p></p> <p></p>
<label>Auto-Configure <label class="labelClass">Auto-Configure
<span class="small">If no Username and Password is set and SABnzbd is on the same system as NzbDrone, you cna auto-configure it</span> <span class="small">If no Username and Password is set and SABnzbd is on the same system as NzbDrone, you can auto-configure it</span>
</label> </label>
<input type="button" onclick="autoConfigureSab(); return false;" value="Auto-Configure" /> <input type="button" onclick="autoConfigureSab(); return false;" value="Auto-Configure" class="inputClass"/>
<label>@Html.LabelFor(m => m.SabHost) <label class="labelClass">@Html.LabelFor(m => m.SabHost)
<span class="small">@Html.DescriptionFor(m => m.SabHost)</span> <span class="small">@Html.DescriptionFor(m => m.SabHost)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabHost) @Html.TextBoxFor(m => m.SabHost, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabPort) <label class="labelClass">@Html.LabelFor(m => m.SabPort)
<span class="small">@Html.DescriptionFor(m => m.SabPort)</span> <span class="small">@Html.DescriptionFor(m => m.SabPort)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabPort) @Html.TextBoxFor(m => m.SabPort, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabApiKey) <label class="labelClass">@Html.LabelFor(m => m.SabApiKey)
<span class="small">@Html.DescriptionFor(m => m.SabApiKey)</span> <span class="small">@Html.DescriptionFor(m => m.SabApiKey)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabApiKey) @Html.TextBoxFor(m => m.SabApiKey, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabUsername) <label class="labelClass">@Html.LabelFor(m => m.SabUsername)
<span class="small">@Html.DescriptionFor(m => m.SabUsername)</span> <span class="small">@Html.DescriptionFor(m => m.SabUsername)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabUsername) @Html.TextBoxFor(m => m.SabUsername, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabPassword) <label class="labelClass">@Html.LabelFor(m => m.SabPassword)
<span class="small">@Html.DescriptionFor(m => m.SabPassword)</span> <span class="small">@Html.DescriptionFor(m => m.SabPassword)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabPassword) @Html.TextBoxFor(m => m.SabPassword, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabTvCategory) <label class="labelClass">@Html.LabelFor(m => m.SabTvCategory)
<span class="small">@Html.DescriptionFor(m => m.SabTvCategory)</span> <span class="small">@Html.DescriptionFor(m => m.SabTvCategory)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabTvCategory) @Html.TextBoxFor(m => m.SabTvCategory, new { @class = "inputClass" })
<label>@Html.LabelFor(m => m.SabTvPriority) <label class="labelClass">@Html.LabelFor(m => m.SabTvPriority)
<span class="small">@Html.DescriptionFor(m => m.SabTvPriority)</span> <span class="small">@Html.DescriptionFor(m => m.SabTvPriority)</span>
</label> </label>
@Html.DropDownListFor(m => m.SabTvPriority, Model.PrioritySelectList) @Html.DropDownListFor(m => m.SabTvPriority, Model.PrioritySelectList, new { @class = "inputClass selectClass" })
<label>@Html.LabelFor(m => m.SabDropDirectory) <label class="labelClass">@Html.LabelFor(m => m.SabDropDirectory)
<span class="small">@Html.DescriptionFor(m => m.SabDropDirectory)</span> <span class="small">@Html.DescriptionFor(m => m.SabDropDirectory)</span>
</label> </label>
@Html.TextBoxFor(m => m.SabDropDirectory) @Html.TextBoxFor(m => m.SabDropDirectory, new { @class = "inputClass" })
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/> <button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
} }