From a42b842345496e316d77f530afe6f6fe278d80a4 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 1 Jul 2010 15:06:24 -0700 Subject: [PATCH] Hooked up part removal from a content type - + some type editor related markup cleanup --HG-- branch : dev --- .../DefinitionTemplates/BodyPartSettings.ascx | 10 +- .../BodyTypePartSettings.ascx | 10 +- .../Fields/Common.TextField.ascx | 9 +- .../Controllers/AdminController.cs | 40 +++++ .../Orchard.ContentTypes.csproj | 2 + .../ViewModels/EditTypeViewModel.cs | 8 +- .../ViewModels/RemovePartViewModel.cs | 8 + .../Views/Admin/Edit.ascx | 33 ++-- .../Views/Admin/RemovePartFrom.ascx | 11 ++ .../Views/DisplayTemplates/Settings.ascx | 15 +- .../Views/EditorTemplates/Field.ascx | 13 +- .../Views/EditorTemplates/Part.ascx | 23 +-- .../Views/EditorTemplates/Parts.ascx | 3 +- .../DefinitionTemplates/FieldIndexing.ascx | 10 +- .../DefinitionTemplates/TypeIndexing.ascx | 10 +- .../Modules/Orchard.Themes/Scripts/base.js | 151 ++++++++++-------- 16 files changed, 217 insertions(+), 139 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/RemovePartViewModel.cs create mode 100644 src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.ascx diff --git a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyPartSettings.ascx b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyPartSettings.ascx index b4a75d0f0..d50af1f2f 100644 --- a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyPartSettings.ascx +++ b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyPartSettings.ascx @@ -1,6 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> -
- - <%:Html.EditorFor(m => m.FlavorDefault)%> - <%:Html.ValidationMessageFor(m => m.FlavorDefault)%> -
+
+ + <%:Html.EditorFor(m => m.FlavorDefault)%> + <%:Html.ValidationMessageFor(m => m.FlavorDefault)%> +
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyTypePartSettings.ascx b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyTypePartSettings.ascx index e1b503fa4..b6089b1e2 100644 --- a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyTypePartSettings.ascx +++ b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/BodyTypePartSettings.ascx @@ -1,6 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> -
- - <%:Html.EditorFor(m => m.Flavor) %> - <%:Html.ValidationMessageFor(m => m.Flavor) %> -
+
+ + <%:Html.EditorFor(m => m.Flavor) %> + <%:Html.ValidationMessageFor(m => m.Flavor) %> +
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields/Common.TextField.ascx b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields/Common.TextField.ascx index b0efc7830..67d19f41d 100644 --- a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields/Common.TextField.ascx +++ b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields/Common.TextField.ascx @@ -1,6 +1,5 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> -
- - <%: Html.EditorFor(m=>m.Value) %> - <%: Html.ValidationMessageFor(m=>m.Value) %> -
+
+ + <%:Html.EditorFor(m=>m.Value) %><%:Html.ValidationMessageFor(m=>m.Value) %> +
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs index 00c33ec29..087d62988 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs @@ -238,6 +238,46 @@ namespace Orchard.ContentTypes.Controllers { return RedirectToAction("Edit", new {id}); } + public ActionResult RemovePartFrom(string id) { + if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type."))) + return new HttpUnauthorizedResult(); + + var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id); + + var viewModel = new RemovePartViewModel(); + if (contentTypeDefinition == null + || !TryUpdateModel(viewModel) + || !contentTypeDefinition.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) + return new NotFoundResult(); + + viewModel.Type = new EditTypeViewModel { Name = contentTypeDefinition.Name, DisplayName = contentTypeDefinition.DisplayName }; + return View(viewModel); + } + + [HttpPost, ActionName("RemovePartFrom")] + public ActionResult RemovePartFromPOST(string id) { + if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type."))) + return new HttpUnauthorizedResult(); + + var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id); + + var viewModel = new RemovePartViewModel(); + if (contentTypeDefinition == null + || !TryUpdateModel(viewModel) + || !contentTypeDefinition.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) + return new NotFoundResult(); + + if (!ModelState.IsValid) { + viewModel.Type = new EditTypeViewModel { Name = contentTypeDefinition.Name, DisplayName = contentTypeDefinition.DisplayName }; + return View(viewModel); + } + + _contentDefinitionManager.AlterTypeDefinition(id, typeBuilder => typeBuilder.RemovePart(viewModel.Name)); + Services.Notifier.Information(T("The \"{0}\" part has been removed.", viewModel.Name)); + + return RedirectToAction("Edit", new {id}); + } + #endregion #region Parts diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj index 5cbef0319..02c48efba 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj @@ -77,6 +77,7 @@ + @@ -87,6 +88,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypeViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypeViewModel.cs index f912eb7f1..95086f18d 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypeViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypeViewModel.cs @@ -32,11 +32,11 @@ namespace Orchard.ContentTypes.ViewModels { return implicitTypePart == null ? Enumerable.Empty() - : implicitTypePart.PartDefinition.Fields.Select(f => new EditPartFieldViewModel(f)); + : implicitTypePart.PartDefinition.Fields.Select(f => new EditPartFieldViewModel(f) { Part = new EditPartViewModel(implicitTypePart.PartDefinition) }); } private IEnumerable GetTypeParts(ContentTypeDefinition contentTypeDefinition) { - return contentTypeDefinition.Parts.Where(p => p.PartDefinition.Name != Name).Select(p => new EditTypePartViewModel(p)); + return contentTypeDefinition.Parts.Where(p => p.PartDefinition.Name != Name).Select(p => new EditTypePartViewModel(p) { Type = this }); } } @@ -49,6 +49,7 @@ namespace Orchard.ContentTypes.ViewModels { Settings = part.Settings; } + public EditTypeViewModel Type { get; set; } public EditPartViewModel PartDefinition { get; set; } public SettingsDictionary Settings { get; set; } public IEnumerable Templates { get; set; } @@ -61,7 +62,7 @@ namespace Orchard.ContentTypes.ViewModels { } public EditPartViewModel(ContentPartDefinition contentPartDefinition) { Name = contentPartDefinition.Name; - Fields = contentPartDefinition.Fields.Select(f => new EditPartFieldViewModel(f)); + Fields = contentPartDefinition.Fields.Select(f => new EditPartFieldViewModel(f) { Part = this }); Settings = contentPartDefinition.Settings; } @@ -81,6 +82,7 @@ namespace Orchard.ContentTypes.ViewModels { Settings = field.Settings; } + public EditPartViewModel Part { get; set; } public string Name { get; set; } public IEnumerable Templates { get; set; } public EditFieldViewModel FieldDefinition { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/RemovePartViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/RemovePartViewModel.cs new file mode 100644 index 000000000..88844e073 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/RemovePartViewModel.cs @@ -0,0 +1,8 @@ +using Orchard.Mvc.ViewModels; + +namespace Orchard.ContentTypes.ViewModels { + public class RemovePartViewModel : BaseViewModel { + public string Name { get; set; } + public EditTypeViewModel Type { get; set; } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.ascx index e438597b9..f9cd5f5f2 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.ascx +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.ascx @@ -1,25 +1,30 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> -<% Html.RegisterStyle("admin.css"); %> -

<%:Html.TitleForPage(T("Edit Content Type").ToString())%>

+<% Html.RegisterStyle("admin.css"); +%>

<%:Html.TitleForPage(T("Edit Content Type").ToString())%>

<% using (Html.BeginFormAntiForgeryPost()) { %> - <%:Html.ValidationSummary() %> + <%--//todo: come up with real itemtype definitions and locations for said definitions--%> +
<%:Html.ValidationSummary() %>
- <%:Html.TextBoxFor(m => m.DisplayName, new {@class = "textMedium"}) %> - <%--// has unintended consequences (renamging the type) - changing the name creates a new type of that name--%> - - <%:Html.TextBoxFor(m => m.Name, new {@class = "textMedium", disabled = "disabled"}) %> + <%:Html.TextBoxFor(m => m.DisplayName, new { @class = "textMedium" })%> + <%--// todo: if we continue to go down the midrodata route, some helpers would be nice--%> + <%-- + // has unintended consequences (renamging the type) - changing the name creates a new type of that name--%> + + <%:Html.TextBoxFor(m => m.Name, new { @class = "textMedium", disabled = "disabled" })%> + <%:Html.HiddenFor(m => m.Name) %> -
- <% Html.RenderTemplates(Model.Templates); %> + <% + Html.RenderTemplates(Model.Templates); %>

<%:T("Parts") %>

-
<%: Html.ActionLink(T("Add").Text, "AddPartsTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" })%>
- <%:Html.EditorFor(m => m.Parts, "Parts", "") %> +
<%: Html.ActionLink(T("Add").Text, "AddPartsTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" })%>
<%: + Html.EditorFor(m => m.Parts, "Parts", "") %>

<%:T("Fields") %>

-
<%: Html.ActionLink(T("Add").Text, "AddFieldTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" }) %>
- <%:Html.EditorFor(m => m.Fields, "Fields", "") %> +
<%: Html.ActionLink(T("Add").Text, "AddFieldTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" }) %>
<%: + Html.EditorFor(m => m.Fields, "Fields", "") %>
-
<% + +
<% } %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.ascx new file mode 100644 index 000000000..c2c5cfa45 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.ascx @@ -0,0 +1,11 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<% +Html.RegisterStyle("admin.css"); %> +

<%:Html.TitleForPage(T("Remove the \"{0}\" part from \"{1}\"", Model.Name, Model.Type.DisplayName).ToString())%>

<% +using (Html.BeginFormAntiForgeryPost()) { %> +

<%:T("Looks like you couldn't use the fancy way to remove the part. Try hitting the button below to force the issue.") %>

+
+ <%=Html.HiddenFor(m => m.Name) %> + +
<% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/Settings.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/Settings.ascx index 24d4536cd..47687cbe1 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/Settings.ascx +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/Settings.ascx @@ -1,8 +1,11 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ import Namespace="Orchard.ContentManagement.MetaData.Models" %> -
<% - foreach (var setting in Model) { %> -
<%:setting.Key %>
-
<%:setting.Value %>
<% - } %> -
\ No newline at end of file +<% +if (Model.Any()) { %> +
<% + foreach (var setting in Model) { %> +
<%:setting.Key %>
+
<%:setting.Value %>
<% + } %> +
<% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Field.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Field.ascx index af061a2a1..d59fbfc65 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Field.ascx +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Field.ascx @@ -2,15 +2,8 @@

<%:Model.Name %> (<%:Model.FieldDefinition.Name %>)

- <%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link. - // get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%> <%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork!") %> -<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Orchard.ContentTypes" }), FormMethod.Post, new {@class = "inline link"})) { %> - <%:Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %> - - <% } %> --%> -
- <% Html.RenderTemplates(Model.Templates); %> - <%:Html.HiddenFor(m => m.Name) %> - <%:Html.HiddenFor(m => m.FieldDefinition.Name) %> + <% + Html.RenderTemplates(Model.Templates); %> + <%:Html.HiddenFor(m => m.Name) %><%:Html.HiddenFor(m => m.FieldDefinition.Name) %>
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Part.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Part.ascx index 78cb2e201..6743e1adf 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Part.ascx +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Part.ascx @@ -1,20 +1,13 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> -
-

<%:Model.PartDefinition.Name %>

+
+

<%:Model.PartDefinition.Name %>

- <%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link. - // get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%> - <%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork") %> -<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %> - <%:Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %> - - <% } %> --%> -
- <% Html.RenderTemplates(Model.Templates); %> - + <%:Html.ActionLink(T("Remove").Text, "RemovePartFrom", new { area = "Orchard.ContentTypes", id = Model.Type.Name, Model.PartDefinition.Name }, new { itemprop = "RemoveUrl UnsafeUrl" })%><%--// <- some experimentation--%> + <% + Html.RenderTemplates(Model.Templates); %>

<%:T("Global configuration") %>

<%:Html.ActionLink(T("Edit").Text, "EditPart", new { area = "Orchard.ContentTypes", id = Model.PartDefinition.Name }) %>
- <%:Html.DisplayFor(m => m.PartDefinition.Settings, "Settings", "PartDefinition") %> - <%:Html.EditorFor(m => m.PartDefinition.Fields, "Fields", "PartDefinition") %> - <%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %> + <%:Html.DisplayFor(m => m.PartDefinition.Settings, "Settings", "PartDefinition") + %><%:Html.EditorFor(m => m.PartDefinition.Fields, "Fields", "PartDefinition") + %><%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %>
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Parts.ascx b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Parts.ascx index 8f6e4b0ff..b821e2d1e 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Parts.ascx +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/EditorTemplates/Parts.ascx @@ -1,5 +1,4 @@ -<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> -<% +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %><% if (Model.Any()) { %>
<% var pi = 0; diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.ascx b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.ascx index 2f4404622..2856e7740 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.ascx +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.ascx @@ -1,7 +1,7 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Mvc.Html" %> -
- <%:Html.EditorFor(m=>m.Included) %> - - <%:Html.ValidationMessageFor(m => m.Included)%> -
+
+ <%:Html.EditorFor(m=>m.Included) %> + <%: + Html.ValidationMessageFor(m => m.Included)%> +
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.ascx b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.ascx index 2dc8a7721..01e1ef1ab 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.ascx +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.ascx @@ -1,7 +1,7 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Mvc.Html" %> -
- <%:Html.EditorFor(m=>m.Included) %> - - <%:Html.ValidationMessageFor(m=>m.Included) %> -
+
+ <%:Html.EditorFor(m=>m.Included) %> + <%: + Html.ValidationMessageFor(m=>m.Included) %> +
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Scripts/base.js b/src/Orchard.Web/Modules/Orchard.Themes/Scripts/base.js index a5f3d1ec7..590aa4e1b 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Scripts/base.js +++ b/src/Orchard.Web/Modules/Orchard.Themes/Scripts/base.js @@ -1,69 +1,92 @@ -(function($){ -//todo: (heskew) make use of the autofocus attribute instead -$.fn.extend({ - helpfullyFocus: function() { - var _this = $(this); - var firstError = _this.find(".input-validation-error").first(); - // try to focus the first error on the page - if (firstError.size() === 1) { - return firstError.focus(); - } - // or, give it up to the browser to autofocus - if ('autofocus' in document.createElement('input')) { - return; - } - // otherwise, make the autofocus attribute work - var autofocus = _this.find(":input[autofocus=autofocus]").first(); - return autofocus.focus(); - }, - toggleWhatYouControl: function() { - var _this = $(this); - var _controllees = $("[data-controllerid=" + _this.attr("id") + "]"); - var _controlleesAreHidden = _controllees.is(":hidden"); - if (_this.is(":checked") && _controlleesAreHidden) { - _controllees.hide(); // <- unhook this when the following comment applies - $(_controllees.show()[0]).find("input").focus(); // <- aaaand a slideDown there...eventually - } else if (!(_this.is(":checked") && _controlleesAreHidden)) { - //_controllees.slideUp(200); <- hook this back up when chrome behaves, or when I care less - _controllees.hide() - } - } -}); -// collapsable areas - anything with a data-controllerid attribute has its visibility controlled by the id-ed radio/checkbox -(function() { - $("[data-controllerid]").each(function() { - var controller = $("#" + $(this).attr("data-controllerid")); - if (controller.data("isControlling")) { - return; - } - controller.data("isControlling", 1); - if (!controller.is(":checked")) { - $("[data-controllerid=" + controller.attr("id") + "]").hide(); - } - if (controller.is(":checkbox")) { - controller.click($(this).toggleWhatYouControl); - } else if (controller.is(":radio")) { - $("[name=" + controller.attr("name") + "]").click(function() { $("[name=" + $(this).attr("name") + "]").each($(this).toggleWhatYouControl); }); +(function ($) { + //todo: (heskew) make use of the autofocus attribute instead + $.fn.extend({ + helpfullyFocus: function () { + var _this = $(this); + var firstError = _this.find(".input-validation-error").first(); + // try to focus the first error on the page + if (firstError.size() === 1) { + return firstError.focus(); + } + // or, give it up to the browser to autofocus + if ('autofocus' in document.createElement('input')) { + return; + } + // otherwise, make the autofocus attribute work + var autofocus = _this.find(":input[autofocus=autofocus]").first(); + return autofocus.focus(); + }, + toggleWhatYouControl: function () { + var _this = $(this); + var _controllees = $("[data-controllerid=" + _this.attr("id") + "]"); + var _controlleesAreHidden = _controllees.is(":hidden"); + if (_this.is(":checked") && _controlleesAreHidden) { + _controllees.hide(); // <- unhook this when the following comment applies + $(_controllees.show()[0]).find("input").focus(); // <- aaaand a slideDown there...eventually + } else if (!(_this.is(":checked") && _controlleesAreHidden)) { + //_controllees.slideUp(200); <- hook this back up when chrome behaves, or when I care less + _controllees.hide() + } } }); -})(); -// inline form link buttons (form.inline.link button) swapped out for a link that submits said form -(function() { - $("form.inline.link").each(function() { - var _this = $(this); - var link = $(""); - var button = _this.children("button").first(); - link.text(button.text()) + // collapsable areas - anything with a data-controllerid attribute has its visibility controlled by the id-ed radio/checkbox + (function () { + $("[data-controllerid]").each(function () { + var controller = $("#" + $(this).attr("data-controllerid")); + if (controller.data("isControlling")) { + return; + } + controller.data("isControlling", 1); + if (!controller.is(":checked")) { + $("[data-controllerid=" + controller.attr("id") + "]").hide(); + } + if (controller.is(":checkbox")) { + controller.click($(this).toggleWhatYouControl); + } else if (controller.is(":radio")) { + $("[name=" + controller.attr("name") + "]").click(function () { $("[name=" + $(this).attr("name") + "]").each($(this).toggleWhatYouControl); }); + } + }); + })(); + // inline form link buttons (form.inline.link button) swapped out for a link that submits said form + (function () { + $("form.inline.link").each(function () { + var _this = $(this); + var link = $(""); + var button = _this.children("button").first(); + link.text(button.text()) .addClass(button.attr("class")) - .click(function() { _this.submit(); return false; }) - .unload(function() { _this = 0; }); - _this.replaceWith(link); - _this.css({ "position": "absolute", "left": "-9999em" }); - $("body").append(_this); + .click(function () { _this.submit(); return false; }) + .unload(function () { _this = 0; }); + _this.replaceWith(link); + _this.css({ "position": "absolute", "left": "-9999em" }); + $("body").append(_this); + }); + })(); + // a little better autofocus + $(function () { + $("body").helpfullyFocus(); + }); + // UnsafeUrl links -> form POST + //todo: need some real microdata support eventually (incl. revisiting usage of data-* attributes) + $(function () { + var magicToken = $("input[name=__RequestVerificationToken]"); + if (!magicToken) { return; } // no sense in continuing if form POSTS will fail + $("a[itemprop~=UnsafeUrl]").each(function () { + var _this = $(this); + var hrefParts = _this.attr("href").split("?"); + var form = $("
"); + form.append(magicToken.clone()); + if (hrefParts.length > 1) { + var queryParts = hrefParts[1].split("&"); + for (var i = 0; i < queryParts.length; i++) { + var queryPartKVP = queryParts[i].split("="); + //trusting hrefs in the page here + form.append($("")); + } + } + form.css({ "position": "absolute", "left": "-9999em" }); + $("body").append(form); + _this.click(function () { form.submit(); return false; }); + }); }); -})(); -// a little better autofocus -$(function() { - $("body").helpfullyFocus(); -}); })(jQuery); \ No newline at end of file