Newer
Older
/**
* Created by Helena on 29.12.2015.
*
* Adding of events inspired by:
* http://stackoverflow.com/questions/10591747/making-a-google-calendar-like-dragging-interface
*
*/
var down, dragging; // Boolean: mouse down?, mouse down and moving?
var xOnMousedown, yOnMousedown; // click coordinates (in px)
var xFirstCellLeft, yFirstCellTop; // coordinates of clicked cell (in px)
var horizontalBorderPx = 2; // a marked cell's top and bottom border sum in px
var verticalBorderPx = 4; // a marked cell's left and right border sum in px
/**
* Create one column per (unique) context item
* @param contextList An array containing all context items (incl. duplicates) added in the author system
*/
function createColumns(contextListLength) {
// in case no context has been added to any unit in the scenario yet
if (contextListLength == 0 || typeof contextListLength == "undefined")
contextListLength = 5;
for (var i = 0; i < contextListLength; i++) {
// add one column for each context item
$(".timelineStep").each(function() {
var newCell = $("<td>").addClass("timelineCell");
$(this).append(newCell);
});
}
}
/** *
* Sets handlers for mouse events on table cells and on document, consequently
*/
function setCellEventHandlers() {
$(".timelineCell").on("mousedown", _mousedown);
$(document).mousemove(_mousemove);
$(document).mouseup(_mouseup);
}
/**
* Triggered if the user clicks on a cell: sets down to true and records click coordinates.
*
* @param event
* @private
*/
function _mousedown(event) {
down = true;
yOnMousedown = event.pageY;
xOnMousedown = event.pageX;
xFirstCellLeft = $(this).offset().left;
yFirstCellTop = $(this).offset().top;
}
/**
* If a cell has been clicked, all cells where the mouse is dragged over will be marked.
*
* @param event The mousemove event. Not restricted to cells because cursor may leave the table.
* @private
*/
function _mousemove(event) {
event.preventDefault();
if (down) {
dragging = true;
_mark(event);
}
}
/**
* When down stops: create a new DIV where cells have been marked and attach context CRUD functionality.
*
* @param event The mouseup event. Can occur anywhere in the document.
* @private
*/
function _mouseup(event) {
event.preventDefault();
// if the mouse has been down, and is now released
if (down) {
// get height of marked area
var height = _getHeight(event);
// prevent erroneous behavior when cursor is dragged beyond top
if (event.pageY > yFirstCellTop) {
// create and add the draggable, resizable information container
var eventDiv = _createEventDiv(height);
//var popoverDiv = _createPopover();
// TODO: just a mock-up for now, will be replaced by formatting in author system
var contextColor = "#"+((1<<24)*Math.random()|0).toString(16);
eventDiv.css("background-color", contextColor)
.css("z-index", 1000);
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// add new div to timeline
$("#timelineContainer").append(eventDiv);
}
}
down = false;
dragging = false;
_unmark();
}
/**
* Creates a new div as interactable for adding, editing, removing, copying, hiding context in the timeline.
*
* @param height The height of the div to be created.
* @returns {*|jQuery} The new div with set style and features: drag, resize, tooltip, popover, quick edit buttons...
*/
function _createEventDiv(height) {
// get width and height of a cell
var cellWidth = $(".timelineCell").width() + verticalBorderPx;
var cellHeight = $(".timelineCell").height() + horizontalBorderPx;
// in case no height was provided
height = height || cellHeight;
// create a new div with style and functionality
return $("<div>")
.addClass("resizableEvent")
.css("height", height+"px")
.css("min-height", cellHeight+"px")
.css("width", cellWidth+"px")
.css("background-color", "#1ABC9C")
.css("border", "1px solid gray")
.css("position", "absolute")
.css("top", yFirstCellTop+"px")
.css("left", xFirstCellLeft+"px")
.resizable({
handles: "s",
grid: [cellWidth, cellHeight],
containment: "table",
distance: 0,
resize: function(event, ui) {
ui.size.height += horizontalBorderPx;
}
})
.draggable({
grid: [cellWidth, cellHeight],
axis: "y",
cursor: "move",
containment: "table"
})
.tooltip({
hide: false,
show: false,
content: "awesome",
items: ".resizable",
track: true
});
}
/**
* Create a popover for adding/editing/deleting a context "event"
*
* @returns {*|jQuery}
* @private
*/
function _createPopover () {
return $("<div>").popover(); // TODO
}
/**
* Goes through all cells and marks those that were selected, restricted to the column clicked.
*
* @param event The mousemove or mouseup event (only triggered after mousedown on a cell).
* @private
*/
function _mark(event) {
$('.timelineCell').each(function () {
var top = $(this).offset().top;
var bottom = top + $(this).height()+horizontalBorderPx;
var left = $(this).offset().left;
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
var right = left + $(this).width()+verticalBorderPx;
if( bottom > yOnMousedown && event.pageY >= top && xOnMousedown >= left && xOnMousedown < right)
$(this).addClass( 'timelineCellMarked' );
else
$(this).removeClass( 'timelineCellMarked' );
});
}
/**
* Removes the markup from all cells.
*
* @private
*/
function _unmark() {
$('.timelineCell').each(function () {
$(this).removeClass( 'timelineCellMarked' );
});
}
/**
* Returns the Y coordinate of the element's bottom.
*
* @param element The DOM element whose bottom is searched.
* @returns {*} A number representing the y coordinate (in px).
* @private
*/
function _bottom(element){
return $(element).offset().top + $(element).height()+horizontalBorderPx;
}
/**
*
* @returns {number} The height of the selected, i.e. marked area in px
* @private
*/
function _getHeight(event) {
// if a single cell was clicked, without dragging, mark it (to access it afterwards)
if (!dragging)
_mark(event);
// get the y coordinate of the lowest selected cell's bottom
var yEnd = 0;
$('.timelineCellMarked').each(function() {
var y = _bottom(this);
yEnd = y > yEnd ? y : yEnd;
});
// calculate the distance between start and end y coordinates, i.e. height of the marked area
return yEnd - yFirstCellTop;
}