@websy/websy-designs 1.0.4 → 1.1.2

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.
@@ -10,6 +10,7 @@
10
10
  WebsyRouter
11
11
  WebsyResultList
12
12
  WebsyTable
13
+ WebsyTable2
13
14
  WebsyChart
14
15
  WebsyChartTooltip
15
16
  WebsyLegend
@@ -21,6 +22,11 @@
21
22
  APIService
22
23
  ButtonGroup
23
24
  WebsyUtils
25
+ <<<<<<< HEAD
26
+ WebsyCarousel
27
+ =======
28
+ Pager
29
+ >>>>>>> master
24
30
  */
25
31
 
26
32
  /* global XMLHttpRequest fetch ENV */
@@ -195,16 +201,204 @@ class ButtonGroup {
195
201
  }
196
202
  }
197
203
 
204
+ /* global */
205
+
206
+ class WebsyCarousel {
207
+ constructor (elementId, options) {
208
+ const DEFAULTS = {
209
+ currentFrame: 0,
210
+ frameDuration: 4000,
211
+ showFrameSelector: true,
212
+ showPrevNext: true
213
+ }
214
+ this.playTimeoutFn = null
215
+ this.options = Object.assign({}, DEFAULTS, options)
216
+ if (!elementId) {
217
+ console.log('No element Id provided')
218
+ }
219
+ const el = document.getElementById(elementId)
220
+ if (el) {
221
+ this.elementId = elementId
222
+ el.addEventListener('click', this.handleClick.bind(this))
223
+ this.render()
224
+ }
225
+ }
226
+ handleClick (event) {
227
+ if (event.target.classList.contains('websy-next-arrow')) {
228
+ this.next()
229
+ }
230
+ if (event.target.classList.contains('websy-prev-arrow')) {
231
+ this.prev()
232
+ }
233
+ if (event.target.classList.contains('websy-progress-btn' || 'websy-progress-btn-active')) {
234
+ const index = +event.target.getAttribute('data-index')
235
+ let prevFrameIndex = this.options.currentFrame
236
+ this.options.currentFrame = index
237
+ this.showFrame(prevFrameIndex, index)
238
+ }
239
+ }
240
+ next () {
241
+ this.pause()
242
+ let prevFrameIndex = this.options.currentFrame
243
+ if (this.options.currentFrame === this.options.frames.length - 1) {
244
+ this.options.currentFrame = 0
245
+ }
246
+ else {
247
+ this.options.currentFrame++
248
+ }
249
+ this.showFrame(prevFrameIndex, this.options.currentFrame)
250
+ // this.play()
251
+ // document.getElementById(`${this.elementId}_frame_${this.options.currentFrame}`)
252
+ // .style.transform = `translateX(-100%)`
253
+ // if (`${this.options.currentFrame === this.options.frames.length - 1}`) {
254
+ // document.getElementById`${this.elementId}_frame_${this.options.currentFrame}`.style.transform = `translateX('-100%')`
255
+ // }
256
+ }
257
+ pause () {
258
+ if (this.playTimeoutFn) {
259
+ clearTimeout(this.playTimeoutFn)
260
+ }
261
+ }
262
+ play () {
263
+ this.playTimeoutFn = setTimeout(() => {
264
+ let prevFrameIndex = this.options.currentFrame
265
+ if (this.options.currentFrame === this.options.frames.length - 1) {
266
+ this.options.currentFrame = 0
267
+ }
268
+ else {
269
+ this.options.currentFrame++
270
+ }
271
+ this.showFrame(prevFrameIndex, this.options.currentFrame)
272
+ this.play()
273
+ }, this.options.frameDuration)
274
+ }
275
+ prev () {
276
+ this.pause()
277
+ let prevFrameIndex = this.options.currentFrame
278
+ if (this.options.currentFrame === 0) {
279
+ this.options.currentFrame = this.options.frames.length - 1
280
+ }
281
+ else {
282
+ this.options.currentFrame--
283
+ }
284
+ this.showFrame(prevFrameIndex, this.options.currentFrame)
285
+ // this.play()
286
+ // document.getElementById(`${this.elementId}_frame_${this.options.currentFrame}`)
287
+ // .style.transform = `translateX(100%)`
288
+ }
289
+
290
+ render (options) {
291
+ this.options = Object.assign({}, this.options, options)
292
+ this.resize()
293
+ }
294
+
295
+ resize () {
296
+ const el = document.getElementById(this.elementId)
297
+ if (el) {
298
+ let html = `
299
+ <div class="websy-carousel">
300
+ `
301
+ this.options.frames.forEach((frame, frameIndex) => {
302
+ html += `
303
+ <div id="${this.elementId}_frame_${frameIndex}" class="websy-frame-container animate" style="transform: translateX(${frameIndex === 0 ? '0' : '100%'})">
304
+ `
305
+ frame.images.forEach(image => {
306
+ html += `
307
+ <div style="${image.style || 'position: absolute; width: 100%; height: 100%; top: 0; left: 0;'} background-image: url('${image.url}')" class="${image.classes || ''} websy-carousel-image">
308
+ </div>
309
+ `
310
+ })
311
+ frame.text && frame.text.forEach(text => {
312
+ html += `
313
+ <div style="${text.style || 'position: absolute; width: 100%; height: 100%; top: 0; left: 0;'}" class="${text.classes || ''} websy-carousel-image">
314
+ ${text.html}
315
+ </div>
316
+ `
317
+ })
318
+ html += `</div>`
319
+ })
320
+ if (this.options.showFrameSelector === true) {
321
+ html += `<div class="websy-btn-parent">`
322
+ this.options.frames.forEach((frame, frameIndex) => {
323
+ html += `
324
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" data-index="${frameIndex}" id="${this.elementId}_selector_${frameIndex}"
325
+ class="websy-progress-btn ${this.options.currentFrame === frameIndex ? 'websy-progress-btn-active' : ''}">
326
+ <title>Ellipse</title><circle cx="256" cy="256" r="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/>
327
+ </svg>
328
+ `
329
+ })
330
+ html += `</div>`
331
+ }
332
+ if (this.options.showPrevNext === true) {
333
+ html += `
334
+ <svg xmlns="http://www.w3.org/2000/svg" class="websy-prev-arrow"
335
+ viewBox="0 0 512 512">
336
+ <title>Caret Back</title>
337
+ <path d="M321.94 98L158.82 237.78a24 24 0 000 36.44L321.94 414c15.57 13.34 39.62 2.28 39.62-18.22v-279.6c0-20.5-24.05-31.56-39.62-18.18z"/>
338
+ </svg>
339
+ </div>
340
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="websy-next-arrow">
341
+ <title>Caret Forward</title>
342
+ <path d="M190.06 414l163.12-139.78a24 24 0 000-36.44L190.06 98c-15.57-13.34-39.62-2.28-39.62 18.22v279.6c0 20.5 24.05 31.56 39.62 18.18z"/>
343
+ </svg>
344
+ `
345
+ }
346
+ html += `
347
+ </div>
348
+ `
349
+ el.innerHTML = html
350
+ }
351
+ // this.play()
352
+ // this.showFrameSelector()
353
+ }
354
+
355
+ showFrame (prevFrameIndex, currFrameIndex) {
356
+ let prevTranslateX = prevFrameIndex > currFrameIndex ? '100%' : '-100%'
357
+ let nextTranslateX = prevFrameIndex < currFrameIndex ? '100%' : '-100%'
358
+ if (currFrameIndex === 0 && prevFrameIndex === this.options.frames.length - 1) {
359
+ prevTranslateX = '-100%'
360
+ nextTranslateX = '100%'
361
+ }
362
+ else if (prevFrameIndex === 0 && currFrameIndex === this.options.frames.length - 1) {
363
+ prevTranslateX = '100%'
364
+ nextTranslateX = '-100%'
365
+ }
366
+ const prevF = document.getElementById(
367
+ `${this.elementId}_frame_${prevFrameIndex}`)
368
+ prevF.style.transform = `translateX(${prevTranslateX})`
369
+ const btnInactive = document.getElementById(`${this.elementId}_selector_${prevFrameIndex}`)
370
+ btnInactive.classList.remove('websy-progress-btn-active')
371
+ const newF = document.getElementById(`${this.elementId}_frame_${currFrameIndex}`)
372
+ newF.classList.remove('animate')
373
+ newF.style.transform = `translateX(${nextTranslateX})`
374
+ setTimeout(() => {
375
+ newF.classList.add('animate')
376
+ newF.style.transform = 'translateX(0%)'
377
+ }, 100)
378
+
379
+ const btnActive = document.getElementById(`${this.elementId}_selector_${currFrameIndex}`)
380
+ btnActive.classList.add('websy-progress-btn-active')
381
+ }
382
+
383
+ // showFrameSelector () {
384
+ // }
385
+ }
386
+
198
387
  class WebsyDatePicker {
199
388
  constructor (elementId, options) {
200
389
  this.oneDay = 1000 * 60 * 60 * 24
201
390
  this.currentselection = []
202
391
  this.validDates = []
392
+ this.validYears = []
393
+ this.customRangeSelected = true
203
394
  const DEFAULTS = {
204
395
  defaultRange: 0,
205
396
  minAllowedDate: this.floorDate(new Date(new Date((new Date().setFullYear(new Date().getFullYear() - 1))).setDate(1))),
206
397
  maxAllowedDate: this.floorDate(new Date((new Date()))),
398
+ minAllowedYear: 1970,
399
+ maxAllowedYear: new Date().getFullYear(),
207
400
  daysOfWeek: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
401
+ mode: 'date',
208
402
  monthMap: {
209
403
  0: 'Jan',
210
404
  1: 'Feb',
@@ -221,44 +415,62 @@ class WebsyDatePicker {
221
415
  },
222
416
  ranges: []
223
417
  }
224
- DEFAULTS.ranges = [
225
- {
226
- label: 'All Dates',
227
- range: [DEFAULTS.minAllowedDate, DEFAULTS.maxAllowedDate]
228
- },
229
- {
230
- label: 'Today',
231
- range: [this.floorDate(new Date())]
232
- },
233
- {
234
- label: 'Yesterday',
235
- range: [this.floorDate(new Date().setDate(new Date().getDate() - 1))]
236
- },
237
- {
238
- label: 'Last 7 Days',
239
- range: [this.floorDate(new Date().setDate(new Date().getDate() - 6)), this.floorDate(new Date())]
240
- },
241
- {
242
- label: 'This Month',
243
- range: [this.floorDate(new Date().setDate(1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() + 1) - this.oneDay)]
244
- },
245
- {
246
- label: 'Last Month',
247
- range: [this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() - 1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth()) - this.oneDay)]
248
- },
249
- {
250
- label: 'This Year',
251
- range: [this.floorDate(new Date(`1/1/${new Date().getFullYear()}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear()}`))]
252
- },
253
- {
254
- label: 'Last Year',
255
- range: [this.floorDate(new Date(`1/1/${new Date().getFullYear() - 1}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear() - 1}`))]
256
- }
257
- ]
418
+ DEFAULTS.ranges = {
419
+ date: [
420
+ {
421
+ label: 'All Dates',
422
+ range: [DEFAULTS.minAllowedDate, DEFAULTS.maxAllowedDate]
423
+ },
424
+ {
425
+ label: 'Today',
426
+ range: [this.floorDate(new Date())]
427
+ },
428
+ {
429
+ label: 'Yesterday',
430
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 1))]
431
+ },
432
+ {
433
+ label: 'Last 7 Days',
434
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 6)), this.floorDate(new Date())]
435
+ },
436
+ {
437
+ label: 'This Month',
438
+ range: [this.floorDate(new Date().setDate(1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() + 1) - this.oneDay)]
439
+ },
440
+ {
441
+ label: 'Last Month',
442
+ range: [this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() - 1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth()) - this.oneDay)]
443
+ },
444
+ {
445
+ label: 'This Year',
446
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear()}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear()}`))]
447
+ },
448
+ {
449
+ label: 'Last Year',
450
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear() - 1}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear() - 1}`))]
451
+ }
452
+ ],
453
+ year: [
454
+ {
455
+ label: 'All Years',
456
+ range: [DEFAULTS.minAllowedYear, DEFAULTS.maxAllowedYear]
457
+ },
458
+ {
459
+ label: 'Last 5 Years',
460
+ range: [new Date().getFullYear() - 4, DEFAULTS.maxAllowedYear]
461
+ },
462
+ {
463
+ label: 'Last 10 Years',
464
+ range: [new Date().getFullYear() - 9, DEFAULTS.maxAllowedYear]
465
+ }
466
+ ]
467
+ }
258
468
  this.options = Object.assign({}, DEFAULTS, options)
259
469
  this.selectedRange = this.options.defaultRange || 0
260
- this.selectedRangeDates = [...this.options.ranges[this.options.defaultRange || 0].range]
470
+ this.selectedRangeDates = [...this.options.ranges[this.options.mode][this.options.defaultRange || 0].range]
261
471
  this.priorSelectedDates = null
472
+ this.priorselection = null
473
+ this.priorCustomRangeSelected = null
262
474
  if (!elementId) {
263
475
  console.log('No element Id provided')
264
476
  return
@@ -267,11 +479,14 @@ class WebsyDatePicker {
267
479
  if (el) {
268
480
  this.elementId = elementId
269
481
  el.addEventListener('click', this.handleClick.bind(this))
482
+ el.addEventListener('mousedown', this.handleMouseDown.bind(this))
483
+ el.addEventListener('mouseover', this.handleMouseOver.bind(this))
484
+ el.addEventListener('mouseup', this.handleMouseUp.bind(this))
270
485
  let html = `
271
486
  <div class='websy-date-picker-container'>
272
487
  <span class='websy-dropdown-header-label'>${this.options.label || 'Date'}</span>
273
488
  <div class='websy-date-picker-header'>
274
- <span id='${this.elementId}_selectedRange'>${this.options.ranges[this.selectedRange].label}</span>
489
+ <span id='${this.elementId}_selectedRange'>${this.options.ranges[this.options.mode][this.selectedRange].label}</span>
275
490
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.677 18.52c.914 1.523-.183 3.472-1.967 3.472h-19.414c-1.784 0-2.881-1.949-1.967-3.472l9.709-16.18c.891-1.483 3.041-1.48 3.93 0l9.709 16.18z"/></svg>
276
491
  </div>
277
492
  <div id='${this.elementId}_mask' class='websy-date-picker-mask'></div>
@@ -283,8 +498,12 @@ class WebsyDatePicker {
283
498
  </div><!--
284
499
  --><div id='${this.elementId}_datelist' class='websy-date-picker-custom'>${this.renderDates()}</div>
285
500
  <div class='websy-dp-button-container'>
286
- <button class='websy-btn websy-dp-cancel'>Cancel</button>
287
- <button class='websy-btn websy-dp-confirm'>Confirm</button>
501
+ <button class='${this.options.cancelBtnClasses || ''} websy-btn websy-dp-cancel'>
502
+ <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512"><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
503
+ </button>
504
+ <button class='${this.options.confirmBtnClasses || ''} websy-btn websy-dp-confirm'>
505
+ <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512"><polyline points="416 128 192 384 96 288" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
506
+ </button>
288
507
  </div>
289
508
  </div>
290
509
  </div>
@@ -303,13 +522,21 @@ class WebsyDatePicker {
303
522
  contentEl.classList.remove('active')
304
523
  if (confirm === true) {
305
524
  if (this.options.onChange) {
306
- this.options.onChange(this.selectedRangeDates)
525
+ if (this.customRangeSelected === true) {
526
+ this.options.onChange(this.selectedRangeDates, true)
527
+ }
528
+ else {
529
+ this.options.onChange(this.currentselection, false)
530
+ }
307
531
  }
308
532
  this.updateRange()
309
533
  }
310
534
  else {
311
535
  this.selectedRangeDates = [...this.priorSelectedDates]
312
536
  this.selectedRange = this.priorSelectedRange
537
+ this.customRangeSelected = this.priorCustomRangeSelected
538
+ this.currentselection = [...this.priorselection]
539
+ this.highlightRange()
313
540
  }
314
541
  }
315
542
  floorDate (d) {
@@ -334,11 +561,11 @@ class WebsyDatePicker {
334
561
  this.updateRange(index)
335
562
  }
336
563
  else if (event.target.classList.contains('websy-dp-date')) {
337
- if (event.target.classList.contains('websy-disabled-date')) {
338
- return
339
- }
340
- const timestamp = event.target.id.split('_')[0]
341
- this.selectDate(+timestamp)
564
+ // if (event.target.classList.contains('websy-disabled-date')) {
565
+ // return
566
+ // }
567
+ // const timestamp = event.target.id.split('_')[0]
568
+ // this.selectDate(+timestamp)
342
569
  }
343
570
  else if (event.target.classList.contains('websy-dp-confirm')) {
344
571
  this.close(true)
@@ -347,6 +574,39 @@ class WebsyDatePicker {
347
574
  this.close()
348
575
  }
349
576
  }
577
+ handleMouseDown (event) {
578
+ this.mouseDown = true
579
+ this.dragging = false
580
+ if (event.target.classList.contains('websy-dp-date')) {
581
+ if (event.target.classList.contains('websy-disabled-date')) {
582
+ return
583
+ }
584
+ if (this.customRangeSelected === true) {
585
+ this.currentselection = []
586
+ this.customRangeSelected = false
587
+ }
588
+ this.mouseDownId = +event.target.id.split('_')[0]
589
+ this.selectDate(this.mouseDownId)
590
+ }
591
+ }
592
+ handleMouseOver (event) {
593
+ if (this.mouseDown === true) {
594
+ if (event.target.classList.contains('websy-dp-date')) {
595
+ if (event.target.classList.contains('websy-disabled-date')) {
596
+ return
597
+ }
598
+ if (event.target.id.split('_')[0] !== this.mouseDownId) {
599
+ this.dragging = true
600
+ this.selectDate(+event.target.id.split('_')[0])
601
+ }
602
+ }
603
+ }
604
+ }
605
+ handleMouseUp (event) {
606
+ this.mouseDown = false
607
+ this.dragging = false
608
+ this.mouseDownId = null
609
+ }
350
610
  highlightRange () {
351
611
  const el = document.getElementById(`${this.elementId}_dateList`)
352
612
  const dateEls = el.querySelectorAll('.websy-dp-date')
@@ -358,23 +618,67 @@ class WebsyDatePicker {
358
618
  if (this.selectedRange === 0) {
359
619
  return
360
620
  }
361
- let daysDiff = Math.floor((this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime() - this.selectedRangeDates[0].getTime()) / this.oneDay)
362
- if (this.selectedRangeDates[0].getMonth() !== this.selectedRangeDates[this.selectedRangeDates.length - 1].getMonth()) {
363
- daysDiff += 1
364
- }
365
- for (let i = 0; i < daysDiff + 1; i++) {
366
- let d = this.floorDate(new Date(this.selectedRangeDates[0].getTime() + (i * this.oneDay)))
367
- const dateEl = document.getElementById(`${d.getTime()}_date`)
368
- if (dateEl) {
369
- dateEl.classList.add('selected')
370
- if (d.getTime() === this.selectedRangeDates[0].getTime()) {
371
- dateEl.classList.add('first')
621
+ if (this.customRangeSelected === true) {
622
+ let diff
623
+ if (this.options.mode === 'date') {
624
+ diff = Math.floor((this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime() - this.selectedRangeDates[0].getTime()) / this.oneDay)
625
+ if (this.selectedRangeDates[0].getMonth() !== this.selectedRangeDates[this.selectedRangeDates.length - 1].getMonth()) {
626
+ diff += 1
627
+ }
628
+ }
629
+ else if (this.options.mode === 'year') {
630
+ diff = this.selectedRangeDates[this.selectedRangeDates.length - 1] - this.selectedRangeDates[0]
631
+ if (this.selectedRangeDates[this.selectedRangeDates.length - 1] !== this.selectedRangeDates[0]) {
632
+ // diff += 1
633
+ }
634
+ }
635
+ for (let i = 0; i < diff + 1; i++) {
636
+ let d
637
+ let rangeStart
638
+ let rangeEnd
639
+ if (this.options.mode === 'date') {
640
+ d = this.floorDate(new Date(this.selectedRangeDates[0].getTime() + (i * this.oneDay)))
641
+ d = d.getTime()
642
+ rangeStart = this.selectedRangeDates[0].getTime()
643
+ rangeEnd = this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime()
644
+ }
645
+ else if (this.options.mode === 'year') {
646
+ d = this.selectedRangeDates[0] + i
647
+ rangeStart = this.selectedRangeDates[0]
648
+ rangeEnd = this.selectedRangeDates[this.selectedRangeDates.length - 1]
372
649
  }
373
- if (d.getTime() === this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime()) {
374
- dateEl.classList.add('last')
650
+ let dateEl
651
+ if (this.options.mode === 'date') {
652
+ dateEl = document.getElementById(`${d.getTime()}_date`)
653
+ }
654
+ else if (this.options.mode === 'year') {
655
+ dateEl = document.getElementById(`${d}_year`)
656
+ }
657
+ if (dateEl) {
658
+ dateEl.classList.add('selected')
659
+ if (d === rangeStart) {
660
+ dateEl.classList.add(`${this.options.sortDirection === 'desc' ? 'last' : 'first'}`)
661
+ }
662
+ if (d === rangeEnd) {
663
+ dateEl.classList.add(`${this.options.sortDirection === 'desc' ? 'first' : 'last'}`)
664
+ }
375
665
  }
376
666
  }
377
667
  }
668
+ else {
669
+ this.currentselection.forEach(d => {
670
+ let dateEl
671
+ if (this.options.mode === 'date') {
672
+ dateEl = document.getElementById(`${d}_date`)
673
+ }
674
+ else if (this.options.mode === 'year') {
675
+ dateEl = document.getElementById(`${d}_year`)
676
+ }
677
+ dateEl.classList.add('selected')
678
+ dateEl.classList.add('first')
679
+ dateEl.classList.add('last')
680
+ })
681
+ }
378
682
  }
379
683
  open (options, override = false) {
380
684
  const maskEl = document.getElementById(`${this.elementId}_mask`)
@@ -383,6 +687,8 @@ class WebsyDatePicker {
383
687
  contentEl.classList.add('active')
384
688
  this.priorSelectedDates = [...this.selectedRangeDates]
385
689
  this.priorSelectedRange = this.selectedRange
690
+ this.priorselection = [...this.currentselection]
691
+ this.priorCustomRangeSelected = this.customRangeSelected
386
692
  this.scrollRangeIntoView()
387
693
  }
388
694
  render (disabledDates) {
@@ -403,87 +709,154 @@ class WebsyDatePicker {
403
709
  renderDates (disabledDates) {
404
710
  let disabled = []
405
711
  this.validDates = []
712
+ this.validYears = []
406
713
  if (disabledDates) {
407
- disabled = disabledDates.map(d => d.getTime())
714
+ disabled = disabledDates.map(d => {
715
+ if (this.options.mode === 'date') {
716
+ return d.getTime()
717
+ }
718
+ else if (this.options.mode === 'year') {
719
+ return d
720
+ }
721
+ return d.getTime()
722
+ })
408
723
  }
409
724
  // first disabled all of the ranges
410
- this.options.ranges.forEach(r => (r.disabled = true))
411
- let daysDiff = Math.ceil((this.options.maxAllowedDate.getTime() - this.options.minAllowedDate.getTime()) / this.oneDay) + 1
725
+ this.options.ranges[this.options.mode].forEach(r => (r.disabled = true))
726
+ let diff
727
+ if (this.options.mode === 'date') {
728
+ diff = Math.ceil((this.options.maxAllowedDate.getTime() - this.options.minAllowedDate.getTime()) / this.oneDay) + 1
729
+ }
730
+ else if (this.options.mode === 'year') {
731
+ diff = (this.options.maxAllowedYear - this.options.minAllowedYear) + 1
732
+ }
412
733
  let months = {}
413
- for (let i = 0; i < daysDiff; i++) {
414
- let d = this.floorDate(new Date(this.options.minAllowedDate.getTime() + (i * this.oneDay)))
415
- let monthYear = `${this.options.monthMap[d.getMonth()]} ${d.getFullYear()}`
416
- if (!months[monthYear]) {
417
- months[monthYear] = []
418
- }
419
- if (disabled.indexOf(d.getTime()) === -1) {
420
- this.validDates.push(d.getTime())
734
+ let yearList = []
735
+ for (let i = 0; i < diff; i++) {
736
+ if (this.options.mode === 'date') {
737
+ let d = this.floorDate(new Date(this.options.minAllowedDate.getTime() + (i * this.oneDay)))
738
+ let monthYear = `${this.options.monthMap[d.getMonth()]} ${d.getFullYear()}`
739
+ if (!months[monthYear]) {
740
+ months[monthYear] = []
741
+ }
742
+ if (disabled.indexOf(d.getTime()) === -1) {
743
+ this.validDates.push(d.getTime())
744
+ }
745
+ months[monthYear].push({date: d, dayOfMonth: d.getDate(), dayOfWeek: d.getDay(), id: d.getTime(), disabled: disabled.indexOf(d.getTime()) !== -1})
421
746
  }
422
- months[monthYear].push({date: d, dayOfMonth: d.getDate(), dayOfWeek: d.getDay(), id: d.getTime(), disabled: disabled.indexOf(d.getTime()) !== -1})
747
+ else if (this.options.mode === 'year') {
748
+ let d = this.options.minAllowedYear + i
749
+ yearList.push({year: d, id: d, disabled: disabled.indexOf(d) !== -1})
750
+ if (disabled.indexOf(d) === -1) {
751
+ this.validYears.push(d)
752
+ }
753
+ }
423
754
  }
424
755
  // check each range to see if it can be enabled
425
- for (let i = 0; i < this.options.ranges.length; i++) {
426
- const r = this.options.ranges[i]
427
- // check the first date
428
- if (this.validDates.indexOf(r.range[0].getTime()) !== -1) {
429
- r.disabled = false
430
- }
431
- else if (r.range[1]) {
432
- // check the last date
433
- if (this.validDates.indexOf(r.range[1].getTime()) !== -1) {
756
+ for (let i = 0; i < this.options.ranges[this.options.mode].length; i++) {
757
+ const r = this.options.ranges[this.options.mode][i]
758
+ if (this.options.mode === 'date') {
759
+ // check the first date
760
+ if (this.validDates.indexOf(r.range[0].getTime()) !== -1) {
761
+ r.disabled = false
762
+ }
763
+ else if (r.range[1]) {
764
+ // check the last date
765
+ if (this.validDates.indexOf(r.range[1].getTime()) !== -1) {
766
+ r.disabled = false
767
+ }
768
+ else {
769
+ // check the full range until a match is found
770
+ for (let i = r.range[0].getTime(); i <= r.range[1].getTime(); i += this.oneDay) {
771
+ let testDate = this.floorDate(new Date(i))
772
+ if (this.validDates.indexOf(testDate.getTime()) !== -1) {
773
+ r.disabled = false
774
+ break
775
+ }
776
+ }
777
+ }
778
+ }
779
+ }
780
+ else if (this.options.mode === 'year') {
781
+ if (this.validYears.indexOf(r.range[0]) !== -1) {
434
782
  r.disabled = false
435
783
  }
436
- else {
437
- // check the full range until a match is found
438
- for (let i = r.range[0].getTime(); i <= r.range[1].getTime(); i += this.oneDay) {
439
- let testDate = this.floorDate(new Date(i))
440
- if (this.validDates.indexOf(testDate.getTime()) !== -1) {
441
- r.disabled = false
442
- break
443
- }
784
+ else if (r.range[1]) {
785
+ if (this.validYears.indexOf(r.range[1]) !== -1) {
786
+ r.disabled = false
787
+ }
788
+ else {
789
+ // check the full range until a match is found
790
+ for (let i = r.range[0]; i <= r.range[1]; i++) {
791
+ if (this.validYears.indexOf(r.range[0] + i) !== -1) {
792
+ r.disabled = false
793
+ break
794
+ }
795
+ }
444
796
  }
445
- }
446
- }
797
+ }
798
+ }
447
799
  }
448
800
  let html = ''
449
- html += `
450
- <ul class='websy-dp-days-header'>
451
- `
452
- html += this.options.daysOfWeek.map(d => `<li>${d}</li>`).join('')
453
- html += `
454
- </ul>
455
- <div id='${this.elementId}_dateList' class='websy-dp-date-list'>
456
- `
457
- for (let key in months) {
801
+ if (this.options.mode === 'date') {
458
802
  html += `
459
- <div class='websy-dp-month-container'>
460
- <span id='${key.replace(/\s/g, '_')}'>${key}</span>
461
- <ul>
803
+ <ul class='websy-dp-days-header'>
462
804
  `
463
- if (months[key][0].dayOfWeek > 0) {
464
- let paddedDays = []
465
- for (let i = 0; i < months[key][0].dayOfWeek; i++) {
466
- paddedDays.push(`<li>&nbsp;</li>`)
467
- }
468
- html += paddedDays.join('')
469
- }
470
- html += months[key].map(d => `<li id='${d.id}_date' class='websy-dp-date ${d.disabled === true ? 'websy-disabled-date' : ''}'>${d.dayOfMonth}</li>`).join('')
805
+ html += this.options.daysOfWeek.map(d => `<li>${d}</li>`).join('')
471
806
  html += `
472
- </ul>
473
- </div>
807
+ </ul>
808
+ <div id='${this.elementId}_dateList' class='websy-dp-date-list'>
474
809
  `
475
- }
476
- html += '</div>'
810
+ for (let key in months) {
811
+ html += `
812
+ <div class='websy-dp-month-container'>
813
+ <span id='${key.replace(/\s/g, '_')}'>${key}</span>
814
+ <ul>
815
+ `
816
+ if (months[key][0].dayOfWeek > 0) {
817
+ let paddedDays = []
818
+ for (let i = 0; i < months[key][0].dayOfWeek; i++) {
819
+ paddedDays.push(`<li>&nbsp;</li>`)
820
+ }
821
+ html += paddedDays.join('')
822
+ }
823
+ html += months[key].map(d => `<li id='${d.id}_date' class='websy-dp-date ${d.disabled === true ? 'websy-disabled-date' : ''}'>${d.dayOfMonth}</li>`).join('')
824
+ html += `
825
+ </ul>
826
+ </div>
827
+ `
828
+ }
829
+ html += '</div>'
830
+ }
831
+ else if (this.options.mode === 'year') {
832
+ if (this.options.sortDirection === 'desc') {
833
+ yearList.reverse()
834
+ }
835
+ html += `<div id='${this.elementId}_dateList' class='websy-dp-date-list'><ul>`
836
+ html += yearList.map(d => `<li id='${d.id}_year' class='websy-dp-date websy-dp-year ${d.disabled === true ? 'websy-disabled-date' : ''}'>${d.year}</li>`).join('')
837
+ html += `</ul></div>`
838
+ }
477
839
  return html
478
840
  }
479
841
  renderRanges () {
480
- return this.options.ranges.map((r, i) => `
842
+ return this.options.ranges[this.options.mode].map((r, i) => `
481
843
  <li data-index='${i}' class='websy-date-picker-range ${i === this.selectedRange ? 'active' : ''} ${r.disabled === true ? 'websy-disabled-range' : ''}'>${r.label}</li>
482
- `).join('')
844
+ `).join('') + `<li data-index='-1' class='websy-date-picker-range ${this.selectedRange === -1 ? 'active' : ''}'>Custom</li>`
483
845
  }
484
846
  scrollRangeIntoView () {
485
847
  if (this.selectedRangeDates[0]) {
486
- const el = document.getElementById(`${this.selectedRangeDates[0].getTime()}_date`)
848
+ let el
849
+ if (this.options.mode === 'date') {
850
+ el = document.getElementById(`${this.selectedRangeDates[0].getTime()}_date`)
851
+ }
852
+ else if (this.options.mode === 'year') {
853
+ if (this.options.sortDirection === 'desc') {
854
+ el = document.getElementById(`${this.selectedRangeDates[this.selectedRangeDates.length - 1]}_year`)
855
+ }
856
+ else {
857
+ el = document.getElementById(`${this.selectedRangeDates[0]}_year`)
858
+ }
859
+ }
487
860
  const parentEl = document.getElementById(`${this.elementId}_dateList`)
488
861
  if (el && parentEl) {
489
862
  parentEl.scrollTo(0, el.offsetTop)
@@ -495,23 +868,38 @@ class WebsyDatePicker {
495
868
  this.currentselection.push(timestamp)
496
869
  }
497
870
  else {
498
- if (timestamp > this.currentselection[0]) {
499
- this.currentselection.push(timestamp)
871
+ if (this.dragging === true) {
872
+ this.currentselection = [this.mouseDownId]
873
+ if (timestamp > this.currentselection[0]) {
874
+ this.currentselection.push(timestamp)
875
+ }
876
+ else {
877
+ this.currentselection.splice(0, 0, timestamp)
878
+ }
879
+ this.customRangeSelected = true
500
880
  }
501
881
  else {
502
- this.currentselection.splice(0, 0, timestamp)
503
- }
882
+ this.currentselection.push(timestamp)
883
+ this.currentselection.sort((a, b) => a - b)
884
+ this.customRangeSelected = false
885
+ }
504
886
  }
505
- this.selectedRangeDates = [new Date(this.currentselection[0]), new Date(this.currentselection[1] || this.currentselection[0])]
506
- if (this.currentselection.length === 2) {
507
- this.currentselection = []
887
+ if (this.options.mode === 'date') {
888
+ this.selectedRangeDates = [new Date(this.currentselection[0]), new Date(this.currentselection[1] || this.currentselection[0])]
508
889
  }
890
+ else if (this.options.mode === 'year') {
891
+ this.selectedRangeDates = [this.currentselection[0], this.currentselection[1] || this.currentselection[0]]
892
+ }
893
+ // if (this.currentselection.length === 2) {
894
+ // this.currentselection = []
895
+ // }
509
896
  this.selectedRange = -1
510
897
  this.highlightRange()
511
898
  }
512
899
  selectRange (index) {
513
- if (this.options.ranges[index]) {
514
- this.selectedRangeDates = [...this.options.ranges[index].range]
900
+ if (this.options.ranges[this.options.mode][index]) {
901
+ this.selectedRangeDates = [...this.options.ranges[this.options.mode][index].range]
902
+ this.currentselection = [...this.options.ranges[this.options.mode][index].range]
515
903
  this.selectedRange = +index
516
904
  this.highlightRange()
517
905
  this.close(true)
@@ -520,28 +908,60 @@ class WebsyDatePicker {
520
908
  selectCustomRange (range) {
521
909
  this.selectedRange = -1
522
910
  this.selectedRangeDates = range
911
+ // check if the custom range matches a configured range
912
+ for (let i = 0; i < this.options.ranges[this.options.mode].length; i++) {
913
+ if (this.options.ranges[this.options.mode][i].range.length === 1) {
914
+ if (this.options.ranges[this.options.mode][i].range[0] === range[0]) {
915
+ this.selectedRange = i
916
+ break
917
+ }
918
+ }
919
+ else if (this.options.ranges[this.options.mode][i].range.length === 2) {
920
+ if (this.options.ranges[this.options.mode][i].range[0] === range[0] && this.options.ranges[this.options.mode][i].range[1] === range[1]) {
921
+ this.selectedRange = i
922
+ break
923
+ }
924
+ }
925
+ }
523
926
  this.highlightRange()
524
927
  this.updateRange()
525
928
  }
526
929
  setDateBounds (range) {
527
- if (this.options.ranges[0].label === 'All Dates') {
528
- this.options.ranges[0].range = [range[0], range[1] || range[0]]
930
+ if (['All Dates', 'All Years'].indexOf(this.options.ranges[this.options.mode][0].label) !== -1) {
931
+ this.options.ranges[this.options.mode][0].range = [range[0], range[1] || range[0]]
529
932
  }
530
- this.options.minAllowedDate = range[0]
531
- this.options.maxAllowedDate = range[1] || range[0]
933
+ if (this.options.mode === 'date') {
934
+ this.options.minAllowedDate = range[0]
935
+ this.options.maxAllowedDate = range[1] || range[0]
936
+ }
937
+ else if (this.options.mode === 'year') {
938
+ this.options.minAllowedYear = range[0]
939
+ this.options.maxAllowedYear = range[1] || range[0]
940
+ }
532
941
  }
533
942
  updateRange () {
534
943
  let range
535
944
  if (this.selectedRange === -1) {
536
- let start = this.selectedRangeDates[0].toLocaleDateString()
945
+ const list = (this.currentselection.length > 0 ? this.currentselection : this.selectedRangeDates).map(d => {
946
+ if (this.options.mode === 'date') {
947
+ return d.toLocaleDateString()
948
+ }
949
+ else if (this.options.mode === 'year') {
950
+ return d
951
+ }
952
+ })
953
+ let start = list[0]
537
954
  let end = ''
538
- if (this.selectedRangeDates[1] && (this.selectedRangeDates[0].getTime() !== this.selectedRangeDates[1].getTime())) {
539
- end = ` - ${this.selectedRangeDates[1].toLocaleDateString()}`
540
- }
541
- range = { label: `${start}${end}` }
955
+ if (this.customRangeSelected === true) {
956
+ end = ` - ${list[list.length - 1]}`
957
+ }
958
+ else {
959
+ start = `${list.length} selected`
960
+ }
961
+ range = { label: `${start}${end}` }
542
962
  }
543
963
  else {
544
- range = this.options.ranges[this.selectedRange]
964
+ range = this.options.ranges[this.options.mode][this.selectedRange]
545
965
  }
546
966
  const el = document.getElementById(this.elementId)
547
967
  const labelEl = document.getElementById(`${this.elementId}_selectedRange`)
@@ -591,7 +1011,45 @@ class WebsyDropdown {
591
1011
  el.addEventListener('click', this.handleClick.bind(this))
592
1012
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
593
1013
  el.addEventListener('mouseout', this.handleMouseOut.bind(this))
594
- el.addEventListener('mousemove', this.handleMouseMove.bind(this))
1014
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
1015
+ const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1016
+ const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1017
+ let html = `
1018
+ <div id='${this.elementId}_container' class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''} ${this.options.style}'>
1019
+ <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1020
+ <svg class='search' width="20" height="20" viewBox="0 0 512 512"><path d="M221.09,64A157.09,157.09,0,1,0,378.18,221.09,157.1,157.1,0,0,0,221.09,64Z" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px"/><line x1="338.29" y1="338.29" x2="448" y2="448" style="fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/></svg>
1021
+ <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
1022
+ <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1023
+ <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1024
+ <svg class='arrow' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.677 18.52c.914 1.523-.183 3.472-1.967 3.472h-19.414c-1.784 0-2.881-1.949-1.967-3.472l9.709-16.18c.891-1.483 3.041-1.48 3.93 0l9.709 16.18z"/></svg>
1025
+ `
1026
+ if (this.options.allowClear === true) {
1027
+ html += `
1028
+ <svg class='clear' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512"><title>ionicons-v5-l</title><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
1029
+ `
1030
+ }
1031
+ html += `
1032
+ </div>
1033
+ <div id='${this.elementId}_mask' class='websy-dropdown-mask'></div>
1034
+ <div id='${this.elementId}_content' class='websy-dropdown-content'>
1035
+ `
1036
+ if (this.options.disableSearch !== true) {
1037
+ html += `
1038
+ <input id='${this.elementId}_search' class='websy-dropdown-search' placeholder='${this.options.searchPlaceholder || 'Search'}'>
1039
+ `
1040
+ }
1041
+ html += `
1042
+ <div id='${this.elementId}_itemsContainer' class='websy-dropdown-items'>
1043
+ <ul id='${this.elementId}_items'>
1044
+ </ul>
1045
+ </div><!--
1046
+ --><div class='websy-dropdown-custom'></div>
1047
+ </div>
1048
+ </div>
1049
+ `
1050
+ el.innerHTML = html
1051
+ const scrollEl = document.getElementById(`${this.elementId}_itemsContainer`)
1052
+ scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
595
1053
  this.render()
596
1054
  }
597
1055
  else {
@@ -616,6 +1074,9 @@ class WebsyDropdown {
616
1074
  }
617
1075
  get data () {
618
1076
  return this.options.items
1077
+ }
1078
+ appendRows () {
1079
+
619
1080
  }
620
1081
  clearSelected () {
621
1082
  this.selectedItems = []
@@ -655,6 +1116,10 @@ class WebsyDropdown {
655
1116
  else if (event.target.classList.contains('clear')) {
656
1117
  this.clearSelected()
657
1118
  }
1119
+ else if (event.target.classList.contains('search')) {
1120
+ const el = document.getElementById(`${this.elementId}_container`)
1121
+ el.classList.toggle('search-open')
1122
+ }
658
1123
  }
659
1124
  handleKeyUp (event) {
660
1125
  if (event.target.classList.contains('websy-dropdown-search')) {
@@ -724,6 +1189,13 @@ class WebsyDropdown {
724
1189
  clearTimeout(this.tooltipTimeoutFn)
725
1190
  }
726
1191
  }
1192
+ handleScroll (event) {
1193
+ if (event.target.classList.contains('websy-dropdown-items')) {
1194
+ if (this.options.onScroll) {
1195
+ this.options.onScroll(event)
1196
+ }
1197
+ }
1198
+ }
727
1199
  open (options, override = false) {
728
1200
  const maskEl = document.getElementById(`${this.elementId}_mask`)
729
1201
  const contentEl = document.getElementById(`${this.elementId}_content`)
@@ -744,51 +1216,51 @@ class WebsyDropdown {
744
1216
  console.log('No element Id provided for Websy Dropdown')
745
1217
  return
746
1218
  }
747
- const el = document.getElementById(this.elementId)
748
- const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
749
- const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
750
- let html = `
751
- <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
752
- <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
753
- <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
754
- <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
755
- <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
756
- <svg class='arrow' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.677 18.52c.914 1.523-.183 3.472-1.967 3.472h-19.414c-1.784 0-2.881-1.949-1.967-3.472l9.709-16.18c.891-1.483 3.041-1.48 3.93 0l9.709 16.18z"/></svg>
757
- `
758
- if (this.options.allowClear === true) {
759
- html += `
760
- <svg class='clear' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512"><title>ionicons-v5-l</title><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
761
- `
762
- }
763
- html += `
764
- </div>
765
- <div id='${this.elementId}_mask' class='websy-dropdown-mask'></div>
766
- <div id='${this.elementId}_content' class='websy-dropdown-content'>
767
- `
768
- if (this.options.disableSearch !== true) {
769
- html += `
770
- <input id='${this.elementId}_search' class='websy-dropdown-search' placeholder='${this.options.searchPlaceholder || 'Search'}'>
771
- `
772
- }
773
- html += `
774
- <div class='websy-dropdown-items'>
775
- <ul id='${this.elementId}_items'>
776
- </ul>
777
- </div><!--
778
- --><div class='websy-dropdown-custom'></div>
779
- </div>
780
- </div>
781
- `
782
- el.innerHTML = html
783
- this.renderItems()
784
- }
785
- renderItems () {
786
- let html = this.options.items.map((r, i) => `
787
- <li data-index='${i}' class='websy-dropdown-item ${(r.classes || []).join(' ')} ${this.selectedItems.indexOf(i) !== -1 ? 'active' : ''}'>${r.label}</li>
788
- `).join('')
789
- const el = document.getElementById(`${this.elementId}_items`)
790
- if (el) {
791
- el.innerHTML = html
1219
+ // const el = document.getElementById(this.elementId)
1220
+ // const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1221
+ // const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1222
+ // let html = `
1223
+ // <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1224
+ // <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1225
+ // <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
1226
+ // <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1227
+ // <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1228
+ // <svg class='arrow' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.677 18.52c.914 1.523-.183 3.472-1.967 3.472h-19.414c-1.784 0-2.881-1.949-1.967-3.472l9.709-16.18c.891-1.483 3.041-1.48 3.93 0l9.709 16.18z"/></svg>
1229
+ // `
1230
+ // if (this.options.allowClear === true) {
1231
+ // html += `
1232
+ // <svg class='clear' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512"><title>ionicons-v5-l</title><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
1233
+ // `
1234
+ // }
1235
+ // html += `
1236
+ // </div>
1237
+ // <div id='${this.elementId}_mask' class='websy-dropdown-mask'></div>
1238
+ // <div id='${this.elementId}_content' class='websy-dropdown-content'>
1239
+ // `
1240
+ // if (this.options.disableSearch !== true) {
1241
+ // html += `
1242
+ // <input id='${this.elementId}_search' class='websy-dropdown-search' placeholder='${this.options.searchPlaceholder || 'Search'}'>
1243
+ // `
1244
+ // }
1245
+ // html += `
1246
+ // <div class='websy-dropdown-items'>
1247
+ // <ul id='${this.elementId}_items'>
1248
+ // </ul>
1249
+ // </div><!--
1250
+ // --><div class='websy-dropdown-custom'></div>
1251
+ // </div>
1252
+ // </div>
1253
+ // `
1254
+ // el.innerHTML = html
1255
+ this.renderItems()
1256
+ }
1257
+ renderItems () {
1258
+ let html = this.options.items.map((r, i) => `
1259
+ <li data-index='${i}' class='websy-dropdown-item ${(r.classes || []).join(' ')} ${this.selectedItems.indexOf(i) !== -1 ? 'active' : ''}'>${r.label}</li>
1260
+ `).join('')
1261
+ const el = document.getElementById(`${this.elementId}_items`)
1262
+ if (el) {
1263
+ el.innerHTML = html
792
1264
  }
793
1265
  let item
794
1266
  if (this.selectedItems.length === 1) {
@@ -829,9 +1301,11 @@ class WebsyDropdown {
829
1301
  }
830
1302
  if (labelEl) {
831
1303
  if (this.selectedItems.length === 1) {
832
- labelEl.innerHTML = item.label
833
- labelEl.setAttribute('data-info', item.label)
834
- inputEl.value = item.value
1304
+ if (item) {
1305
+ labelEl.innerHTML = item.label
1306
+ labelEl.setAttribute('data-info', item.label)
1307
+ inputEl.value = item.value
1308
+ }
835
1309
  }
836
1310
  else if (this.selectedItems.length > 1) {
837
1311
  if (this.options.showCompleteSelectedList === true) {
@@ -902,9 +1376,9 @@ class WebsyForm {
902
1376
  this.elementId = elementId
903
1377
  const el = document.getElementById(elementId)
904
1378
  if (el) {
905
- if (this.options.classes) {
906
- this.options.classes.forEach(c => el.classList.add(c))
907
- }
1379
+ // if (this.options.classes) {
1380
+ // this.options.classes.forEach(c => el.classList.add(c))
1381
+ // }
908
1382
  el.addEventListener('click', this.handleClick.bind(this))
909
1383
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
910
1384
  el.addEventListener('keydown', this.handleKeyDown.bind(this))
@@ -992,7 +1466,7 @@ class WebsyForm {
992
1466
  else {
993
1467
  components.forEach(c => {
994
1468
  if (typeof WebsyDesigns[c.component] !== 'undefined') {
995
- const comp = new WebsyDesigns[c.component](`${this.elementId}_input_${c.field}_component`, c.options)
1469
+ c.instance = new WebsyDesigns[c.component](`${this.elementId}_input_${c.field}_component`, c.options)
996
1470
  }
997
1471
  else {
998
1472
  // some user feedback here
@@ -1014,13 +1488,13 @@ class WebsyForm {
1014
1488
  let componentsToProcess = []
1015
1489
  if (el) {
1016
1490
  let html = `
1017
- <form id="${this.elementId}Form">
1491
+ <form id="${this.elementId}Form" class="${this.options.classes || ''}">
1018
1492
  `
1019
1493
  this.options.fields.forEach((f, i) => {
1020
1494
  if (f.component) {
1021
1495
  componentsToProcess.push(f)
1022
1496
  html += `
1023
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1497
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1024
1498
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1025
1499
  <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
1026
1500
  </div><!--
@@ -1028,7 +1502,7 @@ class WebsyForm {
1028
1502
  }
1029
1503
  else if (f.type === 'longtext') {
1030
1504
  html += `
1031
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1505
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1032
1506
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1033
1507
  <textarea
1034
1508
  id="${this.elementId}_input_${f.field}"
@@ -1042,7 +1516,7 @@ class WebsyForm {
1042
1516
  }
1043
1517
  else {
1044
1518
  html += `
1045
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1519
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1046
1520
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1047
1521
  <input
1048
1522
  id="${this.elementId}_input_${f.field}"
@@ -1052,6 +1526,7 @@ class WebsyForm {
1052
1526
  name="${f.field}"
1053
1527
  placeholder="${f.placeholder || ''}"
1054
1528
  value="${f.value || ''}"
1529
+ valueAsDate="${f.type === 'date' ? f.value : ''}"
1055
1530
  oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
1056
1531
  />
1057
1532
  </div><!--
@@ -1059,11 +1534,11 @@ class WebsyForm {
1059
1534
  }
1060
1535
  })
1061
1536
  html += `
1062
- --><button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
1537
+ --><button class="websy-btn submit ${this.options.submit.classes || ''}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
1063
1538
  `
1064
1539
  if (this.options.cancel) {
1065
1540
  html += `
1066
- --><button class="websy-btn cancel ${this.options.cancel.classes}">${this.options.cancel.text || 'Cancel'}</button>
1541
+ --><button class="websy-btn cancel ${this.options.cancel.classes || ''}">${this.options.cancel.text || 'Cancel'}</button>
1067
1542
  `
1068
1543
  }
1069
1544
  html += `
@@ -1284,9 +1759,6 @@ class WebsyNavigationMenu {
1284
1759
  html += this.renderBlock(this.options.items, 'main', 0)
1285
1760
  html += `</div>`
1286
1761
  el.innerHTML = html
1287
- if (this.options.navigator) {
1288
- this.options.navigator.registerElements(el)
1289
- }
1290
1762
  }
1291
1763
  }
1292
1764
  renderBlock (items, block, level = 0) {
@@ -1378,6 +1850,92 @@ class WebsyNavigationMenu {
1378
1850
  }
1379
1851
  }
1380
1852
 
1853
+ /* global WebsyDesigns */
1854
+ class Pager {
1855
+ constructor (elementId, options) {
1856
+ this.elementId = elementId
1857
+ const DEFAULTS = {
1858
+ pageSizePrefix: 'Show',
1859
+ pageSizeSuffix: 'rows',
1860
+ pageSizeOptions: [
1861
+ { label: '10', value: 10 },
1862
+ { label: '20', value: 20 },
1863
+ { label: '50', value: 50 },
1864
+ { label: '100', value: 100 }
1865
+ ],
1866
+ selectedPageSize: 20,
1867
+ pageLabel: 'Page',
1868
+ showPageSize: true,
1869
+ activePage: 0,
1870
+ pages: []
1871
+ }
1872
+ this.options = Object.assign({}, DEFAULTS, options)
1873
+ const el = document.getElementById(this.elementId)
1874
+ if (el) {
1875
+ let html = `
1876
+ <div class="websy-pager-container">
1877
+ `
1878
+ if (this.options.showPageSize === true) {
1879
+ html += `
1880
+ ${this.options.pageSizePrefix} <div id="${this.elementId}_pageSizeSelector" class="websy-page-selector"></div> ${this.options.pageSizeSuffix}
1881
+ `
1882
+ }
1883
+ html += `
1884
+ <ul id="${this.elementId}_pageList" class="websy-page-list"></ul>
1885
+ </div>
1886
+ `
1887
+ el.innerHTML = html
1888
+ el.addEventListener('click', this.handleClick.bind(this))
1889
+ if (this.options.showPageSize === true) {
1890
+ this.pageSizeSelector = new WebsyDesigns.Dropdown(`${this.elementId}_pageSizeSelector`, {
1891
+ selectedItems: [this.options.pageSizeOptions.indexOf(this.options.selectedPageSize)],
1892
+ items: this.pageSizeOptions.map(p => ({ label: p.toString(), value: p })),
1893
+ allowClear: false,
1894
+ disableSearch: true,
1895
+ onItemSelected: (selectedItem) => {
1896
+ if (this.options.onChangePageSize) {
1897
+ this.options.onChangePageSize(selectedItem.value)
1898
+ }
1899
+ }
1900
+ })
1901
+ }
1902
+ this.render()
1903
+ }
1904
+ }
1905
+ handleClick (event) {
1906
+ if (event.target.classList.contains('websy-page-num')) {
1907
+ const pageNum = +event.target.getAttribute('data-index')
1908
+ if (this.options.onSetPage) {
1909
+ this.options.onSetPage(this.options.pages[pageNum])
1910
+ }
1911
+ }
1912
+ }
1913
+ render () {
1914
+ const el = document.getElementById(`${this.elementId}_pageList`)
1915
+ if (el) {
1916
+ let pages = this.options.pages.map((item, index) => {
1917
+ return `<li data-index="${index}" class="websy-page-num ${(this.options.activePage === index) ? 'active' : ''}">${index + 1}</li>`
1918
+ })
1919
+ let startIndex = 0
1920
+ if (this.options.pages.length > 8) {
1921
+ startIndex = Math.max(0, this.options.activePage - 4)
1922
+ pages = pages.splice(startIndex, 10)
1923
+ if (startIndex > 0) {
1924
+ pages.splice(0, 0, `<li>${this.options.pageLabel}&nbsp;</li><li data-page="0" class="websy-page-num">First</li><li>...</li>`)
1925
+ }
1926
+ else {
1927
+ pages.splice(0, 0, `<li>${this.options.pageLabel}&nbsp;</li>`)
1928
+ }
1929
+ if (this.options.activePage < this.options.pages.length - 1) {
1930
+ pages.push('<li>...</li>')
1931
+ pages.push(`<li data-page="${this.options.pages.length - 1}" class="websy-page-num">Last</li>`)
1932
+ }
1933
+ }
1934
+ el.innerHTML = pages.join('')
1935
+ }
1936
+ }
1937
+ }
1938
+
1381
1939
  /* global WebsyDesigns Blob */
1382
1940
  class WebsyPDFButton {
1383
1941
  constructor (elementId, options) {
@@ -2701,76 +3259,462 @@ const WebsyUtils = {
2701
3259
  // decimals = 0
2702
3260
  }
2703
3261
  else {
2704
- numOut = v
2705
- for (let i = 0; i < ranges.length; i++) {
2706
- if (v >= ranges[i].divider) {
2707
- numOut = (v / ranges[i].divider) // .toFixed(decimals).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$100,')
2708
- suffix = ranges[i].suffix
2709
- break
2710
- }
2711
- // else if (isPercentage === true) {
2712
- // numOut = (this * 100).toFixed(decimals)
2713
- // }
2714
- // else {
2715
- // numOut = (this).toFixed(decimals)
2716
- // }
3262
+ numOut = v
3263
+ for (let i = 0; i < ranges.length; i++) {
3264
+ if (v >= ranges[i].divider) {
3265
+ numOut = (v / ranges[i].divider) // .toFixed(decimals).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$100,')
3266
+ suffix = ranges[i].suffix
3267
+ break
3268
+ }
3269
+ // else if (isPercentage === true) {
3270
+ // numOut = (this * 100).toFixed(decimals)
3271
+ // }
3272
+ // else {
3273
+ // numOut = (this).toFixed(decimals)
3274
+ // }
3275
+ }
3276
+ }
3277
+ if (isPercentage === true) {
3278
+ numOut = numOut * 100
3279
+ }
3280
+ if (numOut % 1 > 0) {
3281
+ decimals = 1
3282
+ }
3283
+ if (numOut < 1) {
3284
+ decimals = getZeroDecimals(numOut)
3285
+ }
3286
+ numOut = (+numOut).toFixed(decimals)
3287
+ if (test === true) {
3288
+ return numOut
3289
+ }
3290
+ if (numOut.replace) {
3291
+ numOut = numOut.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
3292
+ }
3293
+ function getDivider (n) {
3294
+ let s = ''
3295
+ let d = 1
3296
+ // let out
3297
+ for (let i = 0; i < ranges.length; i++) {
3298
+ if (n >= ranges[i].divider) {
3299
+ d = ranges[i].divider
3300
+ s = ranges[i].suffix
3301
+ // out = (n / ranges[i].divider).toFixed(decimals).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$100,')
3302
+ break
3303
+ }
3304
+ }
3305
+ return { divider: d, suffix: s }
3306
+ }
3307
+ function getZeroDecimals (n) {
3308
+ let d = 0
3309
+ n = Math.abs(n)
3310
+ if (n === 0) {
3311
+ return 0
3312
+ }
3313
+ while (n < 10) {
3314
+ d++
3315
+ n = n * 10
3316
+ }
3317
+ return d
3318
+ }
3319
+ return `${numOut}${suffix}${isPercentage === true ? '%' : ''}`
3320
+ },
3321
+ toQlikDateNum: d => {
3322
+ return Math.floor(d.getTime() / 86400000 + 25570)
3323
+ }
3324
+ }
3325
+
3326
+ /* global WebsyDesigns */
3327
+ class WebsyTable {
3328
+ constructor (elementId, options) {
3329
+ const DEFAULTS = {
3330
+ pageSize: 20,
3331
+ paging: 'scroll'
3332
+ }
3333
+ this.elementId = elementId
3334
+ this.options = Object.assign({}, DEFAULTS, options)
3335
+ this.rowCount = 0
3336
+ this.busy = false
3337
+ this.tooltipTimeoutFn = null
3338
+ this.data = []
3339
+ const el = document.getElementById(this.elementId)
3340
+ if (el) {
3341
+ let html = `
3342
+ <div id='${this.elementId}_tableContainer' class='websy-vis-table ${this.options.paging === 'pages' ? 'with-paging' : ''}'>
3343
+ <!--<div class="download-button">
3344
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 11h5l-9 10-9-10h5v-11h8v11zm1 11h-10v2h10v-2z"/></svg>
3345
+ </div>-->
3346
+ <table>
3347
+ <thead id="${this.elementId}_head">
3348
+ </thead>
3349
+ <tbody id="${this.elementId}_body">
3350
+ </tbody>
3351
+ <tfoot id="${this.elementId}_foot">
3352
+ </tfoot>
3353
+ </table>
3354
+ <div id="${this.elementId}_errorContainer" class='websy-vis-error-container'>
3355
+ <div>
3356
+ <div id="${this.elementId}_errorTitle"></div>
3357
+ <div id="${this.elementId}_errorMessage"></div>
3358
+ </div>
3359
+ </div>
3360
+ <div id="${this.elementId}_loadingContainer"></div>
3361
+ </div>
3362
+ `
3363
+ if (this.options.paging === 'pages') {
3364
+ html += `
3365
+ <div class="websy-table-paging-container">
3366
+ Show <div id="${this.elementId}_pageSizeSelector" class="websy-vis-page-selector"></div> rows
3367
+ <ul id="${this.elementId}_pageList" class="websy-vis-page-list"></ul>
3368
+ </div>
3369
+ `
3370
+ }
3371
+ let pageOptions = [10, 20, 50, 100, 200]
3372
+ el.innerHTML = html
3373
+ if (this.options.paging === 'pages') {
3374
+ this.pageSizeSelector = new WebsyDesigns.Dropdown(`${this.elementId}_pageSizeSelector`, {
3375
+ selectedItems: [pageOptions.indexOf(this.options.pageSize)],
3376
+ items: pageOptions.map(p => ({ label: p.toString(), value: p })),
3377
+ allowClear: false,
3378
+ disableSearch: true,
3379
+ onItemSelected: (selectedItem) => {
3380
+ if (this.options.onChangePageSize) {
3381
+ this.options.onChangePageSize(selectedItem.value)
3382
+ }
3383
+ }
3384
+ })
3385
+ }
3386
+ el.addEventListener('click', this.handleClick.bind(this))
3387
+ el.addEventListener('mouseout', this.handleMouseOut.bind(this))
3388
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
3389
+ const scrollEl = document.getElementById(`${this.elementId}_tableContainer`)
3390
+ scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
3391
+ this.loadingDialog = new WebsyDesigns.LoadingDialog(`${this.elementId}_loadingContainer`)
3392
+ this.render()
3393
+ }
3394
+ else {
3395
+ console.error(`No element found with ID ${this.elementId}`)
3396
+ }
3397
+ }
3398
+ appendRows (data) {
3399
+ this.hideError()
3400
+ let bodyHTML = ''
3401
+ if (data) {
3402
+ bodyHTML += data.map((r, rowIndex) => {
3403
+ return '<tr>' + r.map((c, i) => {
3404
+ if (this.options.columns[i].show !== false) {
3405
+ let style = ''
3406
+ if (c.style) {
3407
+ style += c.style
3408
+ }
3409
+ if (this.options.columns[i].width) {
3410
+ style += `width: ${this.options.columns[i].width}; `
3411
+ }
3412
+ if (c.backgroundColor) {
3413
+ style += `background-color: ${c.backgroundColor}; `
3414
+ if (!c.color) {
3415
+ style += `color: ${WebsyDesigns.Utils.getLightDark(c.backgroundColor)}; `
3416
+ }
3417
+ }
3418
+ if (c.color) {
3419
+ style += `color: ${c.color}; `
3420
+ }
3421
+ if (this.options.columns[i].showAsLink === true && c.value.trim() !== '') {
3422
+ return `
3423
+ <td
3424
+ data-row-index='${this.rowCount + rowIndex}'
3425
+ data-col-index='${i}'
3426
+ class='${this.options.columns[i].classes || ''}'
3427
+ style='${style}'
3428
+ colspan='${c.colspan || 1}'
3429
+ rowspan='${c.rowspan || 1}'
3430
+ >
3431
+ <a href='${c.value}' target='${this.options.columns[i].openInNewTab === true ? '_blank' : '_self'}'>${c.displayText || this.options.columns[i].linkText || c.value}</a>
3432
+ </td>
3433
+ `
3434
+ }
3435
+ else if ((this.options.columns[i].showAsNavigatorLink === true || this.options.columns[i].showAsRouterLink === true) && c.value.trim() !== '') {
3436
+ return `
3437
+ <td
3438
+ data-view='${c.value}'
3439
+ data-row-index='${this.rowCount + rowIndex}'
3440
+ data-col-index='${i}'
3441
+ class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
3442
+ style='${style}'
3443
+ colspan='${c.colspan || 1}'
3444
+ rowspan='${c.rowspan || 1}'
3445
+ >${c.displayText || this.options.columns[i].linkText || c.value}</td>
3446
+ `
3447
+ }
3448
+ else {
3449
+ let info = c.value
3450
+ if (this.options.columns[i].showAsImage === true) {
3451
+ c.value = `
3452
+ <img src='${c.value}'>
3453
+ `
3454
+ }
3455
+ return `
3456
+ <td
3457
+ data-info='${info}'
3458
+ data-row-index='${this.rowCount + rowIndex}'
3459
+ data-col-index='${i}'
3460
+ class='${this.options.columns[i].classes || ''}'
3461
+ style='${style}'
3462
+ colspan='${c.colspan || 1}'
3463
+ rowspan='${c.rowspan || 1}'
3464
+ >${c.value}</td>
3465
+ `
3466
+ }
3467
+ }
3468
+ }).join('') + '</tr>'
3469
+ }).join('')
3470
+ this.data = this.data.concat(data)
3471
+ this.rowCount = this.data.length
3472
+ }
3473
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
3474
+ bodyEl.innerHTML += bodyHTML
3475
+ }
3476
+ buildSearchIcon (field) {
3477
+ return `
3478
+ <div>
3479
+ <svg
3480
+ class="tableSearchIcon"
3481
+ data-field="${field}"
3482
+ xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"
3483
+ >
3484
+ <path d="M0 0h24v24H0z" fill="none"/>
3485
+ <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
3486
+ </svg>
3487
+ </div>
3488
+ `
3489
+ }
3490
+ handleClick (event) {
3491
+ if (event.target.classList.contains('download-button')) {
3492
+ window.viewManager.dataExportController.exportData(this.options.model)
3493
+ }
3494
+ if (event.target.classList.contains('sortable-column')) {
3495
+ const colIndex = +event.target.getAttribute('data-index')
3496
+ const column = this.options.columns[colIndex]
3497
+ if (this.options.onSort) {
3498
+ this.options.onSort(event, column, colIndex)
3499
+ }
3500
+ else {
3501
+ this.internalSort(column, colIndex)
3502
+ }
3503
+ // const colIndex = +event.target.getAttribute('data-index')
3504
+ // const dimIndex = +event.target.getAttribute('data-dim-index')
3505
+ // const expIndex = +event.target.getAttribute('data-exp-index')
3506
+ // const reverse = event.target.getAttribute('data-reverse') === 'true'
3507
+ // const patchDefs = [{
3508
+ // qOp: 'replace',
3509
+ // qPath: '/qHyperCubeDef/qInterColumnSortOrder',
3510
+ // qValue: JSON.stringify([colIndex])
3511
+ // }]
3512
+ // patchDefs.push({
3513
+ // qOp: 'replace',
3514
+ // qPath: `/qHyperCubeDef/${dimIndex > -1 ? 'qDimensions' : 'qMeasures'}/${dimIndex > -1 ? dimIndex : expIndex}/qDef/qReverseSort`,
3515
+ // qValue: JSON.stringify(reverse)
3516
+ // })
3517
+ // this.options.model.applyPatches(patchDefs) // .then(() => this.render())
3518
+ }
3519
+ else if (event.target.classList.contains('tableSearchIcon')) {
3520
+ let field = event.target.getAttribute('data-field')
3521
+ window.viewManager.views.global.objects[1].instance.show(field, { x: event.pageX, y: event.pageY }, () => {
3522
+ event.target.classList.remove('active')
3523
+ })
3524
+ }
3525
+ else if (event.target.classList.contains('clickable')) {
3526
+ const colIndex = +event.target.getAttribute('data-col-index')
3527
+ const rowIndex = +event.target.getAttribute('data-row-index')
3528
+ if (this.options.onClick) {
3529
+ this.options.onClick(event, this.data[rowIndex][colIndex], this.data[rowIndex], this.options.columns[colIndex])
3530
+ }
3531
+ }
3532
+ else if (event.target.classList.contains('websy-page-num')) {
3533
+ const pageNum = +event.target.getAttribute('data-page')
3534
+ if (this.options.onSetPage) {
3535
+ this.options.onSetPage(pageNum)
3536
+ }
3537
+ }
3538
+ }
3539
+ handleMouseMove (event) {
3540
+ if (this.tooltipTimeoutFn) {
3541
+ event.target.classList.remove('websy-delayed-info')
3542
+ clearTimeout(this.tooltipTimeoutFn)
3543
+ }
3544
+ if (event.target.tagName === 'TD') {
3545
+ this.tooltipTimeoutFn = setTimeout(() => {
3546
+ event.target.classList.add('websy-delayed-info')
3547
+ }, 500)
3548
+ }
3549
+ }
3550
+ handleMouseOut (event) {
3551
+ if (this.tooltipTimeoutFn) {
3552
+ event.target.classList.remove('websy-delayed-info')
3553
+ clearTimeout(this.tooltipTimeoutFn)
3554
+ }
3555
+ }
3556
+ handleScroll (event) {
3557
+ if (this.options.onScroll && this.options.paging === 'scroll') {
3558
+ this.options.onScroll(event)
3559
+ }
3560
+ }
3561
+ hideError () {
3562
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3563
+ if (containerEl) {
3564
+ containerEl.classList.remove('active')
3565
+ }
3566
+ }
3567
+ hideLoading () {
3568
+ this.loadingDialog.hide()
3569
+ }
3570
+ internalSort (column, colIndex) {
3571
+ this.options.columns.forEach((c, i) => {
3572
+ c.activeSort = i === colIndex
3573
+ })
3574
+ if (column.sortFunction) {
3575
+ this.data = column.sortFunction(this.data, column)
3576
+ }
3577
+ else {
3578
+ let sortProp = 'value'
3579
+ let sortOrder = column.sort === 'asc' ? 'desc' : 'asc'
3580
+ column.sort = sortOrder
3581
+ let sortType = column.sortType || 'alphanumeric'
3582
+ if (column.sortProp) {
3583
+ sortProp = column.sortProp
2717
3584
  }
3585
+ this.data.sort((a, b) => {
3586
+ switch (sortType) {
3587
+ case 'numeric':
3588
+ if (sortOrder === 'asc') {
3589
+ return a[colIndex][sortProp] - b[colIndex][sortProp]
3590
+ }
3591
+ else {
3592
+ return b[colIndex][sortProp] - a[colIndex][sortProp]
3593
+ }
3594
+ default:
3595
+ if (sortOrder === 'asc') {
3596
+ return a[colIndex][sortProp] > b[colIndex][sortProp] ? 1 : -1
3597
+ }
3598
+ else {
3599
+ return a[colIndex][sortProp] < b[colIndex][sortProp] ? 1 : -1
3600
+ }
3601
+ }
3602
+ })
2718
3603
  }
2719
- if (isPercentage === true) {
2720
- numOut = numOut * 100
3604
+ this.render(this.data)
3605
+ }
3606
+ render (data) {
3607
+ if (!this.options.columns) {
3608
+ return
2721
3609
  }
2722
- if (numOut % 1 > 0) {
2723
- decimals = 1
3610
+ this.hideError()
3611
+ this.data = []
3612
+ this.rowCount = 0
3613
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
3614
+ bodyEl.innerHTML = ''
3615
+ if (this.options.allowDownload === true) {
3616
+ // doesn't do anything yet
3617
+ const el = document.getElementById(this.elementId)
3618
+ if (el) {
3619
+ el.classList.add('allow-download')
3620
+ }
3621
+ else {
3622
+ el.classList.remove('allow-download')
3623
+ }
2724
3624
  }
2725
- if (numOut < 1) {
2726
- decimals = getZeroDecimals(numOut)
2727
- }
2728
- numOut = (+numOut).toFixed(decimals)
2729
- if (test === true) {
2730
- return numOut
3625
+ let headHTML = '<tr>' + this.options.columns.map((c, i) => {
3626
+ if (c.show !== false) {
3627
+ return `
3628
+ <th ${c.width ? 'style="width: ' + (c.width || 'auto') + ';"' : ''}>
3629
+ <div class ="tableHeader">
3630
+ <div class="leftSection">
3631
+ <div
3632
+ class="tableHeaderField ${['asc', 'desc'].indexOf(c.sort) !== -1 ? 'sortable-column' : ''}"
3633
+ data-index="${i}"
3634
+ data-sort="${c.sort}"
3635
+ >
3636
+ ${c.name}
3637
+ </div>
3638
+ </div>
3639
+ <div class="${c.activeSort ? c.sort + ' sortOrder' : ''}"></div>
3640
+ <!--${c.searchable === true ? this.buildSearchIcon(c.qGroupFieldDefs[0]) : ''}-->
3641
+ </div>
3642
+ </th>
3643
+ `
3644
+ }
3645
+ }).join('') + '</tr>'
3646
+ const headEl = document.getElementById(`${this.elementId}_head`)
3647
+ headEl.innerHTML = headHTML
3648
+ // let footHTML = '<tr>' + this.options.columns.map((c, i) => {
3649
+ // if (c.show !== false) {
3650
+ // return `
3651
+ // <th></th>
3652
+ // `
3653
+ // }
3654
+ // }).join('') + '</tr>'
3655
+ // const footEl = document.getElementById(`${this.elementId}_foot`)
3656
+ // footEl.innerHTML = footHTML
3657
+ if (this.options.paging === 'pages') {
3658
+ const pagingEl = document.getElementById(`${this.elementId}_pageList`)
3659
+ if (pagingEl) {
3660
+ let pages = (new Array(this.options.pageCount)).fill('').map((item, index) => {
3661
+ return `<li data-page="${index}" class="websy-page-num ${(this.options.pageNum === index) ? 'active' : ''}">${index + 1}</li>`
3662
+ })
3663
+ let startIndex = 0
3664
+ if (this.options.pageCount > 8) {
3665
+ startIndex = Math.max(0, this.options.pageNum - 4)
3666
+ pages = pages.splice(startIndex, 10)
3667
+ if (startIndex > 0) {
3668
+ pages.splice(0, 0, `<li>Page&nbsp;</li><li data-page="0" class="websy-page-num">First</li><li>...</li>`)
3669
+ }
3670
+ else {
3671
+ pages.splice(0, 0, '<li>Page&nbsp;</li>')
3672
+ }
3673
+ if (this.options.pageNum < this.options.pageCount - 1) {
3674
+ pages.push('<li>...</li>')
3675
+ pages.push(`<li data-page="${this.options.pageCount - 1}" class="websy-page-num">Last</li>`)
3676
+ }
3677
+ }
3678
+ pagingEl.innerHTML = pages.join('')
3679
+ }
2731
3680
  }
2732
- if (numOut.replace) {
2733
- numOut = numOut.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
3681
+ if (data) {
3682
+ // this.data = this.data.concat(data)
3683
+ this.appendRows(data)
2734
3684
  }
2735
- function getDivider (n) {
2736
- let s = ''
2737
- let d = 1
2738
- // let out
2739
- for (let i = 0; i < ranges.length; i++) {
2740
- if (n >= ranges[i].divider) {
2741
- d = ranges[i].divider
2742
- s = ranges[i].suffix
2743
- // out = (n / ranges[i].divider).toFixed(decimals).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$100,')
2744
- break
2745
- }
2746
- }
2747
- return { divider: d, suffix: s }
3685
+ }
3686
+ showError (options) {
3687
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3688
+ if (containerEl) {
3689
+ containerEl.classList.add('active')
2748
3690
  }
2749
- function getZeroDecimals (n) {
2750
- let d = 0
2751
- n = Math.abs(n)
2752
- if (n === 0) {
2753
- return 0
2754
- }
2755
- while (n < 10) {
2756
- d++
2757
- n = n * 10
2758
- }
2759
- return d
3691
+ if (options.title) {
3692
+ const titleEl = document.getElementById(`${this.elementId}_errorTitle`)
3693
+ if (titleEl) {
3694
+ titleEl.innerHTML = options.title
3695
+ }
2760
3696
  }
2761
- return `${numOut}${suffix}${isPercentage === true ? '%' : ''}`
2762
- },
2763
- toQlikDateNum: d => {
2764
- return Math.floor(d.getTime() / 86400000 + 25570)
3697
+ if (options.message) {
3698
+ const messageEl = document.getElementById(`${this.elementId}_errorTitle`)
3699
+ if (messageEl) {
3700
+ messageEl.innerHTML = options.message
3701
+ }
3702
+ }
3703
+ }
3704
+ showLoading (options) {
3705
+ this.loadingDialog.show(options)
2765
3706
  }
2766
3707
  }
2767
3708
 
2768
3709
  /* global WebsyDesigns */
2769
- class WebsyTable {
3710
+ class WebsyTable2 {
2770
3711
  constructor (elementId, options) {
2771
3712
  const DEFAULTS = {
2772
3713
  pageSize: 20,
2773
- paging: 'scroll'
3714
+ paging: 'scroll',
3715
+ cellSize: 35,
3716
+ virtualScroll: false,
3717
+ leftColumns: 0
2774
3718
  }
2775
3719
  this.elementId = elementId
2776
3720
  this.options = Object.assign({}, DEFAULTS, options)
@@ -2781,11 +3725,11 @@ class WebsyTable {
2781
3725
  const el = document.getElementById(this.elementId)
2782
3726
  if (el) {
2783
3727
  let html = `
2784
- <div id='${this.elementId}_tableContainer' class='websy-vis-table ${this.options.paging === 'pages' ? 'with-paging' : ''}'>
3728
+ <div id='${this.elementId}_tableContainer' class='websy-vis-table ${this.options.paging === 'pages' ? 'with-paging' : ''} ${this.options.virtualScroll === true ? 'with-virtual-scroll' : ''}'>
2785
3729
  <!--<div class="download-button">
2786
3730
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 11h5l-9 10-9-10h5v-11h8v11zm1 11h-10v2h10v-2z"/></svg>
2787
3731
  </div>-->
2788
- <table>
3732
+ <table id="${this.elementId}_table">
2789
3733
  <thead id="${this.elementId}_head">
2790
3734
  </thead>
2791
3735
  <tbody id="${this.elementId}_body">
@@ -2799,6 +3743,13 @@ class WebsyTable {
2799
3743
  <div id="${this.elementId}_errorMessage"></div>
2800
3744
  </div>
2801
3745
  </div>
3746
+ <div id="${this.elementId}_vScrollContainer" class="websy-v-scroll-container">
3747
+ <div id="${this.elementId}_vScrollHandle" class="websy-scroll-handle websy-scroll-handle-y"></div>
3748
+ </div>
3749
+ <div id="${this.elementId}_hScrollContainer" class="websy-h-scroll-container">
3750
+ <div id="${this.elementId}_hScrollHandle" class="websy-scroll-handle websy-scroll-handle-x"></div>
3751
+ </div>
3752
+ <div id="${this.elementId}_dropdownContainer"></div>
2802
3753
  <div id="${this.elementId}_loadingContainer"></div>
2803
3754
  </div>
2804
3755
  `
@@ -2828,6 +3779,9 @@ class WebsyTable {
2828
3779
  el.addEventListener('click', this.handleClick.bind(this))
2829
3780
  el.addEventListener('mouseout', this.handleMouseOut.bind(this))
2830
3781
  el.addEventListener('mousemove', this.handleMouseMove.bind(this))
3782
+ el.addEventListener('mousedown', this.handleMouseDown.bind(this))
3783
+ el.addEventListener('mouseup', this.handleMouseUp.bind(this))
3784
+ document.addEventListener('mouseup', this.handleGlobalMouseUp.bind(this))
2831
3785
  const scrollEl = document.getElementById(`${this.elementId}_tableContainer`)
2832
3786
  scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
2833
3787
  this.loadingDialog = new WebsyDesigns.LoadingDialog(`${this.elementId}_loadingContainer`)
@@ -2839,12 +3793,13 @@ class WebsyTable {
2839
3793
  }
2840
3794
  appendRows (data) {
2841
3795
  this.hideError()
2842
- let bodyHTML = ''
2843
- if (data) {
3796
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
3797
+ let bodyHTML = ''
3798
+ if (data) {
2844
3799
  bodyHTML += data.map((r, rowIndex) => {
2845
3800
  return '<tr>' + r.map((c, i) => {
2846
3801
  if (this.options.columns[i].show !== false) {
2847
- let style = ''
3802
+ let style = `height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px;`
2848
3803
  if (c.style) {
2849
3804
  style += c.style
2850
3805
  }
@@ -2853,10 +3808,13 @@ class WebsyTable {
2853
3808
  }
2854
3809
  if (c.backgroundColor) {
2855
3810
  style += `background-color: ${c.backgroundColor}; `
3811
+ if (!c.color) {
3812
+ style += `color: ${WebsyDesigns.Utils.getLightDark(c.backgroundColor)}; `
3813
+ }
2856
3814
  }
2857
3815
  if (c.color) {
2858
3816
  style += `color: ${c.color}; `
2859
- }
3817
+ }
2860
3818
  if (this.options.columns[i].showAsLink === true && c.value.trim() !== '') {
2861
3819
  return `
2862
3820
  <td
@@ -2907,22 +3865,29 @@ class WebsyTable {
2907
3865
  }).join('') + '</tr>'
2908
3866
  }).join('')
2909
3867
  this.data = this.data.concat(data)
2910
- this.rowCount = this.data.length
3868
+ this.rowCount = this.data.length
3869
+ }
3870
+ bodyEl.innerHTML += bodyHTML
3871
+ if (this.options.virtualScroll === true) {
3872
+ // get height of the thead
3873
+ if (this.options.paging !== 'pages') {
3874
+ const headEl = document.getElementById(`${this.elementId}_head`)
3875
+ const vScrollContainerEl = document.getElementById(`${this.elementId}_vScrollContainer`)
3876
+ vScrollContainerEl.style.top = `${headEl.clientHeight}px`
3877
+ }
3878
+ const hScrollContainerEl = document.getElementById(`${this.elementId}_hScrollContainer`)
3879
+ let left = 0
3880
+ const cells = bodyEl.querySelectorAll(`tr:first-of-type td`)
3881
+ for (let i = 0; i < this.options.leftColumns; i++) {
3882
+ left += cells[i].offsetWidth || cells[i].clientWidth
3883
+ }
3884
+ hScrollContainerEl.style.left = `${left}px`
2911
3885
  }
2912
- const bodyEl = document.getElementById(`${this.elementId}_body`)
2913
- bodyEl.innerHTML += bodyHTML
2914
3886
  }
2915
- buildSearchIcon (field) {
3887
+ buildSearchIcon (columnIndex) {
2916
3888
  return `
2917
- <div>
2918
- <svg
2919
- class="tableSearchIcon"
2920
- data-field="${field}"
2921
- xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"
2922
- >
2923
- <path d="M0 0h24v24H0z" fill="none"/>
2924
- <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
2925
- </svg>
3889
+ <div class="websy-table-search-icon" data-col-index="${columnIndex}">
3890
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 512 512"><title>ionicons-v5-f</title><path d="M221.09,64A157.09,157.09,0,1,0,378.18,221.09,157.1,157.1,0,0,0,221.09,64Z" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px"/><line x1="338.29" y1="338.29" x2="448" y2="448" style="fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/></svg>
2926
3891
  </div>
2927
3892
  `
2928
3893
  }
@@ -2955,11 +3920,15 @@ class WebsyTable {
2955
3920
  // })
2956
3921
  // this.options.model.applyPatches(patchDefs) // .then(() => this.render())
2957
3922
  }
2958
- else if (event.target.classList.contains('tableSearchIcon')) {
2959
- let field = event.target.getAttribute('data-field')
2960
- window.viewManager.views.global.objects[1].instance.show(field, { x: event.pageX, y: event.pageY }, () => {
2961
- event.target.classList.remove('active')
2962
- })
3923
+ else if (event.target.classList.contains('websy-table-search-icon')) {
3924
+ // let field = event.target.getAttribute('data-field')
3925
+ // window.viewManager.views.global.objects[1].instance.show(field, { x: event.pageX, y: event.pageY }, () => {
3926
+ // event.target.classList.remove('active')
3927
+ // })
3928
+ const colIndex = +event.target.getAttribute('data-col-index')
3929
+ if (this.options.columns[colIndex].onSearch) {
3930
+ this.options.columns[colIndex].onSearch(event, this.options.columns[colIndex])
3931
+ }
2963
3932
  }
2964
3933
  else if (event.target.classList.contains('clickable')) {
2965
3934
  const colIndex = +event.target.getAttribute('data-col-index')
@@ -2975,6 +3944,29 @@ class WebsyTable {
2975
3944
  }
2976
3945
  }
2977
3946
  }
3947
+ handleMouseDown (event) {
3948
+ if (event.target.classList.contains('websy-scroll-handle')) {
3949
+ this.scrolling = true
3950
+ const el = document.getElementById(this.elementId)
3951
+ el.classList.add('scrolling')
3952
+ }
3953
+ if (event.target.classList.contains('websy-scroll-handle-x')) {
3954
+ const handleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
3955
+ this.handleXStart = handleEl.offsetLeft
3956
+ this.scrollXStart = event.clientX
3957
+ this.scrollDirection = 'X'
3958
+ }
3959
+ }
3960
+ handleGlobalMouseUp (event) {
3961
+ this.scrolling = false
3962
+ const el = document.getElementById(this.elementId)
3963
+ el.classList.remove('scrolling')
3964
+ }
3965
+ handleMouseUp (event) {
3966
+ this.scrolling = false
3967
+ const el = document.getElementById(this.elementId)
3968
+ el.classList.remove('scrolling')
3969
+ }
2978
3970
  handleMouseMove (event) {
2979
3971
  if (this.tooltipTimeoutFn) {
2980
3972
  event.target.classList.remove('websy-delayed-info')
@@ -2985,6 +3977,28 @@ class WebsyTable {
2985
3977
  event.target.classList.add('websy-delayed-info')
2986
3978
  }, 500)
2987
3979
  }
3980
+ if (this.scrolling === true && this.options.virtualScroll === true) {
3981
+ const tableContainerEl = document.getElementById(`${this.elementId}_tableContainer`)
3982
+ if (this.scrollDirection === 'X') {
3983
+ const handleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
3984
+ // console.log(this.handleXStart + handleEl.offsetWidth + (event.clientX - this.scrollXStart), this.columnParameters.scrollableWidth)
3985
+ let startPoint = 0
3986
+ if (this.handleXStart + (event.clientX - this.scrollXStart) < this.columnParameters.scrollableWidth - handleEl.offsetWidth) {
3987
+ handleEl.style.left = `${this.handleXStart + (event.clientX - this.scrollXStart)}px`
3988
+ startPoint = this.handleXStart + (event.clientX - this.scrollXStart)
3989
+ }
3990
+ else {
3991
+ startPoint = this.columnParameters.scrollableWidth - handleEl.offsetWidth
3992
+ }
3993
+ if (this.handleXStart + (event.clientX - this.scrollXStart) < 0) {
3994
+ handleEl.style.left = 0
3995
+ startPoint = 0
3996
+ }
3997
+ if (this.options.onScrollX) {
3998
+ this.options.onScrollX(startPoint)
3999
+ }
4000
+ }
4001
+ }
2988
4002
  }
2989
4003
  handleMouseOut (event) {
2990
4004
  if (this.tooltipTimeoutFn) {
@@ -2998,6 +4012,12 @@ class WebsyTable {
2998
4012
  }
2999
4013
  }
3000
4014
  hideError () {
4015
+ const el = document.getElementById(`${this.elementId}_tableContainer`)
4016
+ if (el) {
4017
+ el.classList.remove('has-error')
4018
+ }
4019
+ const tableEl = document.getElementById(`${this.elementId}_table`)
4020
+ tableEl.classList.remove('hidden')
3001
4021
  const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3002
4022
  if (containerEl) {
3003
4023
  containerEl.classList.remove('active')
@@ -3061,6 +4081,7 @@ class WebsyTable {
3061
4081
  el.classList.remove('allow-download')
3062
4082
  }
3063
4083
  }
4084
+ // let colGroupHTML = this.options.columns.map(c => `<col style="${c.width ? 'width: ' + c.width : ''}"></col>`)
3064
4085
  let headHTML = '<tr>' + this.options.columns.map((c, i) => {
3065
4086
  if (c.show !== false) {
3066
4087
  return `
@@ -3076,7 +4097,7 @@ class WebsyTable {
3076
4097
  </div>
3077
4098
  </div>
3078
4099
  <div class="${c.activeSort ? c.sort + ' sortOrder' : ''}"></div>
3079
- <!--${c.searchable === true ? this.buildSearchIcon(c.qGroupFieldDefs[0]) : ''}-->
4100
+ ${c.searchable === true ? this.buildSearchIcon(i) : ''}
3080
4101
  </div>
3081
4102
  </th>
3082
4103
  `
@@ -3084,6 +4105,20 @@ class WebsyTable {
3084
4105
  }).join('') + '</tr>'
3085
4106
  const headEl = document.getElementById(`${this.elementId}_head`)
3086
4107
  headEl.innerHTML = headHTML
4108
+ const dropdownEl = document.getElementById(`${this.elementId}_dropdownContainer`)
4109
+ if (dropdownEl.innerHTML === '') {
4110
+ let dropdownHTML = ``
4111
+ this.options.columns.forEach((c, i) => {
4112
+ if (c.searchable && c.searchField) {
4113
+ dropdownHTML += `
4114
+ <div id="${this.elementId}_columnSearch_${i}" class="websy-modal-dropdown"></div>
4115
+ `
4116
+ }
4117
+ })
4118
+ dropdownEl.innerHTML = dropdownHTML
4119
+ }
4120
+ // const colGroupEl = document.getElementById(`${this.elementId}_cols`)
4121
+ // colGroupEl.innerHTML = colGroupHTML
3087
4122
  // let footHTML = '<tr>' + this.options.columns.map((c, i) => {
3088
4123
  // if (c.show !== false) {
3089
4124
  // return `
@@ -3117,12 +4152,17 @@ class WebsyTable {
3117
4152
  pagingEl.innerHTML = pages.join('')
3118
4153
  }
3119
4154
  }
3120
- if (data) {
3121
- // this.data = this.data.concat(data)
3122
- this.appendRows(data)
4155
+ if (data) {
4156
+ this.appendRows(data)
3123
4157
  }
3124
4158
  }
3125
4159
  showError (options) {
4160
+ const el = document.getElementById(`${this.elementId}_tableContainer`)
4161
+ if (el) {
4162
+ el.classList.add('has-error')
4163
+ }
4164
+ const tableEl = document.getElementById(`${this.elementId}_table`)
4165
+ tableEl.classList.add('hidden')
3126
4166
  const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3127
4167
  if (containerEl) {
3128
4168
  containerEl.classList.add('active')
@@ -3134,15 +4174,64 @@ class WebsyTable {
3134
4174
  }
3135
4175
  }
3136
4176
  if (options.message) {
3137
- const messageEl = document.getElementById(`${this.elementId}_errorTitle`)
4177
+ const messageEl = document.getElementById(`${this.elementId}_errorMessage`)
3138
4178
  if (messageEl) {
3139
4179
  messageEl.innerHTML = options.message
3140
4180
  }
3141
4181
  }
3142
4182
  }
4183
+ setHorizontalScroll (options) {
4184
+ const el = document.getElementById(`${this.elementId}_hScrollHandle`)
4185
+ if (options.width) {
4186
+ el.style.width = `${options.width}px`
4187
+ }
4188
+ }
4189
+ setWidth (width) {
4190
+ const el = document.getElementById(`${this.elementId}_table`)
4191
+ if (el) {
4192
+ el.style.width = `${width}px`
4193
+ }
4194
+ }
3143
4195
  showLoading (options) {
3144
4196
  this.loadingDialog.show(options)
3145
4197
  }
4198
+ getColumnParameters (values) {
4199
+ const tableEl = document.getElementById(`${this.elementId}_table`)
4200
+ tableEl.style.tableLayout = 'auto'
4201
+ tableEl.style.width = 'auto'
4202
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
4203
+ bodyEl.innerHTML = '<tr>' + values.map(c => `
4204
+ <td
4205
+ style='height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px;'
4206
+ >${c.value || '&nbsp;'}</td>
4207
+ `).join('') + '</tr>'
4208
+ // get height of the first data cell
4209
+ const cells = bodyEl.querySelectorAll(`tr:first-of-type td`)
4210
+ const tableContainerEl = document.getElementById(`${this.elementId}_tableContainer`)
4211
+ const cellHeight = cells[0].offsetHeight || cells[0].clientHeight
4212
+ const cellWidths = []
4213
+ let nonScrollableWidth = 0
4214
+ for (let i = 0; i < cells.length; i++) {
4215
+ if (i < this.options.leftColumns) {
4216
+ nonScrollableWidth += values[i].width || cells[i].offsetWidth || cells[i].clientWidth
4217
+ }
4218
+ cellWidths.push(values[i].width || cells[i].offsetWidth || cells[i].clientWidth)
4219
+ }
4220
+ // const cellWidth = firstDataCell.offsetWidth || firstDataCell.clientWidth
4221
+ // tableEl.style.width = ''
4222
+ this.columnParameters = {
4223
+ cellHeight,
4224
+ cellWidths,
4225
+ availableHeight: tableContainerEl.offsetHeight || tableContainerEl.clientHeight,
4226
+ availableWidth: tableContainerEl.offsetWidth || tableContainerEl.clientWidth,
4227
+ nonScrollableWidth,
4228
+ scrollableWidth: (tableContainerEl.offsetWidth || tableContainerEl.clientWidth) - nonScrollableWidth
4229
+ }
4230
+ bodyEl.innerHTML = ''
4231
+ tableEl.style.tableLayout = ''
4232
+ tableEl.style.width = ''
4233
+ return this.columnParameters
4234
+ }
3146
4235
  }
3147
4236
 
3148
4237
  /* global d3 include WebsyDesigns */
@@ -3429,7 +4518,7 @@ if (this.options.data[side].scale === 'Time') {
3429
4518
  }
3430
4519
  }
3431
4520
  this.tooltip.setHeight(this.plotHeight)
3432
- this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
4521
+ this.options.showTooltip && this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
3433
4522
  // }
3434
4523
  // else {
3435
4524
  // xPoint = x0
@@ -4011,7 +5100,7 @@ function getBarX (d, i) {
4011
5100
  }
4012
5101
  }
4013
5102
  else {
4014
- if (this.options.grouping === 'stacked') {
5103
+ if (this.options.grouping !== 'stacked') {
4015
5104
  return this[xAxis](this.parseX(d.x.value))
4016
5105
  }
4017
5106
  else {
@@ -4021,7 +5110,7 @@ function getBarX (d, i) {
4021
5110
  }
4022
5111
  function getBarY (d, i) {
4023
5112
  if (this.options.orientation === 'horizontal') {
4024
- if (this.options.grouping === 'stacked') {
5113
+ if (this.options.grouping !== 'stacked') {
4025
5114
  return this[xAxis](this.parseX(d.x.value))
4026
5115
  }
4027
5116
  else {
@@ -4804,7 +5893,9 @@ const WebsyDesigns = {
4804
5893
  WebsyRouter,
4805
5894
  Router: WebsyRouter,
4806
5895
  WebsyTable,
5896
+ WebsyTable2,
4807
5897
  Table: WebsyTable,
5898
+ Table2: WebsyTable2,
4808
5899
  WebsyChart,
4809
5900
  Chart: WebsyChart,
4810
5901
  WebsyChartTooltip,
@@ -4821,6 +5912,7 @@ const WebsyDesigns = {
4821
5912
  Utils: WebsyUtils,
4822
5913
  ButtonGroup,
4823
5914
  WebsySwitch: Switch,
5915
+ Pager,
4824
5916
  Switch
4825
5917
  }
4826
5918