Created
April 12, 2013 03:05
-
-
Save ilumin/5369004 to your computer and use it in GitHub Desktop.
A CodePen by Tim Pietrusky. Kudos Please - A simple kudos widget without any external lib and it works with touch & mouse devices. Inspired by [dcurt.is](http://dcurt.is/).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="kudos" data-amount="0" data-url="codepen.io/TimPietrusky/pen/acBCf"></div> | |
<footer> | |
2013 by | |
<a href="http://twitter.com/TimPietrusky" target="_blank">@TimPietrusky</a> | |
</footer> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Kudos Please | |
A simple kudos widget without any external lib and it works | |
with touch & mouse devices. | |
Inspired by dcurt.is | |
The heart in this example is served by weloveiconfonts.com, | |
but you can just add a value manually (.finish:before{content:''}). | |
# 2013 by Tim Pietrusky | |
# timpietrusky.com | |
**/ | |
KudosPlease = (function() { | |
var _$; | |
// Constructor | |
function KudosPlease(args) { | |
_$ = this; | |
// All widgets | |
this.elements = document.querySelectorAll(args.el); | |
// Set the status | |
this.status = args.status; | |
// Is localStorage enabled? | |
this.persistent = (args.persistent != undefined && args.persistent && localStorage != undefined); | |
// Duration of activation | |
this.duration = args.duration; | |
// setTimeout-ID's | |
this.timer = {}; | |
// @TODO [TimPietrusky] - This should be an array | |
this.currentStatus = ''; | |
for (var i = 0; i < this.elements.length; i++) { | |
var el = this.elements[i]; | |
// Delete all elements from localStorage | |
// localStorage.setItem('kudos:saved:'+el.getAttribute('data-url'), 0); | |
// Identify element | |
el.setAttribute('data-id', i); | |
// Load kudos via ajax | |
_$.request(el, 'GET'); | |
// Amount is 0 | |
if (this.loadAmount(i) == 0) { | |
// Set kudos amount | |
el.setAttribute('data-amount', 0); | |
// Init timer id | |
this.timer[i] = -1; | |
// Events | |
if (this.isTouch()) { | |
this.on(el, 'touchstart', this.enter); | |
this.on(el, 'touchend', this.out); | |
} else { | |
this.on(el, 'mouseover', this.enter); | |
this.on(el, 'mouseout', this.out); | |
} | |
// Load the amount and display it, because user already voted | |
} else { | |
this.finish(el); | |
} | |
} | |
}; | |
/* | |
* Enter the element | |
*/ | |
KudosPlease.prototype.enter = function(e) { | |
var that = this, | |
id = -1; | |
// Do the kudo twist | |
if (!_$.hasClass(this, 'finish')) { | |
// Activate the kudo twist | |
_$.addClass(that, 'active'); | |
// Start timeout | |
id = setTimeout(function() { | |
_$.removeClass(that, 'active'); | |
_$.finish(that, true); | |
}, _$.duration); | |
// Add timeout id to global object | |
_$.timer[that.getAttribute('data-id')] = id; | |
} | |
}; | |
// Leave the element | |
KudosPlease.prototype.out = function(e) { | |
if (!_$.hasClass(this, 'finish')) { | |
_$.removeClass(this, 'active'); | |
clearTimeout(_$.timer[this.getAttribute('data-id')]); | |
} | |
}; | |
/* | |
* State: finished (kudos given) | |
*/ | |
KudosPlease.prototype.finish = function(el, increase) { | |
// Finished | |
_$.addClass(el, 'finish'); | |
_$.changeStatus(el, 'gamma'); | |
increase = increase || false; | |
amount = _$.loadAmount(parseInt(el.getAttribute('data-id'), 10)); | |
if (increase) { | |
++amount; | |
// Update kudos via ajax | |
_$.request(el, 'POST'); | |
} | |
}; | |
/* | |
* Change the status of the widget and | |
* aply 3 different classes for the icon | |
* in the middle. | |
*/ | |
KudosPlease.prototype.changeStatus = function(el, state) { | |
if (_$.status != undefined) { | |
_$.removeClass(el, _$.currentStatus); | |
_$.addClass(el, _$.status[state]); | |
_$.currentStatus = _$.status[state]; | |
} | |
}; | |
/** | |
* Helper functions | |
*/ | |
/* | |
* Bind event | |
*/ | |
KudosPlease.prototype.on = function(el, event, func) { | |
try { | |
el.addEventListener(event, func, false); | |
} catch(e) { | |
el.attachEvent('on' + event, func); | |
} | |
}; | |
/* | |
* Add <CODE>class</CODE> to <CODE>el</CODE> | |
*/ | |
KudosPlease.prototype.addClass = function(el, classes) { | |
classes = classes.split(','); | |
for (var i=0; i < classes.length; i++) { | |
if (el.className.indexOf(classes[i]) == -1) { | |
el.className = el.className.trim() + ' ' + classes[i]; | |
} | |
} | |
}; | |
/* | |
* Remove <CODE>class</CODE> to <CODE>el</CODE> | |
*/ | |
KudosPlease.prototype.removeClass = function(el, classes) { | |
classes = classes.split(','); | |
for (var i = 0; i < classes.length; i++) { | |
el.className = el.className.replace(classes[i], '').trim(); | |
} | |
}; | |
/* | |
* Returns <CODE>true</CODE> if <CODE>el</CODE> has | |
* the <CODE>class</CODE>, <CODE>false</CODE> otherwise | |
*/ | |
KudosPlease.prototype.hasClass = function(el, className) { | |
var classes = el.className.split(' '), | |
result = false; | |
for (var i = 0; i < classes.length; i++) { | |
if (classes[i] == className) { | |
result = true; | |
} | |
} | |
return result; | |
}; | |
/* | |
* Returns <CODE>true</CODE> if the actual | |
* device is a touch device, <CODE>false</CODE> otherwise | |
* | |
* http://stackoverflow.com/a/4819886/1012875 | |
*/ | |
KudosPlease.prototype.isTouch = function() { | |
return !!('ontouchstart' in window) | |
|| !!('onmsgesturechange' in window); | |
}; | |
/* | |
* Saves the amount of a specific widget into localStorage | |
* when <CODE>persistent</CODE> is <CODE>true</CODE>. | |
*/ | |
KudosPlease.prototype.save = function(el, amount) { | |
if (_$.persistent) { | |
localStorage.setItem('kudos:saved:' + el.getAttribute('data-url'), amount); | |
} | |
}; | |
/* | |
* Loads the amount of a specific widget from the localStorage | |
* when <CODE>persistent</CODE> is <CODE>true</CODE>. | |
*/ | |
KudosPlease.prototype.loadAmount = function(id) { | |
var result = _$.elements[id].getAttribute('data-amount') || 0; | |
if (_$.persistent) { | |
if ((amount = localStorage.getItem('kudos:saved:' + _$.elements[id].getAttribute('data-url'))) != null) { | |
result = amount; | |
} | |
} | |
return result; | |
}; | |
/* | |
* Create a ajax request to a backend | |
* which just keeps track of the kudos counter | |
* via php & mysql | |
*/ | |
KudosPlease.prototype.request = function(el, type) { | |
var xhr; | |
// Initialize | |
try { | |
xhr = new ActiveXObject("Microsoft.XMLHTTP"); | |
} catch(e) { | |
xhr = new XMLHttpRequest(); | |
} | |
// Change the amount | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState == 4 && xhr.status == 200) { | |
var amount = xhr.responseText; | |
el.setAttribute('data-amount', amount); | |
if (type == 'GET') { | |
_$.changeStatus(el, amount == 0 ? 'alpha' : 'beta'); | |
if (_$.persistent | |
&& localStorage.getItem('kudos:saved:' + el.getAttribute('data-url')) != null) { | |
_$.changeStatus(el, 'gamma'); | |
} | |
} | |
if (type == 'POST') { | |
_$.save(el, amount); | |
} | |
} | |
} | |
var url = "?url="+encodeURIComponent(el.getAttribute('data-url')); | |
// Open request | |
xhr.open(type, "http://api.kudosplease.com/" + url, true); | |
xhr.send(); | |
}; | |
// trim polyfill | |
''.trim || (String.prototype.trim = function(){ | |
return this.replace(/^\s+|\s+$/g,''); | |
}); | |
return KudosPlease; | |
})(); | |
/* | |
* DOM ready function | |
* http://dustindiaz.com/smallest-domready-ever | |
*/ | |
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()} | |
r(function() { | |
/* | |
* Create Kudos Please widget | |
*/ | |
var kudosPlease = new KudosPlease({ | |
el : '.kudos', | |
duration : 1500, | |
persistent : false, | |
status : { | |
alpha : 'fontawesome-star', | |
beta : 'fontawesome-glass', | |
gamma : 'fontawesome-bolt' | |
} | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import "compass"; | |
@import url(http://weloveiconfonts.com/api/?family=fontawesome); | |
/* | |
* Use FontAwesome from weloveiconfonts.com | |
*/ | |
[class*="fontawesome-"]:before { | |
font-family: 'FontAwesome', sans-serif; | |
font-weight:normal; | |
} | |
/* | |
* Default styles | |
*/ | |
body { | |
font: 1.5em sans-serif; | |
margin:.5em; | |
text-align:center; | |
} | |
footer { | |
margin:3.75em 0 0 0; | |
font-size:.65em; | |
a { | |
color:rgba(#000, .7); | |
text-decoration:none; | |
&:hover { | |
color:#000; | |
} | |
} | |
} | |
/* | |
* Kudos | |
*/ | |
$kudos_duration: 1.5s; | |
$kudos_duration_finish: .45s; | |
$kudos_width: 6em; | |
$kudos_height: 6em; | |
$kudos_color_alpha: #fff; // default | |
$kudos_color_beta: #cc3d39; // active | |
$kudos_color_gamma: #000; // default border | |
.kudos { | |
position:relative; | |
width:$kudos_width; | |
height:$kudos_height; | |
margin:0 auto; | |
background:$kudos_color_alpha; | |
box-shadow: | |
inset 0 0 0 .25em $kudos_color_gamma, | |
inset 0 0 0 $kudos_width / 3 $kudos_color_alpha, | |
inset 0 0 0 $kudos_width #000 | |
; | |
line-height:$kudos_height; | |
text-align:center; | |
border-radius:50%; | |
@include transition(box-shadow $kudos_duration_finish / 2 ease-out); | |
&:before { | |
@include transition(font-size $kudos_duration_finish ease-in); | |
font-size:1.75em; | |
color:$kudos_color_alpha; | |
line-height:$kudos_height / 1.725; | |
} | |
&.active { | |
@include transition(box-shadow $kudos_duration linear); | |
box-shadow: | |
inset 0 0 0 .25em $kudos_color_gamma, | |
inset 0 0 0 0 $kudos_color_alpha, | |
inset 0 0 0 .75em rgba($kudos_color_beta, .75), | |
inset 0 0 0 $kudos_width $kudos_color_beta | |
; | |
&:before { | |
@include transition(color $kudos_duration linear); | |
color: $kudos-color-beta; | |
} | |
&:after { | |
content: 'Don\'t move!'; | |
} | |
} | |
&.finish { | |
@include transition( | |
box-shadow $kudos_duration_finish linear, | |
transform $kudos_duration_finish * 1.25 ease-in-out | |
); | |
box-shadow: | |
inset 0 0 0 .25em rgba($kudos_color_beta, .5), | |
inset 0 0 0 .5em $kudos_color_alpha, | |
inset 0 0 0 .75em rgba($kudos_color_beta, .75), | |
inset 0 0 0 1em $kudos_color_alpha, | |
inset 0 0 0 0 $kudos_color_alpha, | |
inset 0 0 0 $kudos_width $kudos_color_beta | |
; | |
&:before { | |
font-size:2.25em; | |
color:$kudos_color_alpha; | |
line-height:$kudos_height / 2.125; | |
} | |
} | |
&:after { | |
position:absolute; | |
content: attr(data-amount) ' Kudos'; | |
bottom:-1.25em; | |
left:0; | |
width:$kudos_width; | |
text-align:center; | |
line-height:1em; | |
font-variant:small-caps; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment