From d26dc1cef1d7b4dc1d22abfcebeeb46a6b1c0a15 Mon Sep 17 00:00:00 2001 From: Jonathan Rosenbaum Date: Wed, 27 Jan 2016 10:36:27 +0000 Subject: [PATCH] Adds a Calendar Date Picker (PickMeUp). This is nice stuff, always a delight to utilize ajax. More stat pages may have this change with stats.js operated globally. --- css/pickmeup.css | 86 +++ include_header_stats.html | 4 +- js/jquery.pickmeup.js | 1141 +++++++++++++++++++++++++++++++++++++ stats/status_totals.php | 85 ++- 4 files changed, 1291 insertions(+), 25 deletions(-) create mode 100644 css/pickmeup.css create mode 100644 js/jquery.pickmeup.js diff --git a/css/pickmeup.css b/css/pickmeup.css new file mode 100644 index 0000000..12a440d --- /dev/null +++ b/css/pickmeup.css @@ -0,0 +1,86 @@ +/** + * @package PickMeUp - jQuery datepicker plugin + * @author Nazar Mokrynskyi + * @author Stefan Petre + * @copyright Copyright (c) 2013-2015, Nazar Mokrynskyi + * @copyright Copyright (c) 2008-2009, Stefan Petre + * @license MIT License, see license.txt + */ +.pickmeup { + background: #000; + border-radius: 0.4em; + -moz-box-sizing: content-box; + box-sizing: content-box; + display: none; + position: absolute; } + .pickmeup * { + -moz-box-sizing: border-box; + box-sizing: border-box; } + .pickmeup .pmu-instance { + display: inline-block; + height: 13.8em; + padding: .5em; + text-align: center; + width: 15em; } + .pickmeup .pmu-instance .pmu-button { + color: #eee; + cursor: pointer; + outline: none; + text-decoration: none; } + .pickmeup .pmu-instance .pmu-today { + background: #17384d; + color: #88c5eb; } + .pickmeup .pmu-instance .pmu-button:hover { + background: "transparent"; + color: #88c5eb; } + .pickmeup .pmu-instance .pmu-not-in-month { + color: #666; } + .pickmeup .pmu-instance .pmu-disabled, + .pickmeup .pmu-instance .pmu-disabled:hover { + color: #333; + cursor: default; } + .pickmeup .pmu-instance .pmu-selected { + background: #136a9f; + color: #eee; } + .pickmeup .pmu-instance .pmu-not-in-month.pmu-selected { + background: #17384d; } + .pickmeup .pmu-instance nav { + color: #eee; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + line-height: 2em; } + .pickmeup .pmu-instance nav *:first-child :hover { + color: #88c5eb; } + .pickmeup .pmu-instance nav .pmu-prev, + .pickmeup .pmu-instance nav .pmu-next { + display: none; + height: 2em; + width: 1em; } + .pickmeup .pmu-instance nav .pmu-month { + width: 14em; } + .pickmeup .pmu-instance .pmu-years *, + .pickmeup .pmu-instance .pmu-months * { + display: inline-block; + line-height: 3.6em; + width: 3.5em; } + .pickmeup .pmu-instance .pmu-day-of-week { + color: #999; + cursor: default; } + .pickmeup .pmu-instance .pmu-day-of-week *, + .pickmeup .pmu-instance .pmu-days * { + display: inline-block; + line-height: 1.5em; + width: 2em; } + .pickmeup .pmu-instance .pmu-day-of-week * { + line-height: 1.8em; } + .pickmeup .pmu-instance:first-child .pmu-prev, + .pickmeup .pmu-instance:last-child .pmu-next { + display: block; } + .pickmeup .pmu-instance:first-child .pmu-month, + .pickmeup .pmu-instance:last-child .pmu-month { + width: 13em; } + .pickmeup .pmu-instance:first-child:last-child .pmu-month { + width: 12em; } + .pickmeup:not(.pmu-view-days) .pmu-days, .pickmeup:not(.pmu-view-days) .pmu-day-of-week, .pickmeup:not(.pmu-view-months) .pmu-months, .pickmeup:not(.pmu-view-years) .pmu-years { + display: none; } diff --git a/include_header_stats.html b/include_header_stats.html index 9756387..fd51c10 100644 --- a/include_header_stats.html +++ b/include_header_stats.html @@ -24,9 +24,11 @@ function resetTimer() + - + + diff --git a/js/jquery.pickmeup.js b/js/jquery.pickmeup.js new file mode 100644 index 0000000..951f841 --- /dev/null +++ b/js/jquery.pickmeup.js @@ -0,0 +1,1141 @@ +/** + * @package PickMeUp - jQuery datepicker plugin + * @author Nazar Mokrynskyi + * @author Stefan Petre + * @copyright Copyright (c) 2013-2015, Nazar Mokrynskyi + * @copyright Copyright (c) 2008-2009, Stefan Petre + * @license MIT License, see license.txt + */ + +(function (d) { + function getMaxDays () { + var tmpDate = new Date(this.toString()), + d = 28, + m = tmpDate.getMonth(); + while (tmpDate.getMonth() == m) { + ++d; + tmpDate.setDate(d); + } + return d - 1; + } + d.addDays = function (n) { + this.setDate(this.getDate() + n); + }; + d.addMonths = function (n) { + var day = this.getDate(); + this.setDate(1); + this.setMonth(this.getMonth() + n); + this.setDate(Math.min(day, getMaxDays.apply(this))); + }; + d.addYears = function (n) { + var day = this.getDate(); + this.setDate(1); + this.setFullYear(this.getFullYear() + n); + this.setDate(Math.min(day, getMaxDays.apply(this))); + }; + d.getDayOfYear = function() { + var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / 24*60*60*1000); + }; +})(Date.prototype); + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + var instances_count = 0; + $.pickmeup = $.extend($.pickmeup || {}, { + date : new Date, + default_date : new Date, + flat : false, + first_day : 1, + prev : '◀', + next : '▶', + mode : 'single', + select_year : true, + select_month : true, + select_day : true, + view : 'days', + calendars : 1, + format : 'd-m-Y', + position : 'bottom', + trigger_event : 'click touchstart', + class_name : '', + separator : ' - ', + hide_on_select : false, + min : null, + max : null, + render : function () {}, + change : function () {return true;}, + before_show : function () {return true;}, + show : function () {return true;}, + hide : function () {return true;}, + fill : function () {return true;}, + locale : { + days : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], + daysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + daysMin : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'], + months : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + } + }); + var views = { + years : 'pmu-view-years', + months : 'pmu-view-months', + days : 'pmu-view-days' + }, + tpl = { + wrapper : '
', + head : function (d) { + var result = ''; + for (var i = 0; i < 7; ++i) { + result += '
' + d.day[i] + '
' + } + return '
' + + '' + + '' + + '
'; + }, + body : function (elements, container_class_name) { + var result = ''; + for (var i = 0; i < elements.length; ++i) { + result += '
' + elements[i].text + '
' + } + return '
' + result + '
'; + } + }; + function fill () { + var options = $(this).data('pickmeup-options'), + pickmeup = this.pickmeup, + current_cal = Math.floor(options.calendars / 2), + actual_date = options.date, + current_date = options.current, + min_date = options.min ? new Date(options.min) : null, + max_date = options.max ? new Date(options.max) : null, + local_date, + header, + html, + instance, + today = (new Date).setHours(0,0,0,0).valueOf(), + shown_date_from, + shown_date_to, + tmp_date; + if (min_date) { + min_date.setDate(1); + min_date.addMonths(1); + min_date.addDays(-1); + } + if (max_date) { + max_date.setDate(1); + max_date.addMonths(1); + max_date.addDays(-1); + } + /** + * Remove old content except header navigation + */ + pickmeup.find('.pmu-instance > :not(nav)').remove(); + /** + * If several calendars should be shown + */ + for (var i = 0; i < options.calendars; i++) { + local_date = new Date(current_date); + instance = pickmeup.find('.pmu-instance').eq(i); + if (pickmeup.hasClass('pmu-view-years')) { + local_date.addYears((i - current_cal) * 12); + header = (local_date.getFullYear() - 6) + ' - ' + (local_date.getFullYear()+5); + } else if (pickmeup.hasClass('pmu-view-months')) { + local_date.addYears(i - current_cal); + header = local_date.getFullYear(); + } else if (pickmeup.hasClass('pmu-view-days')) { + local_date.addMonths(i - current_cal); + header = formatDate(local_date, 'B, Y', options.locale); + } + if (!shown_date_to) { + if (max_date) { + // If all dates in this month (months in year or years in years block) are after max option - set next month as current + // in order not to show calendar with all disabled dates + tmp_date = new Date(local_date); + if (options.select_day) { + tmp_date.addMonths(options.calendars - 1); + } else if (options.select_month) { + tmp_date.addYears(options.calendars - 1); + } else { + tmp_date.addYears((options.calendars - 1) * 12); + } + if (tmp_date > max_date) { + --i; + current_date.addMonths(-1); + shown_date_to = undefined; + continue; + } + } + } + shown_date_to = new Date(local_date); + if (!shown_date_from) { + shown_date_from = new Date(local_date); + // If all dates in this month are before min option - set next month as current in order not to show calendar with all disabled dates + shown_date_from.setDate(1); + shown_date_from.addMonths(1); + shown_date_from.addDays(-1); + if (min_date && min_date > shown_date_from) { + --i; + current_date.addMonths(1); + shown_date_from = undefined; + continue; + } + } + instance + .find('.pmu-month') + .text(header); + html = ''; + var is_year_selected = function (year) { + return ( + options.mode == 'range' && + year >= new Date(actual_date[0]).getFullYear() && + year <= new Date(actual_date[1]).getFullYear() + ) || + ( + options.mode == 'multiple' && + actual_date.reduce(function (prev, current) { + prev.push(new Date(current).getFullYear()); + return prev; + }, []).indexOf(year) !== -1 + ) || + new Date(actual_date).getFullYear() == year; + }; + var is_months_selected = function (year, month) { + var first_year = new Date(actual_date[0]).getFullYear(), + lastyear = new Date(actual_date[1]).getFullYear(), + first_month = new Date(actual_date[0]).getMonth(), + last_month = new Date(actual_date[1]).getMonth(); + return ( + options.mode == 'range' && + year > first_year && + year < lastyear + ) || + ( + options.mode == 'range' && + year == first_year && + year < lastyear && + month >= first_month + ) || + ( + options.mode == 'range' && + year > first_year && + year == lastyear && + month <= last_month + ) || + ( + options.mode == 'range' && + year == first_year && + year == lastyear && + month >= first_month && + month <= last_month + ) || + ( + options.mode == 'multiple' && + actual_date.reduce(function (prev, current) { + current = new Date(current); + prev.push(current.getFullYear() + '-' + current.getMonth()); + return prev; + }, []).indexOf(year + '-' + month) !== -1 + ) || + ( + new Date(actual_date).getFullYear() == year && + new Date(actual_date).getMonth() == month + ) + }; + (function () { + var years = [], + start_from_year = local_date.getFullYear() - 6, + min_year = new Date(options.min).getFullYear(), + max_year = new Date(options.max).getFullYear(), + year; + for (var j = 0; j < 12; ++j) { + year = { + text : start_from_year + j, + class_name : [] + }; + if ( + ( + options.min && year.text < min_year + ) || + ( + options.max && year.text > max_year + ) + ) { + year.class_name.push('pmu-disabled'); + } else if (is_year_selected(year.text)) { + year.class_name.push('pmu-selected'); + } + year.class_name = year.class_name.join(' '); + years.push(year); + } + html += tpl.body(years, 'pmu-years'); + })(); + (function () { + var months = [], + current_year = local_date.getFullYear(), + min_year = new Date(options.min).getFullYear(), + min_month = new Date(options.min).getMonth(), + max_year = new Date(options.max).getFullYear(), + max_month = new Date(options.max).getMonth(), + month; + for (var j = 0; j < 12; ++j) { + month = { + text : options.locale.monthsShort[j], + class_name : [] + }; + if ( + ( + options.min && + ( + current_year < min_year || + ( + j < min_month && current_year == min_year + ) + ) + ) || + ( + options.max && + ( + current_year > max_year || + ( + j > max_month && current_year >= max_year + ) + ) + ) + ) { + month.class_name.push('pmu-disabled'); + } else if (is_months_selected(current_year, j)) { + month.class_name.push('pmu-selected'); + } + month.class_name = month.class_name.join(' '); + months.push(month); + } + html += tpl.body(months, 'pmu-months'); + })(); + (function () { + var days = [], + current_month = local_date.getMonth(), + day; + // Correct first day in calendar taking into account first day of week (Sunday or Monday) + (function () { + local_date.setDate(1); + var day = (local_date.getDay() - options.first_day) % 7; + local_date.addDays(-(day + (day < 0 ? 7 : 0))); + })(); + for (var j = 0; j < 42; ++j) { + day = { + text : local_date.getDate(), + class_name : [] + }; + if (current_month != local_date.getMonth()) { + day.class_name.push('pmu-not-in-month'); + } + if (local_date.getDay() == 0) { + day.class_name.push('pmu-sunday'); + } else if (local_date.getDay() == 6) { + day.class_name.push('pmu-saturday'); + } + var from_user = options.render(new Date(local_date)) || {}, + val = local_date.valueOf(), + disabled = (options.min && options.min > local_date) || (options.max && options.max < local_date); + if (from_user.disabled || disabled) { + day.class_name.push('pmu-disabled'); + } else if ( + from_user.selected || + options.date == val || + $.inArray(val, options.date) !== -1 || + ( + options.mode == 'range' && val >= options.date[0] && val <= options.date[1] + ) + ) { + day.class_name.push('pmu-selected'); + } + if (val == today) { + day.class_name.push('pmu-today'); + } + if (from_user.class_name) { + day.class_name.push(from_user.class_name); + } + day.class_name = day.class_name.join(' '); + days.push(day); + // Move to next day + local_date.addDays(1); + } + html += tpl.body(days, 'pmu-days'); + })(); + instance.append(html); + } + shown_date_from.setDate(1); + shown_date_to.setDate(1); + shown_date_to.addMonths(1); + shown_date_to.addDays(-1); + pickmeup.find('.pmu-prev').css( + 'visibility', + options.min && options.min >= shown_date_from ? 'hidden' : 'visible' + ); + pickmeup.find('.pmu-next').css( + 'visibility', + options.max && options.max <= shown_date_to ? 'hidden' : 'visible' + ); + options.fill.apply(this); + } + function parseDate (date, format, separator, locale) { + if (date.constructor == Date) { + return date; + } else if (!date) { + return new Date; + } + var splitted_date = date.split(separator); + if (splitted_date.length > 1) { + splitted_date.forEach(function (element, index, array) { + array[index] = parseDate($.trim(element), format, separator, locale); + }); + return splitted_date; + } + var months_text = locale.monthsShort.join(')(') + ')(' + locale.months.join(')('), + separator = new RegExp('[^0-9a-zA-Z(' + months_text + ')]+'), + parts = date.split(separator), + against = format.split(separator), + d, + m, + y, + h, + min, + now = new Date(); + for (var i = 0; i < parts.length; i++) { + switch (against[i]) { + case 'b': + m = locale.monthsShort.indexOf(parts[i]); + break; + case 'B': + m = locale.months.indexOf(parts[i]); + break; + case 'd': + case 'e': + d = parseInt(parts[i],10); + break; + case 'm': + m = parseInt(parts[i], 10)-1; + break; + case 'Y': + case 'y': + y = parseInt(parts[i], 10); + y += y > 100 ? 0 : (y < 29 ? 2000 : 1900); + break; + case 'H': + case 'I': + case 'k': + case 'l': + h = parseInt(parts[i], 10); + break; + case 'P': + case 'p': + if (/pm/i.test(parts[i]) && h < 12) { + h += 12; + } else if (/am/i.test(parts[i]) && h >= 12) { + h -= 12; + } + break; + case 'M': + min = parseInt(parts[i], 10); + break; + } + } + var parsed_date = new Date( + y === undefined ? now.getFullYear() : y, + m === undefined ? now.getMonth() : m, + d === undefined ? now.getDate() : d, + h === undefined ? now.getHours() : h, + min === undefined ? now.getMinutes() : min, + 0 + ); + if (isNaN(parsed_date * 1)) { + parsed_date = new Date; + } + return parsed_date; + } + function formatDate (date, format, locale) { + var m = date.getMonth(); + var d = date.getDate(); + var y = date.getFullYear(); + var w = date.getDay(); + var s = {}; + var hr = date.getHours(); + var pm = (hr >= 12); + var ir = (pm) ? (hr - 12) : hr; + var dy = date.getDayOfYear(); + if (ir == 0) { + ir = 12; + } + var min = date.getMinutes(); + var sec = date.getSeconds(); + var parts = format.split(''), part; + for (var i = 0; i < parts.length; i++) { + part = parts[i]; + switch (part) { + case 'a': + part = locale.daysShort[w]; + break; + case 'A': + part = locale.days[w]; + break; + case 'b': + part = locale.monthsShort[m]; + break; + case 'B': + part = locale.months[m]; + break; + case 'C': + part = 1 + Math.floor(y / 100); + break; + case 'd': + part = (d < 10) ? ("0" + d) : d; + break; + case 'e': + part = d; + break; + case 'H': + part = (hr < 10) ? ("0" + hr) : hr; + break; + case 'I': + part = (ir < 10) ? ("0" + ir) : ir; + break; + case 'j': + part = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; + break; + case 'k': + part = hr; + break; + case 'l': + part = ir; + break; + case 'm': + part = (m < 9) ? ("0" + (1+m)) : (1+m); + break; + case 'M': + part = (min < 10) ? ("0" + min) : min; + break; + case 'p': + case 'P': + part = pm ? "PM" : "AM"; + break; + case 's': + part = Math.floor(date.getTime() / 1000); + break; + case 'S': + part = (sec < 10) ? ("0" + sec) : sec; + break; + case 'u': + part = w + 1; + break; + case 'w': + part = w; + break; + case 'y': + part = ('' + y).substr(2, 2); + break; + case 'Y': + part = y; + break; + } + parts[i] = part; + } + return parts.join(''); + } + function update_date () { + var $this = $(this), + options = $this.data('pickmeup-options'), + current_date = options.current, + new_value; + switch (options.mode) { + case 'multiple': + new_value = current_date.setHours(0,0,0,0).valueOf(); + if ($.inArray(new_value, options.date) !== -1) { + $.each(options.date, function (index, value){ + if (value == new_value) { + options.date.splice(index,1); + return false; + } + return true; + }); + } else { + options.date.push(new_value); + } + break; + case 'range': + if (!options.lastSel) { + options.date[0] = current_date.setHours(0,0,0,0).valueOf(); + } + new_value = current_date.setHours(0,0,0,0).valueOf(); + if (new_value <= options.date[0]) { + options.date[1] = options.date[0]; + options.date[0] = new_value; + } else { + options.date[1] = new_value; + } + options.lastSel = !options.lastSel; + break; + default: + options.date = current_date.valueOf(); + break; + } + var prepared_date = prepareDate(options); + if ($this.is('input')) { + $this.val(options.mode == 'single' ? prepared_date[0] : prepared_date[0].join(options.separator)); + } + options.change.apply(this, prepared_date); + if ( + !options.flat && + options.hide_on_select && + ( + options.mode != 'range' || + !options.lastSel + ) + ) { + options.binded.hide(); + return false; + } + } + function click (e) { + var el = $(e.target); + if (!el.hasClass('pmu-button')) { + el = el.closest('.pmu-button'); + } + if (el.length) { + if (el.hasClass('pmu-disabled')) { + return false; + } + var $this = $(this), + options = $this.data('pickmeup-options'), + instance = el.parents('.pmu-instance').eq(0), + root = instance.parent(), + instance_index = $('.pmu-instance', root).index(instance); + if (el.parent().is('nav')) { + if (el.hasClass('pmu-month')) { + options.current.addMonths(instance_index - Math.floor(options.calendars / 2)); + if (root.hasClass('pmu-view-years')) { + // Shift back to current date, otherwise with min value specified may jump on few (tens) years forward + if (options.mode != 'single') { + options.current = new Date(options.date[options.date.length - 1]); + } else { + options.current = new Date(options.date); + } + if (options.select_day) { + root.removeClass('pmu-view-years').addClass('pmu-view-days'); + } else if (options.select_month) { + root.removeClass('pmu-view-years').addClass('pmu-view-months'); + } + } else if (root.hasClass('pmu-view-months')) { + if (options.select_year) { + root.removeClass('pmu-view-months').addClass('pmu-view-years'); + } else if (options.select_day) { + root.removeClass('pmu-view-months').addClass('pmu-view-days'); + } + } else if (root.hasClass('pmu-view-days')) { + if (options.select_month) { + root.removeClass('pmu-view-days').addClass('pmu-view-months'); + } else if (options.select_year) { + root.removeClass('pmu-view-days').addClass('pmu-view-years'); + } + } + } else { + if (el.hasClass('pmu-prev')) { + options.binded.prev(false); + } else { + options.binded.next(false); + } + } + } else if (!el.hasClass('pmu-disabled')) { + if (root.hasClass('pmu-view-years')) { + options.current.setFullYear(parseInt(el.text(), 10)); + if (options.select_month) { + root.removeClass('pmu-view-years').addClass('pmu-view-months'); + } else if (options.select_day) { + root.removeClass('pmu-view-years').addClass('pmu-view-days'); + } else { + options.binded.update_date(); + } + } else if (root.hasClass('pmu-view-months')) { + options.current.setMonth(instance.find('.pmu-months .pmu-button').index(el)); + options.current.setFullYear(parseInt(instance.find('.pmu-month').text(), 10)); + if (options.select_day) { + root.removeClass('pmu-view-months').addClass('pmu-view-days'); + } else { + options.binded.update_date(); + } + // Move current month to the first place + options.current.addMonths(Math.floor(options.calendars / 2) - instance_index); + } else { + var val = parseInt(el.text(), 10); + options.current.addMonths(instance_index - Math.floor(options.calendars / 2)); + if (el.hasClass('pmu-not-in-month')) { + options.current.addMonths(val > 15 ? -1 : 1); + } + options.current.setDate(val); + options.binded.update_date(); + } + } + options.binded.fill(); + } + return false; + } + function prepareDate (options) { + var result; + if (options.mode == 'single') { + result = new Date(options.date); + return [formatDate(result, options.format, options.locale), result]; + } else { + result = [[],[]]; + $.each(options.date, function(nr, val){ + var date = new Date(val); + result[0].push(formatDate(date, options.format, options.locale)); + result[1].push(date); + }); + return result; + } + } + function show (force) { + var pickmeup = this.pickmeup; + if (force || !pickmeup.is(':visible')) { + var $this = $(this), + options = $this.data('pickmeup-options'), + pos = $this.offset(), + viewport = { + l : document.documentElement.scrollLeft, + t : document.documentElement.scrollTop, + w : document.documentElement.clientWidth, + h : document.documentElement.clientHeight + }, + top = pos.top, + left = pos.left; + options.binded.fill(); + if ($this.is('input')) { + $this + .pickmeup('set_date', parseDate($this.val() ? $this.val() : options.default_date, options.format, options.separator, options.locale)) + .keydown(function (e) { + if (e.which == 9) { + $this.pickmeup('hide'); + } + }); + options.lastSel = false; + } + options.before_show(); + if (options.show() == false) { + return; + } + if (!options.flat) { + switch (options.position){ + case 'top': + top -= pickmeup.outerHeight(); + break; + case 'left': + left -= pickmeup.outerWidth(); + break; + case 'right': + left += this.offsetWidth; + break; + case 'bottom': + top += this.offsetHeight; + break; + } + if (top + pickmeup.offsetHeight > viewport.t + viewport.h) { + top = pos.top - pickmeup.offsetHeight; + } + if (top < viewport.t) { + top = pos.top + this.offsetHeight + pickmeup.offsetHeight; + } + if (left + pickmeup.offsetWidth > viewport.l + viewport.w) { + left = pos.left - pickmeup.offsetWidth; + } + if (left < viewport.l) { + left = pos.left + this.offsetWidth + } + pickmeup.css({ + display : 'inline-block', + top : top + 'px', + left : left + 'px' + }); + $(document) + .on( + 'mousedown' + options.events_namespace + ' touchstart' + options.events_namespace, + options.binded.hide + ) + .on( + 'resize' + options.events_namespace, + [ + true + ], + options.binded.forced_show + ); + } + } + } + function forced_show () { + show.call(this, true); + } + function hide (e) { + if ( + !e || + !e.target || //Called directly + ( + e.target != this && //Clicked not on element itself + !(this.pickmeup.get(0).compareDocumentPosition(e.target) & 16) //And not o its children + ) + ) { + var pickmeup = this.pickmeup, + options = $(this).data('pickmeup-options'); + if (options.hide() != false) { + pickmeup.hide(); + $(document) + .off('mousedown touchstart', options.binded.hide) + .off('resize', options.binded.forced_show); + options.lastSel = false; + } + } + } + function update () { + var options = $(this).data('pickmeup-options'); + $(document) + .off('mousedown', options.binded.hide) + .off('resize', options.binded.forced_show); + options.binded.forced_show(); + } + function clear () { + var options = $(this).data('pickmeup-options'); + if (options.mode != 'single') { + options.date = []; + options.lastSel = false; + options.binded.fill(); + } + } + function prev (fill) { + if (typeof fill == 'undefined') { + fill = true; + } + var root = this.pickmeup; + var options = $(this).data('pickmeup-options'); + if (root.hasClass('pmu-view-years')) { + options.current.addYears(-12); + } else if (root.hasClass('pmu-view-months')) { + options.current.addYears(-1); + } else if (root.hasClass('pmu-view-days')) { + options.current.addMonths(-1); + } + if (fill) { + options.binded.fill(); + } + } + function next (fill) { + if (typeof fill == 'undefined') { + fill = true; + } + var root = this.pickmeup; + var options = $(this).data('pickmeup-options'); + if (root.hasClass('pmu-view-years')) { + options.current.addYears(12); + } else if (root.hasClass('pmu-view-months')) { + options.current.addYears(1); + } else if (root.hasClass('pmu-view-days')) { + options.current.addMonths(1); + } + if (fill) { + options.binded.fill(); + } + } + function get_date (formatted) { + var options = $(this).data('pickmeup-options'), + prepared_date = prepareDate(options); + if (typeof formatted === 'string') { + var date = prepared_date[1]; + if (date.constructor == Date) { + return formatDate(date, formatted, options.locale) + } else { + return date.map(function (value) { + return formatDate(value, formatted, options.locale); + }); + } + } else { + return prepared_date[formatted ? 0 : 1]; + } + } + function set_date (date) { + var $this = $(this), + options = $this.data('pickmeup-options'); + options.date = date; + if (typeof options.date === 'string') { + options.date = parseDate(options.date, options.format, options.separator, options.locale).setHours(0,0,0,0); + } else if (options.date.constructor == Date) { + options.date.setHours(0,0,0,0); + } + if (!options.date) { + options.date = new Date; + options.date.setHours(0,0,0,0); + } + if (options.mode != 'single') { + if (options.date.constructor != Array) { + options.date = [options.date.valueOf()]; + if (options.mode == 'range') { + options.date.push(((new Date(options.date[0])).setHours(0,0,0,0)).valueOf()); + } + } else { + for (var i = 0; i < options.date.length; i++) { + options.date[i] = (parseDate(options.date[i], options.format, options.separator, options.locale).setHours(0,0,0,0)).valueOf(); + } + if (options.mode == 'range') { + options.date[1] = ((new Date(options.date[1])).setHours(0,0,0,0)).valueOf(); + } + } + } else { + if($this.val() || options.default_date !== false) { + options.date = options.date.constructor == Array ? options.date[0].valueOf() : options.date.valueOf(); + } + } + options.current = new Date (options.mode != 'single' ? options.date[0] : options.date); + options.binded.fill(); + if ($this.is('input')) { + var prepared_date = prepareDate(options); + $this.val( + options.mode == 'single' + ? (options.default_date === false ? $this.val() : prepared_date[0]) + : prepared_date[0].join(options.separator) + ); + } + } + function destroy () { + var $this = $(this), + options = $this.data('pickmeup-options'); + $this.removeData('pickmeup-options'); + $this.off(options.events_namespace); + $(document).off(options.events_namespace); + $(this.pickmeup).remove(); + } + $.fn.pickmeup = function (initial_options) { + if (typeof initial_options === 'string') { + var data, + parameters = Array.prototype.slice.call(arguments, 1); + switch (initial_options) { + case 'hide': + case 'show': + case 'clear': + case 'update': + case 'prev': + case 'next': + case 'destroy': + this.each(function () { + data = $(this).data('pickmeup-options'); + if (data) { + data.binded[initial_options](); + } + }); + break; + case 'get_date': + data = this.data('pickmeup-options'); + if (data) { + return data.binded.get_date(parameters[0]); + } else { + return null; + } + break; + case 'set_date': + this.each(function () { + data = $(this).data('pickmeup-options'); + if (data) { + data.binded[initial_options].apply(this, parameters); + } + }); + } + return this; + } + return this.each(function () { + var $this = $(this); + if ($this.data('pickmeup-options')) { + return; + } + var i, + option, + options = $.extend({}, $.pickmeup, initial_options || {}); + for (i in options) { + option = $this.data('pmu-' + i); + if (typeof option !== 'undefined') { + options[i] = option; + } + } + // 4 conditional statements in order to account all cases + if (options.view == 'days' && !options.select_day) { + options.view = 'months'; + } + if (options.view == 'months' && !options.select_month) { + options.view = 'years'; + } + if (options.view == 'years' && !options.select_year) { + options.view = 'days'; + } + if (options.view == 'days' && !options.select_day) { + options.view = 'months'; + } + options.calendars = Math.max(1, parseInt(options.calendars, 10) || 1); + options.mode = /single|multiple|range/.test(options.mode) ? options.mode : 'single'; + if (typeof options.min === 'string') { + options.min = parseDate(options.min, options.format, options.separator, options.locale).setHours(0,0,0,0); + } else if (options.min && options.min.constructor == Date) { + options.min.setHours(0,0,0,0); + } + if (typeof options.max === 'string') { + options.max = parseDate(options.max, options.format, options.separator, options.locale).setHours(0,0,0,0); + } else if (options.max && options.max.constructor == Date) { + options.max.setHours(0,0,0,0); + } + if (!options.select_day) { + if (options.min) { + options.min = new Date(options.min); + options.min.setDate(1); + options.min = options.min.valueOf(); + } + if (options.max) { + options.max = new Date(options.max); + options.max.setDate(1); + options.max = options.max.valueOf(); + } + } + if (typeof options.date === 'string') { + options.date = parseDate(options.date, options.format, options.separator, options.locale).setHours(0,0,0,0); + } else if (options.date.constructor == Date) { + options.date.setHours(0,0,0,0); + } + if (!options.date) { + options.date = new Date; + options.date.setHours(0,0,0,0); + } + if (options.mode != 'single') { + if (options.date.constructor != Array) { + options.date = [options.date.valueOf()]; + if (options.mode == 'range') { + options.date.push(((new Date(options.date[0])).setHours(0,0,0,0)).valueOf()); + } + } else { + for (i = 0; i < options.date.length; i++) { + options.date[i] = (parseDate(options.date[i], options.format, options.separator, options.locale).setHours(0,0,0,0)).valueOf(); + } + if (options.mode == 'range') { + options.date[1] = ((new Date(options.date[1])).setHours(0,0,0,0)).valueOf(); + } + } + options.current = new Date(options.date[0]); + // Set days to 1 in order to handle them consistently + if (!options.select_day) { + for (i = 0; i < options.date.length; ++i) { + options.date[i] = new Date(options.date[i]); + options.date[i].setDate(1); + options.date[i] = options.date[i].valueOf(); + // Remove duplicates + if ( + options.mode != 'range' && + options.date.indexOf(options.date[i]) !== i + ) { + delete options.date.splice(i, 1); + --i; + } + } + } + } else { + options.date = options.date.valueOf(); + options.current = new Date(options.date); + if (!options.select_day) { + options.date = new Date(options.date); + options.date.setDate(1); + options.date = options.date.valueOf(); + } + } + options.current.setDate(1); + options.current.setHours(0,0,0,0); + var cnt, + pickmeup = $(tpl.wrapper); + this.pickmeup = pickmeup; + if (options.class_name) { + pickmeup.addClass(options.class_name); + } + var html = ''; + for (i = 0; i < options.calendars; i++) { + cnt = options.first_day; + html += tpl.head({ + prev : options.prev, + next : options.next, + day : [ + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7], + options.locale.daysMin[(cnt++) % 7] + ] + }); + } + $this.data('pickmeup-options', options); + for (i in options) { + if (['render', 'change', 'before_show', 'show', 'hide'].indexOf(i) != -1) { + options[i] = options[i].bind(this); + } + } + options.binded = { + fill : fill.bind(this), + update_date : update_date.bind(this), + click : click.bind(this), + show : show.bind(this), + forced_show : forced_show.bind(this), + hide : hide.bind(this), + update : update.bind(this), + clear : clear.bind(this), + prev : prev.bind(this), + next : next.bind(this), + get_date : get_date.bind(this), + set_date : set_date.bind(this), + destroy : destroy.bind(this) + }; + options.events_namespace = '.pickmeup-' + (++instances_count); + pickmeup + .on('click touchstart', options.binded.click) + .addClass(views[options.view]) + .append(html) + .on( + $.support.selectstart ? 'selectstart' : 'mousedown', + function(e){ + e.preventDefault(); + } + ); + options.binded.fill(); + if (options.flat) { + pickmeup.appendTo(this).css({ + position : 'relative', + display : 'inline-block' + }); + } else { + pickmeup.appendTo(document.body); + // Multiple events support + var trigger_event = options.trigger_event.split(' '); + for (i = 0; i < trigger_event.length; ++i) { + trigger_event[i] += options.events_namespace; + } + trigger_event = trigger_event.join(' '); + $this.on(trigger_event, options.binded.show); + } + }); + }; +})); diff --git a/stats/status_totals.php b/stats/status_totals.php index b7cdea1..4b6f5b6 100644 --- a/stats/status_totals.php +++ b/stats/status_totals.php @@ -9,19 +9,48 @@ mysql_select_db($database_YBDB, $YBDB); // SELECT shop_user_role_id FROM shop_user_roles WHERE volunteer=1 AND other_volunteer!=1;; +// Defaults -$query = "SELECT shop_user_role, COUNT(DISTINCT shop_hours.contact_id) as unique_volunteers, - COUNT(shop_hours.contact_id) as volunteer_visits, - ROUND(SUM(HOUR(SUBTIME( TIME(time_out), TIME(time_in))) + MINUTE(SUBTIME( TIME(time_out), - TIME(time_in)))/60)) AS volunteer_hours + +$today = date("Y/m/d"); +$year_ago = date("Y/m/d", strtotime("$today -1 year")); + +$today_date = new DateTime('now'); +$past = new DateTime($year_ago); +$interval = $today_date->diff($past); + +$chosen_date = $today; +$days_range1 = $interval->days; +$days_range2 = 0; + +// Do some ajax stuff +if (isset($_POST['range1'])) { + $range1 = $_POST['range1']; + $range2 = $_POST['range2']; + + $choice1 = new DateTime($range1); + $interval = $today_date->diff($choice1); + $days_range1 = $interval->days; + + $choice2 = new DateTime($range2); + $interval = $today_date->diff($choice2); + $days_range2 = $interval->days; + + $year_ago = $range1; + $today = $range2; +} + +$query = "SELECT shop_user_role, + COUNT(DISTINCT shop_hours.contact_id) as unique_volunteers, + COUNT(shop_hours.contact_id) as volunteer_visits, + ROUND(SUM(HOUR(SUBTIME( TIME(time_out), TIME(time_in))) + MINUTE(SUBTIME( TIME(time_out), TIME(time_in)))/60)) AS volunteer_hours FROM shop_hours - LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id - LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id - WHERE shop_user_roles.volunteer = 1 - OR shop_user_roles.other_volunteer = 1 - AND time_in > DATE_SUB(CURDATE(),INTERVAL 12 MONTH) GROUP BY shop_user_role - ORDER BY volunteer_hours DESC;"; -$volunteers_sql = mysql_query($query, $YBDB) or die(mysql_error()); + LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id + LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id + WHERE (time_in > DATE_SUB(CURDATE(),INTERVAL $days_range1 DAY) AND time_in <= DATE_SUB(CURDATE(), INTERVAL $days_range2 DAY)) + AND (shop_user_roles.volunteer = 1 OR shop_user_roles.other_volunteer = 1) + GROUP BY shop_user_role ORDER BY volunteer_hours DESC;"; + $volunteers_sql = mysql_query($query, $YBDB) or die(mysql_error()); $query = "SELECT COUNT(DISTINCT shop_hours.contact_id) as unique_volunteers, COUNT(shop_hours.contact_id) as volunteer_visits, @@ -29,9 +58,8 @@ $query = "SELECT COUNT(DISTINCT shop_hours.contact_id) as unique_volunteers, FROM shop_hours LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id - WHERE shop_user_roles.volunteer = 1 - OR shop_user_roles.other_volunteer = 1 - AND time_in > DATE_SUB(CURDATE(),INTERVAL 12 MONTH);"; + WHERE (time_in > DATE_SUB(CURDATE(),INTERVAL $days_range1 DAY) AND time_in <= DATE_SUB(CURDATE(), INTERVAL $days_range2 DAY)) + AND (shop_user_roles.volunteer = 1 OR shop_user_roles.other_volunteer = 1);"; $total_volunteers_sql = mysql_query($query, $YBDB) or die(mysql_error()); $query = "SELECT shop_user_role, COUNT(DISTINCT shop_hours.contact_id) as unique_visitors, @@ -41,9 +69,9 @@ $query = "SELECT shop_user_role, COUNT(DISTINCT shop_hours.contact_id) as unique FROM shop_hours LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id - WHERE shop_user_roles.volunteer = 0 - AND shop_user_roles.other_volunteer = 0 - AND time_in > DATE_SUB(CURDATE(),INTERVAL 12 MONTH) GROUP BY shop_user_role + WHERE (time_in > DATE_SUB(CURDATE(),INTERVAL $days_range1 DAY) AND time_in <= DATE_SUB(CURDATE(), INTERVAL $days_range2 DAY)) + AND (shop_user_roles.volunteer = 0 AND shop_user_roles.other_volunteer = 0) + GROUP BY shop_user_role ORDER BY hours DESC;"; $visitors_sql = mysql_query($query, $YBDB) or die(mysql_error()); @@ -53,9 +81,8 @@ $query = "SELECT COUNT(DISTINCT shop_hours.contact_id) as unique_visitors, FROM shop_hours LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id - WHERE shop_user_roles.volunteer = 0 - AND shop_user_roles.other_volunteer = 0 - AND time_in > DATE_SUB(CURDATE(),INTERVAL 12 MONTH);"; + WHERE (time_in > DATE_SUB(CURDATE(),INTERVAL $days_range1 DAY) AND time_in <= DATE_SUB(CURDATE(), INTERVAL $days_range2 DAY)) + AND (shop_user_roles.volunteer = 0 AND shop_user_roles.other_volunteer = 0);"; $total_visitors_sql = mysql_query($query, $YBDB) or die(mysql_error()); $query = "SELECT COUNT(DISTINCT shop_hours.contact_id) as unique_vv, @@ -64,9 +91,8 @@ $query = "SELECT COUNT(DISTINCT shop_hours.contact_id) as unique_vv, FROM shop_hours LEFT JOIN contacts ON shop_hours.contact_id = contacts.contact_id LEFT JOIN shop_user_roles ON shop_hours.shop_user_role = shop_user_roles.shop_user_role_id - WHERE shop_user_roles.volunteer >= 0 - OR shop_user_roles.other_volunteer >= 0 - AND time_in > DATE_SUB(CURDATE(),INTERVAL 12 MONTH);"; + WHERE (time_in > DATE_SUB(CURDATE(),INTERVAL $days_range1 DAY) AND time_in <= DATE_SUB(CURDATE(), INTERVAL $days_range2 DAY)) + AND (shop_user_roles.volunteer >= 0 OR shop_user_roles.other_volunteer >= 0);"; $total_sql = mysql_query($query, $YBDB) or die(mysql_error()); ?> @@ -213,11 +239,22 @@ $total_sql = mysql_query($query, $YBDB) or die(mysql_error()); - + +

+ +
Date Range:
+
+ +
+
+ +
+