Skip to content

Instantly share code, notes, and snippets.

@andrewbranch
Last active December 17, 2015 16:01
Show Gist options
  • Save andrewbranch/9935630 to your computer and use it in GitHub Desktop.
Save andrewbranch/9935630 to your computer and use it in GitHub Desktop.
A nice notification pattern for MVC .NET, along with a better theme for alertify.js
@* displays the flash messages via alertify plugin *@
@section head {
<script>
$(document).ready(function() {
var flashes = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Html.Flash(), Newtonsoft.Json.Formatting.None));
for (var i = 0; i < flashes.length; i++) {
alertify.log(flashes[i].text, flashes[i].class, 10000);
}
});
</script>
}
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using App.Utilities;
namespace App.Helpers
{
public static class ActionResultExtensions
{
public static WrappedActionResultWithFlash<RedirectResult> WithFlash(this RedirectResult instance, object arguments)
{
return Flash(instance, ToDictionary(arguments));
}
public static WrappedActionResultWithFlash<RedirectResult> WithFlash(this RedirectResult instance, IDictionary<string, string> arguments)
{
return Flash(instance, arguments);
}
public static WrappedActionResultWithFlash<RedirectToRouteResult> WithFlash(this RedirectToRouteResult instance, object arguments)
{
return Flash(instance, ToDictionary(arguments));
}
public static WrappedActionResultWithFlash<RedirectToRouteResult> WithFlash(this RedirectToRouteResult instance, IDictionary<string, string> arguments)
{
return Flash(instance, arguments);
}
public static WrappedActionResultWithFlash<ViewResult> WithFlash(this ViewResult instance, object arguments)
{
return Flash(instance, ToDictionary(arguments));
}
public static WrappedActionResultWithFlash<ViewResult> WithFlash(this ViewResult instance, IDictionary<string, string> arguments)
{
return Flash(instance, arguments);
}
private static WrappedActionResultWithFlash<TActionResult> Flash<TActionResult>(TActionResult instance, IDictionary<string, string> arguments) where TActionResult : ActionResult
{
return new WrappedActionResultWithFlash<TActionResult>(instance, arguments);
}
private static IDictionary<string, string> ToDictionary(object arguments)
{
if (arguments == null)
{
return new Dictionary<string, string>();
}
return arguments.GetType()
.GetProperties()
.Where(p => p.CanRead && p.GetIndexParameters().Length == 0)
.ToDictionary(p => p.Name, p => p.GetValue(arguments, null).ToString());
}
}
}
#alertify,
.alertify-logs .alertify-log {
-webkit-transition: all 350ms ease;
-moz-transition: all 350ms ease;
-ms-transition: all 350ms ease;
-o-transition: all 350ms ease;
transition: all 350ms ease;
}
.alertify, .alertify-log {
font-family: inherit;
}
.alertify {
background: #fefefe;
background: rgba(253, 253, 253, 0.98);
border: 8px solid #222;
border: 8px solid rgba(0, 0, 0, .9);
border-radius: 0;
box-shadow: 0 3px 3px rgba(0, 0, 0, .3);
-webkit-background-clip: padding; /* Safari 4? Chrome 6? */
-moz-background-clip: padding; /* Firefox 3.6 */
background-clip: padding-box; /* Firefox 4, Safari 5, Opera 10, IE 9 */
}
.alertify-text {
-webkit-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.428571429;
color: #555;
vertical-align: middle;
background-color: #fff;
border: 1px solid #ccc;
background-image: none;
}
.alertify-text:focus {
border-color: #66afe9;
outline: 0;
}
.alertify .alertify-button,
.alertify .alertify-button:hover,
.alertify .alertify-button:active {
outline: 0;
-webkit-border-radius: 0;
border-radius: 0;
background-image: none;
background: white;
text-shadow: none;
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
border: 1px solid #cacaca;
color: #555;
-webkit-box-shadow: 0 2px 3px rgba(0,0,0,.02);
-moz-box-shadow: 0 2px 3px rgba(0,0,0,.02);
box-shadow: 0 2px 3px rgba(0,0,0,.02);
}
.alertify-cover {
filter: alpha(opacity=70);
opacity: .7;
}
/* Default buttons */
.alertify-button:focus {
border-color: #66afe9;
}
.alertify .alertify-button:hover {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
border-color: #ddd;
color: #888;
}
.alertify .alertify-button:active {
-webkit-box-shadow: 0 2px 3px rgba(0,0,0,.05) inset;
-moz-box-shadow: 0 2px 3px rgba(0,0,0,.05) inset;
box-shadow: 0 2px 3px rgba(0,0,0,.05) inset;
}
/* Danger buttons */
.alertify-button.alertify-button-danger {
-webkit-box-shadow: 0 3px 3px rgba(0, 0, 0, .07);
-moz-box-shadow: 0 3px 3px rgba(0, 0, 0, .07);
box-shadow: 0 3px 3px rgba(0, 0, 0, .07);
background: #db5151;
color: white;
border-color: #b17d7d;
}
.alertify-button.alertify-button-danger:hover {
background: #ec6262;
border-color: #c28e8e;
color: white;
}
.alertify-button.alertify-button-danger:focus {
border-color: white;
}
.alertify-button.alertify-button-danger:active {
background: #EC6252;
color: white;
box-shadow: 0 2px 3px rgba(0,0,0,.15) inset;
}
.alertify-log {
background: #222;
background: rgba(0, 0, 0, .85);
padding: 15px;
border-radius: 4px;
color: white;
text-shadow: none;
max-height: 100%;
}
.alertify-log a {
color: #69c;
text-decoration: none;
}
.alertify-log a:hover {
color: #8be;
text-decoration: none;
}
.alertify-log-error {
background: rgba(150, 20, 20, .95);
}
.alertify-log-error a {
color: #f99;
}
.alertify-log-error a:hover {
color: #fcc;
}
.alertify-log-success {
background: rgba(30, 110, 20, .85);
}
.alertify-log-success a {
color: #ac9;
}
.alertify-log-success a:hover {
color: #cfb;
}
.alertify-inner {
font-size: 14px;
}
/* don't remember if I changed anything in here or not... */
.alertify,
.alertify-show,
.alertify-log {
-webkit-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
-moz-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
-ms-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
-o-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275); /* easeOutBack */
}
.alertify-hide {
-webkit-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-moz-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-ms-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-o-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045); /* easeInBack */
}
.alertify-log-hide {
-webkit-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-moz-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-ms-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
-o-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045); /* easeInBack */
}
.alertify-cover {
position: fixed; z-index: 99999;
top: 0; right: 0; bottom: 0; left: 0;
background-color:white;
filter:alpha(opacity=0);
opacity:0;
}
.alertify-cover-hidden {
display: none;
}
.alertify {
position: fixed; z-index: 99999;
top: 50px; left: 50%;
width: 550px;
margin-left: -275px;
opacity: 1;
}
.alertify-hidden {
-webkit-transform: translate(0,-150px);
-moz-transform: translate(0,-150px);
-ms-transform: translate(0,-150px);
-o-transform: translate(0,-150px);
transform: translate(0,-150px);
opacity: 0;
display: none;
}
/* overwrite display: none; for everything except IE6-8 */
:root *> .alertify-hidden {
display: block;
visibility: hidden;
}
.alertify-logs {
position: fixed;
z-index: 5000;
bottom: 10px;
right: 10px;
width: 300px;
}
.alertify-logs-hidden {
display: none;
}
.alertify-log {
display: block;
margin-top: 10px;
position: relative;
right: -300px;
opacity: 0;
}
.alertify-log-show {
right: 0;
opacity: 1;
}
.alertify-log-hide {
overflow: hidden;
-webkit-transform: translate(300px, 0);
-moz-transform: translate(300px, 0);
-ms-transform: translate(300px, 0);
-o-transform: translate(300px, 0);
transform: translate(300px, 0);
opacity: 0;
}
.alertify-dialog {
padding: 25px;
}
.alertify-resetFocus {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.alertify-inner {
text-align: center;
}
.alertify-text {
margin-bottom: 15px;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-size: 100%;
}
.alertify-buttons {
}
.alertify-button,
.alertify-button:hover,
.alertify-button:active,
.alertify-button:visited {
background: none;
text-decoration: none;
border: none;
/* line-height and font-size for input button */
line-height: 1.5;
font-size: 100%;
display: inline-block;
cursor: pointer;
margin-left: 5px;
}
@media only screen and (max-width: 680px) {
.alertify,
.alertify-logs {
width: 90%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.alertify {
left: 5%;
margin: 0;
}
}
using App.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using App.Helpers;
namespace Big.Controllers
{
public class LocationsController : Controller
{
private AppContext context;
public LocationsController() {
this.context = new AppContext();
}
public ActionResult Edit(int id) {
return View(context.Locations.Find(id));
}
[HttpPut]
public ActionResult Edit(Location location) {
if (ModelState.IsValid) {
context.Entry(location).State = EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index").WithFlash(new { success = String.Format("Changes to “{0}” saved.", location.Name) });
} else {
return View(location);
}
}
protected override void Dispose(bool disposing) {
context.Dispose();
base.Dispose(disposing);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace App.Utilities {
public class FlashStorage
{
public static readonly string Key = typeof(FlashStorage).FullName;
public FlashStorage(TempDataDictionary backingStore)
{
if (backingStore == null)
{
throw new ArgumentNullException("backingStore");
}
BackingStore = backingStore;
}
public TempDataDictionary BackingStore { get; private set; }
public IEnumerable<KeyValuePair<string, string>> Messages
{
get
{
try
{
object value;
if (!BackingStore.TryGetValue(Key, out value))
{
return new List<KeyValuePair<string, string>>();
}
return (IEnumerable<KeyValuePair<string, string>>)value;
}
finally
{
BackingStore.Remove(Key);
}
}
}
public void Add(string type, string message)
{
if (string.IsNullOrWhiteSpace(message))
{
return;
}
IList<KeyValuePair<string, string>> messages;
object temp;
if (!BackingStore.TryGetValue(Key, out temp))
{
messages = new List<KeyValuePair<string, string>>();
BackingStore.Add(Key, messages);
}
else
{
messages = (IList<KeyValuePair<string, string>>)temp;
}
var item = messages.SingleOrDefault(p => p.Key.Equals(type, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(item.Value))
{
messages.Remove(item);
}
messages.Add(new KeyValuePair<string, string>(type, message));
BackingStore.Keep(Key);
}
}
}
@belchev
Copy link

belchev commented Dec 17, 2015

Where is the implementation for Html.Flash() ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment