Skip to content

Instantly share code, notes, and snippets.

@amcdnl
Created December 5, 2012 20:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save amcdnl/4219301 to your computer and use it in GitHub Desktop.
Save amcdnl/4219301 to your computer and use it in GitHub Desktop.
CanJS Notification System

CanJS Notification System

This widget creates a growl-like notification on a website using CanJS framework.

JavaScript

steal('can/construct',
	  'can/construct/super',
	  'can/construct/proxy',
	  'can/control',
	  'can/view/ejs',
	  './growl.less',
	  './views/growl.ejs', 
function(){

/**
 * `can.ui.notify` is a system for creating notifications.
 */
can.Construct("can.ui.notify", {
	defaults:{
		time: 1500,
		position: "bottom right",
		animate: 'fade',
		sticky: true,
		template: '//canui/growl/views/growl.ejs',
		dismissable: false,
		dismissText: "Dismiss"
	},

	queue: [],

	counter: 0,

	init:function(options){
		this.defaults = can.extend(this.defaults, options || {});

		this.wrapper = $('<div class="notification-wrapper ' + 
			this.defaults.position.split(' ').join('-') + '" />').appendTo(document.body);
	},

	/**
	 * Adds a notification to the screen.
	 *
	 * For example:
	 * 		{
	 * 			title: "Tip",
	 * 			image: "",
	 * 			text: "Click and hold for a moment to pan."
	 * 		}
	 *
	 *	Additionally, you can pass any arguments that are
	 *	included in the defaults to override a particular 
	 *	action.
	 * 
	 * @param {[type]} note
	 */
	add: function(note){
		this.queue.push(new mj.notify.Bubble(this.wrapper, 
			can.extend(this.defaults, note || {}, { id: this.counter++ })));
	},

	/**
	 * Dismisses a single notification by `id`.
	 * @param  {Number} id
	 */
	dismiss:function(id){
		$.each(this.queue, function(bubble, i){
			if(bubble.id === id){
				bubble.dismiss();
			}
		});
	},

	/**
	 * Dismisses all notifications.
	 */
	dismissAll:function(){
		$.each(this.queue, function(bubble, i){
			bubble.dismiss();
		});
	}

},{});

/**
 * Bubbles are the notifications themselves.
 */
can.Control('can.notify.Bubble',{
	setup:function(el,options){
		this.id = options.id;
		this._super($(can.view.render(options.template, options))
			.appendTo(el), options);
	},

	init:function(){
		this.element[this.options.animate + "In"]();
		this.startTimer();	
	},

	startTimer:function(){
		if(!this.options.sticky){
			this.timer = setTimeout(this.proxy('dismiss'), this.options.time);
		}
	},

	dismiss:function(){
		this.element[this.options.animate + "Out"]();
	},

	" click": "dismiss",

	" mouseenter":function(elm,ev){
		clearTimeout(this.timer);
	},

	" mouseleave": "startTimer",

	".dismiss click": "dismiss"
});

});

LESS

.notification-wrapper{
	position:fixed;
	z-index:9999;

	&.top-right{
		top:20px;
		right:20px;
	}
	&.top-left {
	    left: 20px;
	    right: auto;
	}
	&.bottom-right {
	    top: auto;
	    left: auto;
	    bottom: 20px;
	    right: 20px;
	}
	&.bottom-left {
	    top: auto;
	    right: auto;
	    bottom: 20px;
	    left: 20px;
	}
}

.notification{
	color: #eee;
	padding:8px 11px;
	background:#000;
	cursor:pointer;
	display:none;

	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	border-radius: 5px;

	opacity: 0.7;
	filter: alpha(opacity=70);

	&:hover{
		opacity: 1;
		filter: alpha(opacity=100);
	}

	.image{
		float:left;
	}

	h2{
		margin:0;
		font-size: 14px;
		font-weight: bold;
		padding: 0 0 5px 0;
		display: block;
		text-shadow: 1px 1px 0 #000;
	}

	p{
		padding:0;
		margin:0;
		font-size: 11px;
	}

	.dismiss{
		padding-top:5px;
		color:#FFF;
		text-decoration: none;
		font-size:10px;
	}

}

EJS

<div class="notification">
	<% if(this.image){ %>
		<img class="image" src="<%== this.image %>" />
	<% } %>

	<% if(this.header){ %>
		<h2><%== this.header %></h2>
	<% } %>

	<% if(this.text){ %>
		<p><%== this.text %></p>
	<% } %>

	<% if(this.dismissable) { %>
		<a class="dismiss" href="#"><%== this.dismissText %></a>
	<% } %>
</div>

HTML

<script type='text/javascript'>
	steal('can/ui/growl').then(function($, Control){
		can.ui.notify.add({
			header: "Amazing things",
			text: "Click and hold down your mouse for a moment to pan."
		});
			
	})
</script>
@justinbmeyer
Copy link

You don't need the space in can.Control for any standard DOM events, and for when you have the event handler name followed by a string. So, the space in " click" and " mouseleave" is doubly incorrect. In " mouseenter" it is only singularly unnecessary.

 " click": "dismiss",

    " mouseenter":function(elm,ev){
        clearTimeout(this.timer);
    },

    " mouseleave": "startTimer",

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