added captcha to submit quote form

This commit is contained in:
tmont 2011-02-28 10:34:46 +00:00
parent b503a20400
commit 9cc0df5980
12 changed files with 138 additions and 88 deletions

View File

@ -4,7 +4,6 @@ using System.Net.Mail;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Web;
using Portoa.Web.Controllers; using Portoa.Web.Controllers;
using Portoa.Web.Filters; using Portoa.Web.Filters;
using Portoa.Web.Security; using Portoa.Web.Security;
@ -12,22 +11,34 @@ using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models; using VideoGameQuotes.Web.Models;
namespace VideoGameQuotes.Web.Controllers { namespace VideoGameQuotes.Web.Controllers {
public class HomeController : Controller {
private readonly IAuthenticationService authenticationService;
private readonly ICurrentUserProvider<User> userProvider;
public static class CaptchaUtil {
private static readonly Random random = new Random();
private static readonly string[] answers = new[] { private static readonly string[] answers = new[] {
"I AM ERROR.", "I AM ERROR",
"shyron", "shyron",
"our princess is in another castle", "our princess is in another castle",
"the cake is a lie", "the cake is a lie",
"all your base", "all your base",
"ganon not gannon", "ganon not gannon",
"thunderbird", "thunderbird",
"'glad you came, pit!", "glad you came, pit",
"ryu huyabasa" "ryu huyabasa"
}; };
public static string GetRandomAnswer() {
return answers[random.Next(answers.Length)];
}
public static string Hash(string value) {
return Convert.ToBase64String(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(value ?? string.Empty)));
}
}
public class HomeController : Controller {
private readonly IAuthenticationService authenticationService;
private readonly ICurrentUserProvider<User> userProvider;
public HomeController(IAuthenticationService authenticationService, ICurrentUserProvider<User> userProvider) { public HomeController(IAuthenticationService authenticationService, ICurrentUserProvider<User> userProvider) {
this.authenticationService = authenticationService; this.authenticationService = authenticationService;
this.userProvider = userProvider; this.userProvider = userProvider;
@ -41,6 +52,10 @@ namespace VideoGameQuotes.Web.Controllers {
return View(); return View();
} }
public ActionResult Favicon() {
return File("/media/images/favicon.png", "image/png");
}
[HttpPost] [HttpPost]
public ActionResult Login([Required]string username, [Required]string password) { public ActionResult Login([Required]string username, [Required]string password) {
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
@ -66,32 +81,24 @@ namespace VideoGameQuotes.Web.Controllers {
} }
public ActionResult Contact() { public ActionResult Contact() {
var randomAnswer = GetRandomAnswer(); var randomAnswer = CaptchaUtil.GetRandomAnswer();
var model = new ContactModel { var model = new ContactModel {
UnhashedCaptchaAnswer = randomAnswer, UnhashedCaptchaAnswer = randomAnswer,
HashedCaptchaAnswer = GetHashedCaptcha(randomAnswer) HashedCaptchaAnswer = CaptchaUtil.Hash(randomAnswer)
}; };
return View(model); return View(model);
} }
private static string GetRandomAnswer() {
return answers[new Random().Next(answers.Length)];
}
private static string GetHashedCaptcha(string value) {
return Convert.ToBase64String(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(value ?? string.Empty)));
}
private static void ResetModel(ContactModel model) { private static void ResetModel(ContactModel model) {
model.UnhashedCaptchaAnswer = GetRandomAnswer(); model.UnhashedCaptchaAnswer = CaptchaUtil.GetRandomAnswer();
model.HashedCaptchaAnswer = GetHashedCaptcha(model.UnhashedCaptchaAnswer); model.HashedCaptchaAnswer = CaptchaUtil.Hash(model.UnhashedCaptchaAnswer);
model.CaptchaAnswer = null; model.CaptchaAnswer = null;
} }
[HttpPost] [HttpPost]
public ActionResult Contact(ContactModel model) { public ActionResult Contact(ContactModel model) {
if (GetHashedCaptcha(model.CaptchaAnswer) != model.HashedCaptchaAnswer) { if (CaptchaUtil.Hash(model.CaptchaAnswer) != model.HashedCaptchaAnswer) {
ModelState.AddModelError("CaptchaAnswer", "You are not human"); ModelState.AddModelError("CaptchaAnswer", "You are not human");
} }

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web.Mvc; using System.Web.Mvc;
using Portoa.Persistence; using Portoa.Persistence;
using Portoa.Search; using Portoa.Search;
@ -171,55 +173,56 @@ namespace VideoGameQuotes.Web.Controllers {
} }
try { try {
var model = new EditQuoteModel(quoteService.GetQuote(id)); return View(ResetEditQuoteModel(new EditQuoteModel(quoteService.GetQuote(id))));
ResetEditQuoteModel(model);
return View(model);
} catch (EntityNotFoundException) { } catch (EntityNotFoundException) {
return View("QuoteNotFound"); return View("QuoteNotFound");
} }
} }
[HttpPost, VerifyUser(Group = UserGroup.Admin)] [HttpPost, VerifyUser(Group = UserGroup.Admin)]
public ActionResult Edit(EditQuoteModel model) { public ActionResult Edit(EditQuoteModelBase model) {
return CreateOrEditQuote(model, "Edit"); return CreateOrEditQuote(model, "Edit");
} }
[VerifyUser] [VerifyUser]
public ActionResult Submit() { public ActionResult Submit() {
var model = new EditQuoteModel(); return View(ResetEditQuoteModel(new SubmitQuoteModel()));
ResetEditQuoteModel(model);
return View(model);
} }
[HttpPost, VerifyUser] [HttpPost, VerifyUser]
public ActionResult Submit(EditQuoteModel model) { public ActionResult Submit(SubmitQuoteModel model) {
if (CaptchaUtil.Hash(model.CaptchaAnswer) != model.HashedCaptchaAnswer) {
ModelState.AddModelError("CaptchaAnswer", "You are not human");
}
return CreateOrEditQuote(model, "Submit"); return CreateOrEditQuote(model, "Submit");
} }
private ActionResult CreateOrEditQuote(EditQuoteModel model, string viewName) { private ActionResult CreateOrEditQuote(EditQuoteModelBase model, string viewName) {
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
ResetEditQuoteModel(model); model = ResetEditQuoteModel(model);
return View(viewName, model); return View(viewName, model);
} }
try { try {
var quote = model.QuoteId > 0 var editModel = model as EditQuoteModel;
? quoteService.GetQuote(model.QuoteId)
var quote = editModel != null && editModel.QuoteId > 0
? quoteService.GetQuote(editModel.QuoteId)
: new Quote { Creator = currentUserProvider.CurrentUser }; : new Quote { Creator = currentUserProvider.CurrentUser };
quote.Game = quoteService.GetGame(model.GameId); quote.Game = new Game { Id = model.GameId };
quote.Text = model.QuoteText; quote.Text = model.QuoteText;
if (model.CategoryIds != null && model.CategoryIds.Count > 0) { if (model.CategoryIds != null && model.CategoryIds.Count > 0) {
quote.ClearCategories(); quote.ClearCategories();
foreach (var categoryId in model.CategoryIds) { foreach (var categoryId in model.CategoryIds) {
quote.AddCategory(quoteService.GetCategory(categoryId)); quote.AddCategory(new Category { Id = categoryId });
} }
} }
if (quote.Game == null) { if (quote.Game == null) {
ResetEditQuoteModel(model); return View(viewName, ResetEditQuoteModel(model));
return View(viewName, model);
} }
quote = quoteService.SaveQuote(quote); quote = quoteService.SaveQuote(quote);
@ -227,17 +230,26 @@ namespace VideoGameQuotes.Web.Controllers {
return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() }); return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() });
} catch (Exception e) { } catch (Exception e) {
ModelState.AddModelError("save", e.Message); ModelState.AddModelError("save", e.Message);
ResetEditQuoteModel(model); return View(viewName, ResetEditQuoteModel(model));
return View(viewName, model);
} }
} }
private void ResetEditQuoteModel(EditQuoteModel model) { private EditQuoteModelBase ResetEditQuoteModel(EditQuoteModelBase model) {
model.CurrentUser = currentUserProvider.CurrentUser; model.CurrentUser = currentUserProvider.CurrentUser;
model.AllGames = quoteService.GetAllGames().OrderBy(game => game.Name); model.AllGames = quoteService.GetAllGames().OrderBy(game => game.Name);
model.AllSystems = quoteService.GetAllSystems().OrderBy(system => system.ReleaseDate); model.AllSystems = quoteService.GetAllSystems().OrderBy(system => system.ReleaseDate);
model.AllPublishers = quoteService.GetAllPublishers().OrderBy(publisher => publisher.Name); model.AllPublishers = quoteService.GetAllPublishers().OrderBy(publisher => publisher.Name);
model.AllCategories = quoteService.GetAllCategories().OrderBy(category => category.Name); model.AllCategories = quoteService.GetAllCategories().OrderBy(category => category.Name);
var submitModel = model as SubmitQuoteModel;
if (submitModel != null) {
submitModel.UnhashedCaptchaAnswer = CaptchaUtil.GetRandomAnswer();
submitModel.HashedCaptchaAnswer = CaptchaUtil.Hash(submitModel.UnhashedCaptchaAnswer);
submitModel.CaptchaAnswer = null;
return submitModel;
}
return model;
} }
public ActionResult Quote(int id) { public ActionResult Quote(int id) {

View File

@ -61,18 +61,17 @@ namespace VideoGameQuotes.Web {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("media/{*anything}"); routes.IgnoreRoute("media/{*anything}");
routes.MapRoute("favicon", "favicon.ico", new { controller = "Home", action = "Favicon" });
//bullshit route so that RenderAction works //bullshit route so that RenderAction works
routes.MapRoute("mainmenu", "home/mainmenu", new { controller = "Home", action = "MainMenu" }); routes.MapRoute("mainmenu", "home/mainmenu", new { controller = "Home", action = "MainMenu" });
routes.MapRoute("quote-of-the-day", "quote/quoteoftheday", new { controller = "Quote", action = "QuoteOfTheDay" }); routes.MapRoute("quote-of-the-day", "quote/quoteoftheday", new { controller = "Quote", action = "QuoteOfTheDay" });
routes.MapRoute("crud-default", "{controller}/{action}", null, new { controller = "system|publisher|game|category", action = "create|edit|delete" }); routes.MapRoute("crud-default", "{controller}/{action}", null, new { controller = "system|publisher|game|category", action = "create|edit|delete" });
routes.MapRoute("users-paged", "admin/users/{start}-{end}", new { controller = "Admin", action = "Users" }, new { start = @"\d+", end = @"\d+" }); routes.MapRoute("users-paged", "admin/users/{start}-{end}", new { controller = "Admin", action = "Users" }, new { start = @"\d+", end = @"\d+" });
routes.MapRoute("admin", "admin/{action}", new { controller = "Admin", action = "Index" }, new { action = "users|create|flags|password" }); routes.MapRoute("admin", "admin/{action}", new { controller = "Admin", action = "Index" }, new { action = "users|create|flags|password" });
routes.MapRoute("user-edit", "user/edit/{usernameOrIp}", new { controller = "User", action = "Edit", usernameOrIp = @"\w+" }); routes.MapRoute("user-edit", "user/edit/{usernameOrIp}", new { controller = "User", action = "Edit", usernameOrIp = @"\w+" });
routes.MapRoute("user-default", "user/{action}/{id}", new { controller = "User", action = "delete|ban", id = UrlParameter.Optional }); routes.MapRoute("user-default", "user/{action}/{id}", new { controller = "User", action = "delete|ban", id = UrlParameter.Optional });
routes.MapRoute("api", "api/{action}/{id}/{*criteria}", new { controller = "Api" }, new { action = "game|system|category|publisher|quote", id = @"\d+|all" }); routes.MapRoute("api", "api/{action}/{id}/{*criteria}", new { controller = "Api" }, new { action = "game|system|category|publisher|quote", id = @"\d+|all" });
routes.MapRoute("home", "{action}", new { controller = "Home", action = "Index" }, new { action = "about|contact|login|logout" }); routes.MapRoute("home", "{action}", new { controller = "Home", action = "Index" }, new { action = "about|contact|login|logout" });
routes.MapRoute("paged", "{action}/{page}", new { controller = "Quote", page = 1 }, new { action = "best|recent", page = @"\d+" }); routes.MapRoute("paged", "{action}/{page}", new { controller = "Quote", page = 1 }, new { action = "best|recent", page = @"\d+" });

View File

@ -10,13 +10,14 @@ using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Models { namespace VideoGameQuotes.Web.Models {
public class EditQuoteModel { public class SubmitQuoteModel : EditQuoteModelBase {
public EditQuoteModel() { public string CaptchaAnswer { get; set; }
ControllerName = "Quote"; public string HashedCaptchaAnswer { get; set; }
ActionName = "Submit"; public string UnhashedCaptchaAnswer { get; set; }
} }
public EditQuoteModel(Quote quote) : this() { public class EditQuoteModel : EditQuoteModelBase {
public EditQuoteModel(Quote quote) {
QuoteId = quote.Id; QuoteId = quote.Id;
Flags = quote.Flags.ToList(); Flags = quote.Flags.ToList();
QuoteText = quote.Text; QuoteText = quote.Text;
@ -25,22 +26,27 @@ namespace VideoGameQuotes.Web.Models {
ActionName = "Edit"; ActionName = "Edit";
} }
public User CurrentUser { get; set; }
public string ActionName { get; set; }
public string ControllerName { get; set; }
public int QuoteId { get; set; } public int QuoteId { get; set; }
public List<QuoteFlag> Flags { get; set; } public List<QuoteFlag> Flags { get; set; }
}
public abstract class EditQuoteModelBase {
protected EditQuoteModelBase() {
ControllerName = "quote";
ActionName = "submit";
}
public User CurrentUser { get; set; }
public string ActionName { get; set; }
public string ControllerName { get; set; }
[Required(ErrorMessage = "Quote text must be non-empty, saddlebags")] [Required(ErrorMessage = "Quote text must be non-empty, saddlebags")]
[StringLength(1024, ErrorMessage = "Quote can't be longer than 1024 characters, slut")] [StringLength(1024, ErrorMessage = "Quote can't be longer than 1024 characters, slut")]
[DisplayName("Quote")] [DisplayName("Quote")]
public string QuoteText { get; set; } public string QuoteText { get; set; }
[DisplayName("Categories")]
public IList<int> CategoryIds { get; set; } public IList<int> CategoryIds { get; set; }
[GreaterThanZero(ErrorMessage = "Quit screwing with the form, faggle"), DisplayName("Game")] [Required(ErrorMessage = "Quit screwing with the form, faggle"), DisplayName("Game")]
public int GameId { get; set; } public int GameId { get; set; }
public IEnumerable<Game> AllGames { get; set; } public IEnumerable<Game> AllGames { get; set; }
@ -48,7 +54,6 @@ namespace VideoGameQuotes.Web.Models {
public IEnumerable<Publisher> AllPublishers { get; set; } public IEnumerable<Publisher> AllPublishers { get; set; }
public IEnumerable<Category> AllCategories { get; set; } public IEnumerable<Category> AllCategories { get; set; }
public IEnumerable<SelectListItem> GetGameList() { public IEnumerable<SelectListItem> GetGameList() {
return AllGames.Select(game => new SelectListItem { Value = game.Id.ToString(), Text = game.Name }); return AllGames.Select(game => new SelectListItem { Value = game.Id.ToString(), Text = game.Name });
} }
@ -83,7 +88,7 @@ namespace VideoGameQuotes.Web.Models {
return table.ToString(TagRenderMode.Normal); return table.ToString(TagRenderMode.Normal);
} }
public string MakePublisherTable(HtmlHelper<EditQuoteModel> html, int cellsPerRow = 4) { public string MakePublisherTable(HtmlHelper<EditQuoteModelBase> html, int cellsPerRow = 4) {
return MakeTable( return MakeTable(
"publisher-checkbox-table", "publisher-checkbox-table",
cellsPerRow, cellsPerRow,
@ -92,7 +97,7 @@ namespace VideoGameQuotes.Web.Models {
); );
} }
public string MakeSystemTable(HtmlHelper<EditQuoteModel> html, int cellsPerRow = 6) { public string MakeSystemTable(HtmlHelper<EditQuoteModelBase> html, int cellsPerRow = 6) {
return MakeTable( return MakeTable(
"system-checkbox-table", "system-checkbox-table",
cellsPerRow, cellsPerRow,
@ -101,7 +106,7 @@ namespace VideoGameQuotes.Web.Models {
); );
} }
public string MakeCategoryTable(HtmlHelper<EditQuoteModel> html, int cellsPerRow = 5) { public string MakeCategoryTable(HtmlHelper<EditQuoteModelBase> html, int cellsPerRow = 5) {
var categoryIds = CategoryIds ?? new List<int>(); var categoryIds = CategoryIds ?? new List<int>();
return MakeTable( return MakeTable(
"category-checkbox-table", "category-checkbox-table",

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Models {
public class QuoteCollectionModel {
public IEnumerable<Quote> Quotes { get; set; }
public User User { get; set; }
}
}

View File

@ -110,7 +110,6 @@
<Compile Include="Models\MainMenuModel.cs" /> <Compile Include="Models\MainMenuModel.cs" />
<Compile Include="Models\QualifiedBrowseModel.cs" /> <Compile Include="Models\QualifiedBrowseModel.cs" />
<Compile Include="Models\PagedModelWithUser.cs" /> <Compile Include="Models\PagedModelWithUser.cs" />
<Compile Include="Models\QuoteCollectionModel.cs" />
<Compile Include="Models\QuoteFlagModel.cs" /> <Compile Include="Models\QuoteFlagModel.cs" />
<Compile Include="Models\QuoteModel.cs" /> <Compile Include="Models\QuoteModel.cs" />
<Compile Include="Models\ReportModel.cs" /> <Compile Include="Models\ReportModel.cs" />
@ -128,7 +127,7 @@
<SubType>ASPXCodeBehind</SubType> <SubType>ASPXCodeBehind</SubType>
</Compile> </Compile>
<Compile Include="Models\ContactModel.cs" /> <Compile Include="Models\ContactModel.cs" />
<Compile Include="Models\EditQuoteModel.cs" /> <Compile Include="Models\EditQuoteModelBase.cs" />
<Compile Include="Security\SessionBasedUserProvider.cs" /> <Compile Include="Security\SessionBasedUserProvider.cs" />
<Compile Include="Global.asax.cs"> <Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon> <DependentUpon>Global.asax</DependentUpon>

View File

@ -55,7 +55,7 @@
.addClass("dialog") .addClass("dialog")
.css({ top: "20px" }) .css({ top: "20px" })
.append( .append(
$("<span>The answer is <strong></strong></span>") $("<span>The answer is: <strong></strong></span>")
.css({ "white-space": "nowrap" }) .css({ "white-space": "nowrap" })
.find("strong") .find("strong")
.text("<%= Model.UnhashedCaptchaAnswer %>") .text("<%= Model.UnhashedCaptchaAnswer %>")

View File

@ -1,4 +1,4 @@
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.EditQuoteModel>" MasterPageFile="~/Views/Shared/Site.Master" %> <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.EditQuoteModelBase>" MasterPageFile="~/Views/Shared/Site.Master" %>
<asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Edit</asp:Content> <asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Edit</asp:Content>
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<h2>Edit Quote</h2> <h2>Edit Quote</h2>

View File

@ -1,11 +1,10 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<VideoGameQuotes.Web.Models.EditQuoteModel>" %> <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<VideoGameQuotes.Web.Models.EditQuoteModelBase>" %>
<%@ Import Namespace="Portoa.Web.Util" %> <%@ Import Namespace="Portoa.Web.Util" %>
<%@ Import Namespace="VideoGameQuotes.Api" %> <%@ Import Namespace="VideoGameQuotes.Api" %>
<%@ Import Namespace="VideoGameQuotes.Web.Models" %>
<div id="edit-quote-form"> <div id="edit-quote-form">
<% using (Html.BeginForm(Model.ActionName, Model.ControllerName)) { %> <% using (Html.BeginForm(Model.ActionName, Model.ControllerName)) { %>
<div><%= Html.HiddenFor(model => model.QuoteId, new { id = "quote-id" })%></div>
<p id="game-select"> <p id="game-select">
<%= Html.LabelFor(model => model.GameId, new { @class = "label" })%> <%= Html.LabelFor(model => model.GameId, new { @class = "label" })%>
<br /> <br />
@ -146,9 +145,10 @@
<p><a href="#" id="create-category-link" class="add-icon" title="create new category"></a></p> <p><a href="#" id="create-category-link" class="add-icon" title="create new category"></a></p>
</div> </div>
<% if (Model.QuoteId > 0) { %> <% var editModel = Model as EditQuoteModel; if (editModel != null && editModel.QuoteId > 0) { %>
<%= Html.Hidden("QuoteId", editModel.QuoteId, new { id = "quote-id" })%>
<div id="quote-flags-container"> <div id="quote-flags-container">
<% foreach (var flag in Model.Flags) { %> <% foreach (var flag in editModel.Flags) { %>
<div class="quote-flag"> <div class="quote-flag">
<input type="hidden" class="quote-flag-id" value="<%= flag.Id %>" /> <input type="hidden" class="quote-flag-id" value="<%= flag.Id %>" />
<p> <p>
@ -166,6 +166,16 @@
<hr /> <hr />
<p><%= Html.Submit(Model.QuoteId > 0 ? "Save" : "Submit Quote") %></p> <% var submitModel = Model as SubmitQuoteModel; if (submitModel != null) { %>
<input type="hidden" name="HashedCaptchaAnswer" id="HashedCaptchaAnswer" value="<%: submitModel.HashedCaptchaAnswer %>" />
<p>
Are you human? <small style="position: relative"><a href="#" id="captcha-question">[click for correct answer]</a></small>
<br />
<input type="text" name="CaptchaAnswer" id="CaptchaAnswer" value="" />
</p>
<% } %>
<p><%= Html.Submit(editModel != null && editModel.QuoteId > 0 ? "Save" : "Submit Quote") %></p>
<% } %> <% } %>
</div> </div>

View File

@ -1,4 +1,4 @@
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.EditQuoteModel>" MasterPageFile="~/Views/Shared/Site.Master" %> <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.SubmitQuoteModel>" MasterPageFile="~/Views/Shared/Site.Master" %>
<asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Submit New Quote</asp:Content> <asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Submit New Quote</asp:Content>
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<h2>Submit New Quote</h2> <h2>Submit New Quote</h2>
@ -8,4 +8,28 @@
</asp:Content> </asp:Content>
<asp:Content runat="server" ID="DeferrableScripts" ContentPlaceHolderID="DeferrableScripts"> <asp:Content runat="server" ID="DeferrableScripts" ContentPlaceHolderID="DeferrableScripts">
<script type="text/javascript" src="/media/js/quoteform.js"></script> <script type="text/javascript" src="/media/js/quoteform.js"></script>
<script type="text/javascript">//<![CDATA[
$(document).ready(function() {
$("#captcha-question").click(function() {
if ($("#captcha-dialog").length) {
$("#captcha-dialog").remove();
$(this).text("[click for correct answer]");
} else {
$("<div/>")
.attr("id", "captcha-dialog")
.addClass("dialog")
.css({ top: "20px" })
.append(
$("<span/>")
.css("white-space", "nowrap")
.text("<%= Model.UnhashedCaptchaAnswer %>")
).insertAfter($("#captcha-question"));
$(this).text("[click to hide]");
}
return false;
});
});
//]]></script>
</asp:Content> </asp:Content>

View File

@ -79,6 +79,10 @@ ul {
ol { ol {
list-style-type: decimal; list-style-type: decimal;
} }
li {
padding: 2px 1px;
margin: 1px 0;
}
dt { dt {
font-weight: bold; font-weight: bold;
padding: 2px; padding: 2px;
@ -471,7 +475,9 @@ a.external {
width: 500px; width: 500px;
position: relative; position: relative;
} }
.quote-game-link { #captcha-dialog {
position: absolute;
left: 0;
} }
.quote-categories a { .quote-categories a {
border: 1px solid #999999 !important; border: 1px solid #999999 !important;
@ -482,10 +488,7 @@ a.external {
color: #FFFFFF !important; color: #FFFFFF !important;
position: relative; position: relative;
} }
.quote-categories a.game-link { .quote-categories a img {
padding-left: 4px;
}
.quote-categories a.game-link img {
position: relative; position: relative;
top: 3px; top: 3px;
} }

View File

@ -41,8 +41,8 @@
data[type] = response.Data.records; data[type] = response.Data.records;
render(); render();
}, },
beforeSend: function() { $link.toggleClass("loading-link"); }, beforeSend: function() { $link.toggleClass("loading-icon"); },
complete: function() { $link.toggleClass("loading-link"); } complete: function() { $link.toggleClass("loading-icon"); }
}); });
} else { } else {
render(); render();