Last active
December 9, 2015 17:01
-
-
Save asacarter/d995834c27bf354738af to your computer and use it in GitHub Desktop.
Recently jQuery Plugin
This file contains 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
// timer function that loops through an array within a given interval | |
$.timer = function (list, callback, time/*, onFinish, index*/) { | |
var onFinish = arguments.length > 3 ? arguments[3] : void 0, | |
index = arguments.length > 4 ? arguments[4] : 0; | |
if (index < list.length) { | |
callback.call(this, index, list[index]); | |
list.__timed = setTimeout(function() { | |
$.timer(list, callback, time, onFinish, ++index); | |
}, time); | |
} | |
else if (onFinish) { | |
onFinish.call(this); | |
} | |
return { | |
cancel: function() { | |
if (list.__timed !== void 0) { | |
clearTimeout(list.__timed); | |
delete list.__timed; | |
} | |
}, | |
pause: function() { | |
clearTimeout(list.__timed); | |
}, | |
resume: function() { | |
list.__timed = setTimeout(function() { | |
$.timer(list, callback, time, onFinish, ++index); | |
}, time); | |
} | |
}; | |
}; | |
// template function that replaces strings from map | |
$.tmpl = function(str, obj) { | |
do { | |
var beforeReplace = str; | |
str = str.replace(/{{([^}]+)}}/g, function(wholeMatch, key) { | |
var substitution = obj[$.trim(key)]; | |
return (substitution === undefined ? wholeMatch : substitution); | |
}); | |
var afterReplace = str !== beforeReplace; | |
} while (afterReplace); | |
return str; | |
}; | |
/** | |
* jQuery.browser.mobile (http://detectmobilebrowser.com/) | |
* | |
* jQuery.browser.mobile will be true if the browser is a mobile device | |
* | |
**/ | |
(function(a){(jQuery.browser=jQuery.browser||{}).mobile=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))})(navigator.userAgent||navigator.vendor||window.opera); | |
/* | |
* recentlyApp | |
* | |
* TODO: | |
* disable specific pages | |
* log requests | |
* CSS animations where available | |
* | |
*/ | |
;(function($, window, document, undefined) { | |
var recently = function(options) { | |
var recentlyApp = this, | |
version = 1.00, | |
defaults = { | |
shop: 'order-test-store.myshopify.com', // Shopify.shop, | |
element: '#recently-notification', | |
active: true, | |
mobileActive: true, | |
loop: false, | |
pause: true, | |
close: true, | |
orderLimit: 0, | |
orderTimeLimit: 0, | |
interval: 3000, | |
delay: 4000, | |
placement: 'bottom-left', | |
direction: 'veritical', | |
image: 'left', | |
size: 'large', | |
animationDuration: 1200, | |
message: '{{first_name}} in {{city}}, {{country}} purchased a <a href="{{product_url}}">{{{product}}}</a>{{purchased}}' | |
}, | |
settings = $.extend(defaults, options || {}); | |
this.init = function() { | |
recentlyApp.isMobile = $.browser.mobile; | |
// check if active | |
if (settings.active == false) return; | |
// check if mobile and mobile active | |
if (recentlyApp.isMobile == true && settings.mobileActive == false) return; | |
var shopHash = recentlyApp.sha1(settings.shop), | |
v = Math.floor(Math.random() * (10000 - 1)) + 1; | |
// add the style sheet to header | |
$('<link type="text/css" rel="stylesheet" href="//recently.appifiny.co.uk/store/' + shopHash + '.css?v=' + v + '">').appendTo('head'); | |
// add the notification container to body | |
$('<div id="' + settings.element.replace('#', '') + '"/>') | |
.addClass(settings.placement) | |
.addClass(settings.direction) | |
.addClass(settings.image) | |
.addClass(settings.size) | |
.appendTo('body'); | |
if (recentlyApp.isMobile == true) { | |
$(settings.element).addClass('mobile'); | |
} | |
// get the recent orders | |
var recentOrders = $.getJSON('//recently.appifiny.co.uk/store/' + shopHash + '.json'); | |
recentOrders.done(function(orders) { | |
if (settings.orderLimit > 0) { | |
var orders = orders.filter(function (el) { | |
now = new Date(); | |
ts = new Date(el.created * 1000); | |
var delta = now.getTime() - ts.getTime(); | |
delta = Math.floor(delta / 1000); | |
return delta <= settings.orderLimit; | |
}); | |
} | |
recentlyApp.orders = orders; | |
// get start index | |
var index = localStorage.getItem('recently-index'); | |
if (index === null) { | |
recentlyApp.startIndex = 0; | |
} else { | |
nextIndex = parseInt(index) + 1; | |
if (nextIndex >= recentlyApp.orders.length) { | |
recentlyApp.startIndex = 0; | |
} else { | |
recentlyApp.startIndex = nextIndex; | |
} | |
} | |
// check style is loaded | |
setTimeout(function() { | |
if ($(settings.element).css('position') == 'fixed') { | |
recentlyApp.start(); | |
} | |
}, 100); | |
}); | |
}; | |
this.start = function() { | |
if (recentlyApp.orders.length) { | |
recentlyApp.timer = $.timer(recentlyApp.orders, function(index, order) { | |
localStorage.setItem('recently-index', index); | |
console.log(index); | |
recentlyApp.displayNotification(order); | |
}, | |
settings.interval + settings.delay + (settings.animationDuration * 2), | |
settings.loop ? recentlyApp.start : void 0, | |
recentlyApp.startIndex); | |
} | |
}; | |
this.stop = function() { | |
recentlyApp.timer.cancel(); | |
}; | |
this.pause = function() { | |
clearTimeout(recentlyApp.currentNotification); | |
recentlyApp.timer.pause(); | |
}; | |
this.resume = function() { | |
recentlyApp.currentNotification = setTimeout(function() { | |
settings.direction == 'horizontal' ? recentlyApp.hideHorizontal() : recentlyApp.hideVertical(); | |
}, settings.delay); | |
recentlyApp.timer.resume(); | |
}; | |
this.displayNotification = function(order) { | |
var messageData = { | |
first_name: order.customer_first_name, | |
city: order.city, | |
state: order.province, | |
country: order.country, | |
product: order.product_title, | |
url: '//' + settings.shop + '/products/' + order.url, | |
purchased: recentlyApp.timeSince(order.created) | |
}; | |
var message = $.tmpl(settings.message, messageData); | |
// add the data to the element | |
var tpl = '<div class="ra-img"><a href="//' + settings.shop + '/products/' + order.url + '"'; | |
if (order.image) { | |
tpl += ' style="background-image: url(' + order.image + ');"'; | |
} | |
tpl += '></a></div>'; | |
tpl += '<div class="ra-content"><div class="ra-message">' + message + '</div>'; | |
now = new Date(); | |
ts = new Date(order.created * 1000); | |
var delta = now.getTime() - ts.getTime(); | |
delta = Math.floor(delta / 1000); | |
if (settings.orderTimeLimit == 0 || delta <= settings.orderTimeLimit) { | |
tpl += '<div class="ra-time">About ' + messageData.purchased + ' ago</div>'; | |
} | |
if (settings.close == true) { | |
tpl += '<div class="ra-close"></div>'; | |
} | |
tpl += '</div>'; | |
$(settings.element).html(tpl); | |
this.show(); | |
settings.direction == 'horizontal' ? recentlyApp.hideHorizontal() : recentlyApp.hideVertical(); | |
}; | |
this.show = function() { | |
if (recentlyApp.isMobile == true) { | |
placement = { bottom: '0px' } | |
} else { | |
switch (settings.placement) { | |
case 'top-right': | |
placement = { right: '20px', top: '20px' } | |
break; | |
case 'top-left': | |
placement = { left: '20px', top: '20px' } | |
break; | |
case 'bottom-right': | |
placement = { right: '20px', bottom: '20px' } | |
break; | |
case 'bottom-left': | |
default: | |
placement = { left: '20px', bottom: '20px' } | |
break; | |
} | |
} | |
$(settings.element).animate(placement, settings.animationDuration, 'linear').delay(settings.delay); | |
}; | |
this.hideVertical = function() { | |
if (recentlyApp.isMobile == true) { | |
placement = { bottom: '-100%' } | |
} else { | |
switch (settings.placement) { | |
case 'top-right': | |
placement = { right: '20px', top: '-100%' } | |
break; | |
case 'top-left': | |
placement = { left: '20px', top: '-100%' } | |
break; | |
case 'bottom-right': | |
placement = { right: '20px', bottom: '-100%' } | |
break; | |
case 'bottom-left': | |
default: | |
placement = { left: '20px', bottom: '-100%' } | |
break; | |
} | |
} | |
$(settings.element).animate(placement, settings.animationDuration, 'linear').delay(settings.interval); | |
}; | |
this.hideHorizontal = function() { | |
if (recentlyApp.isMobile == true) { | |
placement = { bottom: '-100%' } | |
} else { | |
switch (settings.placement) { | |
case 'top-right': | |
placement = { right: '-100%', top: '20px' } | |
break; | |
case 'top-left': | |
placement = { left: '-100%', top: '20px' } | |
break; | |
case 'bottom-right': | |
placement = { right: '-100%', bottom: '20px' } | |
break; | |
case 'bottom-left': | |
default: | |
placement = { left: '-100%', bottom: '20px' } | |
break; | |
} | |
} | |
$(settings.element).animate(placement, settings.animationDuration, 'linear').delay(settings.interval); | |
}; | |
this.timeSince = function(ts) { | |
now = new Date(); | |
ts = new Date(ts * 1000); | |
var ps, pm, ph, pd, min, hou, sec, days, | |
delta = now.getTime() - ts.getTime(); | |
delta = Math.floor(delta / 1000); | |
if (delta <= 59) { | |
ps = (delta > 1) ? 's': ''; | |
return 'a minute'; | |
} | |
if (delta >= 60 && delta <= 3599) { | |
min = Math.floor(delta / 60); | |
pm = (min > 1) ? 's': ''; | |
return min + ' minute' + pm; | |
} | |
if (delta >= 3600 && delta <= 86399) { | |
hours = Math.floor(delta / 3600); | |
min = Math.floor((delta - (hours * 3600)) / 60); | |
ph = (hours > 1) ? 's' : ''; | |
pm = (min > 1) ? 's' : ''; | |
time = hours + ' hour' + ph; | |
if (min > 0) { | |
time += ' ' + min + ' minute' + pm; | |
} | |
return time; | |
} | |
if (delta >= 86400 && delta <= 604799) { | |
days = Math.floor(delta / 86400); | |
hours = Math.floor((delta - (days * 86400)) / 60 / 60); | |
pd = (days > 1) ? 's' : ''; | |
ph = (hours > 1) ? 's' : ''; | |
time = days + ' day' + pd; | |
if (hours > 0) { | |
time += ' ' + hours + ' hour' + ph; | |
} | |
return time; | |
} | |
if (delta >= 604800) { | |
weeks = Math.floor(delta / 604800); | |
days = Math.floor((delta - (weeks * 604800)) / 60 / 60 / 60); | |
pw = (weeks > 1) ? 's' : ''; | |
pd = (days > 1) ? 's' : ''; | |
time = weeks + ' week' + pw; | |
if (days > 0) { | |
time += ' ' + days + ' day' + pd; | |
} | |
return time; | |
} | |
}; | |
this.sha1 = function(str) { | |
var rotate_left = function(n, s) { | |
var t4 = (n << s) | (n >>> (32 - s)); | |
return t4; | |
}; | |
var cvt_hex = function(val) { | |
var str = ''; | |
var i; | |
var v; | |
for (i = 7; i >= 0; i--) { | |
v = (val >>> (i * 4)) & 0x0f; | |
str += v.toString(16); | |
} | |
return str; | |
}; | |
var blockstart; | |
var i, j; | |
var W = new Array(80); | |
var H0 = 0x67452301; | |
var H1 = 0xEFCDAB89; | |
var H2 = 0x98BADCFE; | |
var H3 = 0x10325476; | |
var H4 = 0xC3D2E1F0; | |
var A, B, C, D, E; | |
var temp; | |
str = unescape(encodeURIComponent(str)); | |
var str_len = str.length; | |
var word_array = []; | |
for (i = 0; i < str_len - 3; i += 4) { | |
j = str.charCodeAt(i) << 24 | str.charCodeAt(i + 1) << 16 | str.charCodeAt(i + 2) << 8 | str.charCodeAt(i + 3); | |
word_array.push(j); | |
} | |
switch (str_len % 4) { | |
case 0: | |
i = 0x080000000; | |
break; | |
case 1: | |
i = str.charCodeAt(str_len - 1) << 24 | 0x0800000; | |
break; | |
case 2: | |
i = str.charCodeAt(str_len - 2) << 24 | str.charCodeAt(str_len - 1) << 16 | 0x08000; | |
break; | |
case 3: | |
i = str.charCodeAt(str_len - 3) << 24 | str.charCodeAt(str_len - 2) << 16 | str.charCodeAt(str_len - 1) << | |
8 | 0x80; | |
break; | |
} | |
word_array.push(i); | |
while ((word_array.length % 16) != 14) { | |
word_array.push(0); | |
} | |
word_array.push(str_len >>> 29); | |
word_array.push((str_len << 3) & 0x0ffffffff); | |
for (blockstart = 0; blockstart < word_array.length; blockstart += 16) { | |
for (i = 0; i < 16; i++) { | |
W[i] = word_array[blockstart + i]; | |
} | |
for (i = 16; i <= 79; i++) { | |
W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); | |
} | |
A = H0; | |
B = H1; | |
C = H2; | |
D = H3; | |
E = H4; | |
for (i = 0; i <= 19; i++) { | |
temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff; | |
E = D; | |
D = C; | |
C = rotate_left(B, 30); | |
B = A; | |
A = temp; | |
} | |
for (i = 20; i <= 39; i++) { | |
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff; | |
E = D; | |
D = C; | |
C = rotate_left(B, 30); | |
B = A; | |
A = temp; | |
} | |
for (i = 40; i <= 59; i++) { | |
temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff; | |
E = D; | |
D = C; | |
C = rotate_left(B, 30); | |
B = A; | |
A = temp; | |
} | |
for (i = 60; i <= 79; i++) { | |
temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff; | |
E = D; | |
D = C; | |
C = rotate_left(B, 30); | |
B = A; | |
A = temp; | |
} | |
H0 = (H0 + A) & 0x0ffffffff; | |
H1 = (H1 + B) & 0x0ffffffff; | |
H2 = (H2 + C) & 0x0ffffffff; | |
H3 = (H3 + D) & 0x0ffffffff; | |
H4 = (H4 + E) & 0x0ffffffff; | |
} | |
temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4); | |
return temp.toLowerCase(); | |
}; | |
$('body').on('click', settings.element + ' .ra-close', function() { | |
$(settings.element).remove(); | |
recentlyApp.stop(); | |
}); | |
$('body').on('mouseover', settings.element, function() { | |
if (settings.pause == true) { | |
recentlyApp.pause(); | |
} | |
}); | |
$('body').on('mouseout', settings.element, function() { | |
recentlyApp.resume(); | |
}); | |
this.init(); | |
}; | |
$.recentlyApp = function( options ) { | |
return recently(options); | |
}; | |
})(jQuery, window, document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment