@kendawson-online/vantl 2.0.0
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.
- package/LICENSE +24 -0
- package/README.md +468 -0
- package/dist/timeline.min.js +2 -0
- package/dist/timeline.min.js.map +1 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Original version: Copyright © 2018 Mike Collins (squarechip)
|
|
4
|
+
|
|
5
|
+
Updated version: Copyright © 2026 Ken Dawson (kendawson-online)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# Vanilla JS Timeline
|
|
2
|
+
|
|
3
|
+
A vanilla JavaScript app to create responsive horizontal and vertical timelines.
|
|
4
|
+
|
|
5
|
+
Supports jQuery, external JSON configuration, color theming, HTML support, node images, and deep-linking via URL. Inspired by [timeline](https://github.com/squarechip/timeline) originally created by [Mike Collins](https://github.com/squarechip) in 2018.
|
|
6
|
+
|
|
7
|
+
[Link to Screenshot]
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
#### 🔘 Create / load data via three methods (see Examples)
|
|
14
|
+
- Directly via API using Javascript (e.g. jQuery)
|
|
15
|
+
- Inline in HTML page using data-attributes
|
|
16
|
+
- Externally via JSON configuration file
|
|
17
|
+
|
|
18
|
+
#### 🔘 Library agnostic. If jQuery is present it will register itself as a plugin.
|
|
19
|
+
|
|
20
|
+
#### 🔘 Color customization for nodes, timeline, and navigation buttons
|
|
21
|
+
|
|
22
|
+
#### 🔘 Image support (per-node) with fluid sizing
|
|
23
|
+
|
|
24
|
+
#### 🔘 Deep link to specific nodes via URL parameters
|
|
25
|
+
|
|
26
|
+
#### 🔘 Allows multiple independent timelines on a single page
|
|
27
|
+
|
|
28
|
+
#### 🔘 Auto-initialization when using JSON config
|
|
29
|
+
|
|
30
|
+
#### 🔘 Caches JSON data to local storage for faster loading
|
|
31
|
+
|
|
32
|
+
#### 🔘 Responsive layout switches based on screen size
|
|
33
|
+
|
|
34
|
+
#### 🔘 Small file size
|
|
35
|
+
|
|
36
|
+
<br/>
|
|
37
|
+
|
|
38
|
+
### Examples:
|
|
39
|
+
|
|
40
|
+
- Using Javascript (jQuery):
|
|
41
|
+
[Horizontal](#) | [Vertical](#)
|
|
42
|
+
- Using Inline HTML:
|
|
43
|
+
[Horizontal Layout](#) | [Vertical Layout](#)
|
|
44
|
+
- Using External JSON data:
|
|
45
|
+
[Horizontal Layout](#) | [Vertical Layout](#)
|
|
46
|
+
- Deep Linking to Nodes:
|
|
47
|
+
[Horizontal Layout](#) | [Vertical Layout](#)
|
|
48
|
+
- Using Multiple Timelines On A Page:
|
|
49
|
+
[Horizontal Layout](#) | [Vertical Layout](#)
|
|
50
|
+
|
|
51
|
+
<br/>
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Include required files in your page
|
|
56
|
+
- Download code and load files locally:
|
|
57
|
+
```html
|
|
58
|
+
<html>
|
|
59
|
+
<head>
|
|
60
|
+
<link href="src/css/timeline.css" rel="stylesheet" />
|
|
61
|
+
</head>
|
|
62
|
+
<body>
|
|
63
|
+
<!-- [ timeline code goes here ] -->
|
|
64
|
+
<script src="src/js/timeline.js"></script>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
67
|
+
```
|
|
68
|
+
- Load files via CDN links:
|
|
69
|
+
````html
|
|
70
|
+
<html>
|
|
71
|
+
<head>
|
|
72
|
+
<link href="https://cdn.jsdelivr.net/gh/kendawson-online/vanillajs-timeline/src/css/timeline.css" rel="stylesheet">
|
|
73
|
+
</head>
|
|
74
|
+
<body>
|
|
75
|
+
<!-- [ timeline code goes here ] -->
|
|
76
|
+
<script src="https://cdn.jsdelivr.net/gh/kendawson-online/vanillajs-timeline/src/js/timeline.js"></script>
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
79
|
+
````
|
|
80
|
+
|
|
81
|
+
### 2. Choose a creation method
|
|
82
|
+
- Javascript API (e.g. jQuery)
|
|
83
|
+
- Inline HTML data-attributes
|
|
84
|
+
- External JSON configuration file
|
|
85
|
+
|
|
86
|
+
### 3. Add timeline data
|
|
87
|
+
- If you are using the vanilla JS/Jquery or data-attributes method, you need to add your timeline node data via regular HTML. If you are using the JSON method you can skip this step.
|
|
88
|
+
|
|
89
|
+
````html
|
|
90
|
+
<div class="timeline">
|
|
91
|
+
<div class="timeline__wrap">
|
|
92
|
+
<div class="timeline__items">
|
|
93
|
+
<div class="timeline__item">
|
|
94
|
+
<div class="timeline__content">
|
|
95
|
+
Content / markup here
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="timeline__item">
|
|
99
|
+
<div class="timeline__content">
|
|
100
|
+
Content / markup here
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="timeline__item">
|
|
104
|
+
<div class="timeline__content">
|
|
105
|
+
Content / markup here
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="timeline__item">
|
|
109
|
+
<div class="timeline__content">
|
|
110
|
+
Content / markup here
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="timeline__item">
|
|
114
|
+
<div class="timeline__content">
|
|
115
|
+
Content / markup here
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
````
|
|
122
|
+
|
|
123
|
+
- Add timeline nodes via [JSON config](demo/assets/data/sample1.json) file
|
|
124
|
+
|
|
125
|
+
[Add More Explaination Text Here]
|
|
126
|
+
|
|
127
|
+
- [Convert CSV or Spreadsheet](#) file to JSON [Link to server tool]
|
|
128
|
+
|
|
129
|
+
[Add More Explaination Text Here]
|
|
130
|
+
|
|
131
|
+
### 4. Initialize the app
|
|
132
|
+
- Using vanilla Javascript
|
|
133
|
+
````javascript
|
|
134
|
+
timeline(document.querySelectorAll('.timeline'));
|
|
135
|
+
````
|
|
136
|
+
- Using jQuery
|
|
137
|
+
````javascript
|
|
138
|
+
jQuery('.timeline').timeline();
|
|
139
|
+
````
|
|
140
|
+
|
|
141
|
+
<br/><br/>
|
|
142
|
+
|
|
143
|
+
**NOTE: if you're using an external JSON file, you can skip step four. You don't have to manually initialize the app. Loading the JSON file automatically initializes the app for you.**
|
|
144
|
+
|
|
145
|
+
<br/>
|
|
146
|
+
|
|
147
|
+
### Javascript API and data-attributes:
|
|
148
|
+
|
|
149
|
+
1. Using data-attributes will take priority over settings via the API.
|
|
150
|
+
|
|
151
|
+
2. Using an external JSON file will take priority over data-attributes and/or API settings.
|
|
152
|
+
|
|
153
|
+
<br/><br/>
|
|
154
|
+
|
|
155
|
+
# API Options:
|
|
156
|
+
|
|
157
|
+
<br/>
|
|
158
|
+
|
|
159
|
+
`mode`
|
|
160
|
+
|
|
161
|
+
**Choose whether the timeline should be vertical or horizontal**
|
|
162
|
+
|
|
163
|
+
JavaScript/jQuery
|
|
164
|
+
````js
|
|
165
|
+
default: 'vertical'
|
|
166
|
+
options: 'vertical', 'horizontal'
|
|
167
|
+
````
|
|
168
|
+
|
|
169
|
+
Data attribute
|
|
170
|
+
````html
|
|
171
|
+
<div class="timeline" data-mode="horizontal">
|
|
172
|
+
...
|
|
173
|
+
</div>
|
|
174
|
+
````
|
|
175
|
+
|
|
176
|
+
<br />
|
|
177
|
+
|
|
178
|
+
------
|
|
179
|
+
|
|
180
|
+
<br />
|
|
181
|
+
|
|
182
|
+
`minWidth`
|
|
183
|
+
|
|
184
|
+
**When using the timeline in horizontal mode, define the minimum viewport width (px) to stay horizontal; below this it becomes vertical/mobile**
|
|
185
|
+
|
|
186
|
+
JavaScript/jQuery
|
|
187
|
+
````javascript
|
|
188
|
+
default: 600
|
|
189
|
+
options: integer
|
|
190
|
+
````
|
|
191
|
+
|
|
192
|
+
Data attribute
|
|
193
|
+
````html
|
|
194
|
+
<div class="timeline" data-minwidth="600">
|
|
195
|
+
...
|
|
196
|
+
</div>
|
|
197
|
+
````
|
|
198
|
+
|
|
199
|
+
Notes:
|
|
200
|
+
- Backwards compatibility: legacy `forceVerticalMode` (JS) and `data-force-vertical-mode` (HTML) are still accepted.
|
|
201
|
+
|
|
202
|
+
<br />
|
|
203
|
+
|
|
204
|
+
------
|
|
205
|
+
|
|
206
|
+
<br />
|
|
207
|
+
|
|
208
|
+
`horizontalStartPosition`
|
|
209
|
+
|
|
210
|
+
**When using the timeline in horizontal mode, define the vertical alignment of the first item**
|
|
211
|
+
|
|
212
|
+
JavaScript/jQuery
|
|
213
|
+
````javascript
|
|
214
|
+
default: 'top'
|
|
215
|
+
options: 'bottom', 'top'
|
|
216
|
+
````
|
|
217
|
+
|
|
218
|
+
Data attribute
|
|
219
|
+
````html
|
|
220
|
+
<div class="timeline" data-horizontal-start-position="top">
|
|
221
|
+
...
|
|
222
|
+
</div>
|
|
223
|
+
````
|
|
224
|
+
|
|
225
|
+
<br />
|
|
226
|
+
|
|
227
|
+
------
|
|
228
|
+
|
|
229
|
+
<br />
|
|
230
|
+
|
|
231
|
+
`moveItems`
|
|
232
|
+
|
|
233
|
+
**When using the timeline in horizontal mode, define how many items to move when clicking a navigation button**
|
|
234
|
+
|
|
235
|
+
JavaScript/jQuery
|
|
236
|
+
````javascript
|
|
237
|
+
default: 1
|
|
238
|
+
options: integer
|
|
239
|
+
````
|
|
240
|
+
|
|
241
|
+
Data attribute
|
|
242
|
+
````html
|
|
243
|
+
<div class="timeline" data-move-items="1">
|
|
244
|
+
...
|
|
245
|
+
</div>
|
|
246
|
+
````
|
|
247
|
+
|
|
248
|
+
<br />
|
|
249
|
+
|
|
250
|
+
------
|
|
251
|
+
|
|
252
|
+
<br />
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
`rtlMode`
|
|
256
|
+
|
|
257
|
+
**When using the timeline in horizontal mode, this defines whether the timeline should start from the right. This overrides the startIndex setting.**
|
|
258
|
+
|
|
259
|
+
JavaScript/jQuery
|
|
260
|
+
````javascript
|
|
261
|
+
default: false
|
|
262
|
+
options: true / false
|
|
263
|
+
````
|
|
264
|
+
|
|
265
|
+
Data attribute
|
|
266
|
+
````html
|
|
267
|
+
<div class="timeline" data-rtl-mode="true">
|
|
268
|
+
...
|
|
269
|
+
</div>
|
|
270
|
+
````
|
|
271
|
+
<br />
|
|
272
|
+
|
|
273
|
+
------
|
|
274
|
+
|
|
275
|
+
<br />
|
|
276
|
+
|
|
277
|
+
`startIndex`
|
|
278
|
+
|
|
279
|
+
**When using the timeline in horizontal mode, define which item the timeline should start at**
|
|
280
|
+
|
|
281
|
+
JavaScript/jQuery
|
|
282
|
+
````javascript
|
|
283
|
+
default: 0
|
|
284
|
+
options: integer
|
|
285
|
+
````
|
|
286
|
+
|
|
287
|
+
Data attribute
|
|
288
|
+
````html
|
|
289
|
+
<div class="timeline" data-start-index="0">
|
|
290
|
+
...
|
|
291
|
+
</div>
|
|
292
|
+
````
|
|
293
|
+
|
|
294
|
+
<br />
|
|
295
|
+
|
|
296
|
+
------
|
|
297
|
+
|
|
298
|
+
<br />
|
|
299
|
+
|
|
300
|
+
`verticalStartPosition`
|
|
301
|
+
|
|
302
|
+
**When using the timeline in vertical mode, define the alignment of the first item**
|
|
303
|
+
|
|
304
|
+
JavaScript/jQuery
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
default: 'left'
|
|
308
|
+
options: 'left', 'right'
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Data attribute
|
|
312
|
+
|
|
313
|
+
```html
|
|
314
|
+
<div class="timeline" data-vertical-start-position="right">
|
|
315
|
+
...
|
|
316
|
+
</div>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
<br />
|
|
320
|
+
|
|
321
|
+
------
|
|
322
|
+
|
|
323
|
+
<br />
|
|
324
|
+
|
|
325
|
+
`verticalTrigger`
|
|
326
|
+
|
|
327
|
+
**When using the timeline in vertical mode, define the distance from the bottom of the screen, in percent or pixels, that the items slide into view**
|
|
328
|
+
|
|
329
|
+
JavaScript/jQuery
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
default: '15%'
|
|
333
|
+
options: percentage or pixel value e.g. '20%' or '150px'
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Data attribute
|
|
337
|
+
|
|
338
|
+
```html
|
|
339
|
+
<div class="timeline" data-vertical-trigger="150px">
|
|
340
|
+
...
|
|
341
|
+
</div>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
<br />
|
|
345
|
+
|
|
346
|
+
------
|
|
347
|
+
|
|
348
|
+
<br />
|
|
349
|
+
|
|
350
|
+
`visibleItems`
|
|
351
|
+
|
|
352
|
+
**For horizontal mode: Controls the scrolling range and when navigation arrows appear. Note: With fixed-width timeline items, the actual number of visible items is determined by the container width**
|
|
353
|
+
|
|
354
|
+
JavaScript/jQuery
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
default: 3
|
|
358
|
+
options: integer
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Data attribute
|
|
362
|
+
|
|
363
|
+
```html
|
|
364
|
+
<div class="timeline" data-visible-items="3">
|
|
365
|
+
...
|
|
366
|
+
</div>
|
|
367
|
+
```
|
|
368
|
+
<br />
|
|
369
|
+
|
|
370
|
+
------
|
|
371
|
+
|
|
372
|
+
<br />
|
|
373
|
+
|
|
374
|
+
`nodeColor`, `lineColor`, `navColor`
|
|
375
|
+
|
|
376
|
+
**Set theme colors for nodes, center line, and navigation buttons (horizontal)**
|
|
377
|
+
|
|
378
|
+
JavaScript/jQuery
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
// any subset can be provided
|
|
382
|
+
jQuery('.timeline').timeline({
|
|
383
|
+
nodeColor: '#2d6cdf',
|
|
384
|
+
lineColor: '#2d6cdf',
|
|
385
|
+
navColor: '#f2f2f2'
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Data attributes (container)
|
|
390
|
+
|
|
391
|
+
```html
|
|
392
|
+
<div class="timeline"
|
|
393
|
+
data-node-color="#2d6cdf"
|
|
394
|
+
data-line-color="#2d6cdf"
|
|
395
|
+
data-nav-color="#f2f2f2">
|
|
396
|
+
...
|
|
397
|
+
</div>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
JSON (top-level)
|
|
401
|
+
|
|
402
|
+
```json
|
|
403
|
+
{
|
|
404
|
+
"nodeColor": "#2d6cdf",
|
|
405
|
+
"lineColor": "#2d6cdf",
|
|
406
|
+
"navColor": "#f2f2f2"
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Notes:
|
|
411
|
+
- If only one of `nodeColor` or `lineColor` is set, it is used for both.
|
|
412
|
+
- `navColor` automatically sets a contrasting border and arrow color.
|
|
413
|
+
|
|
414
|
+
------
|
|
415
|
+
|
|
416
|
+
<br />
|
|
417
|
+
|
|
418
|
+
Deep Linking and Node IDs
|
|
419
|
+
|
|
420
|
+
**Link to a specific node by ID using `?timeline=<containerId>&id=<nodeId>`**
|
|
421
|
+
|
|
422
|
+
- JSON nodes: set `id` on each node; the renderer adds `data-node-id` to items.
|
|
423
|
+
- Inline markup: add `data-node-id` to each `.timeline__item` you want addressable.
|
|
424
|
+
- On click modals: inline items can optionally declare `data-modal-title`, `data-modal-content`, `data-modal-image`, or `data-modal-html`. If absent, the library derives reasonable defaults from the markup (first heading, first paragraph, first image).
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
## Server Upload Workflow
|
|
428
|
+
|
|
429
|
+
This repository includes a small PHP utility under the `server-tools/` folder that converts CSV / Excel / Google Sheets into the timeline JSON format used by the demo. The basic flow is:
|
|
430
|
+
|
|
431
|
+
1. Open `server-tools/upload.html` in a browser (or host the `server-tools/` folder on a PHP-capable host).
|
|
432
|
+
2. Upload a CSV or `.xls/.xlsx` file, or provide a public Google Sheets URL. The server runs `convert.php` to parse the sheet and produce JSON.
|
|
433
|
+
3. If conversion succeeds the JSON is saved to `server-tools/tmp/` with a unique filename and you are redirected to `server-tools/done.php` which shows a preview and a download link.
|
|
434
|
+
4. Temporary files are cleaned up automatically by `server-tools/cleanup_tmp.php` (24-hour TTL). Run that as a cron job on the server.
|
|
435
|
+
|
|
436
|
+
Quick local test (from project root):
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
php -S localhost:8000 -t .
|
|
440
|
+
# then visit http://localhost:8000/server/upload.html
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Notes:
|
|
444
|
+
- The converter will set a `lastupdated` timestamp in the JSON if none is provided — this integrates with the client's caching behavior.
|
|
445
|
+
- Excel parsing requires `phpoffice/phpspreadsheet` (installed via Composer). `convert.php` auto-loads `vendor/autoload.php` if available in `server/` or project root.
|
|
446
|
+
|
|
447
|
+
## Security Notes (important)
|
|
448
|
+
|
|
449
|
+
This upload utility is a convenience tool and not hardened for untrusted public hosting. If you plan to run it on a public server, consider the following safeguards:
|
|
450
|
+
|
|
451
|
+
- Validate uploads: restrict accepted MIME types / extensions (`.csv`, `.xls`, `.xlsx`) and enforce a reasonable maximum file size.
|
|
452
|
+
- Run file parsing in a controlled environment; avoid executing any uploaded content.
|
|
453
|
+
- Store temporary files outside the web root or restrict direct listing/access; `server/done.php` only exposes the saved JSON filename.
|
|
454
|
+
- Sanitize all filenames and never use user-supplied filenames for server paths without cleaning.
|
|
455
|
+
- Limit rate and require authentication if the endpoint will be public to avoid abuse.
|
|
456
|
+
- Use HTTPS to protect uploads in transit.
|
|
457
|
+
- Keep Composer dependencies up-to-date and audit for security issues.
|
|
458
|
+
- Consider additional input validation on fields extracted from the spreadsheet (e.g., URLs, image paths) before including them in output JSON.
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
## License & Credits
|
|
462
|
+
|
|
463
|
+
This app is released under the [MIT License](LICENSE)
|
|
464
|
+
|
|
465
|
+
The original `timeline` project was created by Mike Collins and was also released under the MIT License. His project can be found on GitHub here: [https://github.com/squarechip/timeline](https://github.com/squarechip/timeline)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
Last updated: Jan. 5, 2026
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Timeline=function(e){"use strict";const t={count:0,startTime:0,removeTimer:null,overlayEl:null},i={modal:null,overlay:null},n={};function o(){if(i.modal)return;i.overlay=document.createElement("div"),i.overlay.className="timeline-modal-overlay",i.overlay.addEventListener("click",a),i.modal=document.createElement("div"),i.modal.className="timeline-modal",i.modal.innerHTML='\n <button class="timeline-modal__close" aria-label="Close modal"></button>\n <div class="timeline-modal__content">\n <img class="timeline-modal__image" src="" alt="" style="display: none;">\n <h2 class="timeline-modal__title"></h2>\n <div class="timeline-modal__text"></div>\n <hr class="timeline-modal__divider">\n <button class="timeline-modal__close-bottom">Close</button>\n </div>\n ';const e=i.modal.querySelector(".timeline-modal__close"),t=i.modal.querySelector(".timeline-modal__close-bottom");e.addEventListener("click",a),t.addEventListener("click",a),i.modal.addEventListener("click",function(e){e.stopPropagation()}),document.body.appendChild(i.overlay),document.body.appendChild(i.modal),document.addEventListener("keydown",function(e){"Escape"===e.key&&i.modal.classList.contains("timeline-modal-show")&&a()})}function l(e){i.modal||o();const t=e.getAttribute("data-modal-title"),n=e.getAttribute("data-modal-content"),l=e.getAttribute("data-modal-image"),a=e.getAttribute("data-modal-html"),r=i.modal.querySelector(".timeline-modal__title"),s=i.modal.querySelector(".timeline-modal__text"),d=i.modal.querySelector(".timeline-modal__image");r.textContent=t||"",l?(d.src=l,d.alt=t||"",d.style.display="block"):d.style.display="none",s.innerHTML=a||(n?"<p>"+n.replace(/\n/g,"</p><p>")+"</p>":""),setTimeout(function(){i.modal.classList.add("timeline-modal-show"),i.overlay.classList.add("timeline-modal-show"),document.body.style.overflow="hidden"},10)}function a(){i.modal&&(i.modal.classList.remove("timeline-modal-show"),i.overlay.classList.remove("timeline-modal-show"),document.body.style.overflow="")}function r(e){const t=new URLSearchParams(window.location.search),i=t.get("timeline"),n=t.get("id");if(!n)return;let o;if(o=i?document.getElementById(i):document.querySelector(e),!o)return void console.warn("Timeline not found for deep linking:",i||e);o.scrollIntoView({behavior:"smooth",block:"start"});const l=o.querySelector('[data-node-id="'+n+'"]');l&&setTimeout(function(){l.classList.add("timeline__item--active");const e=Array.from(l.parentNode.children).indexOf(l);s(o,e)},500)}function s(e,t){if(!e)return;const i=e.id||e.getAttribute("data-timeline-id");if(!i)return void console.warn("Cannot navigate: timeline container has no ID");const o=n[i];o?e.classList.contains("timeline--horizontal")&&o.setCurrentIndex&&o.updatePosition&&(o.setCurrentIndex(t),o.updatePosition()):console.warn("Timeline not found in registry:",i)}const d=function(){if("undefined"!=typeof window&&window.TimelineConfig&&window.TimelineConfig.basePath)return window.TimelineConfig.basePath;const e=document.getElementsByTagName("script");for(let t=0;t<e.length;t++){const i=e[t].src||"";if(!i)continue;const n=i.substring(0,i.lastIndexOf("/"));if(-1!==i.indexOf("timeline.min.js"))return n.replace("/dist","/src/images");if(-1!==i.indexOf("timeline.js"))return n.replace("/js","/images")}return"../src/images"}();function m(){if(t.count+=1,1!==t.count)return;t.startTime=Date.now(),t.removeTimer&&(clearTimeout(t.removeTimer),t.removeTimer=null);const e=document.createElement("div");e.className="timeline__loader-overlay";const i=document.createElement("div");i.className="timeline__loader";const n=document.createElement("img");n.src=d+"/spinner.gif",n.alt="Loading...",n.title="Loading...",n.className="timeline__loader-spinner",i.appendChild(n),e.appendChild(i),document.body.appendChild(e),t.overlayEl=e}function c(){if(t.count<=0)return;if(t.count-=1,t.count>0)return;const e=Date.now()-t.startTime,i=Math.max(0,1300-e),n=function(){t.overlayEl&&(t.overlayEl.remove(),t.overlayEl=null),t.removeTimer=null};t.removeTimer&&(clearTimeout(t.removeTimer),t.removeTimer=null),i>0?t.removeTimer=setTimeout(n,i):n()}function u(e,t,i){if(!e)return;const n={"json-load":{title:"Timeline Data Could Not Be Loaded",message:"The timeline data failed to load. This could be due to a network error or an incorrect file path.",solution:"Please check that the data-json-config path is correct and the file is accessible."},"json-parse":{title:"Invalid Timeline Data",message:"The timeline data file exists but contains invalid JSON.",solution:"Please validate your JSON using a tool like jsonlint.com and ensure it follows the correct schema."},"missing-element":{title:"Timeline Element Not Found",message:"The required timeline container element could not be found on the page.",solution:'Ensure your HTML includes a container with the class "timeline" and the correct selector.'},"invalid-config":{title:"Invalid Configuration",message:"One or more timeline configuration options are invalid.",solution:"Check your data attributes or JavaScript options and ensure they match the expected format."}}[t]||{title:"Timeline Error",message:"An unexpected error occurred while initializing the timeline.",solution:"Please check the browser console for more details."};c(),e.innerHTML="";const o=document.createElement("div");o.className="timeline__error";const l=document.createElement("img");l.src=d+"/alert.svg",l.alt="Error",l.className="timeline__error-icon";const a=document.createElement("h2");a.className="timeline__error-title",a.textContent=n.title;const r=document.createElement("p");r.className="timeline__error-message",r.textContent=n.message;const s=document.createElement("p");if(s.className="timeline__error-solution",s.innerHTML="<strong>Solution:</strong> "+n.solution,i){const e=document.createElement("p");e.className="timeline__error-details",e.innerHTML="<strong>Details:</strong> "+i,o.appendChild(e)}o.appendChild(l),o.appendChild(a),o.appendChild(r),o.appendChild(s),e.appendChild(o),console.error("Timeline Error ["+t+"]:",n.message,i||"")}function h(e){let t;if(!e||"string"!=typeof e)return 128;if(e.startsWith("#")){let i=e.substring(1);3===i.length&&(i=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]);t=[parseInt(i.substring(0,2),16),parseInt(i.substring(2,4),16),parseInt(i.substring(4,6),16)]}else{if(!e.startsWith("rgb"))return 128;{const i=e.match(/\d+/g);t=i?i.map(Number):[128,128,128]}}return(299*t[0]+587*t[1]+114*t[2])/1e3}function f(e,t){let i=t.nodeColor||null,n=t.lineColor||null;const o=t.navColor||null;if(i&&!n&&(n=i),n&&!i&&(i=n),i&&e.style.setProperty("--timeline-node-color",i),n&&e.style.setProperty("--timeline-line-color",n),o){e.style.setProperty("--timeline-nav-color",o),e.style.setProperty("--timeline-nav-border",h(o)>128?"rgba(0, 0, 0, 0.2)":"rgba(255, 255, 255, 0.3)");const t=h(o)>128?"#333":"#fff";e.style.setProperty("--timeline-arrow-color",t),e.setAttribute("data-arrow-color",t)}}function g(e,t){return"left"===e?'<svg xmlns="http://www.w3.org/2000/svg" width="7.8" height="14" style="display:block;margin:auto;"><path fill="none" stroke="'+t+'" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M6.8 1L1 7l5.8 6"/></svg>':'<svg xmlns="http://www.w3.org/2000/svg" width="7.8" height="14" style="display:block;margin:auto;"><path fill="none" stroke="'+t+'" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M1 1l5.8 6L1 13"/></svg>'}function v(e,t){const i=[],o="Timeline:";let a,r=window.innerWidth,s=0;m();let d=!0;const h={minWidth:{type:"integer",defaultValue:600},horizontalStartPosition:{type:"string",acceptedValues:["bottom","top"],defaultValue:"top"},mode:{type:"string",acceptedValues:["horizontal","vertical"],defaultValue:"vertical"},moveItems:{type:"integer",defaultValue:1},rtlMode:{type:"boolean",acceptedValues:[!0,!1],defaultValue:!1},startIndex:{type:"integer",defaultValue:0},verticalStartPosition:{type:"string",acceptedValues:["left","right"],defaultValue:"left"},verticalTrigger:{type:"string",defaultValue:"15%"},visibleItems:{type:"integer",defaultValue:3}};function v(e,t,i){t.classList.add(i),e.parentNode.insertBefore(t,e),t.appendChild(e)}function p(e,t){const i=e.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,o=h.verticalTrigger.defaultValue.match(/(\d*\.?\d*)(.*)/);let l=t.unit,a=t.value,r=n;return"px"===l&&a>=n&&(console.warn('The value entered for the setting "verticalTrigger" is larger than the window height. The default value will be used instead.'),[,a,l]=o),"px"===l?r=parseInt(r-a,10):"%"===l&&(r=parseInt(r*((100-a)/100),10)),i.top<=r&&i.left<=(window.innerWidth||document.documentElement.clientWidth)&&i.top+i.height>=0&&i.left+i.width>=0}function b(e,t){e.style.webkitTransform=t,e.style.msTransform=t,e.style.transform=t}function w(e){const t=`translate3d(-${e.items[s].offsetLeft}px, 0, 0)`;b(e.scroller,t)}function y(e){s=e.settings.rtlMode?e.items.length>e.settings.visibleItems?e.items.length-e.settings.visibleItems:0:e.settings.startIndex,e.timelineEl.classList.add("timeline--horizontal"),function(e){window.innerWidth>e.settings.minWidth&&(e.itemWidth=200,e.items.forEach(t=>{t.style.width=`${e.itemWidth}px`}),e.scrollerWidth=e.itemWidth*e.items.length,e.scroller.style.width=`${e.scrollerWidth}px`,function(){let t=0,i=0;e.items.forEach((e,n)=>{e.style.height="auto";const o=e.offsetHeight;n%2==0?i=o>i?o:i:t=o>t?o:t});const n=`translateY(${i}px)`;e.items.forEach((o,l)=>{l%2==0?(o.style.height=`${i}px`,"bottom"===e.settings.horizontalStartPosition?(o.classList.add("timeline__item--bottom"),b(o,n)):o.classList.add("timeline__item--top")):(o.style.height=`${t}px`,"bottom"!==e.settings.horizontalStartPosition?(o.classList.add("timeline__item--bottom"),b(o,n)):o.classList.add("timeline__item--top"))}),e.scroller.style.height=`${i+t}px`}())}(e),w(e),function(e){const t=e.wrap.offsetWidth,i=Math.floor(t/e.itemWidth);if(e.items.length>i){const t=document.createElement("button"),n=document.createElement("button"),o=e.items[0].offsetHeight;t.className="timeline-nav-button timeline-nav-button--prev",n.className="timeline-nav-button timeline-nav-button--next",t.textContent="Previous",n.textContent="Next",t.style.top=`${o}px`,n.style.top=`${o}px`;const l=e.timelineEl.getAttribute("data-arrow-color")||"#333";t.innerHTML=g("left",l),n.innerHTML=g("right",l);const a=Math.max(0,e.items.length-i);0===s?t.disabled=!0:s>=a&&(n.disabled=!0),e.timelineEl.appendChild(t),e.timelineEl.appendChild(n)}}(e),function(e){const t=e.timelineEl.querySelector(".timeline-divider");t&&e.timelineEl.removeChild(t);const i=e.items[0].offsetHeight,n=document.createElement("span");n.className="timeline-divider",n.style.top=`${i}px`,e.timelineEl.appendChild(n)}(e),function(e){const t=e.timelineEl.querySelectorAll(".timeline-nav-button"),i=e.timelineEl.querySelector(".timeline-nav-button--prev"),n=e.timelineEl.querySelector(".timeline-nav-button--next"),o=e.wrap.offsetWidth,l=Math.floor(o/e.itemWidth),a=Math.max(0,e.items.length-l),r=parseInt(e.settings.moveItems,10),d=function(t){t.preventDefault(),t.stopPropagation(),this.disabled||(s=this.classList.contains("timeline-nav-button--next")?s+=r:s-=r,0===s||s<0?(s=0,i.disabled=!0,n.disabled=!1):s===a||s>a?(s=a,i.disabled=!1,n.disabled=!0):(i.disabled=!1,n.disabled=!1),w(e))};Array.from(t).forEach(t=>{t.addEventListener("click",d),e.listeners.push({element:t,type:"click",handler:d})})}(e);const t=e.timelineEl.id||e.timelineEl.getAttribute("data-timeline-id");t&&(n[t]={setCurrentIndex:function(t){const i=e.wrap.offsetWidth,n=Math.floor(i/e.itemWidth),o=Math.max(0,e.items.length-n);s=Math.max(0,Math.min(t,o))},updatePosition:function(){w(e);const t=e.timelineEl.querySelector(".timeline-nav-button--prev"),i=e.timelineEl.querySelector(".timeline-nav-button--next");if(t&&i){const n=e.wrap.offsetWidth,o=Math.floor(n/e.itemWidth),l=Math.max(0,e.items.length-o);t.disabled=0===s,i.disabled=s>=l}}})}function E(){i.forEach(e=>{e.timelineEl.style.opacity=0,e.timelineEl.classList.contains("timeline--loaded")||e.items.forEach(e=>{v(e.querySelector(".timeline__content"),document.createElement("div"),"timeline__content__wrap"),v(e.querySelector(".timeline__content__wrap"),document.createElement("div"),"timeline__item__inner")}),function(e){e.listeners&&e.listeners.length>0&&(e.listeners.forEach(({element:e,type:t,handler:i})=>{e.removeEventListener(t,i)}),e.listeners=[]),e.observer&&(e.observer.disconnect(),e.observer=null),e.timelineEl.classList.remove("timeline--horizontal","timeline--mobile"),e.scroller.removeAttribute("style"),e.items.forEach(e=>{e.removeAttribute("style"),e.classList.remove("animated","fadeIn","timeline__item--left","timeline__item--right")});const t=e.timelineEl.querySelectorAll(".timeline-nav-button");Array.from(t).forEach(e=>{e.parentNode.removeChild(e)})}(e),window.innerWidth<=e.settings.minWidth&&e.timelineEl.classList.add("timeline--mobile"),"horizontal"===e.settings.mode&&window.innerWidth>e.settings.minWidth?y(e):function(e){let t=0;e.items.forEach((i,n)=>{i.classList.remove("animated","fadeIn"),!p(i,e.settings.verticalTrigger)&&n>0?i.classList.add("animated"):t=n,n%2==("left"===e.settings.verticalStartPosition?1:0)&&window.innerWidth>e.settings.minWidth?i.classList.add("timeline__item--right"):i.classList.add("timeline__item--left")});for(let i=0;i<t;i+=1)e.items[i].classList.remove("animated","fadeIn");if("IntersectionObserver"in window){const t={rootMargin:"%"===e.settings.verticalTrigger.unit?`${e.settings.verticalTrigger.value}%`:`${e.settings.verticalTrigger.value}px`,threshold:.01},i=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting&&e.target.classList.add("fadeIn")})},t);e.items.forEach(e=>{e.classList.contains("animated")&&i.observe(e)}),e.observer=i}else{const t=()=>{e.items.forEach(t=>{p(t,e.settings.verticalTrigger)&&t.classList.add("fadeIn")})};window.addEventListener("scroll",t),e.listeners.push({element:window,type:"scroll",handler:t})}}(e),e.timelineEl.classList.add("timeline--loaded")}),setTimeout(()=>{i.forEach(e=>{e.timelineEl.style.opacity=1})},500),d&&(c(),d=!1)}e.length&&Array.from(e).forEach(function(e){const n=e.id?`#${e.id}`:`.${e.className}`,a="could not be found as a direct descendant of",r=e.dataset;let s,d,m;const c={};try{if(s=e.querySelector(".timeline__wrap"),!s)throw new Error(`${o} .timeline__wrap ${a} ${n}`);if(d=s.querySelector(".timeline__items"),!d)throw new Error(`${o} .timeline__items ${a} .timeline__wrap`);m=[].slice.call(d.children,0)}catch(t){return console.warn(t.message),u(e,"missing-element",t.message),!1}Object.keys(h).forEach(e=>{if(c[e]=h[e].defaultValue,"minWidth"===e){let e;void 0!==r.minWidth&&(e=r.minWidth),void 0!==r.minwidth&&(e=r.minwidth),void 0!==r.forceVerticalMode&&(e=r.forceVerticalMode),void 0!==r.forceverticalmode&&(e=r.forceverticalmode),void 0===e&&t&&(void 0!==t.minWidth?e=t.minWidth:void 0!==t.forceVerticalMode&&(e=t.forceVerticalMode)),void 0!==e&&(c.minWidth=e)}else r[e]?c[e]=r[e]:t&&void 0!==t[e]&&(c[e]=t[e]);var i,n;"integer"===h[e].type?c[e]&&(n=e,"number"==typeof(i=c[e])||i%1==0||(console.warn(`${o} The value "${i}" entered for the setting "${n}" is not an integer.`),0))||(c[e]=h[e].defaultValue):"string"===h[e].type&&h[e].acceptedValues&&-1===h[e].acceptedValues.indexOf(c[e])&&(console.warn(`${o} The value "${c[e]}" entered for the setting "${e}" was not recognised.`),c[e]=h[e].defaultValue)}),function(){const i=e.dataset,n=function(e){return void 0!==i[e]?i[e]:void 0!==i[e&&e.toLowerCase()]?i[e.toLowerCase()]:void 0};let o=n("nodeColor"),l=n("lineColor"),a=n("navColor");t&&(void 0!==t.nodeColor&&(o=t.nodeColor),void 0!==t.lineColor&&(l=t.lineColor),void 0!==t.navColor&&(a=t.navColor)),(o||l||a)&&f(e,{nodeColor:o,lineColor:l,navColor:a})}();const g=h.verticalTrigger.defaultValue.match(/(\d*\.?\d*)(.*)/),v=c.verticalTrigger.match(/(\d*\.?\d*)(.*)/);let[,p,b]=v,w=!0;p||(console.warn(`${o} No numercial value entered for the 'verticalTrigger' setting.`),w=!1),"px"!==b&&"%"!==b&&(console.warn(`${o} The setting 'verticalTrigger' must be a percentage or pixel value.`),w=!1),"%"===b&&(p>100||p<0)?(console.warn(`${o} The 'verticalTrigger' setting value must be between 0 and 100 if using a percentage value.`),w=!1):"px"===b&&p<0&&(console.warn(`${o} The 'verticalTrigger' setting value must be above 0 if using a pixel value.`),w=!1),!1===w&&([,p,b]=g),c.verticalTrigger={unit:b,value:p},c.moveItems>c.visibleItems&&(console.warn(`${o} The value of "moveItems" (${c.moveItems}) is larger than the number of "visibleItems" (${c.visibleItems}). The value of "visibleItems" has been used instead.`),c.moveItems=c.visibleItems),c.startIndex>m.length-c.visibleItems&&m.length>c.visibleItems?(console.warn(`${o} The 'startIndex' setting must be between 0 and ${m.length-c.visibleItems} for this timeline. The value of ${m.length-c.visibleItems} has been used instead.`),c.startIndex=m.length-c.visibleItems):m.length<=c.visibleItems?(console.warn(`${o} The number of items in the timeline must exceed the number of visible items to use the 'startIndex' option.`),c.startIndex=0):c.startIndex<0&&(console.warn(`${o} The 'startIndex' setting must be between 0 and ${m.length-c.visibleItems} for this timeline. The value of 0 has been used instead.`),c.startIndex=0),function(e,t){t&&t.length&&t.forEach(function(e){"1"!==e.getAttribute("data-modal-bound")&&(function(e){if(!e)return;const t=e.querySelector(".timeline__content")||e;if(!e.hasAttribute("data-modal-title")){const i=t.querySelector("h1,h2,h3,h4,h5,h6");i&&i.textContent&&e.setAttribute("data-modal-title",i.textContent.trim())}if(!e.hasAttribute("data-modal-content")){const i=t.querySelector("p");i&&i.textContent&&e.setAttribute("data-modal-content",i.textContent.trim())}if(!e.hasAttribute("data-modal-image")){const i=t.querySelector("img");i&&i.getAttribute("src")&&e.setAttribute("data-modal-image",i.getAttribute("src"))}}(e),(e.hasAttribute("data-modal-title")||e.hasAttribute("data-modal-content")||e.hasAttribute("data-modal-image")||e.hasAttribute("data-modal-html"))&&(e.addEventListener("click",function(t){t.preventDefault(),l(e)}),e.setAttribute("data-modal-bound","1")))})}(0,m),e.id||e.setAttribute("data-timeline-id","timeline-"+Date.now()+"-"+Math.random().toString(36).substr(2,9)),i.push({timelineEl:e,wrap:s,scroller:d,items:m,settings:c,listeners:[]})}),E(),window.addEventListener("resize",()=>{clearTimeout(a),a=setTimeout(()=>{const e=window.innerWidth;e!==r&&(E(),r=e)},250)})}function p(e,t,i){const n=document.querySelector(e);if(!n)return;let o=n.querySelector(".timeline__items");if(o)o.innerHTML="";else{const e=document.createElement("div");e.className="timeline__wrap",o=document.createElement("div"),o.className="timeline__items",e.appendChild(o),n.appendChild(e)}if(i&&(function(e,t){t.layoutMode&&e.setAttribute("data-mode",t.layoutMode),void 0!==t.visibleItems&&e.setAttribute("data-visible-items",t.visibleItems),void 0!==t.minWidth&&(e.setAttribute("data-minwidth",t.minWidth),e.setAttribute("data-force-vertical-mode",t.minWidth)),void 0!==t.maxWidth&&e.setAttribute("data-maxwidth",t.maxWidth)}(n,i),f(n,i),i.timelineName&&""!==i.timelineName.trim())){const e=n.previousElementSibling;if(e&&e.classList.contains("timeline__heading"))e.textContent=i.timelineName;else{const e=document.createElement("h1");e.className="timeline__heading",e.textContent=i.timelineName,n.parentNode.insertBefore(e,n)}n.setAttribute("data-timeline-name",i.timelineName)}return t.forEach(function(e){o.appendChild(function(e){const t=document.createElement("div");t.className="timeline__item",e.id&&t.setAttribute("data-node-id",e.id),t.setAttribute("data-modal-title",e.title||""),t.setAttribute("data-modal-content",e.content||""),t.setAttribute("data-modal-image",e.image||""),e.html&&t.setAttribute("data-modal-html",e.html);const i=document.createElement("div");if(i.className="timeline__content",e.image){const t=document.createElement("img");t.src=e.image,t.className="timeline__image",t.alt=e.title||"",t.onerror=function(){console.error('Timeline: The image "'+e.image+'" could not be loaded. Please check the path.'),this.src=d+"/missing-image.svg",this.alt="Image not found",this.title="Original image: "+e.image},i.appendChild(t)}const n=document.createElement("div");if(e.title){const t=document.createElement("h3");t.textContent=e.title,n.appendChild(t)}if(e.content){const t=document.createElement("p");let i=e.content;i.length>105&&(i=i.substring(0,105)+"..."),t.innerHTML=i,n.appendChild(t)}if(e.html){const t=document.createElement("div");t.innerHTML=e.html,n.appendChild(t)}return i.appendChild(n),t.appendChild(i),t.addEventListener("click",function(e){e.preventDefault(),"function"==typeof window.openTimelineModal&&window.openTimelineModal(t)}),t.setAttribute("data-modal-bound","1"),t}(e))}),n}function b(e,t,i){const n=p(e,t,i);n&&v([n],i)}function w(e,t){const i=document.querySelector(t);if(!i)return void console.error("Timeline: Container not found:",t);m();const n=i?i.id:null,o=n?"vjs_"+n:null;if(o&&"undefined"!=typeof Storage)try{const i=localStorage.getItem(o);if(i){const l=JSON.parse(i);return void fetch(e).then(function(t){if(!t.ok)throw new Error("Failed to load "+e+" ("+t.status+")");return t.json()}).then(function(e){e.lastupdated&&l.lastupdated&&e.lastupdated===l.lastupdated?(console.log("Using cached timeline data for",n),y(l,t)):(console.log("Updating cached timeline data for",n),localStorage.setItem(o,JSON.stringify(e)),y(e,t))}).catch(function(e){console.warn("Failed to fetch fresh data, using cache:",e),y(l,t)})}}catch(e){console.warn("Error reading from localStorage:",e)}fetch(e).then(function(t){if(!t.ok)throw new Error("Failed to load "+e+" ("+t.status+")");return t.json()}).then(function(e){if(o&&"undefined"!=typeof Storage)try{localStorage.setItem(o,JSON.stringify(e)),console.log("Cached timeline data for",n)}catch(e){console.warn("Failed to cache timeline data:",e)}y(e,t)}).catch(function(e){console.error("Error loading timeline JSON:",e),u(i,"json-load",e.message)})}function y(e,t){const i=document.querySelector(t);if(!i)return void console.error("Timeline: Container not found:",t);let n=null,o=[];try{if(e.nodes&&Array.isArray(e.nodes))o=e.nodes,n={timelineName:e.timelineName,layoutMode:e.layoutMode,visibleItems:e.visibleItems,minWidth:e.minWidth,maxWidth:e.maxWidth,nodeColor:e.nodeColor,lineColor:e.lineColor,navColor:e.navColor,lastupdated:e.lastupdated};else{if(!Array.isArray(e))throw new Error('Invalid JSON format. Expected object with "nodes" array or simple array.');o=e}if(0===o.length)throw new Error("No timeline items found in data.");p(t,o,n);try{v(document.querySelectorAll(t)),r(t),c()}catch(e){console.error("Error initializing timeline:",e);const i=document.querySelector(t);i&&u(i,"invalid-config",e.message),c()}}catch(e){console.error("Error processing timeline data:",e),u(i,"json-parse",e.message),c()}}function E(e){if("undefined"!=typeof Storage)if(e){const t="vjs_"+e;localStorage.removeItem(t),console.log("Cleared cache for timeline:",e)}else{const e=Object.keys(localStorage);let t=0;e.forEach(function(e){e.startsWith("vjs_")&&(localStorage.removeItem(e),t++)}),console.log("Cleared",t,"timeline cache(s)")}else console.warn("localStorage not supported")}return"undefined"!=typeof window&&(window.timeline=v,window.timelineFromData=b,window.renderTimelineFromData=p,window.processTimelineData=y,window.loadDataFromJson=w,window.clearTimelineCache=E,window.createTimelineModal=o,window.openTimelineModal=l,window.closeTimelineModal=a,window.handleTimelineDeepLinking=r,window.navigateTimelineToNodeIndex=s),document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("[data-json-config]").forEach(function(e){const t=e.getAttribute("data-json-config");if(!t)return;const i=(e.className||"").split(" ")[0],n=e.id?"#"+e.id:i?"."+i:null;n&&w(t,n)})}),"undefined"!=typeof window&&window.jQuery&&(window.jQuery.fn.timeline=function(e){return v(this,e),this}),e.clearTimelineCache=E,e.closeTimelineModal=a,e.createTimelineModal=o,e.handleDeepLinking=r,e.loadDataFromJson=w,e.navigateToNodeIndex=s,e.openTimelineModal=l,e.processTimelineData=y,e.renderTimelineFromData=p,e.timeline=v,e.timelineFromData=b,e}({});
|
|
2
|
+
//# sourceMappingURL=timeline.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.min.js","sources":["../src/js/shared/state.js","../src/js/features/modals.js","../src/js/features/deep-linking.js","../src/js/shared/config.js","../src/js/features/loader-ui.js","../src/js/features/error-ui.js","../src/js/shared/utils.js","../src/js/features/colors.js","../src/js/core/timeline-engine.js","../src/js/features/data-loader.js","../src/js/timeline.js"],"sourcesContent":["// Shared state containers\nexport const loaderState = {\n count: 0,\n startTime: 0,\n removeTimer: null,\n overlayEl: null\n};\n\nexport const modalState = {\n modal: null,\n overlay: null\n};\n\n// Global registry to store timeline instances for programmatic navigation\nexport const timelineRegistry = {};\n","import { modalState } from '../shared/state.js';\n\nexport function createTimelineModal() {\n if (modalState.modal) return;\n\n modalState.overlay = document.createElement('div');\n modalState.overlay.className = 'timeline-modal-overlay';\n modalState.overlay.addEventListener('click', closeTimelineModal);\n\n modalState.modal = document.createElement('div');\n modalState.modal.className = 'timeline-modal';\n modalState.modal.innerHTML = `\n <button class=\"timeline-modal__close\" aria-label=\"Close modal\"></button>\n <div class=\"timeline-modal__content\">\n <img class=\"timeline-modal__image\" src=\"\" alt=\"\" style=\"display: none;\">\n <h2 class=\"timeline-modal__title\"></h2>\n <div class=\"timeline-modal__text\"></div>\n <hr class=\"timeline-modal__divider\">\n <button class=\"timeline-modal__close-bottom\">Close</button>\n </div>\n `;\n\n const closeBtn = modalState.modal.querySelector('.timeline-modal__close');\n const closeBottomBtn = modalState.modal.querySelector('.timeline-modal__close-bottom');\n closeBtn.addEventListener('click', closeTimelineModal);\n closeBottomBtn.addEventListener('click', closeTimelineModal);\n\n modalState.modal.addEventListener('click', function(e) {\n e.stopPropagation();\n });\n\n document.body.appendChild(modalState.overlay);\n document.body.appendChild(modalState.modal);\n\n document.addEventListener('keydown', function(e) {\n if (e.key === 'Escape' && modalState.modal.classList.contains('timeline-modal-show')) {\n closeTimelineModal();\n }\n });\n}\n\nexport function openTimelineModal(itemEl) {\n if (!modalState.modal) {\n createTimelineModal();\n }\n\n const title = itemEl.getAttribute('data-modal-title');\n const content = itemEl.getAttribute('data-modal-content');\n const image = itemEl.getAttribute('data-modal-image');\n const html = itemEl.getAttribute('data-modal-html');\n\n const modalTitle = modalState.modal.querySelector('.timeline-modal__title');\n const modalText = modalState.modal.querySelector('.timeline-modal__text');\n const modalImage = modalState.modal.querySelector('.timeline-modal__image');\n\n modalTitle.textContent = title || '';\n\n if (image) {\n modalImage.src = image;\n modalImage.alt = title || '';\n modalImage.style.display = 'block';\n } else {\n modalImage.style.display = 'none';\n }\n\n if (html) {\n modalText.innerHTML = html;\n } else if (content) {\n modalText.innerHTML = '<p>' + content.replace(/\\n/g, '</p><p>') + '</p>';\n } else {\n modalText.innerHTML = '';\n }\n\n setTimeout(function() {\n modalState.modal.classList.add('timeline-modal-show');\n modalState.overlay.classList.add('timeline-modal-show');\n document.body.style.overflow = 'hidden';\n }, 10);\n}\n\nexport function closeTimelineModal() {\n if (modalState.modal) {\n modalState.modal.classList.remove('timeline-modal-show');\n modalState.overlay.classList.remove('timeline-modal-show');\n document.body.style.overflow = '';\n }\n}\n","import { timelineRegistry } from '../shared/state.js';\n\nexport function handleDeepLinking(containerSelector) {\n const urlParams = new URLSearchParams(window.location.search);\n const timelineId = urlParams.get('timeline');\n const nodeId = urlParams.get('id');\n if (!nodeId) return;\n\n let targetContainer;\n if (timelineId) {\n targetContainer = document.getElementById(timelineId);\n } else {\n targetContainer = document.querySelector(containerSelector);\n }\n\n if (!targetContainer) {\n console.warn('Timeline not found for deep linking:', timelineId || containerSelector);\n return;\n }\n\n targetContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });\n\n const targetNode = targetContainer.querySelector('[data-node-id=\"' + nodeId + '\"]');\n if (targetNode) {\n setTimeout(function() {\n targetNode.classList.add('timeline__item--active');\n const itemIndex = Array.from(targetNode.parentNode.children).indexOf(targetNode);\n navigateToNodeIndex(targetContainer, itemIndex);\n }, 500);\n }\n}\n\nexport function navigateToNodeIndex(container, index) {\n if (!container) return;\n const timelineId = container.id || container.getAttribute('data-timeline-id');\n if (!timelineId) {\n console.warn('Cannot navigate: timeline container has no ID');\n return;\n }\n\n const tlData = timelineRegistry[timelineId];\n if (!tlData) {\n console.warn('Timeline not found in registry:', timelineId);\n return;\n }\n\n if (!container.classList.contains('timeline--horizontal')) {\n return;\n }\n\n if (tlData.setCurrentIndex && tlData.updatePosition) {\n tlData.setCurrentIndex(index);\n tlData.updatePosition();\n }\n}\n","// Shared configuration values\n// Auto-detect the timeline.js script location to build correct image paths\nexport const timelineBasePath = (function() {\n // Check for user override\n if (typeof window !== 'undefined' && \n window.TimelineConfig && \n window.TimelineConfig.basePath) {\n return window.TimelineConfig.basePath;\n }\n \n const scripts = document.getElementsByTagName('script');\n for (let i = 0; i < scripts.length; i++) {\n const src = scripts[i].src || '';\n if (!src) continue;\n const dir = src.substring(0, src.lastIndexOf('/'));\n if (src.indexOf('timeline.min.js') !== -1) {\n // When loading from dist, map to src/images\n return dir.replace('/dist', '/src/images');\n }\n if (src.indexOf('timeline.js') !== -1) {\n // When loading from src/js, map to src/images\n return dir.replace('/js', '/images');\n }\n }\n // Fallback relative to demo pages; most demos live under demo/**\n return '../src/images';\n})();\n\n// Minimum time (ms) to keep the loading spinner visible\nlet timelineLoaderMinMs = 1300;\nexport function getTimelineLoaderMinMs() {\n return timelineLoaderMinMs;\n}\nexport function setTimelineLoaderMinMs(value) {\n if (typeof value === 'number' && value >= 0) {\n timelineLoaderMinMs = value;\n }\n}\n","import { loaderState } from '../shared/state.js';\nimport { getTimelineLoaderMinMs, timelineBasePath } from '../shared/config.js';\n\nexport function showTimelineLoader() {\n loaderState.count += 1;\n if (loaderState.count !== 1) return;\n\n loaderState.startTime = Date.now();\n\n if (loaderState.removeTimer) {\n clearTimeout(loaderState.removeTimer);\n loaderState.removeTimer = null;\n }\n\n const overlay = document.createElement('div');\n overlay.className = 'timeline__loader-overlay';\n\n const loader = document.createElement('div');\n loader.className = 'timeline__loader';\n\n const spinner = document.createElement('img');\n spinner.src = timelineBasePath + '/spinner.gif';\n spinner.alt = 'Loading...';\n spinner.title = 'Loading...';\n spinner.className = 'timeline__loader-spinner';\n\n loader.appendChild(spinner);\n overlay.appendChild(loader);\n\n document.body.appendChild(overlay);\n loaderState.overlayEl = overlay;\n}\n\nexport function hideTimelineLoader() {\n if (loaderState.count <= 0) return;\n loaderState.count -= 1;\n if (loaderState.count > 0) return;\n\n const elapsed = Date.now() - loaderState.startTime;\n const minMs = getTimelineLoaderMinMs();\n const remaining = Math.max(0, minMs - elapsed);\n\n const removeOverlay = function() {\n if (loaderState.overlayEl) {\n loaderState.overlayEl.remove();\n loaderState.overlayEl = null;\n }\n loaderState.removeTimer = null;\n };\n\n if (loaderState.removeTimer) {\n clearTimeout(loaderState.removeTimer);\n loaderState.removeTimer = null;\n }\n\n if (remaining > 0) {\n loaderState.removeTimer = setTimeout(removeOverlay, remaining);\n } else {\n removeOverlay();\n }\n}\n","import { timelineBasePath } from '../shared/config.js';\nimport { hideTimelineLoader } from './loader-ui.js';\n\nexport function showTimelineError(container, errorType, details) {\n if (!container) return;\n\n const errorMessages = {\n 'json-load': {\n title: 'Timeline Data Could Not Be Loaded',\n message: 'The timeline data failed to load. This could be due to a network error or an incorrect file path.',\n solution: 'Please check that the data-json-config path is correct and the file is accessible.'\n },\n 'json-parse': {\n title: 'Invalid Timeline Data',\n message: 'The timeline data file exists but contains invalid JSON.',\n solution: 'Please validate your JSON using a tool like jsonlint.com and ensure it follows the correct schema.'\n },\n 'missing-element': {\n title: 'Timeline Element Not Found',\n message: 'The required timeline container element could not be found on the page.',\n solution: 'Ensure your HTML includes a container with the class \"timeline\" and the correct selector.'\n },\n 'invalid-config': {\n title: 'Invalid Configuration',\n message: 'One or more timeline configuration options are invalid.',\n solution: 'Check your data attributes or JavaScript options and ensure they match the expected format.'\n }\n };\n\n const errorInfo = errorMessages[errorType] || {\n title: 'Timeline Error',\n message: 'An unexpected error occurred while initializing the timeline.',\n solution: 'Please check the browser console for more details.'\n };\n\n hideTimelineLoader(container);\n container.innerHTML = '';\n\n const errorDiv = document.createElement('div');\n errorDiv.className = 'timeline__error';\n\n const errorIcon = document.createElement('img');\n errorIcon.src = timelineBasePath + '/alert.svg';\n errorIcon.alt = 'Error';\n errorIcon.className = 'timeline__error-icon';\n\n const errorTitle = document.createElement('h2');\n errorTitle.className = 'timeline__error-title';\n errorTitle.textContent = errorInfo.title;\n\n const errorMessage = document.createElement('p');\n errorMessage.className = 'timeline__error-message';\n errorMessage.textContent = errorInfo.message;\n\n const errorSolution = document.createElement('p');\n errorSolution.className = 'timeline__error-solution';\n errorSolution.innerHTML = '<strong>Solution:</strong> ' + errorInfo.solution;\n\n if (details) {\n const errorDetails = document.createElement('p');\n errorDetails.className = 'timeline__error-details';\n errorDetails.innerHTML = '<strong>Details:</strong> ' + details;\n errorDiv.appendChild(errorDetails);\n }\n\n errorDiv.appendChild(errorIcon);\n errorDiv.appendChild(errorTitle);\n errorDiv.appendChild(errorMessage);\n errorDiv.appendChild(errorSolution);\n\n container.appendChild(errorDiv);\n\n console.error('Timeline Error [' + errorType + ']:', errorInfo.message, details || '');\n}\n","// Utility helpers shared across modules\nexport function getContrastColor(bgColor) {\n const brightness = getColorBrightness(bgColor);\n return brightness > 128 ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.3)';\n}\n\nexport function getColorBrightness(color) {\n let rgb;\n if (!color || typeof color !== 'string') return 128;\n\n if (color.startsWith('#')) {\n let hex = color.substring(1);\n if (hex.length === 3) {\n hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n }\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n rgb = [r, g, b];\n } else if (color.startsWith('rgb')) {\n const matches = color.match(/\\d+/g);\n rgb = matches ? matches.map(Number) : [128, 128, 128];\n } else {\n return 128;\n }\n\n return (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;\n}\n","import { getContrastColor, getColorBrightness } from '../shared/utils.js';\n\nexport function applyTimelineColors(container, config) {\n let nodeColor = config.nodeColor || null;\n let lineColor = config.lineColor || null;\n const navColor = config.navColor || null;\n\n if (nodeColor && !lineColor) lineColor = nodeColor;\n if (lineColor && !nodeColor) nodeColor = lineColor;\n\n if (nodeColor) {\n container.style.setProperty('--timeline-node-color', nodeColor);\n }\n if (lineColor) {\n container.style.setProperty('--timeline-line-color', lineColor);\n }\n if (navColor) {\n container.style.setProperty('--timeline-nav-color', navColor);\n container.style.setProperty('--timeline-nav-border', getContrastColor(navColor));\n const brightness = getColorBrightness(navColor);\n const arrowColor = brightness > 128 ? '#333' : '#fff';\n container.style.setProperty('--timeline-arrow-color', arrowColor);\n container.setAttribute('data-arrow-color', arrowColor);\n }\n}\n","import { showTimelineLoader, hideTimelineLoader } from '../features/loader-ui.js';\nimport { showTimelineError } from '../features/error-ui.js';\nimport { applyTimelineColors } from '../features/colors.js';\nimport { openTimelineModal } from '../features/modals.js';\nimport { timelineRegistry } from '../shared/state.js';\n\nfunction ensureInlineModalData(itemEl) {\n if (!itemEl) return;\n const content = itemEl.querySelector('.timeline__content') || itemEl;\n if (!itemEl.hasAttribute('data-modal-title')) {\n const heading = content.querySelector('h1,h2,h3,h4,h5,h6');\n if (heading && heading.textContent) {\n itemEl.setAttribute('data-modal-title', heading.textContent.trim());\n }\n }\n if (!itemEl.hasAttribute('data-modal-content')) {\n const firstP = content.querySelector('p');\n if (firstP && firstP.textContent) {\n itemEl.setAttribute('data-modal-content', firstP.textContent.trim());\n }\n }\n if (!itemEl.hasAttribute('data-modal-image')) {\n const img = content.querySelector('img');\n if (img && img.getAttribute('src')) {\n itemEl.setAttribute('data-modal-image', img.getAttribute('src'));\n }\n }\n}\n\nfunction enhanceInlineItems(timelineEl, items) {\n if (!items || !items.length) return;\n items.forEach(function(item){\n if (item.getAttribute('data-modal-bound') === '1') return;\n ensureInlineModalData(item);\n const hasModal = item.hasAttribute('data-modal-title') || item.hasAttribute('data-modal-content') || item.hasAttribute('data-modal-image') || item.hasAttribute('data-modal-html');\n if (hasModal) {\n item.addEventListener('click', function(e){\n e.preventDefault();\n openTimelineModal(item);\n });\n item.setAttribute('data-modal-bound', '1');\n }\n });\n}\n\nfunction createArrowSVG(direction, color) {\n if (direction === 'left') {\n return '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"7.8\" height=\"14\" style=\"display:block;margin:auto;\"><path fill=\"none\" stroke=\"' + color + '\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6.8 1L1 7l5.8 6\"/></svg>';\n }\n return '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"7.8\" height=\"14\" style=\"display:block;margin:auto;\"><path fill=\"none\" stroke=\"' + color + '\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M1 1l5.8 6L1 13\"/></svg>';\n}\n\nexport function timeline(collection, options) {\n const timelines = [];\n const warningLabel = 'Timeline:';\n let winWidth = window.innerWidth;\n let resizeTimer;\n let currentIndex = 0;\n const eventListeners = new Map(); // Track listeners for cleanup\n\n showTimelineLoader();\n let shouldHideLoader = true;\n\n const defaultSettings = {\n minWidth: { type: 'integer', defaultValue: 600 },\n horizontalStartPosition: { type: 'string', acceptedValues: ['bottom', 'top'], defaultValue: 'top' },\n mode: { type: 'string', acceptedValues: ['horizontal', 'vertical'], defaultValue: 'vertical' },\n moveItems: { type: 'integer', defaultValue: 1 },\n rtlMode: { type: 'boolean', acceptedValues: [true, false], defaultValue: false },\n startIndex: { type: 'integer', defaultValue: 0 },\n verticalStartPosition: { type: 'string', acceptedValues: ['left', 'right'], defaultValue: 'left' },\n verticalTrigger: { type: 'string', defaultValue: '15%' },\n visibleItems: { type: 'integer', defaultValue: 3 }\n };\n\n function testValues(value, settingName) {\n if (typeof value !== 'number' && value % 1 !== 0) {\n console.warn(`${warningLabel} The value \"${value}\" entered for the setting \"${settingName}\" is not an integer.`);\n return false;\n }\n return true;\n }\n\n function itemWrap(el, wrapper, classes) {\n wrapper.classList.add(classes);\n el.parentNode.insertBefore(wrapper, el);\n wrapper.appendChild(el);\n }\n\n function wrapElements(items) {\n items.forEach((item) => {\n itemWrap(item.querySelector('.timeline__content'), document.createElement('div'), 'timeline__content__wrap');\n itemWrap(item.querySelector('.timeline__content__wrap'), document.createElement('div'), 'timeline__item__inner');\n });\n }\n\n function isElementInViewport(el, triggerPosition) {\n const rect = el.getBoundingClientRect();\n const windowHeight = window.innerHeight || document.documentElement.clientHeight;\n const defaultTrigger = defaultSettings.verticalTrigger.defaultValue.match(/(\\d*\\.?\\d*)(.*)/);\n let triggerUnit = triggerPosition.unit;\n let triggerValue = triggerPosition.value;\n let trigger = windowHeight;\n if (triggerUnit === 'px' && triggerValue >= windowHeight) {\n console.warn('The value entered for the setting \"verticalTrigger\" is larger than the window height. The default value will be used instead.');\n [, triggerValue, triggerUnit] = defaultTrigger;\n }\n if (triggerUnit === 'px') {\n trigger = parseInt(trigger - triggerValue, 10);\n } else if (triggerUnit === '%') {\n trigger = parseInt(trigger * ((100 - triggerValue) / 100), 10);\n }\n return (\n rect.top <= trigger &&\n rect.left <= (window.innerWidth || document.documentElement.clientWidth) &&\n (rect.top + rect.height) >= 0 &&\n (rect.left + rect.width) >= 0\n );\n }\n\n function addTransforms(el, transform) {\n el.style.webkitTransform = transform;\n el.style.msTransform = transform;\n el.style.transform = transform;\n }\n\n function createTimelines(timelineEl) {\n const timelineName = timelineEl.id ? `#${timelineEl.id}` : `.${timelineEl.className}`;\n const errorPart = 'could not be found as a direct descendant of';\n const data = timelineEl.dataset;\n let wrap;\n let scroller;\n let items;\n const settings = {};\n\n try {\n wrap = timelineEl.querySelector('.timeline__wrap');\n if (!wrap) {\n throw new Error(`${warningLabel} .timeline__wrap ${errorPart} ${timelineName}`);\n } else {\n scroller = wrap.querySelector('.timeline__items');\n if (!scroller) {\n throw new Error(`${warningLabel} .timeline__items ${errorPart} .timeline__wrap`);\n } else {\n items = [].slice.call(scroller.children, 0);\n }\n }\n } catch (e) {\n console.warn(e.message);\n showTimelineError(timelineEl, 'missing-element', e.message);\n return false;\n }\n\n Object.keys(defaultSettings).forEach((key) => {\n settings[key] = defaultSettings[key].defaultValue;\n\n if (key === 'minWidth') {\n let candidate = undefined;\n if (data.minWidth !== undefined) candidate = data.minWidth;\n if (data.minwidth !== undefined) candidate = data.minwidth;\n if (data.forceVerticalMode !== undefined) candidate = data.forceVerticalMode;\n if (data.forceverticalmode !== undefined) candidate = data.forceverticalmode;\n if (candidate === undefined && options) {\n if (options.minWidth !== undefined) candidate = options.minWidth;\n else if (options.forceVerticalMode !== undefined) candidate = options.forceVerticalMode;\n }\n if (candidate !== undefined) settings.minWidth = candidate;\n } else {\n if (data[key]) {\n settings[key] = data[key];\n } else if (options && options[key] !== undefined) {\n settings[key] = options[key];\n }\n }\n\n if (defaultSettings[key].type === 'integer') {\n if (!settings[key] || !testValues(settings[key], key)) {\n settings[key] = defaultSettings[key].defaultValue;\n }\n } else if (defaultSettings[key].type === 'string') {\n if (defaultSettings[key].acceptedValues && defaultSettings[key].acceptedValues.indexOf(settings[key]) === -1) {\n console.warn(`${warningLabel} The value \"${settings[key]}\" entered for the setting \"${key}\" was not recognised.`);\n settings[key] = defaultSettings[key].defaultValue;\n }\n }\n });\n\n (function applyColorParity(){\n const data = timelineEl.dataset;\n const getData = function(k){\n return data[k] !== undefined ? data[k] : (data[k && k.toLowerCase()] !== undefined ? data[k.toLowerCase()] : undefined);\n };\n let nodeColor = getData('nodeColor');\n let lineColor = getData('lineColor');\n let navColor = getData('navColor');\n if (options) {\n if (options.nodeColor !== undefined) nodeColor = options.nodeColor;\n if (options.lineColor !== undefined) lineColor = options.lineColor;\n if (options.navColor !== undefined) navColor = options.navColor;\n }\n if (nodeColor || lineColor || navColor) {\n applyTimelineColors(timelineEl, { nodeColor, lineColor, navColor });\n }\n })();\n\n const defaultTrigger = defaultSettings.verticalTrigger.defaultValue.match(/(\\d*\\.?\\d*)(.*)/);\n const triggerArray = settings.verticalTrigger.match(/(\\d*\\.?\\d*)(.*)/);\n let [, triggerValue, triggerUnit] = triggerArray;\n let triggerValid = true;\n if (!triggerValue) {\n console.warn(`${warningLabel} No numercial value entered for the 'verticalTrigger' setting.`);\n triggerValid = false;\n }\n if (triggerUnit !== 'px' && triggerUnit !== '%') {\n console.warn(`${warningLabel} The setting 'verticalTrigger' must be a percentage or pixel value.`);\n triggerValid = false;\n }\n if (triggerUnit === '%' && (triggerValue > 100 || triggerValue < 0)) {\n console.warn(`${warningLabel} The 'verticalTrigger' setting value must be between 0 and 100 if using a percentage value.`);\n triggerValid = false;\n } else if (triggerUnit === 'px' && triggerValue < 0) {\n console.warn(`${warningLabel} The 'verticalTrigger' setting value must be above 0 if using a pixel value.`);\n triggerValid = false;\n }\n\n if (triggerValid === false) {\n [, triggerValue, triggerUnit] = defaultTrigger;\n }\n\n settings.verticalTrigger = {\n unit: triggerUnit,\n value: triggerValue\n };\n\n if (settings.moveItems > settings.visibleItems) {\n console.warn(`${warningLabel} The value of \"moveItems\" (${settings.moveItems}) is larger than the number of \"visibleItems\" (${settings.visibleItems}). The value of \"visibleItems\" has been used instead.`);\n settings.moveItems = settings.visibleItems;\n }\n\n if (settings.startIndex > (items.length - settings.visibleItems) && items.length > settings.visibleItems) {\n console.warn(`${warningLabel} The 'startIndex' setting must be between 0 and ${items.length - settings.visibleItems} for this timeline. The value of ${items.length - settings.visibleItems} has been used instead.`);\n settings.startIndex = items.length - settings.visibleItems;\n } else if (items.length <= settings.visibleItems) {\n console.warn(`${warningLabel} The number of items in the timeline must exceed the number of visible items to use the 'startIndex' option.`);\n settings.startIndex = 0;\n } else if (settings.startIndex < 0) {\n console.warn(`${warningLabel} The 'startIndex' setting must be between 0 and ${items.length - settings.visibleItems} for this timeline. The value of 0 has been used instead.`);\n settings.startIndex = 0;\n }\n\n enhanceInlineItems(timelineEl, items);\n\n if (!timelineEl.id) {\n timelineEl.setAttribute('data-timeline-id', 'timeline-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9));\n }\n\n timelines.push({\n timelineEl,\n wrap,\n scroller,\n items,\n settings,\n listeners: [] // Store listeners for cleanup\n });\n }\n\n if (collection.length) {\n Array.from(collection).forEach(createTimelines);\n }\n\n function setHeightandWidths(tl) {\n function setWidths() {\n tl.itemWidth = 200;\n tl.items.forEach((item) => {\n item.style.width = `${tl.itemWidth}px`;\n });\n tl.scrollerWidth = tl.itemWidth * tl.items.length;\n tl.scroller.style.width = `${tl.scrollerWidth}px`;\n }\n\n function setHeights() {\n let oddIndexTallest = 0;\n let evenIndexTallest = 0;\n tl.items.forEach((item, i) => {\n item.style.height = 'auto';\n const height = item.offsetHeight;\n if (i % 2 === 0) {\n evenIndexTallest = height > evenIndexTallest ? height : evenIndexTallest;\n } else {\n oddIndexTallest = height > oddIndexTallest ? height : oddIndexTallest;\n }\n });\n\n const transformString = `translateY(${evenIndexTallest}px)`;\n tl.items.forEach((item, i) => {\n if (i % 2 === 0) {\n item.style.height = `${evenIndexTallest}px`;\n if (tl.settings.horizontalStartPosition === 'bottom') {\n item.classList.add('timeline__item--bottom');\n addTransforms(item, transformString);\n } else {\n item.classList.add('timeline__item--top');\n }\n } else {\n item.style.height = `${oddIndexTallest}px`;\n if (tl.settings.horizontalStartPosition !== 'bottom') {\n item.classList.add('timeline__item--bottom');\n addTransforms(item, transformString);\n } else {\n item.classList.add('timeline__item--top');\n }\n }\n });\n tl.scroller.style.height = `${evenIndexTallest + oddIndexTallest}px`;\n }\n\n if (window.innerWidth > tl.settings.minWidth) {\n setWidths();\n setHeights();\n }\n }\n\n function addNavigation(tl) {\n const viewportWidth = tl.wrap.offsetWidth;\n const itemsVisible = Math.floor(viewportWidth / tl.itemWidth);\n\n if (tl.items.length > itemsVisible) {\n const prevArrow = document.createElement('button');\n const nextArrow = document.createElement('button');\n const topPosition = tl.items[0].offsetHeight;\n prevArrow.className = 'timeline-nav-button timeline-nav-button--prev';\n nextArrow.className = 'timeline-nav-button timeline-nav-button--next';\n prevArrow.textContent = 'Previous';\n nextArrow.textContent = 'Next';\n prevArrow.style.top = `${topPosition}px`;\n nextArrow.style.top = `${topPosition}px`;\n\n const arrowColor = tl.timelineEl.getAttribute('data-arrow-color') || '#333';\n prevArrow.innerHTML = createArrowSVG('left', arrowColor);\n nextArrow.innerHTML = createArrowSVG('right', arrowColor);\n\n const maxIndex = Math.max(0, tl.items.length - itemsVisible);\n if (currentIndex === 0) {\n prevArrow.disabled = true;\n } else if (currentIndex >= maxIndex) {\n nextArrow.disabled = true;\n }\n tl.timelineEl.appendChild(prevArrow);\n tl.timelineEl.appendChild(nextArrow);\n }\n }\n\n function addHorizontalDivider(tl) {\n const divider = tl.timelineEl.querySelector('.timeline-divider');\n if (divider) {\n tl.timelineEl.removeChild(divider);\n }\n const topPosition = tl.items[0].offsetHeight;\n const horizontalDivider = document.createElement('span');\n horizontalDivider.className = 'timeline-divider';\n horizontalDivider.style.top = `${topPosition}px`;\n tl.timelineEl.appendChild(horizontalDivider);\n }\n\n function timelinePosition(tl) {\n const position = tl.items[currentIndex].offsetLeft;\n const str = `translate3d(-${position}px, 0, 0)`;\n addTransforms(tl.scroller, str);\n }\n\n function slideTimeline(tl) {\n const navArrows = tl.timelineEl.querySelectorAll('.timeline-nav-button');\n const arrowPrev = tl.timelineEl.querySelector('.timeline-nav-button--prev');\n const arrowNext = tl.timelineEl.querySelector('.timeline-nav-button--next');\n\n const viewportWidth = tl.wrap.offsetWidth;\n const itemsVisible = Math.floor(viewportWidth / tl.itemWidth);\n const maxIndex = Math.max(0, tl.items.length - itemsVisible);\n\n const moveItems = parseInt(tl.settings.moveItems, 10);\n \n const handleArrowClick = function(e) {\n e.preventDefault();\n e.stopPropagation();\n\n if (this.disabled) {\n return;\n }\n\n currentIndex = this.classList.contains('timeline-nav-button--next') ? (currentIndex += moveItems) : (currentIndex -= moveItems);\n if (currentIndex === 0 || currentIndex < 0) {\n currentIndex = 0;\n arrowPrev.disabled = true;\n arrowNext.disabled = false;\n } else if (currentIndex === maxIndex || currentIndex > maxIndex) {\n currentIndex = maxIndex;\n arrowPrev.disabled = false;\n arrowNext.disabled = true;\n } else {\n arrowPrev.disabled = false;\n arrowNext.disabled = false;\n }\n timelinePosition(tl);\n };\n \n Array.from(navArrows).forEach((arrow) => {\n arrow.addEventListener('click', handleArrowClick);\n tl.listeners.push({ element: arrow, type: 'click', handler: handleArrowClick });\n });\n }\n\n function setUpHorinzontalTimeline(tl) {\n if (tl.settings.rtlMode) {\n currentIndex = tl.items.length > tl.settings.visibleItems ? tl.items.length - tl.settings.visibleItems : 0;\n } else {\n currentIndex = tl.settings.startIndex;\n }\n tl.timelineEl.classList.add('timeline--horizontal');\n setHeightandWidths(tl);\n timelinePosition(tl);\n addNavigation(tl);\n addHorizontalDivider(tl);\n slideTimeline(tl);\n\n const timelineId = tl.timelineEl.id || tl.timelineEl.getAttribute('data-timeline-id');\n if (timelineId) {\n timelineRegistry[timelineId] = {\n setCurrentIndex: function(index) {\n const viewportWidth = tl.wrap.offsetWidth;\n const itemsVisible = Math.floor(viewportWidth / tl.itemWidth);\n const maxIndex = Math.max(0, tl.items.length - itemsVisible);\n currentIndex = Math.max(0, Math.min(index, maxIndex));\n },\n updatePosition: function() {\n timelinePosition(tl);\n const arrowPrev = tl.timelineEl.querySelector('.timeline-nav-button--prev');\n const arrowNext = tl.timelineEl.querySelector('.timeline-nav-button--next');\n if (arrowPrev && arrowNext) {\n const viewportWidth = tl.wrap.offsetWidth;\n const itemsVisible = Math.floor(viewportWidth / tl.itemWidth);\n const maxIndex = Math.max(0, tl.items.length - itemsVisible);\n arrowPrev.disabled = currentIndex === 0;\n arrowNext.disabled = currentIndex >= maxIndex;\n }\n }\n };\n }\n }\n\n function setUpVerticalTimeline(tl) {\n let lastVisibleIndex = 0;\n tl.items.forEach((item, i) => {\n item.classList.remove('animated', 'fadeIn');\n if (!isElementInViewport(item, tl.settings.verticalTrigger) && i > 0) {\n item.classList.add('animated');\n } else {\n lastVisibleIndex = i;\n }\n const divider = tl.settings.verticalStartPosition === 'left' ? 1 : 0;\n if (i % 2 === divider && window.innerWidth > tl.settings.minWidth) {\n item.classList.add('timeline__item--right');\n } else {\n item.classList.add('timeline__item--left');\n }\n });\n for (let i = 0; i < lastVisibleIndex; i += 1) {\n tl.items[i].classList.remove('animated', 'fadeIn');\n }\n \n // Use IntersectionObserver instead of scroll listener for better performance\n if ('IntersectionObserver' in window) {\n const observerOptions = {\n rootMargin: tl.settings.verticalTrigger.unit === '%' \n ? `${tl.settings.verticalTrigger.value}%` \n : `${tl.settings.verticalTrigger.value}px`,\n threshold: 0.01\n };\n \n const observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n entry.target.classList.add('fadeIn');\n }\n });\n }, observerOptions);\n \n tl.items.forEach((item) => {\n if (item.classList.contains('animated')) {\n observer.observe(item);\n }\n });\n \n // Store observer for cleanup\n tl.observer = observer;\n } else {\n // Fallback for older browsers (though we're targeting 2018+)\n const scrollHandler = () => {\n tl.items.forEach((item) => {\n if (isElementInViewport(item, tl.settings.verticalTrigger)) {\n item.classList.add('fadeIn');\n }\n });\n };\n window.addEventListener('scroll', scrollHandler);\n tl.listeners.push({ element: window, type: 'scroll', handler: scrollHandler });\n }\n }\n\n function resetTimelines(tl) {\n // Clean up event listeners\n if (tl.listeners && tl.listeners.length > 0) {\n tl.listeners.forEach(({ element, type, handler }) => {\n element.removeEventListener(type, handler);\n });\n tl.listeners = [];\n }\n \n // Clean up IntersectionObserver\n if (tl.observer) {\n tl.observer.disconnect();\n tl.observer = null;\n }\n \n tl.timelineEl.classList.remove('timeline--horizontal', 'timeline--mobile');\n tl.scroller.removeAttribute('style');\n tl.items.forEach((item) => {\n item.removeAttribute('style');\n item.classList.remove('animated', 'fadeIn', 'timeline__item--left', 'timeline__item--right');\n });\n const navArrows = tl.timelineEl.querySelectorAll('.timeline-nav-button');\n Array.from(navArrows).forEach((arrow) => {\n arrow.parentNode.removeChild(arrow);\n });\n }\n\n function setUpTimelines() {\n timelines.forEach((tl) => {\n tl.timelineEl.style.opacity = 0;\n if (!tl.timelineEl.classList.contains('timeline--loaded')) {\n wrapElements(tl.items);\n }\n resetTimelines(tl);\n if (window.innerWidth <= tl.settings.minWidth) {\n tl.timelineEl.classList.add('timeline--mobile');\n }\n if (tl.settings.mode === 'horizontal' && window.innerWidth > tl.settings.minWidth) {\n setUpHorinzontalTimeline(tl);\n } else {\n setUpVerticalTimeline(tl);\n }\n tl.timelineEl.classList.add('timeline--loaded');\n });\n\n setTimeout(() => {\n timelines.forEach((tl) => {\n tl.timelineEl.style.opacity = 1;\n });\n }, 500);\n\n if (shouldHideLoader) {\n hideTimelineLoader();\n shouldHideLoader = false;\n }\n }\n\n setUpTimelines();\n\n window.addEventListener('resize', () => {\n clearTimeout(resizeTimer);\n resizeTimer = setTimeout(() => {\n const newWinWidth = window.innerWidth;\n if (newWinWidth !== winWidth) {\n setUpTimelines();\n winWidth = newWinWidth;\n }\n }, 250);\n });\n}","import { timelineBasePath } from '../shared/config.js';\nimport { showTimelineLoader, hideTimelineLoader } from './loader-ui.js';\nimport { showTimelineError } from './error-ui.js';\nimport { applyTimelineColors } from './colors.js';\nimport { handleDeepLinking } from './deep-linking.js';\nimport { timeline } from '../core/timeline-engine.js';\n\nfunction createItemNode(item) {\n const itemEl = document.createElement('div');\n itemEl.className = 'timeline__item';\n\n if (item.id) {\n itemEl.setAttribute('data-node-id', item.id);\n }\n\n itemEl.setAttribute('data-modal-title', item.title || '');\n itemEl.setAttribute('data-modal-content', item.content || '');\n itemEl.setAttribute('data-modal-image', item.image || '');\n if (item.html) {\n itemEl.setAttribute('data-modal-html', item.html);\n }\n\n const content = document.createElement('div');\n content.className = 'timeline__content';\n\n if (item.image) {\n const img = document.createElement('img');\n img.src = item.image;\n img.className = 'timeline__image';\n img.alt = item.title || '';\n img.onerror = function() {\n console.error('Timeline: The image \"' + item.image + '\" could not be loaded. Please check the path.');\n this.src = timelineBasePath + '/missing-image.svg';\n this.alt = 'Image not found';\n this.title = 'Original image: ' + item.image;\n };\n content.appendChild(img);\n }\n\n const textWrapper = document.createElement('div');\n if (item.title) {\n const title = document.createElement('h3');\n title.textContent = item.title;\n textWrapper.appendChild(title);\n }\n\n if (item.content) {\n const para = document.createElement('p');\n let displayText = item.content;\n if (displayText.length > 105) {\n displayText = displayText.substring(0, 105) + '...';\n }\n para.innerHTML = displayText;\n textWrapper.appendChild(para);\n }\n\n if (item.html) {\n const wrapper = document.createElement('div');\n wrapper.innerHTML = item.html;\n textWrapper.appendChild(wrapper);\n }\n\n content.appendChild(textWrapper);\n itemEl.appendChild(content);\n\n itemEl.addEventListener('click', function(e) {\n e.preventDefault();\n if (typeof window.openTimelineModal === 'function') {\n window.openTimelineModal(itemEl);\n }\n });\n itemEl.setAttribute('data-modal-bound', '1');\n\n return itemEl;\n}\n\nfunction applyDataAttributes(container, config) {\n if (config.layoutMode) {\n container.setAttribute('data-mode', config.layoutMode);\n }\n if (config.visibleItems !== undefined) {\n container.setAttribute('data-visible-items', config.visibleItems);\n }\n if (config.minWidth !== undefined) {\n container.setAttribute('data-minwidth', config.minWidth);\n container.setAttribute('data-force-vertical-mode', config.minWidth);\n }\n if (config.maxWidth !== undefined) {\n container.setAttribute('data-maxwidth', config.maxWidth);\n }\n}\n\nexport function renderTimelineFromData(containerSelector, data, config) {\n const container = document.querySelector(containerSelector);\n if (!container) return;\n\n let itemsWrap = container.querySelector('.timeline__items');\n if (!itemsWrap) {\n const wrap = document.createElement('div');\n wrap.className = 'timeline__wrap';\n itemsWrap = document.createElement('div');\n itemsWrap.className = 'timeline__items';\n wrap.appendChild(itemsWrap);\n container.appendChild(wrap);\n } else {\n itemsWrap.innerHTML = '';\n }\n\n if (config) {\n applyDataAttributes(container, config);\n applyTimelineColors(container, config);\n\n if (config.timelineName && config.timelineName.trim() !== '') {\n const existingHeading = container.previousElementSibling;\n if (existingHeading && existingHeading.classList.contains('timeline__heading')) {\n existingHeading.textContent = config.timelineName;\n } else {\n const heading = document.createElement('h1');\n heading.className = 'timeline__heading';\n heading.textContent = config.timelineName;\n container.parentNode.insertBefore(heading, container);\n }\n container.setAttribute('data-timeline-name', config.timelineName);\n }\n }\n\n data.forEach(function (it) {\n itemsWrap.appendChild(createItemNode(it));\n });\n\n return container;\n}\n\nexport function timelineFromData(containerSelector, data, options) {\n const container = renderTimelineFromData(containerSelector, data, options);\n if (!container) return;\n timeline([container], options);\n}\n\nexport function loadDataFromJson(url, containerSelector) {\n const container = document.querySelector(containerSelector);\n if (!container) {\n console.error('Timeline: Container not found:', containerSelector);\n return;\n }\n\n showTimelineLoader();\n\n const timelineId = container ? container.id : null;\n const cacheKey = timelineId ? 'vjs_' + timelineId : null;\n\n if (cacheKey && typeof(Storage) !== 'undefined') {\n try {\n const cached = localStorage.getItem(cacheKey);\n if (cached) {\n const cachedData = JSON.parse(cached);\n fetch(url).then(function(res) {\n if (!res.ok) throw new Error('Failed to load ' + url + ' (' + res.status + ')');\n return res.json();\n }).then(function(json) {\n if (json.lastupdated && cachedData.lastupdated && json.lastupdated === cachedData.lastupdated) {\n console.log('Using cached timeline data for', timelineId);\n processTimelineData(cachedData, containerSelector);\n } else {\n console.log('Updating cached timeline data for', timelineId);\n localStorage.setItem(cacheKey, JSON.stringify(json));\n processTimelineData(json, containerSelector);\n }\n }).catch(function(err) {\n console.warn('Failed to fetch fresh data, using cache:', err);\n processTimelineData(cachedData, containerSelector);\n });\n return;\n }\n } catch (e) {\n console.warn('Error reading from localStorage:', e);\n }\n }\n\n fetch(url).then(function (res) {\n if (!res.ok) throw new Error('Failed to load ' + url + ' (' + res.status + ')');\n return res.json();\n }).then(function (json) {\n if (cacheKey && typeof(Storage) !== 'undefined') {\n try {\n localStorage.setItem(cacheKey, JSON.stringify(json));\n console.log('Cached timeline data for', timelineId);\n } catch (e) {\n console.warn('Failed to cache timeline data:', e);\n }\n }\n processTimelineData(json, containerSelector);\n }).catch(function (err) {\n console.error('Error loading timeline JSON:', err);\n showTimelineError(container, 'json-load', err.message);\n });\n}\n\nexport function processTimelineData(json, containerSelector) {\n const container = document.querySelector(containerSelector);\n if (!container) {\n console.error('Timeline: Container not found:', containerSelector);\n return;\n }\n\n let config = null;\n let nodes = [];\n\n try {\n if (json.nodes && Array.isArray(json.nodes)) {\n nodes = json.nodes;\n config = {\n timelineName: json.timelineName,\n layoutMode: json.layoutMode,\n visibleItems: json.visibleItems,\n minWidth: json.minWidth,\n maxWidth: json.maxWidth,\n nodeColor: json.nodeColor,\n lineColor: json.lineColor,\n navColor: json.navColor,\n lastupdated: json.lastupdated\n };\n } else if (Array.isArray(json)) {\n nodes = json;\n } else {\n throw new Error('Invalid JSON format. Expected object with \"nodes\" array or simple array.');\n }\n\n if (nodes.length === 0) {\n throw new Error('No timeline items found in data.');\n }\n\n renderTimelineFromData(containerSelector, nodes, config);\n\n try {\n timeline(document.querySelectorAll(containerSelector));\n handleDeepLinking(containerSelector);\n hideTimelineLoader();\n } catch (e) {\n console.error('Error initializing timeline:', e);\n const container = document.querySelector(containerSelector);\n if (container) {\n showTimelineError(container, 'invalid-config', e.message);\n }\n hideTimelineLoader();\n }\n\n } catch (e) {\n console.error('Error processing timeline data:', e);\n showTimelineError(container, 'json-parse', e.message);\n hideTimelineLoader();\n }\n}\n\nexport function clearTimelineCache(timelineId) {\n if (typeof(Storage) === 'undefined') {\n console.warn('localStorage not supported');\n return;\n }\n\n if (timelineId) {\n const key = 'vjs_' + timelineId;\n localStorage.removeItem(key);\n console.log('Cleared cache for timeline:', timelineId);\n } else {\n const keys = Object.keys(localStorage);\n let cleared = 0;\n keys.forEach(function(key) {\n if (key.startsWith('vjs_')) {\n localStorage.removeItem(key);\n cleared++;\n }\n });\n console.log('Cleared', cleared, 'timeline cache(s)');\n }\n}\n","// --------------------------------------------------------------------------\r\n// timeline.js - a vanilla JS app to display timelines\r\n// \r\n// Created in 2018 by Mike Collins (https://github.com/squarechip/timeline)\r\n// Modified in 2026 by Ken Dawson (https://github.com/kendawson-online)\r\n// Last updated: 01/08/26\r\n//\r\n// --------------------------------------------------------------------------\r\n\r\nimport { createTimelineModal, openTimelineModal, closeTimelineModal } from './features/modals.js';\r\nimport { handleDeepLinking, navigateToNodeIndex } from './features/deep-linking.js';\r\nimport { renderTimelineFromData, timelineFromData, loadDataFromJson, processTimelineData, clearTimelineCache } from './features/data-loader.js';\r\nimport { timeline } from './core/timeline-engine.js';\r\n\r\nfunction autoInitJsonTimelines() {\r\n const timelinesWithJson = document.querySelectorAll('[data-json-config]');\r\n timelinesWithJson.forEach(function(timelineEl) {\r\n const jsonUrl = timelineEl.getAttribute('data-json-config');\r\n if (!jsonUrl) return;\r\n const className = (timelineEl.className || '').split(' ')[0];\r\n const selector = timelineEl.id ? '#' + timelineEl.id : (className ? '.' + className : null);\r\n if (selector) {\r\n loadDataFromJson(jsonUrl, selector);\r\n }\r\n });\r\n}\r\n\r\nfunction exposeGlobals() {\r\n if (typeof window === 'undefined') return;\r\n window.timeline = timeline;\r\n window.timelineFromData = timelineFromData;\r\n window.renderTimelineFromData = renderTimelineFromData;\r\n window.processTimelineData = processTimelineData;\r\n window.loadDataFromJson = loadDataFromJson;\r\n window.clearTimelineCache = clearTimelineCache;\r\n window.createTimelineModal = createTimelineModal;\r\n window.openTimelineModal = openTimelineModal;\r\n window.closeTimelineModal = closeTimelineModal;\r\n window.handleTimelineDeepLinking = handleDeepLinking;\r\n window.navigateTimelineToNodeIndex = navigateToNodeIndex;\r\n}\r\n\r\nexposeGlobals();\r\n\r\ndocument.addEventListener('DOMContentLoaded', function() {\r\n autoInitJsonTimelines();\r\n});\r\n\r\nif (typeof window !== 'undefined' && window.jQuery) {\r\n (( $) => {\r\n $.fn.timeline = function(opts) {\r\n timeline(this, opts);\r\n return this;\r\n };\r\n })(window.jQuery);\r\n}\r\n\r\nexport {\r\n timeline,\r\n timelineFromData,\r\n renderTimelineFromData,\r\n loadDataFromJson,\r\n processTimelineData,\r\n clearTimelineCache,\r\n createTimelineModal,\r\n openTimelineModal,\r\n closeTimelineModal,\r\n handleDeepLinking,\r\n navigateToNodeIndex\r\n};"],"names":["loaderState","count","startTime","removeTimer","overlayEl","modalState","modal","overlay","timelineRegistry","createTimelineModal","document","createElement","className","addEventListener","closeTimelineModal","innerHTML","closeBtn","querySelector","closeBottomBtn","e","stopPropagation","body","appendChild","key","classList","contains","openTimelineModal","itemEl","title","getAttribute","content","image","html","modalTitle","modalText","modalImage","textContent","src","alt","style","display","replace","setTimeout","add","overflow","remove","handleDeepLinking","containerSelector","urlParams","URLSearchParams","window","location","search","timelineId","get","nodeId","targetContainer","getElementById","console","warn","scrollIntoView","behavior","block","targetNode","itemIndex","Array","from","parentNode","children","indexOf","navigateToNodeIndex","container","index","id","tlData","setCurrentIndex","updatePosition","timelineBasePath","TimelineConfig","basePath","scripts","getElementsByTagName","i","length","dir","substring","lastIndexOf","showTimelineLoader","Date","now","clearTimeout","loader","spinner","hideTimelineLoader","elapsed","remaining","Math","max","removeOverlay","showTimelineError","errorType","details","errorInfo","message","solution","errorDiv","errorIcon","errorTitle","errorMessage","errorSolution","errorDetails","error","getColorBrightness","color","rgb","startsWith","hex","parseInt","matches","match","map","Number","applyTimelineColors","config","nodeColor","lineColor","navColor","setProperty","arrowColor","setAttribute","createArrowSVG","direction","timeline","collection","options","timelines","warningLabel","resizeTimer","winWidth","innerWidth","currentIndex","shouldHideLoader","defaultSettings","minWidth","type","defaultValue","horizontalStartPosition","acceptedValues","mode","moveItems","rtlMode","startIndex","verticalStartPosition","verticalTrigger","visibleItems","itemWrap","el","wrapper","classes","insertBefore","isElementInViewport","triggerPosition","rect","getBoundingClientRect","windowHeight","innerHeight","documentElement","clientHeight","defaultTrigger","triggerUnit","unit","triggerValue","value","trigger","top","left","clientWidth","height","width","addTransforms","transform","webkitTransform","msTransform","timelinePosition","tl","str","items","offsetLeft","scroller","setUpHorinzontalTimeline","settings","timelineEl","itemWidth","forEach","item","scrollerWidth","oddIndexTallest","evenIndexTallest","offsetHeight","transformString","setHeights","setHeightandWidths","viewportWidth","wrap","offsetWidth","itemsVisible","floor","prevArrow","nextArrow","topPosition","maxIndex","disabled","addNavigation","divider","removeChild","horizontalDivider","addHorizontalDivider","navArrows","querySelectorAll","arrowPrev","arrowNext","handleArrowClick","preventDefault","this","arrow","listeners","push","element","handler","slideTimeline","min","setUpTimelines","opacity","removeEventListener","observer","disconnect","removeAttribute","resetTimelines","lastVisibleIndex","observerOptions","rootMargin","threshold","IntersectionObserver","entries","entry","isIntersecting","target","observe","scrollHandler","setUpVerticalTimeline","timelineName","errorPart","data","dataset","Error","slice","call","Object","keys","candidate","undefined","minwidth","forceVerticalMode","forceverticalmode","settingName","getData","k","toLowerCase","triggerArray","triggerValid","hasAttribute","heading","trim","firstP","img","ensureInlineModalData","enhanceInlineItems","random","toString","substr","newWinWidth","renderTimelineFromData","itemsWrap","layoutMode","maxWidth","applyDataAttributes","existingHeading","previousElementSibling","it","onerror","textWrapper","para","displayText","createItemNode","timelineFromData","loadDataFromJson","url","cacheKey","cached","localStorage","getItem","cachedData","JSON","parse","fetch","then","res","ok","status","json","lastupdated","log","processTimelineData","setItem","stringify","catch","err","nodes","isArray","clearTimelineCache","removeItem","cleared","handleTimelineDeepLinking","navigateTimelineToNodeIndex","jsonUrl","split","selector","jQuery","fn","opts"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kendawson-online/vantl",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "A vanilla JavaScript timeline library (modernized fork of squarechip/timeline)",
|
|
5
|
+
"main": "dist/timeline.min.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rollup -c",
|
|
8
|
+
"watch": "rollup -c -w"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
12
|
+
"rollup": "^4.55.1"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"timeline",
|
|
16
|
+
"vanilla",
|
|
17
|
+
"javascript",
|
|
18
|
+
"ui"
|
|
19
|
+
],
|
|
20
|
+
"author": "Ken Dawson",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/kendawson-online/vantl.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/kendawson-online/vantl/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/kendawson-online/vantl#readme",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"files": ["dist"],
|
|
31
|
+
"prepare": "npm run build",
|
|
32
|
+
"publishConfig": { "access": "public" }
|
|
33
|
+
}
|