Arquivo da categoria: Codigo Aberto

Adicionando Atributos em Propriedades (C#)

Adicionando Atributos em Propriedades (C#)

Nem sempre é possível utilizar objetos complexos (classes) para incluir informações em propriedades de classes. Essa situação pode acontecer quando se está dando manutenção em um código que está amarrado a outro comportamento que não pode ser alterado.

No caso que deu origem à esse código, a classe possui uma dezena de propriedades públicas string que já estavam atreladas a outras classes e comportamento em outras partes do código. Não havia liberdade de criação de outras classes que incorporassem mais propriedades, então decidi enfeitar cada propriedade com atributos personalizados.

Dessa forma, foi possível no código acessar mais informações com base somente nessa propriedade string.

O código foi usado em uma aplicação de aluguel de móveis para eventos. Segue o código:

Classe do Objeto amarrado (Furniture.cs) com as classes de atributos no mesmo arquivo (para facilitar o entendimento)

using System;
using System.ComponentModel;
using System.Globalization;
using static ADX18.Library.Helpers.ADX18Helper;
 
namespace ADX18.Library.Models
{
    public class Furniture : iTestObject
    {
        [DisplayName("Mode Cupboard"),
            MemberPrice("225.50"),
            NonMemberPrice("247.50")]
        public string ModeCupboard_Quantity { get; set; }
        public string ModeCupboard_Colour { get; set; }
        [DisplayName("Poly Voge Chair"),
            MemberPrice("52.25"),
            NonMemberPrice("55.00")]
        public string PolyVogue_Quantity { get; set; }
        public string PolyVogue_Colour { get; set; }
        [DisplayName("Poly Vogue Stool"),
            MemberPrice("74.25"),
            NonMemberPrice("80.85")]
        public string PolyVogueStool_Quantity { get; set; }
        public string PolyVogueStool_Colour { get; set; }
        [DisplayName("Club Stool"),
            MemberPrice("77.00"),
            NonMemberPrice("82.50")]
        public string ClubStool_Quantity { get; set; }
        public string ClubStool_Colour { get; set; }
        [DisplayName("Ikon Dry Bar"),
            MemberPrice("165.00"),
            NonMemberPrice("177.65")]
        public string IkonDryBar_Quantity { get; set; }
        public string IkonDryBar_Colour { get; set; }
        [DisplayName("Ikon Meeting Table"),
            MemberPrice("143.00"),
            NonMemberPrice("154.00")]
        public string IkonMeetingTable_Quantity { get; set; }
        public string IkonMeetingTable_Colour { get; set; }
        [DisplayName("Ikon Illuminated Dry Bar"),
            MemberPrice("192.50"),
            NonMemberPrice("209.00")]
        public string IkonIlluminatedDryBar_Quantity { get; set; }
        public string IkonIlluminatedDryBar_Colour { get; set; }
        [DisplayName("Mode Dry Bar Table"),
            MemberPrice("104.50"),
            NonMemberPrice("108.90")]
        public string ModeDryBarTable_Quantity { get; set; }
        public string ModeDryBarTable_Colour { get; set; }
        [DisplayName("Mode Meeting Table"),
            MemberPrice("99.00"),
            NonMemberPrice("107.25")]
        public string ModeMeetingTable_Quantity { get; set; }
        public string ModeMeetingTable_Colour { get; set; }
        [DisplayName("Mode Coffee Table"),
            MemberPrice("93.50"),
            NonMemberPrice("100.65")]
        public string ModeCoffeeTable_Quantity { get; set; }
        public string ModeCoffeeTable_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeater_Quantity { get; set; }
        public string CubaLoungeOneSeater_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater Corner"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeaterCorner_Quantity { get; set; }
        public string CubaLoungeOneSeaterCorner_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater No Arm Rests"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeaterNoArms_Quantity { get; set; }
        public string CubaLoungeOneSeaterNoArms_Colour { get; set; }
        [DisplayName("Cuba Lounge"),
            MemberPrice("275.00"),
            NonMemberPrice("308.00")]
        public string CubaLounge_Quantity { get; set; }
        public string CubaLounge_Colour { get; set; }
        [DisplayName("Quattro Display Plinth 600mm"),
            MemberPrice("165.00"),
            NonMemberPrice("178.75")]
        public string QuattroDisplay600_Quantity { get; set; }
        public string QuattroDisplay600_Colour { get; set; }
        [DisplayName("Quattro Display Plinth 900mm"),
            MemberPrice("187.00"),
            NonMemberPrice("207.90")]
        public string QuattroDisplay900_Quantity { get; set; }
        public string QuattroDisplay900_Colour { get; set; }
        [DisplayName("Zig Zag Brochure Stand"),
            MemberPrice("115.50"),
            NonMemberPrice("123.20")]
        public string ZigZagStand_Quantity { get; set; }
        public string ZigZagStand_Colour { get; set; }
        [DisplayName("Carpet Floor Tiles"),
            MemberPrice("247.50"), NonMemberPrice("287.10"),
            NonMemberUnitPrice("31.90"),
            MemberUnitPrice("27.50")]
        public string CarpetFloorTiles_Quantity { get; set; }
        public string CarpetFloorTiles_Colour { get; set; }
        [DisplayName("Raised Floor Tiles"),
            MemberPrice("940.50"),
            NonMemberPrice("1188.00"),
            NonMemberUnitPrice("132.00"),
            MemberUnitPrice("104.50")]
        public string RaisedFloorTiles_Quantity { get; set; }
        public string RaisedFloorTiles_Colour { get; set; }
 
    }
// Classes de Atributos personalizadas
    public class NonMemberUnitPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public NonMemberUnitPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class NonMemberPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public NonMemberPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class MemberUnitPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public MemberUnitPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class MemberPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public MemberPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
 
 
}

Código de acesso desses atributos listados como um Dictionary<string,object> pois os valores retornados em cada atributo podem variar:

using ADX18.Library.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
 
namespace ADX18.Library.Helpers
{
    public static class ADX18Helper
    {
      #region Furniture Helpers
        public interface iField { }
        public interface iTestObject { }
        //tweaked from https://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property 
        //and https://stackoverflow.com/questions/23329087/get-custom-attribute-from-specific-object-property-field
        public static Dictionary<string, object> GetAttributes<T>(this T source, Expression<Func<object>> field) where T : class
        {
            MemberExpression member = (MemberExpression)field.Body;
            if (member == null) { return null; }

            Dictionary<string, object> _dict = new Dictionary<string, object>();
            object[] propertyAttributes = typeof(T).GetProperty(member.Member.Name)
                .GetCustomAttributes(true);

            foreach (var propertyAttribute in propertyAttributes)
            {
                var attributeAttributes = propertyAttribute.GetType().GetProperties();
                foreach (var attributeAttribute in attributeAttributes)
                {
                    var propName = $"{propertyAttribute.GetType().Name}.{attributeAttribute.Name}";
                    if (!_dict.ContainsKey(propName) && attributeAttribute.Name != "TypeId")
                        _dict.Add(propName, attributeAttribute.GetValue(propertyAttribute, null));
                }
            }
            return _dict;
        }

        #endregion

    }
}

Com essas classes definidas, fica mais fácil acessar os atributos no Razor:

@model Furniture
@using ADX18.Library.Controllers
@using ADX18.Library.Models
@using ADX18.Library.Helpers;

                <div class="col-md-8">
                        @{
                            var modeCupboard = Model.GetAttributes<Furniture>(() => Model.ModeCupboard_Quantity);
                        }
                    <h5>@modeCupboard["DisplayNameAttribute.DisplayName"]</h5>
                    <p>
                        Available in four colours, this includes a lockable cupboard with shelves.<br />
                        L: 1200mm x W: 600mm x H: 1000mm
                    </p>
                    <div>
                        Member: <span class="memberPrice">[email protected]["MemberPrice.Value"] each</span><br />
                        Non-member: <span class="memberPrice">[email protected]["NonMemberPrice.Value"] each</span>
                    </div>
                    Quantity: <input type="text" name="ModeCupboard_Quantity" style="width: 10%;" />
                    <select name="ModeCupboard_Colour">
                        <option value="White">White</option>
                        <option value="Black">Black</option>
                        <option value="Red">Red</option>
                        <option value="Blue">Blue</option>
                    </select>
                </div>

Então, quando não puder mudar uma propriedade para incluir objetos complexos, use atributos personalizados!

Como criar um efeito reflexo de vidro somente com CSS3

Mesmo depois de muito pesquisar, não encontrei nenhum tutorial que fosse aceitável. Então, acabei por criar meu próprio efeito de reflexo de vidro, usando somente CSS3 (sem javascript).

Sem delongas, segue o código base:

HTML

<div class="glass-wrapper">
  <h3>Glass Reflection Box</h3>
  <div class="content">Your Glass content goes here</div>       
  <div class="glass"></div>
</div>

CSS

.glass-wrapper {
  font-family:Arial;
  width: 40%;
  margin:0 auto;
  overflow: hidden;
  min-height: 400px;
  padding:50px;
  box-sizing:border-box;
  background: #DF1922;
  color: #fff;
  border-radius:8px;
  position: relative;
}
.content {
  width: 100%;
  box-sizing:border-box;
  text-align: center;
  font-size: 2em;
  text-shadow: 1px 1px 1px #fff, 1px 1px 1px #000, 1px 1px 1px #ccc;
}

.glass {
  width: 160%;
  height: 316px;
  opacity: .1;
  background: #fff;
  position: absolute;
  top: -114px;
  left: -200px;
  z-index: 9;
  border-radius: 50%;
}

Veja o demo

Plugin para Umbraco 7 (belle)

Tutorial Umbraco 7 de Plugin Backoffice simples

Com o lançamento do Umbraco 7 em 21 de Novembro de 2013, a plataforma CMS do Umbraco mudou considerávelmente e deixou a vida dos usuários e, principalmente, dos desenvolvedores, muito mais fácil.

Não somente a interface administrativa (backoffice) foi bastante melhorada, mais fluida e compatível com aparelhos móveis.

Com isso, o tempo de desenvolvimento diminui bastante, facilitando bastante a vida. Agora, com o uso de simples Html5, CSS3, e Angular.js ficou fácil de criar extensões para a área administrativa.

Para demonstrar, vou mostrar a criação de uma extensão de backoffice simples de limite de carateres, e usei como exemplo o tutorial do Tim Geyssens Char Limit Property Editor for Umbraco Belle (http://www.nibble.be/?p=285)

Como comentei, o processo é simples:

  1. Para se criar um plugin, é necessário criar uma pasta dentro de App_Plugins
    Estrutura Umbraco
  2. Cria-se o package.manifest
    {
        propertyEditors: [
            {
    		alias: "Input.CharLimitEditor",
    		name: "Input Char limit",
    		"hideLabel": false,
          	"icon": "icon-stop-hand",
          	"group": "Common",
    		editor: {
    		view: "~/App_Plugins/Input.CharLimitEditor/views/view.html"
    		},
    		prevalues: {
    			fields: [
    				{
    					label: "Number of Characters",
    					description: "Enter the max number of characters allowed",
    					key: "limit",
    					view: "requiredfield",
    					validation: [
    						{
    							type: "Required" 
    						}						
    					]
    				}
    			]
    		}
            }
        ]
        ,
        javascript: [
            '~/App_Plugins/Input.CharLimitEditor/js/controller.js'
        ],
        css: [
        "~/App_Plugins/Input.CharLimitEditor/css/style.css"
      ]
    }
    
  3. O layout do Html
    
    <div ng-controller="Input.CharLimitEditorController" class="input-limit">
    	<span ng-if="model.config.limit >= 100">
           <textarea ng-model="model.value" ng-change="limitChars()" rows="10" class="umb-editor umb-textarea textstring"></textarea>
       </span>
       <span ng-if="model.config.limit < 100">
           <input ng-model="model.value" ng-change="limitChars()" type="text" class="umb-editor umb-textstring textstring" />
       </span>
       
       <span class="counter {{css}}">
        <i class="icon icon-{{icon}}"></i>
        <span ng-show="countLeft"> 
            <localize key="inputlimit_youhave">you have</localize> {{counter}} <localize key="inputlimit_charleft" >characters left</localize>
        </span>
        <span ng-show="maxReached">
            <localize key="inputlimit_limitReachedOnly">Only</localize> {{limit}} <localize key="inputlimit_limitReachedAllowed">allowed</localize>
        </span>
    </span>
    </div>
    
    
    
    

    Note que a tag

    <localize key="inputlimit_limitReachedOnly">Only</localize>

    está relacionada à Localização e não é obrigatória, mas ajuda se for publicar o pacote na comunidade

  4. (Opcional) Criar os arquivos de Idiomas para Localização
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <language alias="pt_br" intName="Portuguese Brazil" localName="Portuguese Brazil" lcid="" culture="pt-BR">
      <creator>
        <name>Carlos Casalicchio</name>
        <link>http://www.ccasalicchio.com</link>
      </creator>
    
    
    <area alias="inputlimit">
        <key alias="youhave">Você tem</key>
        <key alias="charleft">caracteres sobrando</key>
        <key alias="limitReachedOnly">Somente</key>
        <key alias="limitReachedAllowed">caracteres permitidos!</key>
      </area>
    
    
    </language>
    
  5. O CSS (opcional)
    .input-limit .counter{
    	-webkit-transition: all 0.8s ease-in-out;
    	-moz-transition: all 0.8s ease-in-out;
    	-ms-transition: all 0.8s ease-in-out;
    	-o-transition: all 0.8s ease-in-out;
    	transition: all 0.8s ease-in-out;
    }
    
    .input-limit .thumb-up,.input-limit .alert,.input-limit .stop-hand{
    	padding: 5px 10px;
    }
    
    .input-limit .thumb-up{
    	background:#4FA23C;
    	color:#fff;
    }
    
    .input-limit .alert{
    	background: #B8860B;
    	color: #fff;
    }
    
    .input-limit .stop-hand{
    	color: #fff;
    	background: #DD793F;
    }
    
  6. E o mais importante, o controller.js (Angular.js)
    angular.module("umbraco")
    .controller("Input.CharLimitEditorController",
    	function ($scope) {
    		var limit = parseInt($scope.model.config.limit);
    		var thumbUp = "thumb-up", alert = "alert", warning = "stop-hand";
    		$scope.counter = limit - $scope.model.value.length;
    		$scope.limit = limit;
    		$scope.countLeft = true;
    		$scope.maxReached = false;
    		$scope.icon = thumbUp;
    		$scope.css = thumbUp;
    		
    		$scope.limitChars = function(){
    			$scope.counter = limit - $scope.model.value.length;
    			CheckChars();
    		};
    
    		function CheckChars(){
    			if($scope.model.value.length === 0){
    				$scope.countLeft = true;
    				$scope.maxReached = false;
    				$scope.icon = thumbUp;
    				$scope.css = thumbUp;
    			}
    
    			else if ($scope.model.value.length >= limit)
    			{
    				$scope.maxReached = true;
    				$scope.countLeft = false;
    				$scope.icon	= warning;
    				$scope.css = warning;
    				$scope.model.value = $scope.model.value.substr(0, limit );
    			}
    			
    			else if($scope.model.value.length < (limit/2)){ $scope.icon = thumbUp; $scope.css = thumbUp; $scope.maxReached = false; $scope.countLeft = true; } else if($scope.model.value.length > (limit/2)){
    				$scope.icon = alert;
    				$scope.css = alert;
    				$scope.maxReached = false;
    				$scope.countLeft = true;
    			}
    
    			else
    			{
    				$scope.icon = alert;
    				$scope.css = alert;
    				$scope.maxReached = false;
    				$scope.countLeft = true;
    			}
    		}
    		CheckChars();
    	});
    

Após isso, pode-se criar um pacote e submeter à comunidade, para que outras pessoas também usem, mas isso também é opcional. Este pacote, em particular está disponível em https://our.umbraco.org/projects/backoffice-extensions/input-character-limit/ e o código fonte no GitHub

Este plugin cria uma caixa de texto ou area de texto com um contador de caracteres, com várias chamadas visuais, afim de auxiliar o usuário a digitar o número de caracteres permitido.

Vazio

Em resumo, criar plugins para Umbraco ficou ainda mais fácil, e a curva de aprendizado ainda menor! Vale a pena investir nesse CMS.

Criando um sistema básico de Short Url (parte 2)

Criando um sistema básico de Short Url (parte 2)

Criando um sistema básico de Short Url (parte 2)

Depois de vários meses usando o sistema e tendo que atualizar a lista de links manualmente no XML via FTP, decidi que era hora de melhorar o sistema para que incluísse um banco de dados e um meio de incluir, editar e remover links online.

Portanto, melhorei o sistema e hoje está disponível em http://puul.ga

 

O código fonte (open source) está disponível no Github

Foram feitas várias melhorias no sistema, de forma a ser responsivo e fácil de usar. Mas seu visual e utilidades continuam simples. Cria-se um short link (mesmo conceito que bit.ly) que pode ser compartilhado em qualquer lugar, deixando o link curto e fácil de ser digitado.

O projeto continua sendo em C#, MVC, Entity Framework, Html5, Css3 e jQuery (Bootstrap)

Primeiramente, é necessário criar o objeto/classe que irá conter os dados do Link gerado:

using System;
using System.ComponentModel.DataAnnotations;

namespace Shorten_Urls.Models
{
    public class Url
    {
        public int Id { get; set; }
        [RegularExpression(@"^.{8,}$", ErrorMessage = "Minimum 8 characters required")]
        [Required(ErrorMessage = "Required")]
        [StringLength(30, MinimumLength = 8, ErrorMessage = "Invalid")]
        [Display(Name ="Shareable Url")]
        public string Src { get; set; }
        [Url]
        [Display(Name = "Redirects To")]
        public string Redirect { get; set; }
        public string UserId { get; set; }
        [Display(Name = "Created By")]
        public string Username { get; set; }
        //[DataType(DataType.Date)]
        //[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
        [Display(Name = "Created On")]
        public DateTime CreatedOn { get; set; }
        //[DataType(DataType.Date)]
        //[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
        [Display(Name = "Expires")]
        public DateTime? Expires { get; set; }
    }
}

Também é necessário criar o Repositório (ou Data Layer). Esse repositório permite o uso tanto de XML quanto SQL, sendo configurada a opção no

web.config
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.AspNet.Identity;
using System.Configuration;
using System.Data.Entity;

namespace Shorten_Urls.Models
{
    public class UrlRepository : IRepository<Url>
    {
        private XDocument _urls;
        private List<Url> urls;
        ApplicationDbContext _context;
        private readonly string DbProvider = ConfigurationManager.AppSettings["DbProvider"];
        private const string SQL = "Sql";
        private const string XML = "Xml";
        public bool needLastId { get { return DbProvider.Equals(XML); } }

        public List<Url> Urls { get { return urls; } }
        public int LastId
        { get { return urls.Last().Id; } }

        public UrlRepository()
        {
            urls = new List<Url>();

            if (DbProvider == XML)
            {
                _urls = MvcApplication.IO.Forwards;

                IEnumerable<XElement> rootDescendants = _urls.Descendants("url");
                foreach (XElement e in rootDescendants)
                    urls.Add(MapXElement(e));
            }
            else if (DbProvider == SQL)
            {
                _context = new ApplicationDbContext();
                urls = _context.Forwarders.ToList();
            }
        }

        public bool Exists(string src)
        {
            var yes = from y in urls where y.Src == src select y;
            if (yes.Count() > 0) return true;
            else return false;
        }

        public IEnumerable<Url> GetAll()
        {
            return urls;
        }

        public void Add(Url url)
        {
            urls.Add(url);
            if (DbProvider == XML)
                MvcApplication.IO.AddForward(url);
            else if (DbProvider == SQL)
            {
                _context.Forwarders.Add(url);
                _context.SaveChanges();
            }
        }
        public Url GetById(int Id)
        {
            Url e = (from url in urls where url.Id == Id select url).Single();
            if (DbProvider == SQL)
            {
                PopulateUsername(e);
            }
            return e;
        }
        public List<Url> GetByUserId(string userId)
        {
            List<Url> list = (from urlList in urls where urlList.UserId == userId select urlList).ToList();
            if (DbProvider == SQL)
            {
                foreach (Url url in list) PopulateUsername(url);
            }
            return list;
        }
        public Url GetBySrc(string src)
        {
            var e = (from url in urls where url.Src.Equals(src) select url);
            if (e.Count() == 0) return null;
            else {
                if (DbProvider == SQL)
                {
                    PopulateUsername(e.Single());
                }
                return e.Single();
            }
        }

        public void Remove(int id)
        {
            Url remove = (from url in urls where url.Id == id select url).Single();
            urls.Remove(remove);
            Remove(remove);
        }

        public void Remove(Url url)
        {
            urls.Remove(url);
            if (DbProvider == XML)
                MvcApplication.IO.RemoveForward(url);
            else if (DbProvider == SQL)
            {
                _context.Forwarders.Remove(url);
                _context.SaveChanges();
            }
        }

        public void Remove(string src)
        {
            Url remove = (from url in urls where url.Src == src select url).Single();
            urls.Remove(remove);
            Remove(remove);
        }

        public void RemoveAll()
        {
            urls.Clear();
        }

        public void RemoveByUserId(string userId)
        {
            Url remove = (from url in urls where url.UserId == userId select url).Single();
            urls.Remove(remove);
            Remove(remove);
        }

        public void Update(Url url)
        {
            Url old = (from urlE in urls where urlE.Id == url.Id select urlE).Single();
            urls.Remove(old);
            urls.Add(url);
            if (DbProvider == XML)
            {

                MvcApplication.IO.RemoveForward(old);
                MvcApplication.IO.AddForward(url);
            }
            else if (DbProvider == SQL)
            {
                _context.Entry(url).State = EntityState.Modified;
                _context.SaveChanges();
            }
        }


        private Url PopulateUsername(int id)
        {
            Url url = (from u in urls where u.Id == id select u).Single();
            string userId = url.UserId == null ? "" : url.UserId;
            UserRepository userRepo = new UserRepository();
            url.Username = userRepo.GetUsername(userId);
            return url;
        }
        private Url PopulateUsername(Url url)
        {
            UserRepository userRepo = new UserRepository();
            string userId = url.UserId == null ? "" : url.UserId;
            url.Username = userRepo.GetUsername(userId);
            return url;
        }
        private Url MapXElement(XElement element)
        {
            DateTime expires = element.Attribute("expires").Value == "" ? new DateTime(2999, 12, 31) : DateTime.Parse(element.Attribute("expires").Value);
            DateTime createdOn = element.Attribute("created").Value == "" ? DateTime.Now : DateTime.Parse(element.Attribute("created").Value);
            string userId = element.Attribute("userid").Value;
            int id = int.Parse(element.Attribute("id").Value);
            Url url = new Url
            {
                Id = id,
                CreatedOn = createdOn,
                Expires = expires,
                UserId = userId,
                Redirect = element.Value.Trim(),
                Src = element.Attribute("src").Value
            };
            return PopulateUsername(url);
        }
    }
}

A parte mais importante do projeto é o Controller que vai servir os Links, e as rotas de leitura dos links. Portanto, o

RouteConfig.cs

também tem que estar correto:

ForwardsController.cs
using Shorten_Urls.Models;
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

namespace Shorten_Urls.Controllers
{
    public class ForwardsController : Controller
    {
        private UrlRepository _repo;
        private UserRepository _usersRepo;
        private ApplicationUser user;

        public ForwardsController()
        {
            _repo = new UrlRepository();
            _usersRepo = new UserRepository();
        }
        //
        // GET: /Forwards/

        public ActionResult SendToSrc(string src)
        {
            string error404 = "404.html";
            string redirect = "/Home/Index";

            Url url = _repo.GetBySrc(src);
            if (url != null)
            {

                if (!url.Redirect.Equals(string.Empty) && (url.Expires > DateTime.Now || url.Expires == null))
                    redirect = url.Redirect;
                else
                    redirect = error404;
            }
            return Redirect(redirect);
        }
        [Authorize]
        public ActionResult List()
        {

            List<Url> urls;
            if (User != null)
                user = _usersRepo.GetById(User.Identity.GetUserId());

            if (user.UserType == UserTypes.Administrator)
                urls = _repo.Urls;
            else urls = _repo.GetByUserId(user.Id);

            return View(urls);
        }

        //
        // GET: /Forwards/Details/5
        [Authorize]

        public ActionResult Details(int id)
        {
            if (User != null)
                user = _usersRepo.GetById(User.Identity.GetUserId());

            if (id == 0)
                Redirect("/Home/Index");
            Url url = _repo.GetById(id);
            return View(url);
        }

        //
        // GET: /Forwards/Create
        [Authorize]

        public ActionResult Create()
        {
            if (User != null)
                user = _usersRepo.GetById(User.Identity.GetUserId());

            Url url = new Url();
            string random = Helpers.GenerateRandomgUrl();
            while (_repo.Exists(random))
            {
                random = Helpers.GenerateRandomgUrl();
            }
            ViewBag.RandomUrl = random;
            return View(url);
        }

        [HttpGet]
        public string Available(string Src)
        {
            bool exists = _repo.Exists(Src);
            return new JavaScriptSerializer().Serialize(!exists);
        }
        //
        // POST: /Forwards/Create

        [Authorize]
        [HttpPost]
        public ActionResult Create(string Redirect, string Src, DateTime? Expires)
        {
            try
            {
                // TODO: Add insert logic here
                if (User != null)
                    user = _usersRepo.GetById(User.Identity.GetUserId());

                Url newUrl = new Url
                {
                    Redirect = Redirect,
                    Src = Src,
                    CreatedOn = DateTime.Now,
                    Expires = Expires,
                    UserId = user.Id,
                    Username = _usersRepo.GetUsername(user.Id)
                };

                if (_repo.needLastId)
                    newUrl.Id = _repo.LastId + 1;

                _repo.Add(newUrl);
                TempData["Success"] = "Short Url has been created";
                return RedirectToAction("List");
            }
            catch
            {
                TempData["Error"] = "There was an error saving your new Url";
                return View("List");
            }
        }

        //
        // GET: /Forwards/Edit/5
        [Authorize]

        public ActionResult Edit(int id)
        {
            if (User != null)
                user = _usersRepo.GetById(User.Identity.GetUserId());

            Url editUrl = _repo.GetById(id);
            return View(editUrl);
        }

        //
        // POST: /Forwards/Edit/5
        [Authorize]
        [HttpPost]
        public ActionResult Edit(int Id, string Redirect, string Src, DateTime? Expires = null)
        {
            try
            {
                // TODO: Add update logic here
                if (User != null)
                    user = _usersRepo.GetById(User.Identity.GetUserId());

                Url editUrl = _repo.GetById(Id);
                editUrl.Redirect = Redirect;
                editUrl.Src = Src;
                editUrl.UserId = user.Id;
                editUrl.Expires = Expires;
                editUrl.Username = _usersRepo.GetUsername(user.Id);

                _repo.Update(editUrl);
                TempData["Success"] = "Short Url has been updated";
                return RedirectToAction("List");
            }
            catch
            {
                TempData["Error"] = "There was an error saving your Url";
                return View();
            }
        }

        //
        // GET: /Forwards/Delete/5
        [Authorize]
        public ActionResult Delete(int id)
        {
            if (User != null)
                user = _usersRepo.GetById(User.Identity.GetUserId());
            Url url = _repo.GetById(id);
            return View(url);
        }

        [Authorize]
        [HttpPost]
        public ActionResult Delete(int id, bool confirm)
        {
            try
            {
                if (User != null)
                    user = _usersRepo.GetById(User.Identity.GetUserId());

                _repo.Remove(id);
                TempData["Success"] = "Short Url has been deleted";
                return RedirectToAction("List");

            }
            catch
            {
                TempData["Error"] = "There was an error deleting your Url";
                Url url = _repo.GetById(id);
                return View(url);
            }
        }

    }
}
RouteConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

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

            routes.MapRoute(
                name: "Forward",
                url: "{src}",
                defaults: new { controller = "Forwards", action = "SendToSrc", src = "" }
                );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

Ao final, configura-se o

web.config

com as seguintes chaves:

 <appsettings>
    <add key="ForwardsFile" value="~/App_Data/forwards.xml"></add>
    <add key="LenghtOfRandomString" value="8"></add>
    <add key="WebsiteName" value="Puulga"></add>
    <add key="WebsiteUrl" value="http://puul.ga/"></add>
    <add key="Website" value="true"></add>
    <!--email provider section-->
    <add key="siteadmin" value="email@puul.ga"></add>
    <add key="email-subject" value="Email from Puul.ga"></add>
    <add key="email-from" value="email@puul.ga"></add>
    <add key="email-from-name" value="Puul.ga"></add>
    <add key="email-require-auth" value="false"></add>
    <add key="email-username" value="puul.ga"></add>
    <add key="email-password" value="password"></add>
    <add key="email-port" value="3535"></add>
    <add key="useSSL" value="false"></add>
    <add key="email-server" value="localhost"></add>
    <add key="email-html-share" value="~/Email Templates/share.html"></add>
    <add key="email-html-default" value="~/Email Templates/puulga.html"></add>
    <add key="email-html-forgotten" value="~/Email Templates/puulga.html"></add>
    <add key="email-html-confirmation" value="~/Email Templates/puulga.html"></add>
    <add key="email-html-welcome" value="~/Email Templates/puulga.html"></add>
    <!--Database options. possible values: Xml, Sql-->
    <add key="DbProvider" value="Sql"></add>
  </appsettings>

Basicamente, esses são os elementos mais importantes para o funcionamento do projeto. Todo o código fonte está disponível no Github em código aberto.

Visite o site para ver como funciona.

Módulo Smtp com modelo de Html

Módulo Smtp com modelo de Html

Módulo Smtp com modelo de Html

Todas as vezes que crio um novo projeto que precisa enviar emails acabo indo atrás de projetos anteriores e faço o famoso ctrl+C, ctrl+V mas recentemente cansei desse hábito horrendo e decidi criar uma biblioteca simples que pode ser referenciada em qualquer projeto.

Caso esteja com pressa, baixe a biblioteca aqui, ou o demo completo aqui.

Página do projeto no Github

Para testar o módulo, use Smtp4Dev.

Para começar, criei a classe que gerencia o SmtpClient e SmtpServer:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Web.Hosting;

namespace Simple_Mail
{
    #region Enums
    /// <summary>
    /// Types of Emails that can be sent
    /// </summary>
    public enum EmailType
    {
        Default,
        Confirmation,
        Forgotten,
        Welcome,
        Error
    }
    /// <summary>
    /// Type of Application this module is being ran from
    /// </summary>
    public enum ApplicationType
    {
        Desktop,
        Web
    }
    #endregion

    #region Class
    /// <summary>
    /// Email Module Class
    /// </summary>
    public class Email
    {
        #region Public Members
        // <summary>
        /// The Email address of the Email Module Admin
        /// </summary>
        public string SITE_ADMIN { get; set; }
        /// <summary>
        /// Subject of the Email
        /// </summary>
        public string SUBJECT { get; set; }
        /// <summary>
        /// Body of the Email (default is html)
        /// </summary>
        public string BODY { get; set; }
        /// <summary>
        /// From Email Address (who's sending the email)
        /// </summary>
        public string FROM { get; set; }
        /// <summary>
        /// From Name (name of who is sending the email)
        /// </summary>
        public string FROM_NAME { get; set; }
        /// <summary>
        /// To Email Address (who is going to receive this email)
        /// </summary>
        public string TO { get; private set; }
        /// <summary>
        /// To Name (name of who is going to receive this email)
        /// </summary>
        public string TO_NAME { get; set; }
        /// <summary>
        /// Username of Smtp Service / Server
        /// </summary>
        public string USERNAME { get; private set; }
        /// <summary>
        /// Password for the smtp service / server
        /// </summary>
        public string PASSWORD { get; private set; }
        /// <summary>
        /// The port number for sending the email address (normal ports are 25, 587, 465)
        /// </summary>
        public int PORT { get; private set; }
        /// <summary>
        /// Whether to use SSL Encryption
        /// </summary>
        public bool USESSL { get; private set; }
        /// <summary>
        /// Uri of the Smtp Server
        /// </summary>
        public string SERVER { get; private set; }
        /// <summary>
        /// Whether the smtp server requires authentication
        /// </summary>
        public bool REQUIREAUTH { get; private set; }
        /// <summary>
        /// Name of the Website or App running the Module
        /// </summary>
        public string WEBSITE_NAME { get; set; }
        /// <summary>
        /// Default Html Body for the Email
        /// </summary>
        public string HTML_DEFAULT { get; private set; }
        /// <summary>
        /// Html body for the Forgotten Email
        /// </summary>
        public string HTML_FORGOTEN { get; private set; }
        /// <summary>
        /// Html Body for the Confirmation Email
        /// </summary>
        public string HTML_CONFIRMATION { get; private set; }
        /// <summary>
        /// Html Body for the Welcome Email
        /// </summary>
        public string HTML_WELCOME { get; private set; }
        /// <summary>
        /// Html for the Social Share
        /// </summary>
        public string HTML_SHARE_PATH { get; private set; }
        /// <summary>
        /// Path for the Default Html File
        /// </summary>
        public string HTML_DEFAULT_PATH { get; private set; }
        /// <summary>
        /// Path for the Forgotten Html File
        /// </summary>
        public string HTML_FORGOTEN_PATH { get; private set; }
        /// <summary>
        /// Path for the Confirmation Html File
        /// </summary>
        public string HTML_CONFIRMATION_PATH { get; private set; }
        /// <summary>
        /// Path for the Welcome Html File
        /// </summary>
        public string HTML_WELCOME_PATH { get; private set; }
        /// <summary>
        /// Path for the Social Share Html File
        /// </summary>
        public string HTML_SHARE { get; private set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Manually configures a Smtp Server Instance (when you do not want to use config files)
        /// </summary>
        /// <param name="smtpServer">The Uri for the smtp server</param>
        /// <param name="smtpPort">The Smtp Port</param>
        /// <param name="useAuth">Whether the Smtp Server Requires Authentication</param>
        /// <param name="username">The Smtp Username</param>
        /// <param name="password">The Smtp Password</param>
        /// <param name="useSSL">Whether to Use SSL Encryption</param>
        public Email(string smtpServer, int smtpPort, bool useAuth = false, string username = "", string password = "", bool useSSL = false)
        {
            SERVER = smtpServer;
            PORT = smtpPort;
            REQUIREAUTH = useAuth;
            USERNAME = username;
            PASSWORD = password;
            USESSL = useSSL;
        }
        /// <summary>
        /// Instanciates a new Email Module based on Config Files and Application Type (Web or Desktop)
        /// </summary>
        /// <param name="type"></param>
        public Email(ApplicationType type)
        {
            switch (type)
            {
                case ApplicationType.Desktop:
                    HTML_CONFIRMATION_PATH = ConfigurationManager.AppSettings["email-html-confirmation"];
                    HTML_WELCOME_PATH = ConfigurationManager.AppSettings["email-html-welcome"];
                    HTML_FORGOTEN_PATH = ConfigurationManager.AppSettings["email-html-forgotten"];
                    HTML_DEFAULT_PATH = ConfigurationManager.AppSettings["email-html-default"];
                    HTML_SHARE_PATH = ConfigurationManager.AppSettings["email-html-share"];
                    break;
                case ApplicationType.Web:
                    HTML_CONFIRMATION_PATH = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["email-html-confirmation"]);
                    HTML_WELCOME_PATH = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["email-html-welcome"]);
                    HTML_FORGOTEN_PATH = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["email-html-forgotten"]);
                    HTML_DEFAULT_PATH = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["email-html-default"]);
                    HTML_SHARE_PATH = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["email-html-share"]);
                    break;
                default:
                    break;
            }


            HTML_CONFIRMATION = GetEmailHtml(HTML_CONFIRMATION_PATH);
            HTML_WELCOME = GetEmailHtml(HTML_DEFAULT_PATH);
            HTML_FORGOTEN = GetEmailHtml(HTML_FORGOTEN_PATH);
            HTML_DEFAULT = GetEmailHtml(HTML_WELCOME_PATH);
            HTML_SHARE = GetEmailHtml(HTML_SHARE_PATH);


            WEBSITE_NAME = ConfigurationManager.AppSettings["WebsiteName"];

            SITE_ADMIN = ConfigurationManager.AppSettings["siteadmin"];

            SERVER = ConfigurationManager.AppSettings["email-server"];
            PORT = int.Parse(ConfigurationManager.AppSettings["email-port"]);
            USESSL = bool.Parse(ConfigurationManager.AppSettings["useSSL"]);
            PASSWORD = ConfigurationManager.AppSettings["email-password"];
            USERNAME = ConfigurationManager.AppSettings["email-username"];
            REQUIREAUTH = bool.Parse(ConfigurationManager.AppSettings["email-require-auth"]);

            TO_NAME = "New " + ConfigurationManager.AppSettings["WebsiteName"] + " Member";
            TO = ConfigurationManager.AppSettings["email-to"];
            FROM_NAME = ConfigurationManager.AppSettings["email-from-name"];
            FROM = ConfigurationManager.AppSettings["email-from"];

            SUBJECT = ConfigurationManager.AppSettings["email-subject"];


        }

        #endregion

        #region Private Members

        private EmailType emailMessageType;
        private string emailMessageHtml;
        private System.Net.Mail.SmtpClient SmtpServer;
        #endregion

        #region Private Methods
        private string GetEmailHtml(string path)
        {
            return File.ReadAllText(path);
        }

        private string GetEmailFilePath(EmailType type)
        {
            emailMessageType = type;

            switch (type)
            {
                case EmailType.Confirmation:
                    emailMessageHtml = HTML_CONFIRMATION;
                    break;
                case EmailType.Forgotten:
                    emailMessageHtml = HTML_FORGOTEN;
                    break;
                case EmailType.Welcome:
                    emailMessageHtml = HTML_WELCOME;
                    break;
                case EmailType.Default:
                    emailMessageHtml = HTML_DEFAULT;
                    break;
                default:
                    emailMessageHtml = "";
                    break;
            }
            return emailMessageHtml;
        }

        private bool SetupServer()
        {
            try
            {
                SmtpServer = new System.Net.Mail.SmtpClient();
                SmtpServer.Port = PORT;
                SmtpServer.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
                if (REQUIREAUTH)
                {
                    SmtpServer.UseDefaultCredentials = false;
                    SmtpServer.Credentials = new System.Net.NetworkCredential(USERNAME, PASSWORD);
                }
                else SmtpServer.UseDefaultCredentials = true;

                SmtpServer.Host = SERVER;
                SmtpServer.EnableSsl = USESSL;

                return true;
            }
            catch
            {

                return false;
            }
        }

        #endregion

        #region Public Methods
        /// <summary>
        /// Attempts to send an email
        /// </summary>
        /// <param name="type">The Type of Email Being Sent</param>
        /// <param name="custom">Whether to Customize the email</param>
        /// <param name="body">If customized, set the html body for the email</param>
        /// <param name="To">If customized, defines the TO field</param>
        /// <param name="ToName">If customized, defines the To name</param>
        /// <returns>Returns a KeyValuePair<bool,string> with success (true/false) and a message from the smtp server</returns>
        public KeyValuePair<bool, string> SendMail(EmailType type, bool custom = false, string body = "", string To = "", string ToName = "New Member")
        {

            if (SetupServer())
            {
                System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();

                mail.Subject = SUBJECT;
                mail.From = new System.Net.Mail.MailAddress(FROM, FROM_NAME);
                mail.IsBodyHtml = true;

                if (ToName != "") TO_NAME = ToName;

                if (To == "") mail.To.Add(new System.Net.Mail.MailAddress(TO, TO_NAME));
                else mail.To.Add(new System.Net.Mail.MailAddress(To, TO_NAME));

                if (custom)
                    mail.Body = body;
                else
                {
                    BODY = GetEmailFilePath(type);
                    mail.Body = BODY;
                }

                try
                {
                    SmtpServer.Send(mail);
                    return new KeyValuePair<bool, string>(true, "Email sent succesfully");
                }
                catch (Exception ex)
                {
                    return new KeyValuePair<bool, string>(false, ex.Message);
                }
                finally
                {
                    SmtpServer.Dispose();
                }
            }
            else return new KeyValuePair<bool, string>(false, "Error Setting UP Email");

        }
        /// <summary>
        /// Manually Sets the Body for the Email Message
        /// </summary>
        /// <param name="message">The Html Body for the Email</param>
        public void SetBody(string message)
        {
            BODY = message;
        }
        #endregion

    } 
    #endregion
}

Também inclui algumas configurações no App.Config como modelo, que podem ser usadas no Web.Config caso não queira inserir os dados via código.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!--email provider section-->
    <add key="siteadmin" value="postmaster@simpleemail.com"/>
    <add key="email-subject" value="Email from Email Website"/>
    <add key="email-from" value="postmaster@puul.ga"/>
    <add key="email-from-name" value="Simple Email"/>
    <add key="email-require-auth" value="false"/>
    <add key="email-username" value="simpleemail"/>
    <add key="email-password" value=""/>
    <add key="email-port" value="3535"/>
    <add key="useSSL" value="false"/>
    <add key="email-server" value="localhost"/>
    <add key="email-html-share" value="~/Email Templates/share.html"/>
    <add key="email-html-default" value="~/Email Templates/default.html"/>
    <add key="email-html-forgotten" value="~/Email Templates/default.html"/>
    <add key="email-html-confirmation" value="~/Email Templates/default.html"/>
    <add key="email-html-welcome" value="~/Email Templates/default.html"/>
  </appSettings>
</configuration>

Mas como também havia interesse em mandar emails em html mais bonitos, usei um modelo do MailChimp™ para ficar mais apresentável. Inclui na pasta de “Email Templates”

<!--MAILCHIMP EMAIL TEMPLATE-->
<!--DON'T CHANGE THE *|VALUES|* AS THEY ARE REPLACED IN THE SERVER - CHANGE THE HTML, TEXT IS AUTOMATICALLY ADDED-->
<td align="center" valign="top" id="bodyCell" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;height: 100%;margin: 0;padding: 10px;width: 100%;border-top: 0;">
    <!-- BEGIN TEMPLATE // -->
						<!--[if gte mso 9]>
						<table align="center" border="0" cellspacing="0" cellpadding="0" width="600" style="width:600px;">
						<tr>
						<td align="center" valign="top" width="600" style="width:600px;">
                          <![endif]-->
                          <table border="0" cellpadding="0" cellspacing="0" width="100%" class="templateContainer" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;border: 0;max-width: 600px !important;">
                            <tbody><tr>
                                <td valign="top" id="templatePreheader" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;background-color: #FAFAFA;border-top: 0;border-bottom: 0;padding-top: 9px;padding-bottom: 9px;"><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnTextBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                    <tbody class="mcnTextBlockOuter">
                                        <tr>
                                            <td valign="top" class="mcnTextBlockInner" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">

                                                <table align="left" border="0" cellpadding="0" cellspacing="0" width="366" class="mcnTextContentContainer" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                    <tbody><tr>

                                                        <td valign="top" class="mcnTextContent" style="padding-top: 9px;padding-left: 18px;padding-bottom: 9px;padding-right: 0;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;word-break: break-word;color: #656565;font-family: Helvetica;font-size: 12px;line-height: 150%;text-align: left;">

                                                            *|EMAIL_PREVIEW|*
                                                        </td>
                                                    </tr>
                                                </tbody></table>

                                                <table align="right" border="0" cellpadding="0" cellspacing="0" width="197" class="mcnTextContentContainer" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                    <tbody><tr>

                                                        <td valign="top" class="mcnTextContent" style="padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;word-break: break-word;color: #656565;font-family: Helvetica;font-size: 12px;line-height: 150%;text-align: left;">
                                                        </td>
                                                    </tr>
                                                </tbody></table>

                                            </td>
                                        </tr>
                                    </tbody>
                                </table></td>
                            </tr>
                            <tr>
                                <td valign="top" id="templateHeader" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;background-color: #FFFFFF;border-top: 0;border-bottom: 0;padding-top: 9px;padding-bottom: 0;"><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnImageBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                    <tbody class="mcnImageBlockOuter">
                                        <tr>
                                            <td valign="top" style="padding: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnImageBlockInner">
                                                <table align="left" width="100%" border="0" cellpadding="0" cellspacing="0" class="mcnImageContentContainer" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                    <tbody><tr>
                                                        <td class="mcnImageContent" valign="top" style="padding-right: 9px;padding-left: 9px;padding-top: 0;padding-bottom: 0;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">

                                                            <table style="width: 564px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcpreview-image-uploader"></table>

                                                        </td>
                                                    </tr>
                                                </tbody></table>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table></td>
                            </tr>
                            <tr>
                                <td valign="top" id="templateBody" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;background-color: #FFFFFF;border-top: 0;border-bottom: 2px solid #EAEAEA;padding-top: 0;padding-bottom: 9px;"><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnTextBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                    <tbody class="mcnTextBlockOuter">
                                        <tr>
                                            <td valign="top" class="mcnTextBlockInner" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">

                                                <table align="left" border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnTextContentContainer">
                                                    <tbody><tr>

                                                        <td valign="top" class="mcnTextContent" style="padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;word-break: break-word;color: #202020;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;">

                                                            <h1 style="display: block;margin: 0;padding: 0;color: #202020;font-family: Helvetica;font-size: 26px;font-style: normal;font-weight: bold;line-height: 125%;letter-spacing: normal;text-align: left;">

                                                                *|HEADER|*

                                                            </h1>

                                                            <p style="margin: 10px 0;padding: 0;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #202020;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;">

                                                                *|FIRSTPARAGRAPH|*
                                                            </p>
                                                            <p style="margin: 10px 0;padding: 0;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #202020;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;">
                                                                *|SECONDPARAGRAPH|*
                                                            </p>
                                                            <p style="margin: 10px 0;padding: 0;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #202020;font-family: Helvetica;font-size: 16px;line-height: 150%;text-align: left;">
                                                                If you need a bit of inspiration, you can 
                                                                <a href="http://inspiration.mailchimp.com" class="mc-template-link" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #2BAADF;font-weight: normal;text-decoration: underline;">
                                                                    see what other MailChimp users are doing
                                                                </a>, or <a href="http://mailchimp.com/resources/email-design-guide/" class="mc-template-link" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;color: #2BAADF;font-weight: normal;text-decoration: underline;">
                                                                learn about email design
                                                            </a> 
                                                            and blaze your own trail.
                                                        </p>
                                                    </td>
                                                </tr>
                                            </tbody>
                                        </table>

                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td valign="top" id="templateFooter" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;background-color: #FAFAFA;border-top: 0;border-bottom: 0;padding-top: 9px;padding-bottom: 9px;"><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnFollowBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                        <tbody class="mcnFollowBlockOuter">
                            <tr>
                                <td align="center" valign="top" style="padding: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnFollowBlockInner">
                                    <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnFollowContentContainer" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                        <tbody><tr>
                                            <td align="center" style="padding-left: 9px;padding-right: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnFollowContent">
                                                    <tbody><tr>
                                                        <td align="center" valign="top" style="padding-top: 9px;padding-right: 9px;padding-left: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                            <table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                <tbody><tr>
                                                                    <td align="center" valign="top" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                    <!--[if mso]>
                                    <table align="center" border="0" cellspacing="0" cellpadding="0">
                                    <tr>
                                        <![endif]-->

                                        <!--[if mso]>
                                        <td align="center" valign="top">
                                            <![endif]-->


                                            <table align="left" border="0" cellpadding="0" cellspacing="0" style="display: inline;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                <tbody><tr>
                                                    <td valign="top" style="padding-right: 10px;padding-bottom: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnFollowContentItemContainer">
                                                        <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnFollowContentItem" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                            <tbody><tr>
                                                                <td align="left" valign="middle" style="padding-top: 5px;padding-right: 10px;padding-bottom: 5px;padding-left: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                    <table align="left" border="0" cellpadding="0" cellspacing="0" width="" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                        <tbody><tr>

                                                                            <td align="center" valign="middle" width="24" class="mcnFollowIconContent" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                                <a href="http://www.twitter.com/" target="_blank" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;"><img src="http://cdn-images.mailchimp.com/icons/social-block-v2/color-twitter-48.png" style="display: block;border: 0;height: auto;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;" height="24" width="24" class=""></a>
                                                                            </td>
                                                                            
                                                                            
                                                                        </tr>
                                                                    </tbody></table>
                                                                </td>
                                                            </tr>
                                                        </tbody></table>
                                                    </td>
                                                </tr>
                                            </tbody></table>

                                        <!--[if mso]>
                                        </td>
                                        <![endif]-->

                                        <!--[if mso]>
                                        <td align="center" valign="top">
                                            <![endif]-->


                                            <table align="left" border="0" cellpadding="0" cellspacing="0" style="display: inline;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                <tbody><tr>
                                                    <td valign="top" style="padding-right: 10px;padding-bottom: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnFollowContentItemContainer">
                                                        <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnFollowContentItem" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                            <tbody><tr>
                                                                <td align="left" valign="middle" style="padding-top: 5px;padding-right: 10px;padding-bottom: 5px;padding-left: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                    <table align="left" border="0" cellpadding="0" cellspacing="0" width="" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                        <tbody><tr>

                                                                            <td align="center" valign="middle" width="24" class="mcnFollowIconContent" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                                <a href="http://www.facebook.com" target="_blank" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;"><img src="http://cdn-images.mailchimp.com/icons/social-block-v2/color-facebook-48.png" style="display: block;border: 0;height: auto;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;" height="24" width="24" class=""></a>
                                                                            </td>
                                                                            
                                                                            
                                                                        </tr>
                                                                    </tbody></table>
                                                                </td>
                                                            </tr>
                                                        </tbody></table>
                                                    </td>
                                                </tr>
                                            </tbody></table>

                                        <!--[if mso]>
                                        </td>
                                        <![endif]-->

                                        <!--[if mso]>
                                        <td align="center" valign="top">
                                            <![endif]-->


                                            <table align="left" border="0" cellpadding="0" cellspacing="0" style="display: inline;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                <tbody><tr>
                                                    <td valign="top" style="padding-right: 0;padding-bottom: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnFollowContentItemContainer">
                                                        <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnFollowContentItem" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                            <tbody><tr>
                                                                <td align="left" valign="middle" style="padding-top: 5px;padding-right: 10px;padding-bottom: 5px;padding-left: 9px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                    <table align="left" border="0" cellpadding="0" cellspacing="0" width="" style="border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                        <tbody><tr>

                                                                            <td align="center" valign="middle" width="24" class="mcnFollowIconContent" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                                                                                <a href="http://mailchimp.com" target="_blank" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;"><img src="http://cdn-images.mailchimp.com/icons/social-block-v2/color-link-48.png" style="display: block;border: 0;height: auto;outline: none;text-decoration: none;-ms-interpolation-mode: bicubic;" height="24" width="24" class=""></a>
                                                                            </td>
                                                                            
                                                                            
                                                                        </tr>
                                                                    </tbody></table>
                                                                </td>
                                                            </tr>
                                                        </tbody></table>
                                                    </td>
                                                </tr>
                                            </tbody></table>

                                        <!--[if mso]>
                                        </td>
                                        <![endif]-->

                                    <!--[if mso]>
                                    </tr>
                                    </table>
                                    <![endif]-->
                                </td>
                            </tr>
                        </tbody></table>
                    </td>
                </tr>
            </tbody></table>
        </td>
    </tr>
</tbody></table>

</td>
</tr>
</tbody>
</table><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnDividerBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;table-layout: fixed !important;">
<tbody class="mcnDividerBlockOuter">
    <tr>
        <td class="mcnDividerBlockInner" style="min-width: 100%;padding: 10px 18px 25px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
            <table class="mcnDividerContent" border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width: 100%;border-top-width: 2px;border-top-style: solid;border-top-color: #EEEEEE;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                <tbody><tr>
                    <td style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
                        <span></span>
                    </td>
                </tr>
            </tbody></table>
<!--            
                <td class="mcnDividerBlockInner" style="padding: 18px;">
                <hr class="mcnDividerContent" style="border-bottom-color:none; border-left-color:none; border-right-color:none; border-bottom-width:0; border-left-width:0; border-right-width:0; margin-top:0; margin-right:0; margin-bottom:0; margin-left:0;" />
            -->
        </td>
    </tr>
</tbody>
</table><table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnTextBlock" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">
<tbody class="mcnTextBlockOuter">
    <tr>
        <td valign="top" class="mcnTextBlockInner" style="mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;">

            <table align="left" border="0" cellpadding="0" cellspacing="0" width="100%" style="min-width: 100%;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;" class="mcnTextContentContainer">
                <tbody><tr>

                    <td valign="top" class="mcnTextContent" style="padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%;word-break: break-word;color: #656565;font-family: Helvetica;font-size: 12px;line-height: 150%;text-align: center;">

                        <em>Copyright &copy; *|CURRENT_YEAR|* *|LIST:COMPANY|*, All rights reserved.</em>
                        <br>
                        <br>
                        <br>

                    </td>
                </tr>
            </tbody></table>

        </td>
    </tr>
</tbody>
</table></td>
</tr>
</tbody></table>
						<!--[if gte mso 9]>
						</td>
						</tr>
						</table>
						<![endif]-->
                        <!-- // END TEMPLATE -->
                    </td>

Para usar o módulo, instancia-se desta forma

            Email _email = new Email(ApplicationType.Web);
            string defaultHtml = _email.HTML_CONFIRMATION;
            string body = defaultHtml
                .Replace("*|EMAIL_PREVIEW|*", "This is a Simple Email")
                .Replace("*|HEADER|*", "Simple Email Website")
                .Replace("*|FIRSTPARAGRAPH|*", "The message below has been customized")
                .Replace("*|SECONDPARAGRAPH|*", Message)
                .Replace("*|WEBSITE_URL|*", Request.Url.ToString())
                .Replace("*|WEBSITE_NAME|*", _email.WEBSITE_NAME)
                .Replace("*|CURRENT_YEAR|*", DateTime.Now.Year.ToString());


            _email.SendMail(EmailType.Confirmation, true, body, Email);

Basicamente, está criado um módulo que pode ser reusado em outros projetos, sem o horrendo copy/paste. Claro, melhorias sempre podem ser feitas, por isso o projeto é open source e pode ser baixado do Github.

Para testar a funcionalidade, recomendo usar Smtp4Dev que é bastante prático e não requer nem instalação.

Alerta não Intrusivo

Como criar um Alerta Não Intrusivo

Veja como é fácil criar um alerta não Intrusivo, com algumas poucas linhas de código, criar um alerta que não atrapalha o usuário, e pode ser atualizado de várias formas. Neste exemplo, estou usando um arquivo javascript que contém os alertas (veja abaixo).

  1. Copie o Html que é bastante simples
  2. Copie o CSS que já está bastante completo, mas fique a vontade em modificar
  3. Copie o jQuery (que também pode ser modificado)
  4. Se quiser usar o método de alertas deste demo, copie os alertas
  5. Ou baixe o demo completo em zip

Para este demo, foram usados os seguintes recursos:

 

Veja em ação no demo

Html

<div id="alert">

<div id="close-alert">X</div>

        <span>
            <i class='fa fa-2x' id="alert-icon"></i>
        </span>
        <span id="alert-message"></span>
    </div>

CSS

 #alert {
     z-index: 999;
     position: fixed;
     left: 0;
     width: 100%;
     height: 60px;
     text-align: center;
     padding: 12px 0 30px 0;
     background-color: #000;
     opacity: 0.6;
     color: #fff;
     text-shadow: 0 0 2px #ccc;
     bottom: 0px;
     /*Mude aqui para definir se o 
     alerta vai ser encima ou no rodape; 
     use bottom para rodapé e top para cabeçalho*/
 }
 #alert #close-alert {
     border: 1px solid #000;
     position: absolute;
     right: 0px;
     top: 0;
     color: #fff;
     width: 32px;
     height: 32px;
     line-height: 32px;
     transition: all 0.2s ease;
     cursor: pointer;
 }
 #alert #close-alert:hover {
     background-color: #980000;
     border: 1px solid #fff;
 }
 #alert span {
     max-width: 80%;
 }
 #alert-icon{
     padding-right: 15px
 }
 #alert #alert-message a, #alert #alert-message a:visited{
    color:#c2c2c2;
    font-weight: 800;
    text-decoration: none;
    transition: all 0.2s ease-in;
}
#alert #alert-message a:hover{
    color:#fff;
    text-shadow:0 0 3px #ccc;
}

jQuery

$(function () {

  Rollnews(); //inicia a rolagem de alertas
  
  $("#close-alert").click(function(){
    $("#alert").fadeOut(); //fecha o alerta
  });

});
//Rolagem de alertas
function Rollnews(){
  var i=0;
  $("#alert-icon").addClass(news[i].icon);
  $("#alert-message").html(news[i].text);
  $("#alert-icon,#alert-message").fadeIn();
  setInterval(function(){
    var previous = i;
    i++;
    if(i>news.length-1){
      i = 0;
    }
    $("#alert-icon").removeClass(news[previous].icon).addClass(news[i].icon);
    $("#alert-message").html(news[i].text);
  },3*1000);
}

Alertas

var news = [
        {    
    text : "Este é o primeiro alerta com um &lt;a href='http://www.zueuz.com.br' target='_blank'&gt;Link&lt;/a&gt;", 
    icon : "fa-info-circle"
        },
        {
    text : "Este é o segundo alerta, com outra mensagem qualquer",
    icon : "fa-exclamation-circle"
        },
        {
    text : "Ainda mais um alerta, que pode ser uma mensagem, uma imagem, ou um tweet (tweets necessitam de outro plugin)",
    icon : "fa-bell-o"
        }];

Criando um widget de compartilhamento somente com CSS e SVG

Criando um widget de compartilhamento somente com CSS e SVG

Encher seu site de jquery (javascript) pode causar lentidão na hora de carregar. Pode-se argumentar que isso não é problema se mimificar o script. OK…. não é o ponto discutir performance neste artigo Criando um widget de compartilhamento somente com CSS e SVG.

Este artigo mostra como criar um widget de compartilhamento usando somente CSS3 e SVG. Claro que existe o requisito que o navegador suporte essas duas funcionalidades. Mas a maioria dos navegadores de hoje já estão no padrão Html5 e CSS3.

Para criação deste widget usei o plugin de compartilhamento Ridiculous Responsive Social Sharing Buttons e o Share Link Generator que cria os urls de compartilhamento.

Veja o DEMO

Vamos ao código:

Nota: como é svg, parece muito código, mas não é..
 <ul class="rrssb-buttons clearfix">
                <li class="share-button" title="Compartilhar"></li>
                <li class="email" >
                    <a title="Envie para um amigo" href="mailto:?subject=Conhe&ccedil;a Hebrom Benef&iacute;cios&amp;body=Acabei de conhecer o Hebrom Benef&iacute;cios e gostaria de compartilhar com voc&ecirc;!    http://www.hebromsaude.com.br">
                        <span class="icon-share">
                            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve"><g><path d="M20.111 26.147c-2.336 1.051-4.361 1.401-7.125 1.401c-6.462 0-12.146-4.633-12.146-12.265 c0-7.94 5.762-14.833 14.561-14.833c6.853 0 11.8 4.7 11.8 11.252c0 5.684-3.194 9.265-7.399 9.3 c-1.829 0-3.153-0.934-3.347-2.997h-0.077c-1.208 1.986-2.96 2.997-5.023 2.997c-2.532 0-4.361-1.868-4.361-5.062 c0-4.749 3.504-9.071 9.111-9.071c1.713 0 3.7 0.4 4.6 0.973l-1.169 7.203c-0.388 2.298-0.116 3.3 1 3.4 c1.673 0 3.773-2.102 3.773-6.58c0-5.061-3.27-8.994-9.303-8.994c-5.957 0-11.175 4.673-11.175 12.1 c0 6.5 4.2 10.2 10 10.201c1.986 0 4.089-0.43 5.646-1.245L20.111 26.147z M16.646 10.1 c-0.311-0.078-0.701-0.155-1.207-0.155c-2.571 0-4.595 2.53-4.595 5.529c0 1.5 0.7 2.4 1.9 2.4 c1.441 0 2.959-1.828 3.311-4.087L16.646 10.068z"/></g></svg>
                        </span>
                    </a>
                </li>
                <li class="facebook">
                    <a target="_blank" title="Poste no Facebook" href="https://www.facebook.com/sharer/sharer.php?u=http://www.ccasalicchio.com/criando-um-widget-de-compartilhamento-somente-com-css-e-svg/" class="popup">
                        <span class="icon-share">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
                                <path d="M27.825,4.783c0-2.427-2.182-4.608-4.608-4.608H4.783c-2.422,0-4.608,2.182-4.608,4.608v18.434
                                c0,2.427,2.181,4.608,4.608,4.608H14V17.379h-3.379v-4.608H14v-1.795c0-3.089,2.335-5.885,5.192-5.885h3.718v4.608h-3.726
                                c-0.408,0-0.884,0.492-0.884,1.236v1.836h4.609v4.608h-4.609v10.446h4.916c2.422,0,4.608-2.188,4.608-4.608V4.783z"/>
                            </span>
                        </a>
                    </li>
                    <li class="linkedin">
                        <a target="_blank" title="Poste no LinkedIn" href="https://www.linkedin.com/shareArticle?mini=true&url=http://www.ccasalicchio.com/criando-um-widget-de-compartilhamento-somente-com-css-e-svg/&title=Widget%20de%20CSS3%20e%20SVG%20para%20compartilhamento&summary=Uso%20de%20CSS3%20somente,%20para%20compartilhamento%20em%20m%C3%ADdia%20social&source=" class="popup">
                            <span class="icon-share">
                                <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
                                    <path d="M25.424,15.887v8.447h-4.896v-7.882c0-1.979-0.709-3.331-2.48-3.331c-1.354,0-2.158,0.911-2.514,1.803
                                    c-0.129,0.315-0.162,0.753-0.162,1.194v8.216h-4.899c0,0,0.066-13.349,0-14.731h4.899v2.088c-0.01,0.016-0.023,0.032-0.033,0.048
                                    h0.033V11.69c0.65-1.002,1.812-2.435,4.414-2.435C23.008,9.254,25.424,11.361,25.424,15.887z M5.348,2.501
                                    c-1.676,0-2.772,1.092-2.772,2.539c0,1.421,1.066,2.538,2.717,2.546h0.032c1.709,0,2.771-1.132,2.771-2.546
                                    C8.054,3.593,7.019,2.501,5.343,2.501H5.348z M2.867,24.334h4.897V9.603H2.867V24.334z"/>
                                </svg>
                            </span>
                        </a>
                    </li>
                    <li class="twitter" >
                        <a target="_blank" title="Poste no Twitter" href="https://twitter.com/home?status=%23widget%20%23css3%20%26%20%23svg%20%23sharing%0Ahttp://www.ccasalicchio.com/criando-um-widget-de-compartilhamento-somente-com-css-e-svg/%[email protected]_casalicchio" class="popup">
                            <span class="icon-share">
                                <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
                                width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
                                <path d="M24.253,8.756C24.689,17.08,18.297,24.182,9.97,24.62c-3.122,0.162-6.219-0.646-8.861-2.32
                                c2.703,0.179,5.376-0.648,7.508-2.321c-2.072-0.247-3.818-1.661-4.489-3.638c0.801,0.128,1.62,0.076,2.399-0.155
                                C4.045,15.72,2.215,13.6,2.115,11.077c0.688,0.275,1.426,0.407,2.168,0.386c-2.135-1.65-2.729-4.621-1.394-6.965
                                C5.575,7.816,9.54,9.84,13.803,10.071c-0.842-2.739,0.694-5.64,3.434-6.482c2.018-0.623,4.212,0.044,5.546,1.683
                                c1.186-0.213,2.318-0.662,3.329-1.317c-0.385,1.256-1.247,2.312-2.399,2.942c1.048-0.106,2.069-0.394,3.019-0.851
                                C26.275,7.229,25.39,8.196,24.253,8.756z"/>
                            </svg>
                        </span>
                    </a>
                </li>
                <li class="googleplus" >
                    <a target="_blank" title="Poste no Google+" href="https://plus.google.com/share?url=http://www.ccasalicchio.com/criando-um-widget-de-compartilhamento-somente-com-css-e-svg/" class="popup">
                        <span class="icon-share">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
                                <g>
                                    <g>
                                        <path d="M14.703,15.854l-1.219-0.948c-0.372-0.308-0.88-0.715-0.88-1.459c0-0.748,0.508-1.223,0.95-1.663
                                        c1.42-1.119,2.839-2.309,2.839-4.817c0-2.58-1.621-3.937-2.399-4.581h2.097l2.202-1.383h-6.67c-1.83,0-4.467,0.433-6.398,2.027
                                        C3.768,4.287,3.059,6.018,3.059,7.576c0,2.634,2.022,5.328,5.604,5.328c0.339,0,0.71-0.033,1.083-0.068
                                        c-0.167,0.408-0.336,0.748-0.336,1.324c0,1.04,0.551,1.685,1.011,2.297c-1.524,0.104-4.37,0.273-6.467,1.562
                                        c-1.998,1.188-2.605,2.916-2.605,4.137c0,2.512,2.358,4.84,7.289,4.84c5.822,0,8.904-3.223,8.904-6.41
                                        c0.008-2.327-1.359-3.489-2.829-4.731H14.703z M10.269,11.951c-2.912,0-4.231-3.765-4.231-6.037c0-0.884,0.168-1.797,0.744-2.511
                                        c0.543-0.679,1.489-1.12,2.372-1.12c2.807,0,4.256,3.798,4.256,6.242c0,0.612-0.067,1.694-0.845,2.478
                                        c-0.537,0.55-1.438,0.948-2.295,0.951V11.951z M10.302,25.609c-3.621,0-5.957-1.732-5.957-4.142c0-2.408,2.165-3.223,2.911-3.492
                                        c1.421-0.479,3.25-0.545,3.555-0.545c0.338,0,0.52,0,0.766,0.034c2.574,1.838,3.706,2.757,3.706,4.479
                                        c-0.002,2.073-1.736,3.665-4.982,3.649L10.302,25.609z"/>
                                        <polygon points="23.254,11.89 23.254,8.521 21.569,8.521 21.569,11.89 18.202,11.89 18.202,13.604 21.569,13.604 21.569,17.004
                                        23.254,17.004 23.254,13.604 26.653,13.604 26.653,11.89      "/>
                                    </g>
                                </g>
                            </svg>
                        </span>
                    </a>
                </li>
                <li class="pinterest" >
                    <a target="_blank" title="Poste no Pinterest" href="https://pinterest.com/pin/create/button/?url=http://www.ccasalicchio.com/demos/compartilharwidget/images/node.png&media=Node&description=Widget%20de%20compartilhamento%20usando%20somente%20CSS3%20e%20Svg">
                        <span class="icon-share">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="28px" height="28px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
                                <path d="M14.021,1.57C6.96,1.57,1.236,7.293,1.236,14.355c0,7.062,5.724,12.785,12.785,12.785c7.061,0,12.785-5.725,12.785-12.785
                                C26.807,7.294,21.082,1.57,14.021,1.57z M15.261,18.655c-1.161-0.09-1.649-0.666-2.559-1.219c-0.501,2.626-1.113,5.145-2.925,6.458
                                c-0.559-3.971,0.822-6.951,1.462-10.116c-1.093-1.84,0.132-5.545,2.438-4.632c2.837,1.123-2.458,6.842,1.099,7.557
                                c3.711,0.744,5.227-6.439,2.925-8.775c-3.325-3.374-9.678-0.077-8.897,4.754c0.19,1.178,1.408,1.538,0.489,3.168
                                C7.165,15.378,6.53,13.7,6.611,11.462c0.131-3.662,3.291-6.227,6.46-6.582c4.007-0.448,7.771,1.474,8.29,5.239
                                c0.579,4.255-1.816,8.865-6.102,8.533L15.261,18.655z"/>
                            </svg>
                        </span>
                    </a>
                </li>
            </ul>

Agora o CSS

.rrssb-buttons{
   width:350px;
   height:32px;
   list-style: none;
   opacity: 0.8;
}
.rrssb-buttons li{
    float:left;
    padding:0 5px 0 5px;
    opacity: 0;
    width: 0;
    transition:all 0.6s ease;
}
.rrssb-buttons:hover{
    opacity: 1;
}
.rrssb-buttons:hover >li{
    width:32px;
    opacity: 1;
}
.icon-share{
    fill:#fff;
}
.share-button{
    background:url('../images/node.png')no-repeat center;
    width: 32px !important;
    height: 32px;
    display: block !important;
    opacity: 1 !important;
    cursor:pointer;
}

Só isso! Bem simples mas muito prático!

DEMO

Código Fonte

Simples botão de Fechar com CSS3 e Jquery

Simples botão de Fechar com CSS3 e Jquery

Neste artigo, Simples botão de Fechar com CSS3 e Jquery, mostrarei como usar um código simples, ao invés de ficar criando imagens para botões, por quê não criar um somente com CSS3? Sem mais delongas, segue o código:

Html do botão:

	<div id="alert">
		<div class="close">X</div>
		<h1>Aviso</h1>
		<p>Texto do seu alerta</p>
	</div>

CSS3 do botão:

.close{
	width: 24px; /*largura*/
	height: 24px; /*altura*/
	font-size: 8px; /*tamanho da fonte (X)*/
	line-height: 24px; 
/*tamanho da linha que contem o texto - 
24 é o mesmo tamanho do botão para o X 
ficar alinhado no centro (cima-baixo)*/
	text-align: center; /*alinhamento to texto no meio do botão (esq-dir)*/
	position: relative; /*relativo para ficar por posicionado como está 
- acima e para fora da caixa de alerta*/
	right: -288px; /*posição em relação à  linha da caixa de alerta - horizontal*/
	top: -12px; /*posição em relação à  linha da caixa de alerta - vertical*/
	float: left; /*desacopla o botão do resto dos componentes*/
	border-radius: 50%; /*raio de circunferencia dos cantos - 50% faz cada lado ficar totalmente redondo, criando um botão circular*/
	border: 1px solid #ccc; /*borda do botão*/
	background-color: #F55555; /*cor de fundo do botão*/
	color: #000; /*cor do text*/
	transition: all 0.2s ease; /*animação que ocorre quando alguma ação é realizada*/
	cursor: pointer; /*mostra o dedo de link mostrando que é clicável*/
}

Jquery de fechamento:

$('.close').click(function(event){
		$('#alert').fadeOut();
		event.preventDefault();
	});

Download da fonte: botao_fechar

DEMO

Busca específica em texto usando jQuery

Busca específica em texto usando jQuery

Nem todo usuário conhece o atalho ctrl+F (buscar) que está presente em quase todos os apps de hoje em dia.

Por esse motivo, é sempre válido criar uma caixinha de busca em páginas que contém muito texto. Busca específica em texto usando jQuery mostra como alcançar essa funcionalidade.

Busca específica em texto usando jQuery

Para este demo foi usado o jQuery highlight Plugin do Johann Burkard.

HTML

<html>
<head>
  <meta name="robots" content="noindex, nofollow"/>
  <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
  <script type="text/javascript" src="scripts/page.js"></script>
  <link href='css/style.css' rel="stylesheet" type="text/css"/>
  <title>Busca com JQuery</title>
</head>
<body>
  <div id="keys">
    <div id="searchBox">
      <input type="text" id="txtsearch" placeholder="search" name="search"/>
      <div id="btnsearch" title="Buscar no texto"></div>
      <div class="break"></div>
      <div class='back-top'>inicio &#8593;</div>
    </div>
    <h1>Texto a ser pesquisado</h1>
    <section>
      TEXTO AQUI
    </section>
    <script src="scripts/jquery.highlight-4.closure.js" type="text/javascript"></script>
  </body>
  </html>

CSS

#searchBox{
position: fixed;
top: 0;
right: 0;
width: 190px;
background-color: #000;
box-shadow: 0 0 8px #ccc;
padding: 0 5px 10px 0;
margin: -4px 0 0 0;
border-radius: 4px;
color: #fff;
text-align: right;
}
#searchBox a{
    color:#fff !important;
}
#txtsearch
{
   border: 4px solid #000;
   line-height: 35px;
   font-size: 14px;
   padding-left: 10px;
   font-family: 'Segoe UI';
   border-bottom-right-radius: 8px;
   border-bottom-left-radius: 8px;
   float:left;
   margin-left:5px;
}
#txtsearch:focus{
    outline:none;
}
#btnsearch{
   background:url('../images/search.png') no-repeat center;
   background-size: 24px;
   width: 24px;
   height: 24px;
   float:left;
   cursor: pointer;
   z-index: 999999;
   margin: 10px 0 0 -40px;
}
.highlight { background-color: #F6E8B9; font-weight: bold; }

.back-top{
   color:#fff;
   font-weight: bold;
   padding-left:15%;
   cursor: pointer;
   transition:letter-spacing 0.3s ease;
}
.back-top:hover{
    letter-spacing:3px;
}

#txtsearch
{
   border: 1px solid #000;
   line-height: 18px;
   font-size: 16px;
   padding-left: 10px;
   font-family: 'Segoe UI';
   border-bottom-right-radius: 8px;
   border-bottom-left-radius: 8px;
   float:left;
}
#btnsearch{
   background:url('../images/search.png') no-repeat center;
   background-size: 16px;
   width: 16px;
   height: 16px;
   float:left;
   cursor: pointer;
   z-index: 999999;
   margin: 7px 0 0 -25px;
}

jQuery

 var counter = 0;
 $(function(){
  $('.back-top').click(function(){
   $('html, body').animate({
    scrollTop: 0
  }, 300);
 });

  $("#btnsearch").click(function(e){
    $("body").removeHighlight();
    $("body").highlight($("#txtsearch").val());
    var curr = $('.highlight')[counter];
    var top =  $(curr).offset().top-180;
    $('html, body').animate({
      scrollTop: top
    }, 300);
    counter++;
    if(counter>=$('.highlight').length)counter=0;
  });
  $("#txtsearch").click(function(){
    $(this).select().focus();
  });
  $("#txtsearch").keypress(function(e){
    if(e.which===13) {
      $("#btnsearch").click();
    };
  });

})

Veja o Demo

Código Fonte

Como criar um formulário de contato em Ajax para Umbraco

Como criar um formulário de contato em Ajax para Umbraco

por Carlos Casalicchio

Ao criar uma página responsiva em Umbraco rapidamente encontra-se algumas restrições relativas ao que a atual oferece. E, apesar da comunidade já ter desenvolvido várias coisas úteis, algumas vezes não encontramos o que precisamos.

Por esse motivo acabei por desenvolvendo um formulário de email simples que possibilite o envio de e-mails em Ajax, sem Postback da página.

Para tanto, criei o formulário na página (está fora do escopo discutir o html envolvido na criação do formulário) como na figura:

Como criar um formulário de contato em Ajax para Umbraco

Neste artigo, mostro como criar um formulário de contato em Ajax para Umbraco. O código do formulário é este:

Html

div class="contact_form">
    <div id="note"></div>
    <div id="fields">
        <form id="ajaxSendmail" action="">
            <input type="text" name="name" value="" placeholder="Name" />
            <input type="text" name="email" value="" placeholder="Email" />
            <textarea name="message" id="message" placeholder="Message"></textarea>
            <div class="clear"></div>
            <input type="reset" class="contact_btn" value="Clear Form" />
            <input type="submit" class="contact_btn send_btn" value="Send" />
            <div class="clear"></div>
        </form>
    </div>
</div>

CSS

#note {
            position: relative;
        }

            #note .notification_ok {
                position: absolute;
                top: 0;
                margin-top: 20px;
                padding: 7px 10px;
                text-align: center;
                text-transform: uppercase;
                background: #444;
                font-family: 'Lato', sans-serif;
                font-weight: 400;
                font-size: 14px;
                color: #fff;
            }

            #note .notification_error {
                position: absolute;
                top: 115px;
                font-family: 'Lato', sans-serif;
                font-weight: 400;
                font-size: 16px;
                color: #f00;
            }

Script AJAX

$("#ajaxSendmail").submit(function () {

            $(this).children().each(function () {
                $(this).css("border", "");
            });
            $('#note').html("");

            if ($("input[name='name']").val() === "" || $("input[name='email']").val() === ""
                || $("input[name='message']").val() === "") {
                $("#ajaxSendmail").children().each(function () {
                    if ($(this).val() === "") $(this).css("border", "2px solid #FF0000");
                });

                $('#note').html('<div class="notification_error">All values are required</div>');
                return false;
            }
            else {

                var str = $(this).serialize();

                $.ajax({
                    type: "POST",
                    url: "/SendMail.aspx",
                    data: str,
                    success: function (msg) {
                        // Message Sent - Show the 'Thank You' message and hide the form
                        if (msg.trim() == 'OK') {
                            result = '<div class="notification_ok">Your message has been sent. Thank you!</div>';
                            $("#fields").hide();
                        } else {

                            result = msg;
                        }
                        $('#note').html(result);
                    }
                });
                return false;
            }
        });

Para fazer o formulário funcionar, é preciso criar uma página macro (em Razor) que faça o processo de enviar o email:

Razor

@inherits umbraco.MacroEngines.DynamicNodeContext
@{
	var name = Request["name"];
	var email = Request["email"];
	var message = Request["message"];

	string host = "relay-hosting.secureserver.net",
                subject = "Contact Received from Site",
                body = "<h3>{0}</h3><p>From: {1}<br /><br /> Email: {2} </p><p>Message: {3}</p>",
                from = "mailer@zueuz.com",
                to = "email@myemail.com";
            int port = 25;

           System.Net.Mail.SmtpClient SmtpServer = new System.Net.Mail.SmtpClient(host, port);
           System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();

            mail.From = new System.Net.Mail.MailAddress(from, "Corporate Mailer");
            mail.To.Add(new System.Net.Mail.MailAddress(to, "Admin"));
            mail.Subject = subject;
            mail.Body = string.Format(body, subject, name, email, message);
            mail.IsBodyHtml = true;

	try
            {

                SmtpServer.Send(mail);
                <text>OK</text>;
            }
            catch (Exception e)
            {
                <text>@e.Message</text>;
            }

}

E também uma página sendmail
Template

Webforms do Umbraco

<%@  Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %>

       <asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">
           <umbraco:macro alias="Sendmail" runat="server"></umbraco:macro>
       </asp:Content>

Com esses componentes o formulário já envia e-mails

contact_form_success

contact_form_error