time_table 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascript/time_table/controllers/time_table_controller.js +115 -151
- data/app/assets/javascript/time_table/controllers/time_table_controller_old.js +569 -0
- data/app/assets/javascript/time_table/controllers/time_table_controller_pre_time_keeper.js +350 -0
- data/app/assets/javascript/time_table/helpers/drag_event_state.js +53 -0
- data/app/assets/javascript/time_table/helpers/scroll_frame.js +141 -0
- data/app/assets/javascript/time_table/helpers/time_keeper.js +98 -0
- data/app/assets/javascript/time_table/helpers/time_table_renderer.js +75 -0
- data/app/assets/stylesheets/time_table/time_table.css +16 -2
- data/app/helpers/time_table/time_table_helper.rb +2 -2
- data/app/views/time_table/_time_table.html.erb +2 -2
- data/lib/time_table/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3097f33273401dcac75395ee2e5c7c6b4d40ed596e91319f7f3c90a3d63830e
|
4
|
+
data.tar.gz: 2213ac0acbaa38a91630123f51a2f76d3f4fa2299522dcf61c2541922dd5947b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '095c1a63e9718f31d11edc1e9682fc68783a85fa17660762bfb6a168f51db480dc5a1838bb452a788f516d9c46b1edd6ca91dde35575bc1b4f1373ece86556b3'
|
7
|
+
data.tar.gz: 2750d32a23642329bb5b6211baa1db78cd547bc36e3fccd223b6e7ae959afcb3aad0a9cfd731c4a73816e3d1db00d613ffda8947e2e33d2e4ba3fa525a95c6e1
|
@@ -1,21 +1,29 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import ScrollFrame from "../helpers/scroll_frame.js"
|
3
|
+
import TimeKeeper from "../helpers/time_keeper.js"
|
4
|
+
import DragEventState from "../helpers/drag_event_state.js"
|
5
|
+
import TimeTableRenderer from "../helpers/time_table_renderer.js"
|
2
6
|
|
3
|
-
// Connects to data-controller="dropdown"
|
4
7
|
export default class extends Controller {
|
5
|
-
static targets = ["canvas", "eventsList", "event", "eventName", "eventTime"]
|
8
|
+
static targets = ["canvas", "eventsList", "event", "eventName", "eventTime", "timestamp"]
|
6
9
|
|
7
10
|
connect() {
|
8
|
-
this.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
this.timeKeeper = new TimeKeeper({
|
12
|
+
start: new Date(this.element.dataset.timetableStartTime),
|
13
|
+
end: new Date(this.element.dataset.timetableEndTime),
|
14
|
+
scope: this.element.dataset.timetableScope,
|
15
|
+
scale: this.element.dataset.timetableScale,
|
16
|
+
clip: this.element.dataset.timetableClipSize
|
17
|
+
});
|
18
|
+
|
19
|
+
let topPadding = parseInt(window.getComputedStyle(this.element).paddingTop, 10);
|
20
|
+
|
21
|
+
this.scrollFrame = new ScrollFrame(this.element, { origin: topPadding });
|
22
|
+
|
23
|
+
this.dragEvent = null;
|
16
24
|
|
17
25
|
this.eventTargets.forEach((event) => {
|
18
|
-
|
26
|
+
TimeTableRenderer.setSpecialClasses(event);
|
19
27
|
});
|
20
28
|
}
|
21
29
|
|
@@ -23,180 +31,141 @@ export default class extends Controller {
|
|
23
31
|
event.preventDefault();
|
24
32
|
event.stopPropagation();
|
25
33
|
|
26
|
-
this.
|
34
|
+
this.dragEvent = new DragEventState({
|
35
|
+
type: event.params.dragEvent,
|
36
|
+
scrollFrame: this.scrollFrame,
|
37
|
+
timeKeeper: this.timeKeeper,
|
38
|
+
target: event.currentTarget.closest(".event")
|
39
|
+
});
|
27
40
|
|
28
|
-
this.dragEvent.
|
29
|
-
this.dragEvent.originY = this.dragEvent.originY = this.#relativeCursorPosition(event).y;
|
30
|
-
this.dragEvent.originYTime = this.#timeAtPosition(this.dragEvent.originY);
|
31
|
-
this.dragEvent.currentY = this.dragEvent.originY;
|
32
|
-
this.dragEvent.currentYTime = this.dragEvent.originYTime;
|
41
|
+
this.dragEvent.captureOriginSnapshot(event);
|
33
42
|
|
34
|
-
this.#setDragEventTarget(event.currentTarget.closest(".event"));
|
35
43
|
this.#setDragEventListeners();
|
36
44
|
}
|
37
45
|
|
38
|
-
|
39
|
-
|
40
|
-
event.stopPropagation();
|
46
|
+
drag(event) {
|
47
|
+
if(this.dragEvent) {
|
41
48
|
|
42
|
-
|
43
|
-
this.dragEvent = {};
|
49
|
+
this.dragEvent.captureSnapshot(event);
|
44
50
|
|
45
|
-
|
51
|
+
// Calls dragResize, dragMove, dragCreate, etc.
|
52
|
+
this.#invokeDragMethodFor(this.dragEvent.type);
|
53
|
+
|
54
|
+
if(this.dragEvent.type != undefined && this.dragEvent.type != "rescale") {
|
55
|
+
this.scrollFrame.checkForScroll(this.dragEvent.current.position, this.handleScroll.bind(this));
|
56
|
+
}
|
57
|
+
}
|
46
58
|
}
|
47
59
|
|
48
|
-
|
49
|
-
|
50
|
-
this.dragEvent.currentY = this.#relativeCursorPosition(event).y;
|
51
|
-
this.dragEvent.currentYTime = this.#timeAtPosition(this.dragEvent.currentY);
|
60
|
+
stopDragEvent(event) {
|
61
|
+
event.preventDefault();
|
52
62
|
|
53
|
-
|
63
|
+
this.dragEvent = null;
|
54
64
|
|
55
|
-
|
56
|
-
|
57
|
-
}
|
58
|
-
if(event.clientY < this.element.getBoundingClientRect().top && this.element.scrollTop > 0) {
|
59
|
-
this.element.scrollTop -= 10;
|
60
|
-
}
|
61
|
-
}
|
65
|
+
this.scrollFrame.stopScrolling();
|
66
|
+
this.#removeDragEventListeners();
|
62
67
|
}
|
63
68
|
|
69
|
+
|
64
70
|
//////////////////
|
65
71
|
// Drag Methods //
|
66
72
|
//////////////////
|
67
73
|
|
68
|
-
|
69
74
|
dragCreate(event) {
|
70
|
-
let timeBoundaries = this
|
71
|
-
let
|
72
|
-
|
73
|
-
this.
|
75
|
+
let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.time.clipped);
|
76
|
+
let eventElement = TimeTableRenderer.createEventElement(timeBoundaries);
|
77
|
+
|
78
|
+
this.eventsListTarget.appendChild(eventElement);
|
79
|
+
|
80
|
+
this.dragEvent.shift({ type: "resize", target: eventElement });
|
81
|
+
this.handleOverlap(eventElement);
|
74
82
|
}
|
75
83
|
|
76
84
|
dragResize(event) {
|
77
|
-
let timeBoundaries = this
|
78
|
-
|
79
|
-
|
85
|
+
let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.target.startTime.real);
|
86
|
+
TimeTableRenderer.updateEventElement(this.dragEvent.target, timeBoundaries);
|
87
|
+
this.handleOverlap(this.dragEvent.target);
|
88
|
+
}
|
80
89
|
|
81
90
|
dragMove(event) {
|
82
|
-
let timeChange = (this.dragEvent.
|
83
|
-
|
84
|
-
let
|
85
|
-
let endTime = new Date(this.dragEvent.originEventEndTime.real.getTime() + timeChange);
|
91
|
+
let timeChange = (this.dragEvent.current.time.clipped - this.dragEvent.origin.time.clipped);
|
92
|
+
let updatedStartTime = new Date(this.dragEvent.origin.target.startTime.real.getTime() + timeChange)
|
93
|
+
let updatedEndTime = new Date(this.dragEvent.origin.target.endTime.real.getTime() + timeChange);
|
86
94
|
|
87
|
-
this
|
88
|
-
}
|
89
|
-
|
90
|
-
/////////////////////
|
91
|
-
// Time & Position //
|
92
|
-
/////////////////////
|
93
|
-
|
94
|
-
#relativeCursorPosition(event) {
|
95
|
-
let canvasArea = this.element.getBoundingClientRect();
|
96
|
-
return {
|
97
|
-
x: event.clientX - canvasArea.left,
|
98
|
-
y: (event.clientY - canvasArea.top - 20) + this.element.scrollTop
|
99
|
-
};
|
100
|
-
}
|
95
|
+
let timeBoundaries = this.timeKeeper.timeBoundaries(updatedStartTime, updatedEndTime);
|
101
96
|
|
102
|
-
|
103
|
-
|
104
|
-
let rect = element.getBoundingClientRect();
|
105
|
-
return {
|
106
|
-
x: rect.left - canvasArea.left,
|
107
|
-
y: (rect.top - canvasArea.top - 20) + this.element.scrollTop
|
108
|
-
};
|
97
|
+
TimeTableRenderer.updateEventElement(this.dragEvent.target, timeBoundaries);
|
98
|
+
this.handleOverlap(this.dragEvent.target);
|
109
99
|
}
|
110
100
|
|
111
|
-
|
112
|
-
let
|
113
|
-
let
|
101
|
+
dragRescale(event) {
|
102
|
+
let delta = this.dragEvent.previous.position.scroll.y - this.dragEvent.current.position.scroll.y;
|
103
|
+
let newScale = Math.max(30, Math.min(300, this.timeKeeper.scale - (delta)));
|
104
|
+
this.element.style.setProperty("--hour-scale", newScale);
|
105
|
+
let scaleChange = newScale / this.timeKeeper.scale;
|
114
106
|
|
115
|
-
|
116
|
-
endTime = new Date(startTime.getTime() + (this.clipSize * 60 * 1000));
|
117
|
-
}
|
118
|
-
|
119
|
-
return { start: startTime, end: endTime };
|
120
|
-
}
|
107
|
+
this.timeKeeper.rescale(newScale);
|
121
108
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
return {
|
128
|
-
real: new Date(this.startTime.getTime() + (realSecond * 1000)), // For some reason 1 second is added to real each time you change it.
|
129
|
-
clipped: new Date(this.startTime.getTime() + (clippedSecond * 1000)),
|
130
|
-
}
|
131
|
-
}
|
132
|
-
|
133
|
-
#positionOfTime(time) {
|
134
|
-
let positionInDuration = (time - this.startTime) / (this.endTime - this.startTime + 1000);
|
135
|
-
// console.log(positionInDuration);
|
136
|
-
// console.log(positionInDuration * 1440)
|
137
|
-
return positionInDuration * 1440;
|
109
|
+
this.eventTargets.forEach((event) => {
|
110
|
+
event.style.setProperty("height", `${event.offsetHeight * (scaleChange)}px`);
|
111
|
+
event.style.setProperty("top", `${event.offsetTop * (scaleChange)}px`);
|
112
|
+
TimeTableRenderer.setSpecialClasses(event);
|
113
|
+
});
|
138
114
|
}
|
139
115
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
/////////////////////////////////////////
|
144
|
-
|
145
|
-
#createEventDiv(startTime, endTime){
|
146
|
-
const eventDiv = document.createElement("div");
|
116
|
+
handleOverlap(element) {
|
117
|
+
let eventTop = element.offsetTop;
|
118
|
+
let eventBottom = eventTop + element.offsetHeight;
|
147
119
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
120
|
+
this.eventTargets.forEach((event) => {
|
121
|
+
if(event != element) {
|
122
|
+
let top = event.offsetTop;
|
123
|
+
let bottom = top + event.offsetHeight;
|
124
|
+
|
125
|
+
if(eventTop >= top && eventBottom <= bottom) {
|
126
|
+
element.style.setProperty("left", "50px");
|
127
|
+
event.style.setProperty("right", "20px");
|
128
|
+
} else if(eventTop < bottom && eventBottom > top) {
|
129
|
+
element.style.setProperty("left", "50%");
|
130
|
+
event.style.setProperty("right", "50%");
|
131
|
+
} else {
|
132
|
+
element.style.setProperty("left", "50px");
|
133
|
+
event.style.setProperty("right", "20px");
|
134
|
+
}
|
135
|
+
}
|
136
|
+
});
|
164
137
|
}
|
165
138
|
|
166
|
-
#updateEventDiv(target, startTime, endTime) {
|
167
|
-
let startLocation = this.#positionOfTime(startTime);
|
168
|
-
let endLocation = this.#positionOfTime(endTime);
|
169
139
|
|
170
|
-
target.style.setProperty("top", `${startLocation}px`);
|
171
|
-
target.style.setProperty("height", `${endLocation - startLocation}px`);
|
172
140
|
|
173
|
-
|
141
|
+
////////////////////
|
142
|
+
// Scroll Methods //
|
143
|
+
////////////////////
|
174
144
|
|
175
|
-
|
176
|
-
|
145
|
+
handleScroll(status) {
|
146
|
+
if(status == "ABOVE") {
|
147
|
+
console.log("ABOVE");
|
148
|
+
this.insertTimestampAbove();
|
149
|
+
} else if (status == "BELOW") {
|
150
|
+
console.log("BELOW");
|
151
|
+
this.insertTimestampBelow();
|
152
|
+
}
|
177
153
|
|
178
|
-
|
179
|
-
eventDiv.classList.toggle("tiny", eventDiv.offsetHeight < 15);
|
180
|
-
eventDiv.classList.toggle("small", eventDiv.offsetHeight < 45);
|
154
|
+
this.drag(this.dragEvent.current.event);
|
181
155
|
}
|
182
156
|
|
183
|
-
/////////////////////
|
184
|
-
// Time Formatters //
|
185
|
-
/////////////////////
|
186
|
-
|
187
|
-
#timeString(date) {
|
188
|
-
let hours = date.getUTCHours();
|
189
|
-
let minutes = date.getUTCMinutes();
|
190
|
-
let ampm = hours >= 12 ? 'PM' : 'AM';
|
191
|
-
hours = hours % 12;
|
192
|
-
hours = hours ? hours : 12; // the hour '0' should be '12'
|
193
157
|
|
194
|
-
|
195
|
-
return hours + ':' + minutes + ' ' + ampm;
|
158
|
+
insertTimestampAbove() {
|
196
159
|
}
|
197
160
|
|
198
|
-
|
199
|
-
|
161
|
+
insertTimestampBelow() {
|
162
|
+
// this.dragEvent.inserting = true;
|
163
|
+
// Add 1 hour
|
164
|
+
let time = new Date(this.timeKeeper.endTime.getTime());
|
165
|
+
time.setHours(time.getHours() + 1);
|
166
|
+
this.timeKeeper.endTime = time;
|
167
|
+
let timestampDiv = TimeTableRenderer.timestamp(time);
|
168
|
+
this.element.querySelector(".timestamps").appendChild(timestampDiv);
|
200
169
|
}
|
201
170
|
|
202
171
|
////////////////
|
@@ -204,6 +173,10 @@ export default class extends Controller {
|
|
204
173
|
////////////////
|
205
174
|
|
206
175
|
#invokeDragMethodFor(type) {
|
176
|
+
if(!type) {
|
177
|
+
console.error("No drag type provided");
|
178
|
+
return;
|
179
|
+
}
|
207
180
|
let capitalizedType = type.charAt(0).toUpperCase() + type.slice(1);
|
208
181
|
|
209
182
|
if (this[`drag${capitalizedType}`]) {
|
@@ -217,15 +190,6 @@ export default class extends Controller {
|
|
217
190
|
// Helpers //
|
218
191
|
/////////////
|
219
192
|
|
220
|
-
#setDragEventTarget(target) {
|
221
|
-
if(target) {
|
222
|
-
this.dragEvent.target = target;
|
223
|
-
this.dragEvent.originEventPosition = this.#relativeElementPosition(target);
|
224
|
-
this.dragEvent.originEventStartTime = this.#timeAtPosition(this.dragEvent.originEventPosition.y);
|
225
|
-
this.dragEvent.originEventEndTime = this.#timeAtPosition(this.dragEvent.originEventPosition.y + target.offsetHeight);
|
226
|
-
}
|
227
|
-
}
|
228
|
-
|
229
193
|
#setDragEventListeners() {
|
230
194
|
document.addEventListener("mousemove", this.drag.bind(this));
|
231
195
|
document.addEventListener("mouseup", this.stopDragEvent.bind(this));
|