time_table 0.1.3 → 0.1.5

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: 37cadc0ccd49e70a955ee8a7ce0da2cec2dd07addc3753dbd0dc86254ddc502b
4
+ data.tar.gz: 597c585023837f77e79863fa2f8e0ebf0836463dfc6f67b95f7121511ec089e5
5
5
  SHA512:
6
- metadata.gz: 77475f095f8331be85088b3f799d40cb0564d13d073651182ee217d3dfe7ba071702d4f53462b81c0893de9175599752c19377cb68438d540141c5cb175275ec
7
- data.tar.gz: d80865687adce695d6785b7b8f458b7dd39b51db648ae5f73cb08d7c48d0e55c122c34486e5beea952e2b617bfd39312c71d5db4d3865821650ee50e1b7392d3
6
+ metadata.gz: 017310be8ccce3c0b4d64ee97de60329515fb1e58a1d01d83f9d3eac3ac40b53b5bd40f6c301a5afe77815d9e0ffe249adfa23a84fafbbe2ec619acdfb7051ec
7
+ data.tar.gz: 210f906e47ce4d2ccb088c216e3b856bab10163439628e3ee74e7b1adc72c289ac59809f1ac4958f659b31c0334f21d0500737a24da62686d2b810264f863660
@@ -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,145 @@ export default class extends Controller {
23
31
  event.preventDefault();
24
32
  event.stopPropagation();
25
33
 
26
- this.dragging = true;
34
+ if(event.params.dragEvent != "rescale" && this.element.dataset.timetableFrozenParam == "true") {
35
+ return;
36
+ }
37
+
38
+ this.dragEvent = new DragEventState({
39
+ type: event.params.dragEvent,
40
+ scrollFrame: this.scrollFrame,
41
+ timeKeeper: this.timeKeeper,
42
+ target: event.currentTarget.closest(".event")
43
+ });
27
44
 
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;
45
+ this.dragEvent.captureOriginSnapshot(event);
33
46
 
34
- this.#setDragEventTarget(event.currentTarget.closest(".event"));
35
47
  this.#setDragEventListeners();
36
48
  }
37
49
 
38
- stopDragEvent(event) {
39
- event.preventDefault();
40
- event.stopPropagation();
50
+ drag(event) {
51
+ if(this.dragEvent) {
41
52
 
42
- this.dragging = false;
43
- this.dragEvent = {};
53
+ this.dragEvent.captureSnapshot(event);
44
54
 
45
- this.#removeDragEventListeners();
55
+ // Calls dragResize, dragMove, dragCreate, etc.
56
+ this.#invokeDragMethodFor(this.dragEvent.type);
57
+
58
+ if(this.dragEvent.type != undefined && this.dragEvent.type != "rescale") {
59
+ this.scrollFrame.checkForScroll(this.dragEvent.current.position, this.handleScroll.bind(this));
60
+ }
61
+ }
46
62
  }
47
63
 
48
- drag(event) {
49
- if(this.dragging) {
50
- this.dragEvent.currentY = this.#relativeCursorPosition(event).y;
51
- this.dragEvent.currentYTime = this.#timeAtPosition(this.dragEvent.currentY);
64
+ stopDragEvent(event) {
65
+ event.preventDefault();
52
66
 
53
- this.#invokeDragMethodFor(this.dragEvent.type); // calls dragCreate, dragMove or dragResize
67
+ this.dragEvent = null;
54
68
 
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
- }
69
+ this.scrollFrame.stopScrolling();
70
+ this.#removeDragEventListeners();
62
71
  }
63
72
 
73
+
64
74
  //////////////////
65
75
  // Drag Methods //
66
76
  //////////////////
67
77
 
68
-
69
78
  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";
79
+ let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.time.clipped);
80
+ let eventElement = TimeTableRenderer.createEventElement(timeBoundaries);
81
+
82
+ this.eventsListTarget.appendChild(eventElement);
83
+
84
+ this.dragEvent.shift({ type: "resize", target: eventElement });
85
+ this.handleOverlap(eventElement);
74
86
  }
75
87
 
76
88
  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
- }
89
+ let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.target.startTime.real);
90
+ TimeTableRenderer.updateEventElement(this.dragEvent.target, timeBoundaries);
91
+ this.handleOverlap(this.dragEvent.target);
92
+ }
80
93
 
81
94
  dragMove(event) {
82
- let timeChange = (this.dragEvent.currentYTime.clipped - this.dragEvent.originYTime.clipped);
95
+ let timeChange = (this.dragEvent.current.time.clipped - this.dragEvent.origin.time.clipped);
96
+ let updatedStartTime = new Date(this.dragEvent.origin.target.startTime.real.getTime() + timeChange)
97
+ let updatedEndTime = new Date(this.dragEvent.origin.target.endTime.real.getTime() + timeChange);
83
98
 
84
- let startTime = new Date(this.dragEvent.originEventStartTime.real.getTime() + timeChange);
85
- let endTime = new Date(this.dragEvent.originEventEndTime.real.getTime() + timeChange);
99
+ let timeBoundaries = this.timeKeeper.timeBoundaries(updatedStartTime, updatedEndTime);
86
100
 
87
- this.#updateEventDiv(this.dragEvent.target, startTime, endTime);
101
+ TimeTableRenderer.updateEventElement(this.dragEvent.target, timeBoundaries);
102
+ this.handleOverlap(this.dragEvent.target);
88
103
  }
89
104
 
90
- /////////////////////
91
- // Time & Position //
92
- /////////////////////
105
+ dragRescale(event) {
106
+ let delta = this.dragEvent.previous.position.scroll.y - this.dragEvent.current.position.scroll.y;
107
+ let newScale = Math.max(30, Math.min(300, this.timeKeeper.scale - (delta)));
108
+ this.element.style.setProperty("--hour-scale", newScale);
109
+ let scaleChange = newScale / this.timeKeeper.scale;
93
110
 
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
- }
101
-
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
- };
109
- }
110
-
111
- #timeBoundaries(timeA, timeB) {
112
- let startTime = new Date(Math.min(timeA, timeB));
113
- let endTime = new Date(Math.max(timeA, timeB));
114
-
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
- }
121
-
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;
111
+ this.timeKeeper.rescale(newScale);
125
112
 
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;
113
+ this.eventTargets.forEach((event) => {
114
+ event.style.setProperty("height", `${event.offsetHeight * (scaleChange)}px`);
115
+ event.style.setProperty("top", `${event.offsetTop * (scaleChange)}px`);
116
+ TimeTableRenderer.setSpecialClasses(event);
117
+ });
138
118
  }
139
119
 
140
- /////////////////////////////////////////
141
- // Event Methods //
142
- // (eventually switch to use template) //
143
- /////////////////////////////////////////
144
-
145
- #createEventDiv(startTime, endTime){
146
- const eventDiv = document.createElement("div");
120
+ handleOverlap(element) {
121
+ let eventTop = element.offsetTop;
122
+ let eventBottom = eventTop + element.offsetHeight;
147
123
 
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;
124
+ this.eventTargets.forEach((event) => {
125
+ if(event != element) {
126
+ let top = event.offsetTop;
127
+ let bottom = top + event.offsetHeight;
128
+
129
+ if(eventTop >= top && eventBottom <= bottom) {
130
+ element.style.setProperty("left", "50px");
131
+ event.style.setProperty("right", "20px");
132
+ } else if(eventTop < bottom && eventBottom > top) {
133
+ element.style.setProperty("left", "50%");
134
+ event.style.setProperty("right", "50%");
135
+ } else {
136
+ element.style.setProperty("left", "50px");
137
+ event.style.setProperty("right", "20px");
138
+ }
139
+ }
140
+ });
164
141
  }
165
142
 
166
- #updateEventDiv(target, startTime, endTime) {
167
- let startLocation = this.#positionOfTime(startTime);
168
- let endLocation = this.#positionOfTime(endTime);
169
143
 
170
- target.style.setProperty("top", `${startLocation}px`);
171
- target.style.setProperty("height", `${endLocation - startLocation}px`);
172
144
 
173
- this.#setSpecialClasses(target);
145
+ ////////////////////
146
+ // Scroll Methods //
147
+ ////////////////////
174
148
 
175
- target.querySelector(".event-time").innerHTML = this.#durationString(startTime, endTime);
176
- }
149
+ handleScroll(status) {
150
+ if(status == "ABOVE") {
151
+ console.log("ABOVE");
152
+ this.insertTimestampAbove();
153
+ } else if (status == "BELOW") {
154
+ console.log("BELOW");
155
+ this.insertTimestampBelow();
156
+ }
177
157
 
178
- #setSpecialClasses(eventDiv) {
179
- eventDiv.classList.toggle("tiny", eventDiv.offsetHeight < 15);
180
- eventDiv.classList.toggle("small", eventDiv.offsetHeight < 45);
158
+ this.drag(this.dragEvent.current.event);
181
159
  }
182
160
 
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
161
 
194
- minutes = minutes < 10 ? '0' + minutes : minutes;
195
- return hours + ':' + minutes + ' ' + ampm;
162
+ insertTimestampAbove() {
196
163
  }
197
164
 
198
- #durationString(startTime, endTime) {
199
- return `${this.#timeString(startTime)} - ${this.#timeString(endTime)}`;
165
+ insertTimestampBelow() {
166
+ // this.dragEvent.inserting = true;
167
+ // Add 1 hour
168
+ let time = new Date(this.timeKeeper.endTime.getTime());
169
+ time.setHours(time.getHours() + 1);
170
+ this.timeKeeper.endTime = time;
171
+ let timestampDiv = TimeTableRenderer.timestamp(time);
172
+ this.element.querySelector(".timestamps").appendChild(timestampDiv);
200
173
  }
201
174
 
202
175
  ////////////////
@@ -204,6 +177,10 @@ export default class extends Controller {
204
177
  ////////////////
205
178
 
206
179
  #invokeDragMethodFor(type) {
180
+ if(!type) {
181
+ console.error("No drag type provided");
182
+ return;
183
+ }
207
184
  let capitalizedType = type.charAt(0).toUpperCase() + type.slice(1);
208
185
 
209
186
  if (this[`drag${capitalizedType}`]) {
@@ -217,15 +194,6 @@ export default class extends Controller {
217
194
  // Helpers //
218
195
  /////////////
219
196
 
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
197
  #setDragEventListeners() {
230
198
  document.addEventListener("mousemove", this.drag.bind(this));
231
199
  document.addEventListener("mouseup", this.stopDragEvent.bind(this));