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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53c43c1b433977261aea620158c5a41cec72fae94382a262a785c885278dd615
4
- data.tar.gz: f0a8202bb60e949d9fcc9b3df342f2c6acce9a6f09ecff027e8361f3d9b1ca62
3
+ metadata.gz: a3097f33273401dcac75395ee2e5c7c6b4d40ed596e91319f7f3c90a3d63830e
4
+ data.tar.gz: 2213ac0acbaa38a91630123f51a2f76d3f4fa2299522dcf61c2541922dd5947b
5
5
  SHA512:
6
- metadata.gz: 77475f095f8331be85088b3f799d40cb0564d13d073651182ee217d3dfe7ba071702d4f53462b81c0893de9175599752c19377cb68438d540141c5cb175275ec
7
- data.tar.gz: d80865687adce695d6785b7b8f458b7dd39b51db648ae5f73cb08d7c48d0e55c122c34486e5beea952e2b617bfd39312c71d5db4d3865821650ee50e1b7392d3
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.startTime = new Date(this.element.dataset.timetableStartTime);
9
- this.endTime = new Date(this.element.dataset.timetableEndTime);
10
- this.duration = (this.endTime - this.startTime) / 1000;
11
- this.canvasArea = this.element.getBoundingClientRect();
12
- this.clipSize = this.element.dataset.timetableClipSize;
13
- this.scrollHeight = this.element.scrollHeight - 20; // -20 because of the padding
14
- this.dragging = false;
15
- this.dragEvent = {}
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
- this.#setSpecialClasses(event);
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.dragging = true;
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.type = event.params.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
- stopDragEvent(event) {
39
- event.preventDefault();
40
- event.stopPropagation();
46
+ drag(event) {
47
+ if(this.dragEvent) {
41
48
 
42
- this.dragging = false;
43
- this.dragEvent = {};
49
+ this.dragEvent.captureSnapshot(event);
44
50
 
45
- this.#removeDragEventListeners();
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
- drag(event) {
49
- if(this.dragging) {
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
- this.#invokeDragMethodFor(this.dragEvent.type); // calls dragCreate, dragMove or dragResize
63
+ this.dragEvent = null;
54
64
 
55
- if(event.clientY > this.element.getBoundingClientRect().bottom && this.element.scrollTop < this.scrollHeight) {
56
- this.element.scrollTop += 10;
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.#timeBoundaries(this.dragEvent.currentYTime.clipped, this.dragEvent.originYTime.clipped);
71
- let eventDiv = this.#createEventDiv(timeBoundaries.start, timeBoundaries.end);
72
- this.#setDragEventTarget(eventDiv);
73
- this.dragEvent.type = "resize";
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.#timeBoundaries(this.dragEvent.currentYTime.clipped, this.dragEvent.originEventStartTime.real);
78
- this.#updateEventDiv(this.dragEvent.target, timeBoundaries.start, timeBoundaries.end);
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.currentYTime.clipped - this.dragEvent.originYTime.clipped);
83
-
84
- let startTime = new Date(this.dragEvent.originEventStartTime.real.getTime() + timeChange);
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.#updateEventDiv(this.dragEvent.target, startTime, endTime);
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
- #relativeElementPosition(element) {
103
- let canvasArea = this.element.getBoundingClientRect();
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
- #timeBoundaries(timeA, timeB) {
112
- let startTime = new Date(Math.min(timeA, timeB));
113
- let endTime = new Date(Math.max(timeA, timeB));
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
- if (endTime - startTime < this.clipSize * 60 * 1000) {
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
- #timeAtPosition(y, roundUp = false) {
123
- let realSecond = ((y / this.scrollHeight) * this.duration) + 1;
124
- let clippedSecond = (Math.floor((realSecond / 60).toFixed(0) / this.clipSize) * this.clipSize) * 60;
125
-
126
- // No need for seconds and minutes, should convert to one unit only, probably seconds or milliseconds
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
- // Event Methods //
142
- // (eventually switch to use template) //
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
- eventDiv.classList.add("event");
149
- eventDiv.setAttribute("data-timetable-target", "event");
150
- eventDiv.setAttribute("data-action", "mousedown->time-table#startDragEvent");
151
- eventDiv.setAttribute("data-time-table-drag-event-param", "move");
152
-
153
- eventDiv.innerHTML = `
154
- <div class="event-name"><span style="font-weight: 400; color: gray;">(No Title)</span></div>
155
- <div class="event-time" data-action="mousedown->time-table#startDragEvent" data-time-table-drag-event-param="resize">
156
- ${ this.#durationString(startTime, endTime) }
157
- </div>
158
- `;
159
-
160
- this.#updateEventDiv(eventDiv, startTime, endTime);
161
- this.eventsListTarget.appendChild(eventDiv);
162
-
163
- return eventDiv;
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
- this.#setSpecialClasses(target);
141
+ ////////////////////
142
+ // Scroll Methods //
143
+ ////////////////////
174
144
 
175
- target.querySelector(".event-time").innerHTML = this.#durationString(startTime, endTime);
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
- #setSpecialClasses(eventDiv) {
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
- minutes = minutes < 10 ? '0' + minutes : minutes;
195
- return hours + ':' + minutes + ' ' + ampm;
158
+ insertTimestampAbove() {
196
159
  }
197
160
 
198
- #durationString(startTime, endTime) {
199
- return `${this.#timeString(startTime)} - ${this.#timeString(endTime)}`;
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));