quote of the day, added external image

This commit is contained in:
tmont 2011-02-28 00:38:47 +00:00
parent 86b0918ca5
commit 602a722277
13 changed files with 164 additions and 70 deletions

View File

@ -135,6 +135,13 @@ namespace VideoGameQuotes.Web.Controllers {
return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() }); return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() });
} }
[ChildActionOnly]
public ActionResult QuoteOfTheDay() {
var today = DateTime.UtcNow.DayOfYear;
var quote = quoteService.GetQuoteForDayOfYear(today);
return PartialView("QuoteOfTheDay", quote);
}
[HttpPost, VerifyUser(Group = UserGroup.Admin)] [HttpPost, VerifyUser(Group = UserGroup.Admin)]
public ActionResult DismissFlag([GreaterThanZero]int quoteId, [GreaterThanZero]int flagId) { public ActionResult DismissFlag([GreaterThanZero]int quoteId, [GreaterThanZero]int flagId) {
if (!ModelState.IsValid) { if (!ModelState.IsValid) {

View File

@ -63,6 +63,7 @@ namespace VideoGameQuotes.Web {
//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("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" });

View File

@ -24,6 +24,7 @@ namespace VideoGameQuotes.Web.Services {
IEnumerable<Quote> GetBestQuotes(int start, int end, out int totalCount); IEnumerable<Quote> GetBestQuotes(int start, int end, out int totalCount);
Vote GetVoteOrCreateNew(Quote quote, User voter); Vote GetVoteOrCreateNew(Quote quote, User voter);
IEnumerable<Quote> GetBrowsableQuotes(BrowseModel model, int start, int end, out int totalCount); IEnumerable<Quote> GetBrowsableQuotes(BrowseModel model, int start, int end, out int totalCount);
Quote GetQuoteForDayOfYear(int day);
} }
public class QuoteService : IQuoteService { public class QuoteService : IQuoteService {
@ -34,6 +35,7 @@ namespace VideoGameQuotes.Web.Services {
private readonly IRepository<Category> categoryRepository; private readonly IRepository<Category> categoryRepository;
private readonly IRepository<Vote> voteRepository; private readonly IRepository<Vote> voteRepository;
private static readonly Random random = new Random(); private static readonly Random random = new Random();
private static readonly IDictionary<int, Quote> quoteOfTheDayMap = new Dictionary<int, Quote>();
public QuoteService( public QuoteService(
IRepository<Quote> quoteRepository, IRepository<Quote> quoteRepository,
@ -118,8 +120,16 @@ namespace VideoGameQuotes.Web.Services {
return null; return null;
} }
return quoteRepository return GetRandomQuote(quoteRepository.Records);
.Records }
private static Quote GetRandomQuote(IEnumerable<Quote> quotes) {
var length = quotes.Count();
if (length == 0) {
return null;
}
return quotes
.Skip(random.Next(length)) .Skip(random.Next(length))
.Take(1) .Take(1)
.Single(); .Single();
@ -164,5 +174,15 @@ namespace VideoGameQuotes.Web.Services {
totalCount = quotes.Count(); totalCount = quotes.Count();
return quotes.Skip(start - 1).Take(end - start + 1); return quotes.Skip(start - 1).Take(end - start + 1);
} }
[UnitOfWork, CanBeNull]
public Quote GetQuoteForDayOfYear(int day) {
if (!quoteOfTheDayMap.ContainsKey(day)) {
quoteOfTheDayMap[day] = GetRandomQuote(quoteRepository.Records.Where(quote => quote.Score > 0));
}
return quoteOfTheDayMap[day];
}
} }
} }

View File

@ -149,6 +149,7 @@
<Content Include="media\images\cancel.png" /> <Content Include="media\images\cancel.png" />
<Content Include="media\images\delete.png" /> <Content Include="media\images\delete.png" />
<Content Include="media\images\error.png" /> <Content Include="media\images\error.png" />
<Content Include="media\images\external.png" />
<Content Include="media\images\favicon.png" /> <Content Include="media\images\favicon.png" />
<Content Include="media\images\flag_red.png" /> <Content Include="media\images\flag_red.png" />
<Content Include="media\images\link.png" /> <Content Include="media\images\link.png" />
@ -172,6 +173,7 @@
<Content Include="Views\Home\Contact.aspx" /> <Content Include="Views\Home\Contact.aspx" />
<Content Include="Views\Home\ContactSuccess.aspx" /> <Content Include="Views\Home\ContactSuccess.aspx" />
<Content Include="Views\Quote\PagingMenu.ascx" /> <Content Include="Views\Quote\PagingMenu.ascx" />
<Content Include="Views\Quote\QuoteOfTheDay.ascx" />
<Content Include="Views\Shared\BadPaging.aspx" /> <Content Include="Views\Shared\BadPaging.aspx" />
<Content Include="Views\Quote\Best.aspx" /> <Content Include="Views\Quote\Best.aspx" />
<Content Include="Views\Quote\Edit.aspx" /> <Content Include="Views\Quote\Edit.aspx" />

View File

@ -3,12 +3,11 @@
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<h2>About</h2> <h2>About</h2>
<div class="inset">
<h3>Genesis</h3>
<div class="inset">
<p> <p>
<strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave <strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave
myself a week to implement everything and throw it up on the internet. myself a week to implement everything and throw it up on the internet. It actually took three
weeks as I struggled with <a href="http://incubator.apache.org/lucene.net/" class="external">Lucene</a> and my
obviously poor graphic design skills.
</p> </p>
<p> <p>
@ -17,31 +16,32 @@
</p> </p>
<p> <p>
The infrastructure is modeled after <a href="http://bash.org/">bash.org</a>, which is a database The infrastructure is modeled after <a href="http://bash.org/" class="external">bash.org</a>, which is a database
of IRC quotes. One thing I wanted to make sure of was that it shouldn't require you to login or of IRC quotes. One thing I wanted to make sure of was that it shouldn&rsquo;t require you to login or
register. No email addresses, or usernames, or passwords. The site keeps track of who has voted register. No email addresses, or usernames, or passwords. The site keeps track of who has voted
for what based on IP address, which admittedly is a quite fragile. But it's the only way to for what based on IP address, which admittedly is a quite fragile. But it&rsquo;s the only way to
unique-ish-ly identify someone without requiring a login. So, you could totally game the system unique-ish-ly identify someone without requiring a login. So, you could totally game the system
by voting, resetting your router, closing your browser, and voting again. I won&#39;t stop you. by voting, resetting your router, closing your browser, and voting again. I won&rsquo;t stop you.
</p> </p>
</div>
<h3>Technical Details</h3>
<div class="inset">
<p> <p>
The site was written in C&#9839; using <a href="http://www.asp.net/mvc">ASP.NET MVC 2</a>, The site was written in C&#9839; using <a href="http://www.asp.net/mvc" class="external">ASP.NET MVC 2</a>,
<a href="http://unity.codeplex.com/">Unity</a> and <a href="http://nhforge.org/">NHibernate</a>. <a href="http://unity.codeplex.com/" class="external">Unity</a> and <a href="http://nhforge.org/" class="external">NHibernate</a>.
It runs on <a href="http://nginx.org/">nginx</a> using <a href="http://www.mono-project.com/">Mono</a> It runs on <a href="http://nginx.org/" class="external">nginx</a> using <a href="http://www.mono-project.com/" class="external">Mono</a>
via FastCGI on Ubuntu. It uses MySQL for the backend. via FastCGI on Ubuntu. It uses MySQL for the backend and
<a href="http://incubator.apache.org/lucene.net/" class="external">Lucene.NET</a> for search indexing.
</p> </p>
</div>
<h3>Get in Touch</h3>
<div class="inset">
<p> <p>
If you have any questions, concerns, comments, insults or death threats, don&#39;t hesitate to If you have any questions, concerns, comments, insults or death threats, don&rsquo;t hesitate to
<%= Html.ActionLink("contact me", "Contact", "Home") %>. <%= Html.ActionLink("contact me", "Contact", "Home") %> and you will be ignored immediately.
</p>
<h3><a name="credits"></a>Credits</h3>
<p>
Some of the icons and images used on this site were taken from the
<a href="http://www.famfamfam.com/lab/icons/silk/" class="external">silk icon set</a> and
<a href="http://deleket.deviantart.com/art/Gaming-Icons-Pack-42723812" class="external">deleket&rsquo;s
gaming icon set</a>.
</p> </p>
</div>
</div>
</asp:Content> </asp:Content>

View File

@ -27,4 +27,6 @@
<p> <p>
Here is the quote of the day: Here is the quote of the day:
</p> </p>
<% Html.RenderAction("QuoteOfTheDay", "Quote"); %>
</asp:Content> </asp:Content>

View File

@ -0,0 +1,20 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<VideoGameQuotes.Api.Quote>" %>
<%@ Import Namespace="VideoGameQuotes.Api" %>
<div class="quote-container">
<div class="quote-data clearfix">
<div class="quote-score-container">
<div class="vote-container">
</div>
<div class="quote-score" title="+<%= Model.UpVotes %>, -<%= Model.DownVotes %>"><%= Model.Score %></div>
<div class="vote-container">
</div>
</div>
<div class="quote-text">
<a href="<%= Url.Action("quote", "quote", new { id = Model.Id, text = Model.GetUrlFriendlyText() }) %>">
<%= Model.FormatTextForHtml() %>
</a>
</div>
</div>
</div>

View File

@ -38,6 +38,7 @@
<p> <p>
&copy; <%= DateTime.UtcNow.Year %> <a href="http://tommymontgomery.com/" title="Who is this man?">Tommy Montgomery</a><br /> &copy; <%= DateTime.UtcNow.Year %> <a href="http://tommymontgomery.com/" title="Who is this man?">Tommy Montgomery</a><br />
<%= Html.ActionLink("about", "about", "home") %> | <%= Html.ActionLink("about", "about", "home") %> |
<%= Html.ActionLink("credits", "about", "home", null, null, "credits", null, null) %> |
<% if (!Request.IsAuthenticated) { %> <% if (!Request.IsAuthenticated) { %>
<a href="#" id="login-link">login</a> <a href="#" id="login-link">login</a>
<% } else { %> <% } else { %>

View File

@ -50,6 +50,12 @@ ul.menu {
padding: 0; padding: 0;
list-style: none; list-style: none;
} }
a.external {
background-image: url(/media/images/external.png);
background-position: right center;
background-repeat: no-repeat;
padding-right: 14px;
}
.error-message { .error-message {
padding-left: 18px; padding-left: 18px;
@ -252,7 +258,7 @@ ul.menu {
} }
#main { #main {
padding: 20px 20px 100px 20px; padding: 20px 20px 120px 20px;
} }
#main a { #main a {
color: #669966; color: #669966;
@ -306,6 +312,9 @@ ul.menu {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
#footer p {
margin-top: 30px;
}
#footer a:hover { #footer a:hover {
text-decoration: underline; text-decoration: underline;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

After

Width:  |  Height:  |  Size: 615 B

View File

@ -48,7 +48,12 @@
var $container = $("#create-system-form"); var $container = $("#create-system-form");
var $link = $(this); var $link = $(this);
var data = { SystemName: $("#SystemName").val(), SystemAbbreviation: $("#SystemAbbreviation").val(), SystemReleaseDate: $("#SystemReleaseDate").val() }; var data = {
SystemName: $("#SystemName").val(),
SystemAbbreviation: $("#SystemAbbreviation").val(),
SystemReleaseDate: $("#SystemReleaseDate").val(),
SystemIcon: $("#SystemIcon").val()
};
var url = "/system/create"; var url = "/system/create";
var systemId = $container.find("> .edit-mode").val(); var systemId = $container.find("> .edit-mode").val();
@ -111,6 +116,7 @@
$("#SystemName").val(system.Name); $("#SystemName").val(system.Name);
$("#SystemAbbreviation").val(system.Abbreviation); $("#SystemAbbreviation").val(system.Abbreviation);
$("#SystemReleaseDate").val($.vgquotes.parseAndFormatDate(system.ReleaseDate)); $("#SystemReleaseDate").val($.vgquotes.parseAndFormatDate(system.ReleaseDate));
$("#SystemIcon").val(system.Icon);
}); });
return false; return false;
@ -218,6 +224,7 @@
//populate game form with game data //populate game form with game data
$("#GameName").val(game.Name); $("#GameName").val(game.Name);
$("#GameWebsite").val(game.Website); $("#GameWebsite").val(game.Website);
$("#GameIcon").val(game.Icon);
$.each(game.Regions, function() { $.each(game.Regions, function() {
$("input[name='GameRegions'][value='" + this + "']").attr("checked", "checked"); $("input[name='GameRegions'][value='" + this + "']").attr("checked", "checked");
}); });

View File

@ -1,8 +1,9 @@
(function($, window, undefined){ (function($, window, undefined){
$.fn.center = function() { $.fn.center = function() {
this.css("top", ($(window).height() - this.height()) / 2 + $(window).scrollTop() + "px"); var fixed = this.css("position") === "fixed";
this.css("left", ($(window).width() - this.width()) / 2 + $(window).scrollLeft() + "px"); this.css("top", ($(window).height() - this.height()) / 2 + (fixed ? 0 : $(window).scrollTop()) + "px");
this.css("left", ($(window).width() - this.width()) / 2 + (fixed ? 0 : $(window).scrollLeft()) + "px");
return this; return this;
}; };
@ -70,7 +71,6 @@
alert("An error occurred (" + xhr.status + ")"); alert("An error occurred (" + xhr.status + ")");
}, },
preload: function(images) { preload: function(images) {
//MM_preloadImages(lulz)
$.each(images, function() { $.each(images, function() {
$('<img/>')[0].src = this; $('<img/>')[0].src = this;
}); });
@ -83,6 +83,17 @@
success: ajaxCallback(type, callback), success: ajaxCallback(type, callback),
error: ajaxCallback(type, callback) error: ajaxCallback(type, callback)
}); });
},
createDialog: function($dialog) {
$("body")
.append($("<div/>").attr("id", "modal-background"))
.append($dialog);
$dialog.center();
},
closeDialog: function($dialog) {
$("#modal-background").remove();
$dialog.remove();
} }
}; };
}(); }();
@ -203,11 +214,12 @@
}); });
}; };
var setupReportLink = function() { var setupFlagLink = function() {
$(".quote-flag-link").click(function() { $("a.quote-flag-link").click(function() {
if ($(".report-dialog").length > 0) { if ($(".flag-dialog").length > 0) {
return false; return false;
} }
var $link = $(this); var $link = $(this);
var $container = $link.parents(".quote-container"); var $container = $link.parents(".quote-container");
var quoteId = $container.find("input.quote-id").val(); var quoteId = $container.find("input.quote-id").val();
@ -222,42 +234,51 @@
$row.append($(html)); $row.append($(html));
} }
var $dialog = $("<div/>").addClass("dialog report-dialog"); var $dialog = $("<div/>").addClass("dialog flag-dialog");
var $submit = $("<input/>") var $submit = $("<a/>")
.attr("type", "button") .attr({ href: "#", title: "submit" })
.attr("value", "Submit Report") .addClass("submit-link button-link")
.text("Submit")
.click(function() { .click(function() {
$.ajax("/report", { var $link = $(this);
$link.toggleClass("submit-link loading-link");
$.ajax("/flag", {
type: "POST", type: "POST",
data: { QuoteId: quoteId, Comment: $dialog.find("textarea").val(), FlagType: $dialog.find("input[name='flagType']:checked").val() }, data: { QuoteId: quoteId, Comment: $dialog.find("textarea").val(), FlagType: $dialog.find("input[name='flagType']:checked").val() },
complete: function() { $dialog.remove(); },
success: function(data, status, $xhr) { success: function(data, status, $xhr) {
if (data.Error !== null) { if (data.Error !== null) {
alert(data.Error); alert(data.Error);
return; return;
} }
}
}); $.vgquotes.closeDialog($dialog);
},
complete: function() { $link.toggleClass("submit-link loading-link"); }
}); });
var $cancel = $("<input/>") return false;
.attr("type", "button") });
.attr("value", "Cancel")
.click(function() { $dialog.remove(); }); var $cancel = $("<a/>")
.attr({ href: "#", title: "cancel" })
.addClass("cancel-link button-link")
.text("Cancel")
.click(function() { $.vgquotes.closeDialog($dialog); return false; });
$dialog $dialog
.append($("<p/>").text("Flag as:")) .append($("<p/>").addClass("label").text("Flag as:"))
.append($("<table/>").append($row)) .append($("<table/>").append($row))
.append($("<p/>").text("Comment")) .append($("<p/>").addClass("label").text("Comment"))
.append($("<textarea/>")) .append($("<textarea/>"))
.append($("<div/>").css("text-align", "center").append($submit).append($cancel)); .append($("<div/>").addClass("submit-container").append($submit).append($cancel));
//"other" should be checked by default //"other" should be checked by default
$dialog.find("#flag-type-0").attr("checked", "checked"); $dialog.find("#flag-type-0").attr("checked", "checked");
$("body").append($dialog); $.vgquotes.createDialog($dialog);
$dialog.center();
return false; return false;
}); });
@ -267,7 +288,7 @@
var showLoginForm = function() { var showLoginForm = function() {
var $dialog = $("#login-dialog"); var $dialog = $("#login-dialog");
if ($dialog.length > 0) { if ($dialog.length > 0) {
$dialog.remove(); $.vgquotes.closeDialog($dialog);
return false; return false;
} }
@ -292,13 +313,12 @@
return false; return false;
}); });
var $dialog = $("<div/>").addClass("dialog").attr("id", "login-dialog"); $dialog = $("<div/>").addClass("dialog").attr("id", "login-dialog");
$form.append($usernameInput).append($passwordInput).append($submit); $form.append($usernameInput).append($passwordInput).append($submit);
$dialog.append($form); $dialog.append($form);
$("body").append($dialog); $.vgquotes.createDialog($dialog);
$dialog.center();
$usernameInput.focus(); $usernameInput.focus();
return false; return false;
@ -315,7 +335,7 @@
$(document).ready(function() { $(document).ready(function() {
$.vgquotes.preload([$.vgquotes.loadingGif]); $.vgquotes.preload([$.vgquotes.loadingGif]);
setupReportLink(); setupFlagLink();
setupVoting(); setupVoting();
$("body").ajaxError(function(e, xhr, options, error){ $("body").ajaxError(function(e, xhr, options, error){
@ -323,6 +343,11 @@
}); });
$("#search-query").focus(); $("#search-query").focus();
$(document).keyup(function(e) {
if (e.keyCode === 27) {
$.vgquotes.closeDialog($(".dialog"));
}
});
}); });
}()); }());