@@ -0,0 +1,62 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Autocomplete 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* http://docs.jquery.com/UI/Autocomplete#theming
*/
.ui-autocomplete { position: absolute; cursor: default; }

/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */

/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Menu 1.8.11
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Menu#theming
*/
.ui-menu {
list-style:none;
padding: 2px;
margin: 0;
display:block;
float: left;
}
.ui-menu .ui-menu {
margin-top: -3px;
}
.ui-menu .ui-menu-item {
margin:0;
padding: 0;
zoom: 1;
float: left;
clear: left;
width: 100%;
}
.ui-menu .ui-menu-item a {
text-decoration:none;
display:block;
padding:.2em .4em;
line-height:1.5;
zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
font-weight: normal;
margin: -1px;
}
@@ -0,0 +1,11 @@
@import url("jquery.ui.core.css");
@import url("jquery.ui.resizable.css");
@import url("jquery.ui.selectable.css");
@import url("jquery.ui.accordion.css");
@import url("jquery.ui.autocomplete.css");
@import url("jquery.ui.button.css");
@import url("jquery.ui.dialog.css");
@import url("jquery.ui.slider.css");
@import url("jquery.ui.tabs.css");
@import url("jquery.ui.datepicker.css");
@import url("jquery.ui.progressbar.css");
@@ -0,0 +1,43 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Button 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Button#theming
*/
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }

/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }

/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }

/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }

/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
@@ -0,0 +1,46 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI CSS Framework 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Theming/API
*/

/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }


/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }


/* Icons
----------------------------------*/

/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }


/* Misc visuals
----------------------------------*/

/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
@@ -0,0 +1,73 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Datepicker 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Datepicker#theming
*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }

/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; }

/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }

/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}
@@ -0,0 +1,26 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Dialog 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
@@ -0,0 +1,16 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Progressbar 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Progressbar#theming
*/
.ui-progressbar { height:2em; text-align: left; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
@@ -0,0 +1,25 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Resizable 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)]
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
@@ -0,0 +1,15 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Selectable 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Selectable#theming
*/
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
@@ -0,0 +1,29 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Slider 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Slider#theming
*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }

.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }

.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }
@@ -0,0 +1,23 @@
/*
* Note: While Microsoft is not the author of this file, Microsoft is
* offering you a license subject to the terms of the Microsoft Software
* License Terms for Microsoft ASP.NET Model View Controller 3.
* Microsoft reserves all other rights. The notices below are provided
* for informational purposes only and are not the license terms under
* which Microsoft distributed this file.
*
* jQuery UI Tabs 1.8.11
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
*
* http://docs.jquery.com/UI/Tabs#theming
*/
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }

Large diffs are not rendered by default.

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using GhostmonkEditor.Models;

namespace GhostmonkEditor.Controllers
{
public class AccountController : Controller
{
public ActionResult LogOn()
{
return View();
}

[HttpPost]
public ActionResult LogOn( LogOnModel model, string returnUrl )
{
if( !ModelState.IsValid )
return View( model );

if( Membership.ValidateUser( model.UserName, model.Password ) )
{
FormsAuthentication.SetAuthCookie( model.UserName, model.RememberMe );
bool isValidUrl = Url.IsLocalUrl( returnUrl ) && returnUrl.Length > 1 && returnUrl.StartsWith( "/" )
&& !returnUrl.StartsWith( "//" ) && !returnUrl.StartsWith( "/\\" );

return isValidUrl ? ( ActionResult )Redirect( returnUrl ) : RedirectToAction( "Index", "Home" );
}

ModelState.AddModelError( "", "The user name or password provided is incorrect." );
return View( model );
}

public ActionResult LogOff()
{
FormsAuthentication.SignOut();

return RedirectToAction( "Index", "Home" );
}

public ActionResult Register()
{
return View();
}

[HttpPost]
public ActionResult Register( RegisterModel model )
{
if( ModelState.IsValid )
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser( model.UserName, model.Password, model.Email, null, null, true, null, out createStatus );

if( createStatus == MembershipCreateStatus.Success )
{
FormsAuthentication.SetAuthCookie( model.UserName, false /* createPersistentCookie */);
return RedirectToAction( "Index", "Home" );
}
else
{
ModelState.AddModelError( "", ErrorCodeToString( createStatus ) );
}
}

// If we got this far, something failed, redisplay form
return View( model );
}

[Authorize]
public ActionResult ChangePassword()
{
return View();
}

[Authorize]
[HttpPost]
public ActionResult ChangePassword( ChangePasswordModel model )
{
if( ModelState.IsValid )
{

// ChangePassword will throw an exception rather
// than return false in certain failure scenarios.
bool changePasswordSucceeded;
try
{
MembershipUser currentUser = Membership.GetUser( User.Identity.Name, true /* userIsOnline */);
changePasswordSucceeded = currentUser.ChangePassword( model.OldPassword, model.NewPassword );
}
catch( Exception )
{
changePasswordSucceeded = false;
}

if( changePasswordSucceeded )
{
return RedirectToAction( "ChangePasswordSuccess" );
}
else
{
ModelState.AddModelError( "", "The current password is incorrect or the new password is invalid." );
}
}

// If we got this far, something failed, redisplay form
return View( model );
}

public ActionResult ChangePasswordSuccess()
{
return View();
}

private static string ErrorCodeToString( MembershipCreateStatus createStatus )
{
// See http://go.microsoft.com/fwlink/?LinkID=177550 for
// a full list of status codes.
switch( createStatus )
{
case MembershipCreateStatus.DuplicateUserName:
return "User name already exists. Please enter a different user name.";

case MembershipCreateStatus.DuplicateEmail:
return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

case MembershipCreateStatus.InvalidPassword:
return "The password provided is invalid. Please enter a valid password value.";

case MembershipCreateStatus.InvalidEmail:
return "The e-mail address provided is invalid. Please check the value and try again.";

case MembershipCreateStatus.InvalidAnswer:
return "The password retrieval answer provided is invalid. Please check the value and try again.";

case MembershipCreateStatus.InvalidQuestion:
return "The password retrieval question provided is invalid. Please check the value and try again.";

case MembershipCreateStatus.InvalidUserName:
return "The user name provided is invalid. Please check the value and try again.";

case MembershipCreateStatus.ProviderError:
return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

case MembershipCreateStatus.UserRejected:
return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

default:
return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
}
}
}
}
@@ -0,0 +1,86 @@
using System.Data;
using System.Linq;
using System.Web.Mvc;
using GhostmonkMainSiteModel;
using Microsoft.Security.Application;

namespace GhostmonkEditor.Controllers
{
[Authorize]
public class ArticleEditorController : Controller
{
private readonly GhostmonkMainSiteModelContainer db = new GhostmonkMainSiteModelContainer();

public ViewResult Index()
{
return View( db.Articles.ToList() );
}

public ViewResult Details( int id )
{
Article article = db.Articles.Single( a => a.Id == id );
return View( article );
}

public ActionResult Create()
{
return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create( Article article )
{
if( ModelState.IsValid )
{
article.Body = Sanitizer.GetSafeHtml( article.Body );
db.Articles.AddObject( article );
db.SaveChanges();
return RedirectToAction( "Index" );
}

return View( article );
}

public ActionResult Edit( int id )
{
Article article = db.Articles.Single( a => a.Id == id );
return View( article );
}

[HttpPost]
public ActionResult Edit( Article article )
{
if( ModelState.IsValid )
{
article.Body = Sanitizer.GetSafeHtml( article.Body );
db.Articles.Attach( article );
db.ObjectStateManager.ChangeObjectState( article, EntityState.Modified );
db.SaveChanges();
return RedirectToAction( "Index" );
}
return View( article );
}

public ActionResult Delete( int id )
{
Article article = db.Articles.Single( a => a.Id == id );
return View( article );
}

[HttpPost, ActionName( "Delete" )]
public ActionResult DeleteConfirmed( int id )
{
Article article = db.Articles.Single( a => a.Id == id );
db.Articles.DeleteObject( article );
db.SaveChanges();
return RedirectToAction( "Index" );
}

protected override void Dispose( bool disposing )
{
db.Dispose();
base.Dispose( disposing );
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace GhostmonkEditor.Controllers
{
[Authorize]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";

return View();
}

public ActionResult About()
{
return View();
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using GhostmonkMainSiteModel;

namespace GhostmonkEditor.Controllers
{
[Authorize]
public class JournalEditorController : Controller
{
private GhostmonkMainSiteModelContainer db = new GhostmonkMainSiteModelContainer();

//
// GET: /JournalEditor/

public ViewResult Index()
{
return View(db.Journals.ToList());
}

//
// GET: /JournalEditor/Details/5

public ViewResult Details(int id)
{
Journal journal = db.Journals.Single(j => j.Id == id);
return View(journal);
}

//
// GET: /JournalEditor/Create

public ActionResult Create()
{
return View();
}

//
// POST: /JournalEditor/Create

[HttpPost]
public ActionResult Create(Journal journal)
{
if (ModelState.IsValid)
{
db.Journals.AddObject(journal);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(journal);
}

//
// GET: /JournalEditor/Edit/5

public ActionResult Edit(int id)
{
Journal journal = db.Journals.Single(j => j.Id == id);
return View(journal);
}

//
// POST: /JournalEditor/Edit/5

[HttpPost]
public ActionResult Edit(Journal journal)
{
if (ModelState.IsValid)
{
db.Journals.Attach(journal);
db.ObjectStateManager.ChangeObjectState(journal, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(journal);
}

//
// GET: /JournalEditor/Delete/5

public ActionResult Delete(int id)
{
Journal journal = db.Journals.Single(j => j.Id == id);
return View(journal);
}

//
// POST: /JournalEditor/Delete/5

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Journal journal = db.Journals.Single(j => j.Id == id);
db.Journals.DeleteObject(journal);
db.SaveChanges();
return RedirectToAction("Index");
}

protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using GhostmonkMainSiteModel;

namespace GhostmonkEditor.Controllers
{
[Authorize]
public class UserEditorController : Controller
{
private GhostmonkMainSiteModelContainer db = new GhostmonkMainSiteModelContainer();

//
// GET: /UserEditor/

public ViewResult Index()
{
var users = db.Users.Include("CV");
return View(users.ToList());
}

//
// GET: /UserEditor/Details/5

public ViewResult Details(int id)
{
User user = db.Users.Single(u => u.Id == id);
return View(user);
}

//
// GET: /UserEditor/Create

public ActionResult Create()
{
ViewBag.Id = new SelectList(db.CVs, "Id", "City");
return View();
}

//
// POST: /UserEditor/Create

[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
db.Users.AddObject(user);
db.SaveChanges();
return RedirectToAction("Index");
}

ViewBag.Id = new SelectList(db.CVs, "Id", "City", user.Id);
return View(user);
}

//
// GET: /UserEditor/Edit/5

public ActionResult Edit(int id)
{
User user = db.Users.Single(u => u.Id == id);
ViewBag.Id = new SelectList(db.CVs, "Id", "City", user.Id);
return View(user);
}

//
// POST: /UserEditor/Edit/5

[HttpPost]
public ActionResult Edit(User user)
{
if (ModelState.IsValid)
{
db.Users.Attach(user);
db.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Id = new SelectList(db.CVs, "Id", "City", user.Id);
return View(user);
}

//
// GET: /UserEditor/Delete/5

public ActionResult Delete(int id)
{
User user = db.Users.Single(u => u.Id == id);
return View(user);
}

//
// POST: /UserEditor/Delete/5

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
User user = db.Users.Single(u => u.Id == id);
db.Users.DeleteObject(user);
db.SaveChanges();
return RedirectToAction("Index");
}

protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{63EBA399-F956-464C-ABDE-647471DBC7FC}</ProjectGuid>
<ProjectTypeGuids>{E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GhostmonkEditor</RootNamespace>
<AssemblyName>GhostmonkEditor</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>false</UseIISExpress>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework">
<HintPath>..\packages\EntityFramework.4.1.10331.0\lib\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Web.Routing" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\ArticleEditorController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\JournalEditorController.cs" />
<Compile Include="Controllers\UserEditorController.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Models\AccountModels.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\themes\base\images\ui-bg_flat_0_aaaaaa_40x100.png" />
<Content Include="Content\themes\base\images\ui-bg_flat_75_ffffff_40x100.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_55_fbf9ee_1x400.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_65_ffffff_1x400.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_75_dadada_1x400.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_75_e6e6e6_1x400.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_95_fef1ec_1x400.png" />
<Content Include="Content\themes\base\images\ui-bg_highlight-soft_75_cccccc_1x100.png" />
<Content Include="Content\themes\base\images\ui-icons_222222_256x240.png" />
<Content Include="Content\themes\base\images\ui-icons_2e83ff_256x240.png" />
<Content Include="Content\themes\base\images\ui-icons_454545_256x240.png" />
<Content Include="Content\themes\base\images\ui-icons_888888_256x240.png" />
<Content Include="Content\themes\base\images\ui-icons_cd0a0a_256x240.png" />
<Content Include="Content\themes\base\jquery.ui.accordion.css" />
<Content Include="Content\themes\base\jquery.ui.all.css" />
<Content Include="Content\themes\base\jquery.ui.autocomplete.css" />
<Content Include="Content\themes\base\jquery.ui.base.css" />
<Content Include="Content\themes\base\jquery.ui.button.css" />
<Content Include="Content\themes\base\jquery.ui.core.css" />
<Content Include="Content\themes\base\jquery.ui.datepicker.css" />
<Content Include="Content\themes\base\jquery.ui.dialog.css" />
<Content Include="Content\themes\base\jquery.ui.progressbar.css" />
<Content Include="Content\themes\base\jquery.ui.resizable.css" />
<Content Include="Content\themes\base\jquery.ui.selectable.css" />
<Content Include="Content\themes\base\jquery.ui.slider.css" />
<Content Include="Content\themes\base\jquery.ui.tabs.css" />
<Content Include="Content\themes\base\jquery.ui.theme.css" />
<Content Include="Global.asax" />
<Content Include="Scripts\jquery-1.5.1-vsdoc.js" />
<Content Include="Scripts\jquery-1.5.1.js" />
<Content Include="Scripts\jquery-1.5.1.min.js" />
<Content Include="Scripts\jquery-ui-1.8.11.js" />
<Content Include="Scripts\jquery-ui-1.8.11.min.js" />
<Content Include="Scripts\jquery.validate-vsdoc.js" />
<Content Include="Scripts\jquery.validate.js" />
<Content Include="Scripts\jquery.validate.min.js" />
<Content Include="Scripts\modernizr-1.7.js" />
<Content Include="Scripts\modernizr-1.7.min.js" />
<Content Include="Web.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Content\Site.css" />
<Content Include="Scripts\jquery.unobtrusive-ajax.js" />
<Content Include="Scripts\jquery.unobtrusive-ajax.min.js" />
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
<Content Include="Scripts\MicrosoftAjax.js" />
<Content Include="Scripts\MicrosoftAjax.debug.js" />
<Content Include="Scripts\MicrosoftMvcAjax.js" />
<Content Include="Scripts\MicrosoftMvcAjax.debug.js" />
<Content Include="Scripts\MicrosoftMvcValidation.js" />
<Content Include="Scripts\MicrosoftMvcValidation.debug.js" />
<Content Include="Views\_ViewStart.cshtml" />
<Content Include="Views\Account\ChangePassword.cshtml" />
<Content Include="Views\Account\ChangePasswordSuccess.cshtml" />
<Content Include="Views\Account\LogOn.cshtml" />
<Content Include="Views\Account\Register.cshtml" />
<Content Include="Views\Home\About.cshtml" />
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\Shared\Error.cshtml" />
<Content Include="Views\Shared\_LogOnPartial.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
<Content Include="Views\Web.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
</ItemGroup>
<ItemGroup>
<Content Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GhostmonkMainSiteModel\GhostmonkMainSiteModel.csproj">
<Project>{434400D9-0687-44D9-BF2F-49CDD3076854}</Project>
<Name>GhostmonkMainSiteModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Views\ArticleEditor\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\ArticleEditor\Details.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\ArticleEditor\Create.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\ArticleEditor\Edit.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\ArticleEditor\Delete.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\UserEditor\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\UserEditor\Details.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\UserEditor\Create.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\UserEditor\Edit.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\UserEditor\Delete.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\JournalEditor\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\JournalEditor\Details.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\JournalEditor\Create.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\JournalEditor\Edit.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\JournalEditor\Delete.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target> -->
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>45108</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>
@@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.cs" Inherits="GhostmonkEditor.MvcApplication" Language="C#" %>
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace GhostmonkEditor
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801

public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters( GlobalFilterCollection filters )
{
filters.Add( new HandleErrorAttribute() );
}

public static void RegisterRoutes( RouteCollection routes )
{
routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters( GlobalFilters.Filters );
RegisterRoutes( RouteTable.Routes );
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Security;

namespace GhostmonkEditor.Models
{

public class ChangePasswordModel
{
[Required]
[DataType( DataType.Password )]
[Display( Name = "Current password" )]
public string OldPassword { get; set; }

[Required]
[StringLength( 100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6 )]
[DataType( DataType.Password )]
[Display( Name = "New password" )]
public string NewPassword { get; set; }

[DataType( DataType.Password )]
[Display( Name = "Confirm new password" )]
[Compare( "NewPassword", ErrorMessage = "The new password and confirmation password do not match." )]
public string ConfirmPassword { get; set; }
}

public class LogOnModel
{
[Required]
[Display( Name = "User name" )]
public string UserName { get; set; }

[Required]
[DataType( DataType.Password )]
[Display( Name = "Password" )]
public string Password { get; set; }

[Display( Name = "Remember me?" )]
public bool RememberMe { get; set; }
}

public class RegisterModel
{
[Required]
[Display( Name = "User name" )]
public string UserName { get; set; }

[Required]
[DataType( DataType.EmailAddress )]
[Display( Name = "Email address" )]
public string Email { get; set; }

[Required]
[StringLength( 100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6 )]
[DataType( DataType.Password )]
[Display( Name = "Password" )]
public string Password { get; set; }

[DataType( DataType.Password )]
[Display( Name = "Confirm password" )]
[Compare( "Password", ErrorMessage = "The password and confirmation password do not match." )]
public string ConfirmPassword { get; set; }
}
}
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "GhostmonkEditor" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "" )]
[assembly: AssemblyProduct( "GhostmonkEditor" )]
[assembly: AssemblyCopyright( "Copyright © 2012" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "66a2f057-cdfe-4b0e-a211-edced85c4f4d" )]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,165 @@
/// <reference path="jquery-1.5.1.js" />

/*!
** Unobtrusive Ajax support library for jQuery
** Copyright (C) Microsoft Corporation. All rights reserved.
*/

/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global window: false, jQuery: false */

(function ($) {
var data_click = "unobtrusiveAjaxClick",
data_validation = "unobtrusiveValidation";

function getFunction(code, argNames) {
var fn = window, parts = (code || "").split(".");
while (fn && parts.length) {
fn = fn[parts.shift()];
}
if (typeof (fn) === "function") {
return fn;
}
argNames.push(code);
return Function.constructor.apply(null, argNames);
}

function isMethodProxySafe(method) {
return method === "GET" || method === "POST";
}

function asyncOnBeforeSend(xhr, method) {
if (!isMethodProxySafe(method)) {
xhr.setRequestHeader("X-HTTP-Method-Override", method);
}
}

function asyncOnSuccess(element, data, contentType) {
var mode;

if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us
return;
}

mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
$(element.getAttribute("data-ajax-update")).each(function (i, update) {
var top;

switch (mode) {
case "BEFORE":
top = update.firstChild;
$("<div />").html(data).contents().each(function () {
update.insertBefore(this, top);
});
break;
case "AFTER":
$("<div />").html(data).contents().each(function () {
update.appendChild(this);
});
break;
default:
$(update).html(data);
break;
}
});
}

function asyncRequest(element, options) {
var confirm, loading, method, duration;

confirm = element.getAttribute("data-ajax-confirm");
if (confirm && !window.confirm(confirm)) {
return;
}

loading = $(element.getAttribute("data-ajax-loading"));
duration = element.getAttribute("data-ajax-loading-duration") || 0;

$.extend(options, {
type: element.getAttribute("data-ajax-method") || undefined,
url: element.getAttribute("data-ajax-url") || undefined,
beforeSend: function (xhr) {
var result;
asyncOnBeforeSend(xhr, method);
result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);
if (result !== false) {
loading.show(duration);
}
return result;
},
complete: function () {
loading.hide(duration);
getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments);
},
success: function (data, status, xhr) {
asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments);
},
error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
});

options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });

method = options.type.toUpperCase();
if (!isMethodProxySafe(method)) {
options.type = "POST";
options.data.push({ name: "X-HTTP-Method-Override", value: method });
}

$.ajax(options);
}

function validate(form) {
var validationInfo = $(form).data(data_validation);
return !validationInfo || !validationInfo.validate || validationInfo.validate();
}

$("a[data-ajax=true]").live("click", function (evt) {
evt.preventDefault();
asyncRequest(this, {
url: this.href,
type: "GET",
data: []
});
});

$("form[data-ajax=true] input[type=image]").live("click", function (evt) {
var name = evt.target.name,
$target = $(evt.target),
form = $target.parents("form")[0],
offset = $target.offset();

$(form).data(data_click, [
{ name: name + ".x", value: Math.round(evt.pageX - offset.left) },
{ name: name + ".y", value: Math.round(evt.pageY - offset.top) }
]);

setTimeout(function () {
$(form).removeData(data_click);
}, 0);
});

$("form[data-ajax=true] :submit").live("click", function (evt) {
var name = evt.target.name,
form = $(evt.target).parents("form")[0];

$(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []);

setTimeout(function () {
$(form).removeData(data_click);
}, 0);
});

$("form[data-ajax=true]").live("submit", function (evt) {
var clickInfo = $(this).data(data_click) || [];
evt.preventDefault();
if (!validate(this)) {
return;
}
asyncRequest(this, {
url: this.action,
type: this.method || "GET",
data: clickInfo.concat($(this).serializeArray())
});
});
}(jQuery));

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,319 @@
/// <reference path="jquery-1.5.1.js" />
/// <reference path="jquery.validate.js" />

/*!
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/

/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */

(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";

function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}

function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}

function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}

function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}

function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;

container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);

if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}

function onErrors(form, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");

if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}

function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer"),
replace = $.parseJSON(container.attr("data-valmsg-replace"));

if (container) {
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");

if (replace) {
container.empty();
}
}
}

function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation);

if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: "input-validation-error",
errorElement: "span",
errorPlacement: $.proxy(onError, form),
invalidHandler: $.proxy(onErrors, form),
messages: {},
rules: {},
success: $.proxy(onSuccess, form)
},
attachValidation: function () {
$form.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}

return result;
}

$jQval.unobtrusive = {
adapters: [],

parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;

if (!form) { // Cannot do client-side validation without a form
return;
}

valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};

$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};

if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";

$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});

this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});

jQuery.extend(rules, { "__dummy__": true });

if (!skipAttach) {
valInfo.attachValidation();
}
},

parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
$(selector).find(":input[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});

$("form").each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};

adapters = $jQval.unobtrusive.adapters;

adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};

adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};

adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;

if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};

adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};

$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});

$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}

match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});

adapters.addSingleVal("accept", "exts").addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);

$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
return $(options.form).find(":input[name='" + paramName + "']").val();
};
});

setValidationValues(options, "remote", value);
});

$(function () {
$jQval.unobtrusive.parse(document);
});
}(jQuery));