time_table 0.1.4 → 0.1.6
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/index.js +1 -1
- data/app/assets/javascript/time_table/controllers/time_table_controller_old.js +105 -464
- data/app/assets/javascript/time_table/controllers/{time_table_controller.js → timetable_controller.js} +122 -29
- data/app/assets/javascript/time_table/helpers/drag_event_state.js +11 -2
- data/app/assets/javascript/time_table/helpers/time_table_renderer.js +36 -25
- data/app/assets/stylesheets/time_table/timetable.css +143 -0
- data/app/helpers/time_table/{time_table_helper.rb → time_table_old_helper.rb} +19 -6
- data/app/helpers/time_table/timetable_calendar_helper.rb +206 -0
- data/app/views/time_table/{_time_table.html.erb → _time_table_old.html.erb} +2 -7
- data/app/views/time_table/_timetable.html.erb +49 -0
- data/lib/time_table/version.rb +1 -1
- metadata +8 -7
- data/app/assets/javascript/time_table/controllers/time_table_controller_pre_time_keeper.js +0 -350
- data/app/assets/stylesheets/time_table/time_table.css +0 -136
@@ -5,9 +5,19 @@ import DragEventState from "../helpers/drag_event_state.js"
|
|
5
5
|
import TimeTableRenderer from "../helpers/time_table_renderer.js"
|
6
6
|
|
7
7
|
export default class extends Controller {
|
8
|
-
static targets = ["canvas", "eventsList", "event", "eventName", "eventTime", "timestamp"]
|
8
|
+
// static targets = ["canvas", "eventsList", "event", "eventName", "eventTime", "timestamp", "template"]
|
9
|
+
|
10
|
+
static targets = ["event", "template", "eventsList", "eventActionMenu"]
|
9
11
|
|
10
12
|
connect() {
|
13
|
+
this.renderer = new TimeTableRenderer(this.templateTarget);
|
14
|
+
this.eventTargets.forEach((event) => {
|
15
|
+
this.renderer.setSpecialClasses(event);
|
16
|
+
});
|
17
|
+
|
18
|
+
// A little hacky
|
19
|
+
this.element.classList.remove("loading");
|
20
|
+
|
11
21
|
this.timeKeeper = new TimeKeeper({
|
12
22
|
start: new Date(this.element.dataset.timetableStartTime),
|
13
23
|
end: new Date(this.element.dataset.timetableEndTime),
|
@@ -21,21 +31,33 @@ export default class extends Controller {
|
|
21
31
|
this.scrollFrame = new ScrollFrame(this.element, { origin: topPadding });
|
22
32
|
|
23
33
|
this.dragEvent = null;
|
34
|
+
}
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
|
36
|
+
changeColumn(event) {
|
37
|
+
if(this.dragEvent && this.dragEvent.type == "move") {
|
38
|
+
let currentEvent = this.dragEvent.target;
|
39
|
+
this.dragEvent.column = event.currentTarget.closest(".column");
|
40
|
+
this.dragEvent.date = event.params.column
|
41
|
+
// TODO: Change query method
|
42
|
+
this.dragEvent.column.querySelector(".timetable-events").appendChild(currentEvent);
|
43
|
+
}
|
28
44
|
}
|
29
45
|
|
30
46
|
startDragEvent(event) {
|
31
47
|
event.preventDefault();
|
32
48
|
event.stopPropagation();
|
33
49
|
|
50
|
+
if(event.params.dragEvent != "rescale" && this.element.dataset.timetableFrozenParam == "true") {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
34
54
|
this.dragEvent = new DragEventState({
|
55
|
+
date: event.params.column || event.target.closest(".column").dataset.timetableColumnParam,
|
35
56
|
type: event.params.dragEvent,
|
36
57
|
scrollFrame: this.scrollFrame,
|
37
58
|
timeKeeper: this.timeKeeper,
|
38
|
-
target: event.currentTarget.closest(".event")
|
59
|
+
target: event.currentTarget.closest(".event"),
|
60
|
+
column: event.currentTarget.closest(".column")
|
39
61
|
});
|
40
62
|
|
41
63
|
this.dragEvent.captureOriginSnapshot(event);
|
@@ -46,8 +68,21 @@ export default class extends Controller {
|
|
46
68
|
drag(event) {
|
47
69
|
if(this.dragEvent) {
|
48
70
|
|
71
|
+
if(this.dragEvent.prevent) {
|
72
|
+
this.dragEvent = null;
|
73
|
+
return;
|
74
|
+
}
|
75
|
+
|
49
76
|
this.dragEvent.captureSnapshot(event);
|
77
|
+
if(this.dragEvent.current.realTime - this.dragEvent.origin.realTime < 100) {
|
78
|
+
return;
|
79
|
+
}
|
50
80
|
|
81
|
+
// HACKY
|
82
|
+
this.dragEvent.dragging = true;
|
83
|
+
if(this.dragEvent.type != "create" && this.dragEvent.target) {
|
84
|
+
this.#dispatchDragClick(this.dragEvent.target);
|
85
|
+
}
|
51
86
|
// Calls dragResize, dragMove, dragCreate, etc.
|
52
87
|
this.#invokeDragMethodFor(this.dragEvent.type);
|
53
88
|
|
@@ -59,6 +94,27 @@ export default class extends Controller {
|
|
59
94
|
|
60
95
|
stopDragEvent(event) {
|
61
96
|
event.preventDefault();
|
97
|
+
event.stopPropagation();
|
98
|
+
|
99
|
+
// HACK - Should come up with system of determining form target to submit (ADD CREATE CHECK TO DELETE UNSET EVENT HERE)
|
100
|
+
if(this.dragEvent && (this.dragEvent.type == "move" || this.dragEvent.type == "resize") && this.dragEvent.origin.type != "create") {
|
101
|
+
if(Math.abs(this.dragEvent.origin.time.real - this.dragEvent.current.time.real) > 100 || this.dragEvent.origin.column != this.dragEvent.current.column) {
|
102
|
+
console.log("Submitting form");
|
103
|
+
let form = this.dragEvent.target.querySelector(".calendar-event-form");
|
104
|
+
form.requestSubmit();
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
if(this.dragEvent && !this.dragEvent.dragging && this.dragEvent.target) {
|
109
|
+
this.#dispatchStillClick(this.dragEvent.target)
|
110
|
+
}
|
111
|
+
|
112
|
+
if(this.dragEvent && this.dragEvent.origin.type == "create" && this.dragEvent.previous) {
|
113
|
+
let target = this.dragEvent.target;
|
114
|
+
setTimeout(() => {
|
115
|
+
this.#dispatchStillClick(target);
|
116
|
+
}, 100);
|
117
|
+
}
|
62
118
|
|
63
119
|
this.dragEvent = null;
|
64
120
|
|
@@ -66,6 +122,12 @@ export default class extends Controller {
|
|
66
122
|
this.#removeDragEventListeners();
|
67
123
|
}
|
68
124
|
|
125
|
+
preventDragEvent(event) {
|
126
|
+
event.stopPropagation();
|
127
|
+
if(this.dragEvent) {
|
128
|
+
this.dragEvent.prevent = true;
|
129
|
+
}
|
130
|
+
}
|
69
131
|
|
70
132
|
//////////////////
|
71
133
|
// Drag Methods //
|
@@ -73,17 +135,23 @@ export default class extends Controller {
|
|
73
135
|
|
74
136
|
dragCreate(event) {
|
75
137
|
let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.time.clipped);
|
76
|
-
|
138
|
+
|
139
|
+
let eventElement = this.renderer.createEventElement(this.dragEvent.date, timeBoundaries);
|
77
140
|
|
78
141
|
this.eventsListTarget.appendChild(eventElement);
|
79
142
|
|
143
|
+
// Come up with better way to select events list, maybe remove child div all together
|
144
|
+
this.dragEvent.column.querySelector(".timetable-events").appendChild(eventElement);
|
145
|
+
// this.eventsListTarget
|
146
|
+
|
80
147
|
this.dragEvent.shift({ type: "resize", target: eventElement });
|
81
148
|
this.handleOverlap(eventElement);
|
82
149
|
}
|
83
150
|
|
84
151
|
dragResize(event) {
|
85
152
|
let timeBoundaries = this.timeKeeper.timeBoundaries(this.dragEvent.current.time.clipped, this.dragEvent.origin.target.startTime.real);
|
86
|
-
|
153
|
+
|
154
|
+
this.renderer.updateEventElement(this.dragEvent.target, this.dragEvent.date, timeBoundaries);
|
87
155
|
this.handleOverlap(this.dragEvent.target);
|
88
156
|
}
|
89
157
|
|
@@ -94,7 +162,7 @@ export default class extends Controller {
|
|
94
162
|
|
95
163
|
let timeBoundaries = this.timeKeeper.timeBoundaries(updatedStartTime, updatedEndTime);
|
96
164
|
|
97
|
-
|
165
|
+
this.renderer.updateEventElement(this.dragEvent.target, this.dragEvent.date, timeBoundaries);
|
98
166
|
this.handleOverlap(this.dragEvent.target);
|
99
167
|
}
|
100
168
|
|
@@ -109,31 +177,31 @@ export default class extends Controller {
|
|
109
177
|
this.eventTargets.forEach((event) => {
|
110
178
|
event.style.setProperty("height", `${event.offsetHeight * (scaleChange)}px`);
|
111
179
|
event.style.setProperty("top", `${event.offsetTop * (scaleChange)}px`);
|
112
|
-
|
180
|
+
this.renderer.setSpecialClasses(event);
|
113
181
|
});
|
114
182
|
}
|
115
183
|
|
116
184
|
handleOverlap(element) {
|
117
185
|
let eventTop = element.offsetTop;
|
118
186
|
let eventBottom = eventTop + element.offsetHeight;
|
119
|
-
|
120
|
-
this.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
});
|
187
|
+
// TODO: Change query method
|
188
|
+
// this.dragEvent.column.querySelector(".timetable-events").querySelectorAll(".event").forEach((event) => {
|
189
|
+
// if(event != element) {
|
190
|
+
// let top = event.offsetTop;
|
191
|
+
// let bottom = top + event.offsetHeight;
|
192
|
+
|
193
|
+
// if(eventTop >= top && eventBottom <= bottom) {
|
194
|
+
// element.style.setProperty("left", "50px");
|
195
|
+
// event.style.setProperty("right", "20px");
|
196
|
+
// } else if(eventTop < bottom && eventBottom > top) {
|
197
|
+
// element.style.setProperty("left", "50%");
|
198
|
+
// event.style.setProperty("right", "50%");
|
199
|
+
// } else {
|
200
|
+
// element.style.setProperty("left", "50px");
|
201
|
+
// event.style.setProperty("right", "20px");
|
202
|
+
// }
|
203
|
+
// }
|
204
|
+
// });
|
137
205
|
}
|
138
206
|
|
139
207
|
|
@@ -143,6 +211,7 @@ export default class extends Controller {
|
|
143
211
|
////////////////////
|
144
212
|
|
145
213
|
handleScroll(status) {
|
214
|
+
console.log("SHOULD BE SCROLLING");
|
146
215
|
if(status == "ABOVE") {
|
147
216
|
console.log("ABOVE");
|
148
217
|
this.insertTimestampAbove();
|
@@ -164,7 +233,7 @@ export default class extends Controller {
|
|
164
233
|
let time = new Date(this.timeKeeper.endTime.getTime());
|
165
234
|
time.setHours(time.getHours() + 1);
|
166
235
|
this.timeKeeper.endTime = time;
|
167
|
-
let timestampDiv =
|
236
|
+
let timestampDiv = this.renderer.timestamp(time);
|
168
237
|
this.element.querySelector(".timestamps").appendChild(timestampDiv);
|
169
238
|
}
|
170
239
|
|
@@ -181,7 +250,7 @@ export default class extends Controller {
|
|
181
250
|
|
182
251
|
if (this[`drag${capitalizedType}`]) {
|
183
252
|
this[`drag${capitalizedType}`]();
|
184
|
-
} else {
|
253
|
+
} else {
|
185
254
|
console.error(`No drag method found for type: ${type}`);
|
186
255
|
}
|
187
256
|
}
|
@@ -190,6 +259,30 @@ export default class extends Controller {
|
|
190
259
|
// Helpers //
|
191
260
|
/////////////
|
192
261
|
|
262
|
+
#dispatchStillClick(target) {
|
263
|
+
target.dispatchEvent(this.#stillClickEvent());
|
264
|
+
}
|
265
|
+
|
266
|
+
#stillClickEvent() {
|
267
|
+
return new CustomEvent("still:click", {
|
268
|
+
detail: {
|
269
|
+
dragEvent: this.dragEvent
|
270
|
+
}
|
271
|
+
})
|
272
|
+
}
|
273
|
+
|
274
|
+
#dispatchDragClick(target) {
|
275
|
+
target.dispatchEvent(this.#dragClickEvent());
|
276
|
+
}
|
277
|
+
|
278
|
+
#dragClickEvent() {
|
279
|
+
return new CustomEvent("drag:click", {
|
280
|
+
detail: {
|
281
|
+
dragEvent: this.dragEvent
|
282
|
+
}
|
283
|
+
})
|
284
|
+
}
|
285
|
+
|
193
286
|
#setDragEventListeners() {
|
194
287
|
document.addEventListener("mousemove", this.drag.bind(this));
|
195
288
|
document.addEventListener("mouseup", this.stopDragEvent.bind(this));
|
@@ -1,9 +1,13 @@
|
|
1
1
|
export default class DragEventState {
|
2
|
-
constructor({ type, scrollFrame, timeKeeper, target }) {
|
2
|
+
constructor({ type, scrollFrame, timeKeeper, target, column, prevent = false, date }) {
|
3
3
|
this.type = type;
|
4
4
|
this.scrollFrame = scrollFrame;
|
5
5
|
this.timeKeeper = timeKeeper;
|
6
6
|
this.target = target;
|
7
|
+
// TODO: Reconsider this
|
8
|
+
this.column = column;
|
9
|
+
this.date = date;
|
10
|
+
this.prevent = prevent; // Kinda hacky
|
7
11
|
}
|
8
12
|
|
9
13
|
captureOriginSnapshot(event) {
|
@@ -27,12 +31,17 @@ export default class DragEventState {
|
|
27
31
|
let relativePosition = this.scrollFrame.relativeCursorPosition(event);
|
28
32
|
return {
|
29
33
|
event: event,
|
34
|
+
type: this.type,
|
35
|
+
date: this.date,
|
30
36
|
position: relativePosition,
|
31
37
|
time: this.timeKeeper.timeAtPosition(relativePosition.scroll.y),
|
32
|
-
|
38
|
+
column: this.column,
|
39
|
+
target: this.targetSnapshot(this.target),
|
40
|
+
realTime: new Date(),
|
33
41
|
}
|
34
42
|
}
|
35
43
|
|
44
|
+
// Probably want to add column here
|
36
45
|
targetSnapshot(target) {
|
37
46
|
if(!target) {
|
38
47
|
return null;
|
@@ -1,28 +1,29 @@
|
|
1
|
-
class TimeTableRenderer {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
element.classList.add("event");
|
6
|
-
element.setAttribute("data-time-table-target", "event");
|
7
|
-
element.setAttribute("data-action", "mousedown->time-table#startDragEvent");
|
8
|
-
element.setAttribute("data-time-table-drag-event-param", "move");
|
9
|
-
|
10
|
-
element.innerHTML = `
|
11
|
-
<div class="event-name"><span style="font-weight: 400; color: gray;">(No Title)</span></div>
|
12
|
-
<div class="event-time" data-action="mousedown->time-table#startDragEvent" data-time-table-drag-event-param="resize">
|
13
|
-
${ this.#durationString(start.time, end.time) }
|
14
|
-
</div>
|
15
|
-
`;
|
16
|
-
|
17
|
-
this.updateEventElement(element, {start, end});
|
1
|
+
export default class TimeTableRenderer {
|
2
|
+
constructor(template) {
|
3
|
+
this.template = template;
|
4
|
+
}
|
18
5
|
|
6
|
+
createEventElement(date, {start, end}) {
|
7
|
+
const element = this.template.content.cloneNode(true).firstElementChild;
|
8
|
+
this.updateEventElement(element, date, {start, end});
|
19
9
|
return element;
|
20
10
|
}
|
21
11
|
|
22
|
-
|
12
|
+
// TODO: Move all app specific logic to rails app
|
13
|
+
// Should move updater to a delegate controller in rails app, maybe creater to
|
14
|
+
updateEventElement(element, date, {start, end}) {
|
23
15
|
element.style.setProperty("top", `${start.location}px`);
|
24
16
|
element.style.setProperty("height", `${end.location - start.location}px`);
|
25
17
|
|
18
|
+
let form = element.querySelector(".calendar-event-form");
|
19
|
+
// This shouldn't happen here
|
20
|
+
if(form.querySelector("#event_date_string")) {
|
21
|
+
form.querySelector("#event_date_string").setAttribute("value", date);
|
22
|
+
form.querySelector("#event_date_string").dispatchEvent(new CustomEvent("value:change", { bubbles: true, detail: { value: date }}));
|
23
|
+
}
|
24
|
+
form.querySelector("#event_start_time").value = this.getMilitaryTime(start.time);
|
25
|
+
form.querySelector("#event_end_time").value = this.getMilitaryTime(end.time);
|
26
|
+
|
26
27
|
this.setSpecialClasses(element);
|
27
28
|
|
28
29
|
element.querySelector(".event-time").innerHTML = this.#durationString(start.time, end.time);
|
@@ -30,16 +31,24 @@ class TimeTableRenderer {
|
|
30
31
|
return element;
|
31
32
|
}
|
32
33
|
|
34
|
+
getMilitaryTime(date) {
|
35
|
+
let hours = date.getUTCHours();
|
36
|
+
let minutes = date.getUTCMinutes();
|
37
|
+
minutes = minutes < 10 ? '0' + minutes : minutes; // Ensure two-digit minutes
|
38
|
+
hours = hours < 10 ? '0' + hours : hours; // Ensure two-digit hours
|
39
|
+
return `${hours}:${minutes}`;
|
40
|
+
}
|
41
|
+
|
33
42
|
timestamp(time) {
|
34
43
|
let timestampeElement = document.createElement("div");
|
35
44
|
timestampeElement.classList.add("timestamp");
|
36
45
|
timestampeElement.classList.add("out-of-bounds");
|
37
|
-
timestampeElement.setAttribute("data-
|
38
|
-
timestampeElement.setAttribute("data-action", "mousedown->
|
39
|
-
timestampeElement.setAttribute("data-
|
46
|
+
timestampeElement.setAttribute("data-timetable-target", "timestamp");
|
47
|
+
timestampeElement.setAttribute("data-action", "mousedown->timetable#startDragEvent");
|
48
|
+
timestampeElement.setAttribute("data-timetable-drag-event-param", "rescale");
|
40
49
|
|
41
50
|
timestampeElement.innerHTML = `
|
42
|
-
<div class="label" data-action="mousedown->
|
51
|
+
<div class="label" data-action="mousedown->timetable#startDragEvent" data-timetable-drag-event-param="rescale">
|
43
52
|
${this.#timeString(time, "short")}
|
44
53
|
</div>
|
45
54
|
`;
|
@@ -48,8 +57,10 @@ class TimeTableRenderer {
|
|
48
57
|
}
|
49
58
|
|
50
59
|
setSpecialClasses(element) {
|
51
|
-
element.classList.toggle("
|
52
|
-
element.classList.toggle("
|
60
|
+
element.classList.toggle("no-content", element.offsetHeight < 15);
|
61
|
+
element.classList.toggle("tiny", element.offsetHeight < 30);
|
62
|
+
element.classList.toggle("mini", element.offsetHeight < 45);
|
63
|
+
element.classList.toggle("small", element.offsetHeight < 75);
|
53
64
|
}
|
54
65
|
|
55
66
|
#timeString(date, format = "long") {
|
@@ -72,4 +83,4 @@ class TimeTableRenderer {
|
|
72
83
|
}
|
73
84
|
}
|
74
85
|
|
75
|
-
export default new TimeTableRenderer();
|
86
|
+
// export default new TimeTableRenderer();
|
@@ -0,0 +1,143 @@
|
|
1
|
+
.timetable {
|
2
|
+
position: relative;
|
3
|
+
height: fit-content;
|
4
|
+
overflow: visible;
|
5
|
+
display: grid;
|
6
|
+
}
|
7
|
+
|
8
|
+
.timetable-calendar .timetable {
|
9
|
+
height: 100%;
|
10
|
+
}
|
11
|
+
|
12
|
+
.timetable > * {
|
13
|
+
grid-column: 1;
|
14
|
+
grid-row: 1;
|
15
|
+
}
|
16
|
+
|
17
|
+
.timetable-canvas {
|
18
|
+
height: calc(100%);
|
19
|
+
flex-grow: 1;
|
20
|
+
position: relative;
|
21
|
+
z-index: 1;
|
22
|
+
}
|
23
|
+
|
24
|
+
.timetable-column {
|
25
|
+
border-left: 1px solid var(--backdrop-5);
|
26
|
+
height: 100%;
|
27
|
+
}
|
28
|
+
|
29
|
+
.timetable-events {
|
30
|
+
width: 100%;
|
31
|
+
position: relative;
|
32
|
+
}
|
33
|
+
|
34
|
+
/**************/
|
35
|
+
/* Timestamps */
|
36
|
+
/**************/
|
37
|
+
|
38
|
+
.timetable .timestamps {
|
39
|
+
z-index: 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
.timetable .timestamp {
|
43
|
+
font-size: 0.8em;
|
44
|
+
width: 100%;
|
45
|
+
position: relative;
|
46
|
+
height: calc(var(--hour-scale) * 1px);
|
47
|
+
overflow: visible;
|
48
|
+
}
|
49
|
+
|
50
|
+
.timetable .timestamp.out-of-bounds {
|
51
|
+
color: rgb(168, 167, 167);
|
52
|
+
}
|
53
|
+
|
54
|
+
.timetable .timestamp .label {
|
55
|
+
margin-top: -0.5em;
|
56
|
+
height: 100%;
|
57
|
+
width: fit-content;
|
58
|
+
z-index: 5;
|
59
|
+
width: 45px !important;
|
60
|
+
text-align: right;
|
61
|
+
padding-right: 5px;
|
62
|
+
}
|
63
|
+
|
64
|
+
.timetable .timestamp .label:hover {
|
65
|
+
cursor: ns-resize;
|
66
|
+
}
|
67
|
+
|
68
|
+
.timetable .timestamp::before {
|
69
|
+
content: "";
|
70
|
+
position: absolute;
|
71
|
+
right: 0;
|
72
|
+
left: 45px;
|
73
|
+
height: 1px;
|
74
|
+
background-color: var(--backdrop-7);
|
75
|
+
opacity: 0.5;
|
76
|
+
}
|
77
|
+
|
78
|
+
/************/
|
79
|
+
/* Calendar */
|
80
|
+
/************/
|
81
|
+
|
82
|
+
.timetable-calendar .timetable-headers,
|
83
|
+
.timetable-calendar .timetable-canvas {
|
84
|
+
margin-left: 45px;
|
85
|
+
display: flex;
|
86
|
+
flex-direction: row;
|
87
|
+
}
|
88
|
+
|
89
|
+
.timetable-calendar .timetable-header,
|
90
|
+
.timetable-calendar .timetable-column {
|
91
|
+
flex: 1 1 0 !important;
|
92
|
+
/* overflow: hidden; */
|
93
|
+
}
|
94
|
+
|
95
|
+
.timetable-calendar .timetable-header {
|
96
|
+
display: flex;
|
97
|
+
flex-direction: column;
|
98
|
+
justify-content: center;
|
99
|
+
}
|
100
|
+
|
101
|
+
.timetable-calendar .timetable-header:only-child {
|
102
|
+
align-items: flex-start;
|
103
|
+
}
|
104
|
+
|
105
|
+
/*********/
|
106
|
+
/* SKINS */
|
107
|
+
/*********/
|
108
|
+
|
109
|
+
.timetable-column {
|
110
|
+
display: grid;
|
111
|
+
}
|
112
|
+
|
113
|
+
.timetable-column > * {
|
114
|
+
grid-area: 1 / -1 / 1 / -1; /* Span the single column */
|
115
|
+
width: 100%; /* Ensure full width */
|
116
|
+
}
|
117
|
+
|
118
|
+
.timetable-skins {
|
119
|
+
width: 100%;
|
120
|
+
position: relative;
|
121
|
+
}
|
122
|
+
|
123
|
+
.timetable-skin {
|
124
|
+
width: 100%;
|
125
|
+
background-color: var(--backdrop-3);
|
126
|
+
position: absolute;
|
127
|
+
right: 0;
|
128
|
+
left: 0;
|
129
|
+
opacity: 0.5;
|
130
|
+
}
|
131
|
+
|
132
|
+
/* .timetable-skin:hover { */
|
133
|
+
/* background-color: var(--backdrop-5); */
|
134
|
+
/* opacity: 0.5; */
|
135
|
+
/* } */
|
136
|
+
|
137
|
+
.timetable-events {
|
138
|
+
pointer-events: none;
|
139
|
+
}
|
140
|
+
|
141
|
+
.timetable-events > * {
|
142
|
+
pointer-events: auto;
|
143
|
+
}
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module TimeTable
|
2
|
-
module
|
3
|
-
def time_table(date = nil, scale: 60, events: [], clip: 15, &block)
|
2
|
+
module TimeTableOldHelper
|
3
|
+
def time_table(date = nil, frozen: false, scale: 60, events: [], clip: 15, &block)
|
4
4
|
# @time_table = TimeTable.new
|
5
5
|
# @time_table.scale = scale
|
6
|
-
timetable =
|
7
|
-
render "time_table/time_table", timetable: timetable,
|
6
|
+
timetable = TimeTable.new(date, scale: scale, clip_size: clip, frozen: frozen, events: events, view: self,)
|
7
|
+
render "time_table/time_table", timetable: timetable, &block
|
8
8
|
end
|
9
9
|
|
10
10
|
def hours_in_day
|
11
11
|
end
|
12
12
|
|
13
13
|
|
14
|
-
class
|
15
|
-
attr_accessor :start_time, :end_time, :segment_size, :segment_scale, :clip_size, :clock_type
|
14
|
+
class TimeTable
|
15
|
+
attr_accessor :start_time, :end_time, :segment_size, :segment_scale, :clip_size, :clock_type, :frozen, :events
|
16
16
|
|
17
17
|
def initialize(date = nil, **options)
|
18
18
|
@start_time = options[:start_time] || 0
|
@@ -23,6 +23,9 @@ module TimeTable
|
|
23
23
|
@segment_scale = options[:scale] || 100
|
24
24
|
@clip_size = options[:clip_size] || 15
|
25
25
|
@clock_type = options[:clock_type] || :meridian
|
26
|
+
@frozen = options[:frozen] || false
|
27
|
+
@events = options[:events] || []
|
28
|
+
@view = options[:view] || nil
|
26
29
|
end
|
27
30
|
|
28
31
|
def segments
|
@@ -35,6 +38,16 @@ module TimeTable
|
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
41
|
+
def render_events
|
42
|
+
@view.content_tag :div, class: "timetable-canvas", data: { time_table_target: "canvas" } do
|
43
|
+
@view.content_tag :div, class: "timetable-events", data: { time_table_target: "eventsList" } do
|
44
|
+
events.each do |event|
|
45
|
+
yield event
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
def time_in_meridian(time)
|
39
52
|
hour = time / 60
|
40
53
|
minute = time % 60
|