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,45 +3,45 @@
<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"> <p>
<h3>Genesis</h3> <strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave
<div class="inset"> myself a week to implement everything and throw it up on the internet. It actually took three
<p> weeks as I struggled with <a href="http://incubator.apache.org/lucene.net/" class="external">Lucene</a> and my
<strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave obviously poor graphic design skills.
myself a week to implement everything and throw it up on the internet. </p>
</p>
<p> <p>
The inspiration for the site was that there were a lot of awesome video game quotes, but sadly, The inspiration for the site was that there were a lot of awesome video game quotes, but sadly,
no central place to go to find/search/read them. That made me sad. no central place to go to find/search/read them. That made me sad.
</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> <p>
<div class="inset"> The site was written in C&#9839; using <a href="http://www.asp.net/mvc" class="external">ASP.NET MVC 2</a>,
<p> <a href="http://unity.codeplex.com/" class="external">Unity</a> and <a href="http://nhforge.org/" class="external">NHibernate</a>.
The site was written in C&#9839; using <a href="http://www.asp.net/mvc">ASP.NET MVC 2</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>
<a href="http://unity.codeplex.com/">Unity</a> and <a href="http://nhforge.org/">NHibernate</a>. via FastCGI on Ubuntu. It uses MySQL for the backend and
It runs on <a href="http://nginx.org/">nginx</a> using <a href="http://www.mono-project.com/">Mono</a> <a href="http://incubator.apache.org/lucene.net/" class="external">Lucene.NET</a> for search indexing.
via FastCGI on Ubuntu. It uses MySQL for the backend. </p>
</p>
</div>
<h3>Get in Touch</h3> <p>
<div class="inset"> If you have any questions, concerns, comments, insults or death threats, don&rsquo;t hesitate to
<p> <%= Html.ActionLink("contact me", "Contact", "Home") %> and you will be ignored immediately.
If you have any questions, concerns, comments, insults or death threats, don&#39;t hesitate to </p>
<%= Html.ActionLink("contact me", "Contact", "Home") %>.
</p> <h3><a name="credits"></a>Credits</h3>
</div> <p>
</div> 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>
</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

@ -37,7 +37,8 @@
<div id="footer"> <div id="footer">
<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,11 +1,12 @@
(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;
}; };
$.fn.applyModelErrors = function(errorMessage, errorData) { $.fn.applyModelErrors = function(errorMessage, errorData) {
var $this = this; var $this = 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"); }
}); });
return false;
}); });
var $cancel = $("<input/>") var $cancel = $("<a/>")
.attr("type", "button") .attr({ href: "#", title: "cancel" })
.attr("value", "Cancel") .addClass("cancel-link button-link")
.click(function() { $dialog.remove(); }); .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"));
}
});
}); });
}()); }());