From 7fedcc1821b3e9bcc524ad598710d20915db07b6 Mon Sep 17 00:00:00 2001 From: Tait Brown Date: Sat, 2 Nov 2013 21:10:30 +1100 Subject: [PATCH] merging pull 93 --- CONTRIBUTORS.md | 5 +- css/style.css | 4 +- index.html | 53 ++++++++------- js/jquery.cookie.js | 143 +++++++++++++++++++++++++++------------- js/jquery.fn.gantt.js | 150 ++++++++++++++++++++++++++---------------- tests/moment.min.js | 12 ++-- 6 files changed, 231 insertions(+), 136 deletions(-) mode change 100755 => 100644 js/jquery.fn.gantt.js diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 72d89d2..79c1167 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,7 +1,7 @@ Welcome Contributor = -Thank your very much for your time examining and potentially modifying the source code. I truly believe it is what makes this community so great. This plugin wouldn't have gained the notoriety it has, had I not opened up the original source and been quiet unhappy with it. +Thank you very much for your time examining and potentially modifying the source code. I truly believe it is what makes this community so great. This plugin wouldn't have gained the notoriety it has had I not opened up the original source and been quite unhappy with it. Requirements & Best Practices @@ -12,5 +12,6 @@ Just a few guidelines before submitting issues and pull requests: - Ensure the code passes [JSHint](http://jshint.com) completely - Always strive to write code that meets [best practices](http://taitems.github.com/Front-End-Development-Guidelines/) - If you're attempting to solve a very unique bug, a test case is preferred +- Please target all pull requests to the [develop](/../../tree/develop) branch -And thanks once again! \ No newline at end of file +And thanks once again! diff --git a/css/style.css b/css/style.css index a286fcd..4980b9d 100644 --- a/css/style.css +++ b/css/style.css @@ -105,6 +105,7 @@ background-image: url(../img/grid.png); background-repeat: repeat; background-position: 24px 24px; + position: relative; } .fn-gantt .day, .fn-gantt .date { overflow: visible; @@ -181,7 +182,7 @@ .fn-gantt .bar { background-color: #D0E4FD; height: 18px; - margin: 4px 3px 3px 3px; + margin: 0px 3px 3px 0px; position: absolute; z-index: 10; text-align: center; @@ -402,6 +403,7 @@ top: 0; filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#bf000000', endColorstr='#bf000000',GradientType=0 ); background: rgba(0,0,0,0.75); + cursor: wait; z-index: 30; } .fn-gantt-loader-spinner span { diff --git a/index.html b/index.html index 479bdc6..c46c707 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,12 @@ - - + + jQuery.Gantt - - - - + + + + @@ -108,7 +116,7 @@

source - null + [] Array, String (url) @@ -204,7 +212,7 @@

- onItemClick: + onItemClick function (data) { return; } @@ -427,13 +435,11 @@

- - + - - - \ No newline at end of file + + diff --git a/js/jquery.cookie.js b/js/jquery.cookie.js index 42924b1..f8f852c 100644 --- a/js/jquery.cookie.js +++ b/js/jquery.cookie.js @@ -1,47 +1,96 @@ -/*! -* jQuery Cookie Plugin -* https://github.com/carhartl/jquery-cookie -* -* Copyright 2011, Klaus Hartl -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://www.opensource.org/licenses/mit-license.php -* http://www.opensource.org/licenses/GPL-2.0 -*/ -(function ($) { - $.cookie = function (key, value, options) { - - // key and at least value given, set cookie... - if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { - options = $.extend({}, options); - - if (value === null || value === undefined) { - options.expires = -1; - } - - if (typeof options.expires === 'number') { - var days = options.expires, t = options.expires = new Date(); - t.setDate(t.getDate() + days); - } - - value = String(value); - - return (document.cookie = [ - encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), - options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE - options.path ? '; path=' + options.path : '', - options.domain ? '; domain=' + options.domain : '', - options.secure ? '; secure' : '' - ].join('')); - } - - // key and possibly options given, get cookie... - options = value || {}; - var decode = options.raw ? function (s) { return s; } : decodeURIComponent; - - var pairs = document.cookie.split('; '); - for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { - if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined - } - return null; - }; -})(jQuery); +/*! + * jQuery Cookie Plugin v1.3.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2013 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as anonymous module. + define(['jquery'], factory); + } else { + // Browser globals. + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function decode(s) { + if (config.raw) { + return s; + } + return decodeURIComponent(s.replace(pluses, ' ')); + } + + function decodeAndParse(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape... + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + + s = decode(s); + + try { + return config.json ? JSON.parse(s) : s; + } catch(e) {} + } + + var config = $.cookie = function (key, value, options) { + + // Write + if (value !== undefined) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = config.json ? JSON.stringify(value) : String(value); + + return (document.cookie = [ + config.raw ? key : encodeURIComponent(key), + '=', + config.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // Read + var cookies = document.cookie.split('; '); + var result = key ? undefined : {}; + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = parts.join('='); + + if (key && key === name) { + result = decodeAndParse(cookie); + break; + } + + if (!key) { + result[name] = decodeAndParse(cookie); + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) !== undefined) { + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return true; + } + return false; + }; + +})); diff --git a/js/jquery.fn.gantt.js b/js/jquery.fn.gantt.js old mode 100755 new mode 100644 index 5e14b88..686b420 --- a/js/jquery.fn.gantt.js +++ b/js/jquery.fn.gantt.js @@ -31,7 +31,7 @@ var scales = ["hours", "days", "weeks", "months"]; //Default settings var settings = { - source: null, + source: [], itemsPerPage: 7, months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], dow: ["S", "M", "T", "W", "T", "F", "S"], @@ -117,7 +117,7 @@ // `getRepDate` returns the seconds since the epoch for a given date // depending on the active scale - Date.prototype.genRepDate = function () { + Date.prototype.getRepDate = function () { switch (settings.scale) { case "hours": return this.getTime(); @@ -204,19 +204,23 @@ // Core object is responsible for navigation and rendering var core = { // Return the element whose topmost point lies under the given point - // Normalizes for IE - elementFromPoint: function (x, y) { - - if (!$.support.boxModel) { + // Normalizes for old browsers + elementFromPoint: (function(){ // IIFE + // version for normal browsers + if (document.compatMode === "CSS1Compat") { + return function (x, y) { + x -= window.pageXOffset; + y -= window.pageYOffset; + return document.elementFromPoint(x, y); + }; + } + // version for older browsers + return function (x, y) { x -= $(document).scrollLeft(); y -= $(document).scrollTop(); - } else { - x -= window.pageXOffset; - y -= window.pageYOffset; - } - - return document.elementFromPoint(x, y); - }, + return document.elementFromPoint(x, y); + }; + })(), // **Create the chart** create: function (element) { @@ -265,7 +269,7 @@ element.gantt = $('
').append(content); - $(element).html(element.gantt); + $(element).empty().append(element.gantt); element.scrollNavigation.panelMargin = parseInt($dataPanel.css("margin-left").replace("px", ""), 10); element.scrollNavigation.panelMaxPos = ($dataPanel.width() - $rightPanel.width()); @@ -412,7 +416,7 @@ var range = null; // Days of the week have a class of one of // `sn` (Sunday), `sa` (Saturday), or `wd` (Weekday) - var dowClass = [" sn", " wd", " wd", " wd", " wd", " wd", " sa"]; + var dowClass = ["sn", "wd", "wd", "wd", "wd", "wd", "sa"]; //TODO: was someone planning to allow styles to stretch to the bottom of the chart? //var gridDowClass = [" sn", "", "", "", "", "", " sa"]; @@ -433,7 +437,6 @@ var today = new Date(); today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); - var holidays = settings.holidays ? settings.holidays.join() : ''; // Setup the headings based on the chosen `settings.scale` switch (settings.scale) { @@ -446,7 +449,7 @@ var month = range[0].getMonth(); var day = range[0]; - for (var i = 0; i < range.length; i++) { + for (var i = 0, len = range.length; i < len; i++) { var rday = range[i]; // Fill years @@ -485,13 +488,11 @@ var rgetDay = rday.getDay(); var getDay = day.getDay(); var day_class = dowClass[rgetDay]; - var getTime = day.getTime(); - if (holidays.indexOf((new Date(rday.getFullYear(), rday.getMonth(), rday.getDate())).getTime()) > -1) { + if (tools.isHoliday(rday)) { day_class = "holiday"; } if (rgetDay !== getDay) { - - var day_class2 = (today - day === 0) ? ' today' : (holidays.indexOf(getTime) > -1) ? "holiday" : dowClass[getDay]; + var day_class2 = (today - day === 0) ? "today" : tools.isHoliday( day.getTime() ) ? "holiday" : dowClass[getDay]; dayArr.push('
' @@ -509,14 +510,14 @@ + day_class + '" id="dh-' + rday.getTime() - + '" offset="' + i * tools.getCellSize() + '" repdate="' + rday.genRepDate() + '">
' + + '" offset="' + i * tools.getCellSize() + '" repdate="' + rday.getRepDate() + '">
' + rday.getHours() + '
'); } // Last year - yearArr.push( + yearArr.push( '
' + year @@ -531,7 +532,7 @@ var day_class = dowClass[day.getDay()]; - if (holidays.indexOf((new Date(day.getFullYear(), day.getMonth(), day.getDate())).getTime()) > -1) { + if ( tools.isHoliday(day) ) { day_class = "holiday"; } @@ -564,7 +565,7 @@ var month = range[0].getMonth(); var day = range[0]; - for (var i = 0; i < range.length; i++) { + for (var i = 0, len = range.length; i < len; i++) { var rday = range[i]; // Fill years @@ -595,7 +596,7 @@ // Fill weeks dayArr.push('
' + + ' id="' + rday.getWeekId() + '" offset="' + i * tools.getCellSize() + '" repdate="' + rday.getRepDate() + '"> ' + '
' + rday.getWeekOfYear() + '
'); } @@ -628,7 +629,7 @@ var month = range[0].getMonth(); var day = range[0]; - for (var i = 0; i < range.length; i++) { + for (var i = 0, len = range.length; i < len; i++) { var rday = range[i]; // Fill years @@ -643,7 +644,7 @@ daysInYear = 0; } daysInYear++; - monthArr.push('
' + (1 + rday.getMonth()) + '
'); + monthArr.push('
' + (1 + rday.getMonth()) + '
'); } @@ -657,7 +658,7 @@ // Last month monthArr.push( '
"
' + + tools.getCellSize() * daysInMonth + 'px">
' + settings.months[month] + '
'); @@ -680,7 +681,7 @@ var month = dateBefore.getMonth(); var day = dateBefore; // <- never used? - for (var i = 0; i < range.length; i++) { + for (var i = 0, len = range.length; i < len; i++) { var rday = range[i]; // Fill years @@ -711,15 +712,15 @@ var getDay = rday.getDay(); var day_class = dowClass[getDay]; - if (holidays.indexOf((new Date(rday.getFullYear(), rday.getMonth(), rday.getDate())).getTime()) > -1) { + if ( tools.isHoliday(rday) ) { day_class = "holiday"; } dayArr.push('
' + + ' id="dh-' + tools.genId(rday.getTime()) + '" offset="' + i * tools.getCellSize() + '" repdate="' + rday.getRepDate() + '"> ' + '
' + rday.getDate() + '
'); dowArr.push('
' + + ' id="dw-' + tools.genId(rday.getTime()) + '" repdate="' + rday.getRepDate() + '"> ' + '
' + settings.dow[getDay] + '
'); } //for @@ -811,9 +812,7 @@ .append($('') ) .mousedown(function (e) { - if (e.preventDefault) { - e.preventDefault(); - } + e.preventDefault(); element.scrollNavigation.scrollerMouseDown = true; core.sliderScroll(element, e); }) @@ -940,7 +939,7 @@ var bar = $('
' + label + '
') .addClass(cls) .css({ - width: ((cellWidth * days) - barMarg) + 5 + width: ((cellWidth * days) - barMarg) + 2 }) .data("dataObj", dataObj); @@ -998,7 +997,7 @@ var R = parseInt(rgbArr[0], 10); var G = parseInt(rgbArr[1], 10); var B = parseInt(rgbArr[2], 10); - var gray = Math.round((255 - (0.299 * R + 0.587 * G + 0.114 * B)) * 0.9, 1); + var gray = Math.round((255 - (0.299 * R + 0.587 * G + 0.114 * B)) * 0.9); return "rgb(" + gray + ", " + gray + ", " + gray + ")"; } catch (err) { return ""; @@ -1036,7 +1035,7 @@ var topEl = $(element).find("#rowheader" + i); var top = tools.getCellSize() * 5 + 2 + parseInt(topEl.attr("offset"), 10); - _bar.css({ 'margin-top': top, 'margin-left': Math.floor(cFrom) }); + _bar.css({ 'top': top, 'left': Math.floor(cFrom) }); datapanel.append(_bar); break; @@ -1079,7 +1078,7 @@ var topEl = $(element).find("#rowheader" + i); var top = tools.getCellSize() * 3 + 2 + parseInt(topEl.attr("offset"), 10); - _bar.css({ 'margin-top': top, 'margin-left': Math.floor(cFrom) }); + _bar.css({ 'top': top, 'left': Math.floor(cFrom) }); datapanel.append(_bar); break; @@ -1119,7 +1118,7 @@ var topEl = $(element).find("#rowheader" + i); var top = tools.getCellSize() * 2 + 2 + parseInt(topEl.attr("offset"), 10); - _bar.css({ 'margin-top': top, 'margin-left': Math.floor(cFrom) }); + _bar.css({ 'top': top, 'left': Math.floor(cFrom) }); datapanel.append(_bar); break; @@ -1145,7 +1144,7 @@ var topEl = $(element).find("#rowheader" + i); var top = tools.getCellSize() * 4 + 2 + parseInt(topEl.attr("offset"), 10); - _bar.css({ 'margin-top': top, 'margin-left': Math.floor(cFrom) }); + _bar.css({ 'top': top, 'left': Math.floor(cFrom) }); datapanel.append(_bar); @@ -1303,18 +1302,22 @@ // Move chart via mousewheel wheelScroll: function (element, e) { - var delta = - 50 * ('detail' in e ? e.detail : - 1/120 * e.originalEvent.wheelDelta); + e.preventDefault(); // e is a jQuery Event - core.scrollPanel(element, delta); + // attempts to normalize scroll wheel velocity + var delta = ( 'detail' in e ? e.detail : + 'wheelDelta' in e.originalEvent ? - 1/120 * e.originalEvent.wheelDelta : + e.originalEvent.deltaY ? e.originalEvent.deltaY / Math.abs(e.originalEvent.deltaY) : + e.originalEvent.detail ); + + // simpler normalization, ignoring per-device/browser/platform acceleration & semantic variations + //var delta = e.detail || - (e = e.originalEvent).wheelData || e.deltaY /* || e.deltaX */ || e.detail; + //delta = ( delta / Math.abs(delta) ) || 0; + + core.scrollPanel(element, -50 * delta); clearTimeout(element.scrollNavigation.repositionDelay); element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 50, element); - - if (e.preventDefault) { - e.preventDefault(); - } else { - return false; - } }, // Move chart via slider control @@ -1446,7 +1449,7 @@ maxDate = maxDate < tools.dateDeserialize(date.to) ? tools.dateDeserialize(date.to) : maxDate; }); }); - + maxDate = maxDate || new Date(); switch (settings.scale) { case "hours": maxDate.setHours(Math.ceil((maxDate.getHours()) / element.scaleStep) * element.scaleStep); @@ -1479,6 +1482,7 @@ minDate = minDate > tools.dateDeserialize(date.from) || minDate === null ? tools.dateDeserialize(date.from) : minDate; }); }); + minDate = minDate || new Date(); switch (settings.scale) { case "hours": minDate.setHours(Math.floor((minDate.getHours()) / element.scaleStep) * element.scaleStep); @@ -1607,10 +1611,12 @@ return ret; }, - // Deserialize a date from a string - dateDeserialize: function (dateStr) { - var date = dateStr.replace(/\/Date\((.*)\)\//, "$1"); - date = $.isNumeric(date) ? parseInt(date, 10) : $.trim(date); + // Deserialize a date from a string or integer + dateDeserialize: function (date) { + if (typeof date === "string") { + date = date.replace(/\/Date\((.*)\)\//, "$1"); + date = $.isNumeric(date) ? parseInt(date, 10) : $.trim(date); + } return new Date( date ); }, @@ -1639,6 +1645,36 @@ } }, + // normalizes an array of dates into a map of start-of-day millisecond values + _datesToDays: function ( dates ) { + var dayMap = {}; + for (var i = 0, len = dates.length, day; i < len; i++) { + day = tools.dateDeserialize( dates[i] ); + dayMap[ day.setHours(0, 0, 0, 0) ] = true; + } + return dayMap; + }, + // Returns true when the given date appears in the array of holidays, if provided + isHoliday: (function() { // IIFE + // short-circuits the function if no holidays option was passed + if (!settings.holidays) { + return function () { return false; }; + } + var holidays = false; + // returns the function that will be used to check for holidayness of a given date + return function(date) { + if (!holidays) { + holidays = tools._datesToDays( settings.holidays ); + } + return !!holidays[ + // assumes numeric dates are already normalized to start-of-day + $.isNumeric(date) ? + date : + ( new Date(date.getFullYear(), date.getMonth(), date.getDate()) ).getTime() + ]; + }; + })(), + // Get the current cell size _getCellSize: null, getCellSize: function () { @@ -1652,7 +1688,7 @@ return tools._getCellSize; }, - // Get the current size of the rigth panel + // Get the current size of the right panel getRightPanelSize: function () { $("body").append( $('') @@ -1670,7 +1706,7 @@ // Get the current margin size of the progress bar _getProgressBarMargin: null, getProgressBarMargin: function () { - if (!tools._getProgressBarMargin) { + if (!tools._getProgressBarMargin && tools._getProgressBarMargin !== 0) { $("body").append( $('