Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 82 additions & 36 deletions js/jquery.fn.gantt.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@
onItemClick: function (data) { return; },
onAddClick: function (data) { return; },
onRender: function() { return; },
scrollToToday: true
scrollToToday: true,
scrollOnWheel: true,
scrollOnDrag: false
};

// custom selector `:findday` used to match on specified day in ms.
Expand Down Expand Up @@ -223,6 +225,7 @@
element.dateStart = tools.getMinDate(element);
element.dateEnd = tools.getMaxDate(element);

element.dataPanelIgnoreNextClick = false;

/* core.render(element); */
core.waitToggle(element, true, function () { core.render(element); });
Expand Down Expand Up @@ -338,19 +341,33 @@
dataPanel: function (element, width) {
var dataPanel = $('<div class="dataPanel" style="width: ' + width + 'px;"/>');

// Handle mousewheel events for scrolling the data panel
var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
if (document.attachEvent) {
element.attachEvent("on" + mousewheelevt, function (e) { core.wheelScroll(element, e); });
} else if (document.addEventListener) {
element.addEventListener(mousewheelevt, function (e) { core.wheelScroll(element, e); }, false);
if (settings.scrollOnWheel == true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for == true.

// Handle mousewheel events for scrolling the data panel
$(element).on('wheel', function (e) { core.wheelScroll(element, e); });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still quite a few older (but still globally-popular) browsers that don't support the 'wheel' event, which is why the check was in there, even if it wasn't quite correct. I suggest something like this (adapted from MDN):

var wheel = core.wheel = 'onwheel' in element ? 'wheel' : document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll';
$(element).on(wheel, function (e) { core.wheelScroll(element, e); });

}

if (settings.scrollOnDrag == true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for == true.

dataPanel.on('touchstart', function (e) { core.dragDataPanelStart(element, e.originalEvent.changedTouches[0].screenX, e); });
dataPanel.on('touchmove', function (e) { core.dragDataPanelMove(element, e.originalEvent.changedTouches[0].screenX, e); });
dataPanel.on('touchend', function (e) { core.dragDataPanelStop(element); });

dataPanel.mousedown(function (e) { core.dragDataPanelStart(element, e.screenX, e); });
dataPanel.mousemove(function (e) { core.dragDataPanelMove(element, e.screenX, e); });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mousemove listeners are expensive. The event fires all the dang time. Maybe only bind the handler after (or inside) a dragPanelStart and then unbind it again it after (or inside) a dragPanelStop.

dataPanel.mouseout(function (e) { core.dragDataPanelStop(element); });
dataPanel.mouseup(function (e) { core.dragDataPanelStop(element); });
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a matter of code style, but I would rewrite these to look slightly cleaner, e.g.:

dataPanel.on('mousedown touchstart', function (e) {
    var screenX = e.type.indexOf('mouse') === 0 ? e.screenX : e.originalEvent.changedTouches[0].screenX;
    core.dragDataPanelStart(element, screenX, e);
});
dataPanel.on('mouseup mouseout touchend', function (e) { core.dragDataPanelStop(element); });

// Handle click events and dispatch to registered `onAddClick`
// function
dataPanel.click(function (e) {

e.stopPropagation();

if (element.dataPanelIgnoreNextClick == true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the == true part.

element.dataPanelIgnoreNextClick = false;
return dataPanel;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might also want an e.PreventDefault() before you return.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, actually, just change the line to return false; since you shouldn't be returning the dataPanel in this event handler anyway.

}

var corrX, corrY;
var leftpanel = $(element).find(".fn-gantt .leftPanel");
var datapanel = $(element).find(".fn-gantt .dataPanel");
Expand Down Expand Up @@ -672,7 +689,7 @@
default:
range = tools.parseDateRange(element.dateStart, element.dateEnd);

var dateBefore = ktkGetNextDate(range[0], -1);
var dateBefore = ktkGetNextDate(range[0], -1);
var year = dateBefore.getFullYear();
var month = dateBefore.getMonth();
var day = dateBefore;
Expand Down Expand Up @@ -931,7 +948,7 @@
// **Progress Bar**
// Return an element representing a progress of position within
// the entire chart
createProgressBar: function (days, cls, desc, label, dataObj) {
createProgressBar: function (days, cls, desc, label, dataObj, element) {
var cellWidth = tools.getCellSize();
var barMarg = tools.getProgressBarMargin() || 0;
var bar = $('<div class="bar"><div class="fn-label">' + label + '</div></div>')
Expand Down Expand Up @@ -960,7 +977,12 @@
}
bar.click(function (e) {
e.stopPropagation();
settings.onItemClick($(this).data("dataObj"));

if (element.dataPanelIgnoreNextClick == true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no need for == true.

element.dataPanelIgnoreNextClick = false;
} else {
settings.onItemClick($(this).data("dataObj"));
}
});
return bar;
},
Expand Down Expand Up @@ -1026,7 +1048,8 @@
day.customClass ? day.customClass : "",
day.desc ? day.desc : "",
day.label ? day.label : "",
day.dataObj ? day.dataObj : null
day.dataObj ? day.dataObj : null,
element
);

// find row
Expand Down Expand Up @@ -1069,7 +1092,8 @@
day.customClass ? day.customClass : "",
day.desc ? day.desc : "",
day.label ? day.label : "",
day.dataObj ? day.dataObj : null
day.dataObj ? day.dataObj : null,
element
);

// find row
Expand Down Expand Up @@ -1109,7 +1133,8 @@
day.customClass ? day.customClass : "",
day.desc ? day.desc : "",
day.label ? day.label : "",
day.dataObj ? day.dataObj : null
day.dataObj ? day.dataObj : null,
element
);

// find row
Expand All @@ -1135,7 +1160,8 @@
day.customClass ? day.customClass : "",
day.desc ? day.desc : "",
day.label ? day.label : "",
day.dataObj ? day.dataObj : null
day.dataObj ? day.dataObj : null,
element
);

// find row
Expand Down Expand Up @@ -1303,7 +1329,7 @@

// Move chart via mousewheel
wheelScroll: function (element, e) {
var delta = e.detail ? e.detail * (-50) : e.wheelDelta / 120 * 50;
var delta = e.originalEvent.deltaY * 50;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To go with the cross-browser mouse wheel event solution I suggested above, we should adjust this as well. Something like this (again, stolen from Mozilla):

var delta = - 50 * (core.wheel === 'mousewheel' ? - 1/40 * e.originalEvent.wheelDelta : e.detail);


core.scrollPanel(element, delta);

Expand Down Expand Up @@ -1431,6 +1457,25 @@
}
element.loader = null;
}
},

dragDataPanelStart: function (element, screenX, e) {
element.scrollNavigation.dragStartX = screenX;
},

dragDataPanelMove: function (element, screenX, e) {
if (element.scrollNavigation.dragStartX != undefined) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use !== here, or typeof element.scrollNavigation.dragStartX !== 'undefined'. (To be on the safe side in older browsers, we should probably also add an undefined parameter to the top of the IIFE.)

core.scrollPanel(element, screenX - element.scrollNavigation.dragStartX)
element.scrollNavigation.dragStartX = screenX

// Stop the click event from being generated on mouse up when the drag ends.
element.dataPanelIgnoreNextClick = true;
e.preventDefault();
}
},

dragDataPanelStop: function (element) {
element.scrollNavigation.dragStartX = undefined;
}
};

Expand Down Expand Up @@ -1541,27 +1586,27 @@
var ret = [];
var i = 0;
for(;;) {
var dayStartTime = new Date(current);
dayStartTime.setHours(Math.floor((current.getHours()) / scaleStep) * scaleStep);
var dayStartTime = new Date(current);
dayStartTime.setHours(Math.floor((current.getHours()) / scaleStep) * scaleStep);

if (ret[i] && dayStartTime.getDay() !== ret[i].getDay()) {
// If mark-cursor jumped to next day, make sure it starts at 0 hours
dayStartTime.setHours(0);
// If mark-cursor jumped to next day, make sure it starts at 0 hours
dayStartTime.setHours(0);
}
ret[i] = dayStartTime;
ret[i] = dayStartTime;

// Note that we use ">" because we want to include the end-time point.
if(current.getTime() > to.getTime()) break;
// Note that we use ">" because we want to include the end-time point.
if(current.getTime() > to.getTime()) break;

/* BUG-2: current is moved backwards producing a dead-lock! (crashes chrome/IE/firefox)
* SEE: https://github.com/taitems/jQuery.Gantt/issues/62
/* BUG-2: current is moved backwards producing a dead-lock! (crashes chrome/IE/firefox)
* SEE: https://github.com/taitems/jQuery.Gantt/issues/62
if (current.getDay() !== ret[i].getDay()) {
current.setHours(0);
}
*/
*/

// GR Fix Begin
current = ktkGetNextDate(dayStartTime, scaleStep);
current = ktkGetNextDate(dayStartTime, scaleStep);
// GR Fix End

i++;
Expand Down Expand Up @@ -1728,7 +1773,8 @@
panelMargin: 0,
repositionDelay: 0,
panelMaxPos: 0,
canScroll: true
canScroll: true,
dragStartX: undefined
};

this.gantt = null;
Expand All @@ -1742,15 +1788,15 @@
})(jQuery);

function ktkGetNextDate(currentDate, scaleStep) {
for(var minIncrements = 1;; minIncrements++) {
var nextDate = new Date(currentDate);
nextDate.setHours(currentDate.getHours() + scaleStep * minIncrements);
for(var minIncrements = 1;; minIncrements++) {
var nextDate = new Date(currentDate);
nextDate.setHours(currentDate.getHours() + scaleStep * minIncrements);

if(nextDate.getTime() != currentDate.getTime()) {
return nextDate;
}
if(nextDate.getTime() != currentDate.getTime()) {
return nextDate;
}

// If code reaches here, it's because current didn't really increment (invalid local time) because of daylight-saving adjustments
// => retry adding 2, 3, 4 hours, and so on (until nextDate > current)
}
// If code reaches here, it's because current didn't really increment (invalid local time) because of daylight-saving adjustments
// => retry adding 2, 3, 4 hours, and so on (until nextDate > current)
}
}
19 changes: 17 additions & 2 deletions tests/test01.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ <h1>
</h1>

<p>
<strong>Expected behaviour:</strong> Gantt bar should run from "now" until 2 hours from now. It fails when all the bars are docked left at the hour view.
<strong>Expected behaviour:</strong>
<ul>
<li>Two Gantt bars are present. The first runs from "now" until 2 hours from now. The second runs from "now" until 10 hours from now. It fails when all the bars are docked left at the hour view.</li>
<li>Mouse wheel scrolls the chart.</li>
</ul>
</p>

<p>
Expand Down Expand Up @@ -72,6 +76,7 @@ <h1>

var today_friendly = "/Date(" + today.valueOf() + ")/";
var next_friendly = "/Date(" + andTwoHours.valueOf() + ")/";
var far_next_friendly = "/Date(" + today.add("hours", 10).valueOf() + ")/";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer .getTime() over .valueOf() here.


$(".gantt").gantt({
source: [{
Expand All @@ -83,7 +88,17 @@ <h1>
label: "Test",
customClass: "ganttRed"
}]
}],
},
{
name: "Large bar",
desc: " ",
values: [{
from: today_friendly,
to: far_next_friendly,
label: "Large bar",
customClass: "ganttRed"
}]
} ],
scale: "hours",
minScale: "hours",
navigate: "scroll"
Expand Down
118 changes: 118 additions & 0 deletions tests/test02.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<!doctype html>
<html lang="en-au">
<head>
<title>jQuery.Gantt - Test Suite 02</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge;chrome=1" >
<link rel="stylesheet" href="../css/style.css" />
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://taitems.github.com/UX-Lab/core/css/prettify.css" />
<style type="text/css">
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
padding: 0 0 50px 0;
}
.contain {
width: 800px;
margin: 0 auto;
}
h1 {
margin: 40px 0 20px 0;
}
h2 {
font-size: 1.5em;
padding-bottom: 3px;
border-bottom: 1px solid #DDD;
margin-top: 50px;
margin-bottom: 25px;
}
table th:first-child {
width: 150px;
}
</style>
</head>
<body>

<div class="contain">

<h1>
jQuery.Gantt
<small>&mdash; Test Suite 02</small>
</h1>

<p>
<strong>Expected behaviour:</strong>
<ul>
<li>Chart can be scrolled by dragging empty space in data panel.</li>
<li>Touch screen clients can scroll with drag touches.</li>
<li>Releasing the mouse over a Gantt item after a drag completes doesn't trigger the onItemClick event.</li>
<li>Releasing the mouse over an empty spot on the data panel after a drag completes doesn't trigger the onAddClick event.</li>
<li>Using the scroll wheel while mouse is over the data panel doesn't scroll the data panel.</li>
</ul>
</p>

<p>
<strong>Manual validation:</strong>
<ul>
<li>Passing</li>
</ul>
</p>

<div class="gantt"></div>


</body>
<script src="../js/jquery.min.js"></script>
<script src="../js/jquery.fn.gantt.js"></script>
<script src="moment.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="http://taitems.github.com/UX-Lab/core/js/prettify.js"></script>
<script>

$(function() {

"use strict";

var today = moment();
var future = moment().add("hours",200);

var today_friendly = "/Date(" + today.valueOf() + ")/";
var next_friendly = "/Date(" + future.valueOf() + ")/";
var click_date_friendly = "/Date(" + today.add("hours", -10).valueOf() + ")/";

$(".gantt").gantt({
source: [
{
name: "Testing",
desc: " ",
values: [{
from: today_friendly,
to: next_friendly,
label: "Test",
customClass: "ganttRed"
}]
},
{
name: "Test click release",
desc: " ",
values: [{
from: click_date_friendly,
to: next_friendly,
label: "Test2",
customClass: "ganttRed"
}]
}
],
scale: "hours",
minScale: "hours",
navigate: "scroll",
scrollOnDrag: true,
scrollOnWheel: false,
onItemClick: function() { alert('Gantt item clicked.'); },
onAddClick: function() { alert('Data panel clicked.'); }
});
});

</script>
</html>