@websy/websy-designs 1.0.4 → 1.1.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.
@@ -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,7 @@
21
22
  APIService
22
23
  ButtonGroup
23
24
  WebsyUtils
25
+ Pager
24
26
  */
25
27
 
26
28
  /* global XMLHttpRequest fetch ENV */
@@ -200,11 +202,16 @@ class WebsyDatePicker {
200
202
  this.oneDay = 1000 * 60 * 60 * 24
201
203
  this.currentselection = []
202
204
  this.validDates = []
205
+ this.validYears = []
206
+ this.customRangeSelected = true
203
207
  const DEFAULTS = {
204
208
  defaultRange: 0,
205
209
  minAllowedDate: this.floorDate(new Date(new Date((new Date().setFullYear(new Date().getFullYear() - 1))).setDate(1))),
206
210
  maxAllowedDate: this.floorDate(new Date((new Date()))),
211
+ minAllowedYear: 1970,
212
+ maxAllowedYear: new Date().getFullYear(),
207
213
  daysOfWeek: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
214
+ mode: 'date',
208
215
  monthMap: {
209
216
  0: 'Jan',
210
217
  1: 'Feb',
@@ -221,44 +228,62 @@ class WebsyDatePicker {
221
228
  },
222
229
  ranges: []
223
230
  }
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
- ]
231
+ DEFAULTS.ranges = {
232
+ date: [
233
+ {
234
+ label: 'All Dates',
235
+ range: [DEFAULTS.minAllowedDate, DEFAULTS.maxAllowedDate]
236
+ },
237
+ {
238
+ label: 'Today',
239
+ range: [this.floorDate(new Date())]
240
+ },
241
+ {
242
+ label: 'Yesterday',
243
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 1))]
244
+ },
245
+ {
246
+ label: 'Last 7 Days',
247
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 6)), this.floorDate(new Date())]
248
+ },
249
+ {
250
+ label: 'This Month',
251
+ range: [this.floorDate(new Date().setDate(1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() + 1) - this.oneDay)]
252
+ },
253
+ {
254
+ label: 'Last Month',
255
+ 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)]
256
+ },
257
+ {
258
+ label: 'This Year',
259
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear()}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear()}`))]
260
+ },
261
+ {
262
+ label: 'Last Year',
263
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear() - 1}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear() - 1}`))]
264
+ }
265
+ ],
266
+ year: [
267
+ {
268
+ label: 'All Years',
269
+ range: [DEFAULTS.minAllowedYear, DEFAULTS.maxAllowedYear]
270
+ },
271
+ {
272
+ label: 'Last 5 Years',
273
+ range: [new Date().getFullYear() - 4, DEFAULTS.maxAllowedYear]
274
+ },
275
+ {
276
+ label: 'Last 10 Years',
277
+ range: [new Date().getFullYear() - 9, DEFAULTS.maxAllowedYear]
278
+ }
279
+ ]
280
+ }
258
281
  this.options = Object.assign({}, DEFAULTS, options)
259
282
  this.selectedRange = this.options.defaultRange || 0
260
- this.selectedRangeDates = [...this.options.ranges[this.options.defaultRange || 0].range]
283
+ this.selectedRangeDates = [...this.options.ranges[this.options.mode][this.options.defaultRange || 0].range]
261
284
  this.priorSelectedDates = null
285
+ this.priorselection = null
286
+ this.priorCustomRangeSelected = null
262
287
  if (!elementId) {
263
288
  console.log('No element Id provided')
264
289
  return
@@ -267,11 +292,14 @@ class WebsyDatePicker {
267
292
  if (el) {
268
293
  this.elementId = elementId
269
294
  el.addEventListener('click', this.handleClick.bind(this))
295
+ el.addEventListener('mousedown', this.handleMouseDown.bind(this))
296
+ el.addEventListener('mouseover', this.handleMouseOver.bind(this))
297
+ el.addEventListener('mouseup', this.handleMouseUp.bind(this))
270
298
  let html = `
271
299
  <div class='websy-date-picker-container'>
272
300
  <span class='websy-dropdown-header-label'>${this.options.label || 'Date'}</span>
273
301
  <div class='websy-date-picker-header'>
274
- <span id='${this.elementId}_selectedRange'>${this.options.ranges[this.selectedRange].label}</span>
302
+ <span id='${this.elementId}_selectedRange'>${this.options.ranges[this.options.mode][this.selectedRange].label}</span>
275
303
  <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
304
  </div>
277
305
  <div id='${this.elementId}_mask' class='websy-date-picker-mask'></div>
@@ -283,8 +311,12 @@ class WebsyDatePicker {
283
311
  </div><!--
284
312
  --><div id='${this.elementId}_datelist' class='websy-date-picker-custom'>${this.renderDates()}</div>
285
313
  <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>
314
+ <button class='${this.options.cancelBtnClasses || ''} websy-btn websy-dp-cancel'>
315
+ <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>
316
+ </button>
317
+ <button class='${this.options.confirmBtnClasses || ''} websy-btn websy-dp-confirm'>
318
+ <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>
319
+ </button>
288
320
  </div>
289
321
  </div>
290
322
  </div>
@@ -303,13 +335,21 @@ class WebsyDatePicker {
303
335
  contentEl.classList.remove('active')
304
336
  if (confirm === true) {
305
337
  if (this.options.onChange) {
306
- this.options.onChange(this.selectedRangeDates)
338
+ if (this.customRangeSelected === true) {
339
+ this.options.onChange(this.selectedRangeDates, true)
340
+ }
341
+ else {
342
+ this.options.onChange(this.currentselection, false)
343
+ }
307
344
  }
308
345
  this.updateRange()
309
346
  }
310
347
  else {
311
348
  this.selectedRangeDates = [...this.priorSelectedDates]
312
349
  this.selectedRange = this.priorSelectedRange
350
+ this.customRangeSelected = this.priorCustomRangeSelected
351
+ this.currentselection = [...this.priorselection]
352
+ this.highlightRange()
313
353
  }
314
354
  }
315
355
  floorDate (d) {
@@ -334,11 +374,11 @@ class WebsyDatePicker {
334
374
  this.updateRange(index)
335
375
  }
336
376
  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)
377
+ // if (event.target.classList.contains('websy-disabled-date')) {
378
+ // return
379
+ // }
380
+ // const timestamp = event.target.id.split('_')[0]
381
+ // this.selectDate(+timestamp)
342
382
  }
343
383
  else if (event.target.classList.contains('websy-dp-confirm')) {
344
384
  this.close(true)
@@ -347,6 +387,39 @@ class WebsyDatePicker {
347
387
  this.close()
348
388
  }
349
389
  }
390
+ handleMouseDown (event) {
391
+ this.mouseDown = true
392
+ this.dragging = false
393
+ if (event.target.classList.contains('websy-dp-date')) {
394
+ if (event.target.classList.contains('websy-disabled-date')) {
395
+ return
396
+ }
397
+ if (this.customRangeSelected === true) {
398
+ this.currentselection = []
399
+ this.customRangeSelected = false
400
+ }
401
+ this.mouseDownId = +event.target.id.split('_')[0]
402
+ this.selectDate(this.mouseDownId)
403
+ }
404
+ }
405
+ handleMouseOver (event) {
406
+ if (this.mouseDown === true) {
407
+ if (event.target.classList.contains('websy-dp-date')) {
408
+ if (event.target.classList.contains('websy-disabled-date')) {
409
+ return
410
+ }
411
+ if (event.target.id.split('_')[0] !== this.mouseDownId) {
412
+ this.dragging = true
413
+ this.selectDate(+event.target.id.split('_')[0])
414
+ }
415
+ }
416
+ }
417
+ }
418
+ handleMouseUp (event) {
419
+ this.mouseDown = false
420
+ this.dragging = false
421
+ this.mouseDownId = null
422
+ }
350
423
  highlightRange () {
351
424
  const el = document.getElementById(`${this.elementId}_dateList`)
352
425
  const dateEls = el.querySelectorAll('.websy-dp-date')
@@ -358,23 +431,67 @@ class WebsyDatePicker {
358
431
  if (this.selectedRange === 0) {
359
432
  return
360
433
  }
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')
434
+ if (this.customRangeSelected === true) {
435
+ let diff
436
+ if (this.options.mode === 'date') {
437
+ diff = Math.floor((this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime() - this.selectedRangeDates[0].getTime()) / this.oneDay)
438
+ if (this.selectedRangeDates[0].getMonth() !== this.selectedRangeDates[this.selectedRangeDates.length - 1].getMonth()) {
439
+ diff += 1
440
+ }
441
+ }
442
+ else if (this.options.mode === 'year') {
443
+ diff = this.selectedRangeDates[this.selectedRangeDates.length - 1] - this.selectedRangeDates[0]
444
+ if (this.selectedRangeDates[this.selectedRangeDates.length - 1] !== this.selectedRangeDates[0]) {
445
+ // diff += 1
446
+ }
447
+ }
448
+ for (let i = 0; i < diff + 1; i++) {
449
+ let d
450
+ let rangeStart
451
+ let rangeEnd
452
+ if (this.options.mode === 'date') {
453
+ d = this.floorDate(new Date(this.selectedRangeDates[0].getTime() + (i * this.oneDay)))
454
+ d = d.getTime()
455
+ rangeStart = this.selectedRangeDates[0].getTime()
456
+ rangeEnd = this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime()
457
+ }
458
+ else if (this.options.mode === 'year') {
459
+ d = this.selectedRangeDates[0] + i
460
+ rangeStart = this.selectedRangeDates[0]
461
+ rangeEnd = this.selectedRangeDates[this.selectedRangeDates.length - 1]
462
+ }
463
+ let dateEl
464
+ if (this.options.mode === 'date') {
465
+ dateEl = document.getElementById(`${d.getTime()}_date`)
372
466
  }
373
- if (d.getTime() === this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime()) {
374
- dateEl.classList.add('last')
467
+ else if (this.options.mode === 'year') {
468
+ dateEl = document.getElementById(`${d}_year`)
469
+ }
470
+ if (dateEl) {
471
+ dateEl.classList.add('selected')
472
+ if (d === rangeStart) {
473
+ dateEl.classList.add(`${this.options.sortDirection === 'desc' ? 'last' : 'first'}`)
474
+ }
475
+ if (d === rangeEnd) {
476
+ dateEl.classList.add(`${this.options.sortDirection === 'desc' ? 'first' : 'last'}`)
477
+ }
375
478
  }
376
479
  }
377
480
  }
481
+ else {
482
+ this.currentselection.forEach(d => {
483
+ let dateEl
484
+ if (this.options.mode === 'date') {
485
+ dateEl = document.getElementById(`${d}_date`)
486
+ }
487
+ else if (this.options.mode === 'year') {
488
+ dateEl = document.getElementById(`${d}_year`)
489
+ }
490
+ dateEl.classList.add('selected')
491
+ dateEl.classList.add('first')
492
+ dateEl.classList.add('last')
493
+ })
494
+ }
378
495
  }
379
496
  open (options, override = false) {
380
497
  const maskEl = document.getElementById(`${this.elementId}_mask`)
@@ -383,6 +500,8 @@ class WebsyDatePicker {
383
500
  contentEl.classList.add('active')
384
501
  this.priorSelectedDates = [...this.selectedRangeDates]
385
502
  this.priorSelectedRange = this.selectedRange
503
+ this.priorselection = [...this.currentselection]
504
+ this.priorCustomRangeSelected = this.customRangeSelected
386
505
  this.scrollRangeIntoView()
387
506
  }
388
507
  render (disabledDates) {
@@ -403,87 +522,154 @@ class WebsyDatePicker {
403
522
  renderDates (disabledDates) {
404
523
  let disabled = []
405
524
  this.validDates = []
525
+ this.validYears = []
406
526
  if (disabledDates) {
407
- disabled = disabledDates.map(d => d.getTime())
527
+ disabled = disabledDates.map(d => {
528
+ if (this.options.mode === 'date') {
529
+ return d.getTime()
530
+ }
531
+ else if (this.options.mode === 'year') {
532
+ return d
533
+ }
534
+ return d.getTime()
535
+ })
408
536
  }
409
537
  // 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
538
+ this.options.ranges[this.options.mode].forEach(r => (r.disabled = true))
539
+ let diff
540
+ if (this.options.mode === 'date') {
541
+ diff = Math.ceil((this.options.maxAllowedDate.getTime() - this.options.minAllowedDate.getTime()) / this.oneDay) + 1
542
+ }
543
+ else if (this.options.mode === 'year') {
544
+ diff = (this.options.maxAllowedYear - this.options.minAllowedYear) + 1
545
+ }
412
546
  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())
547
+ let yearList = []
548
+ for (let i = 0; i < diff; i++) {
549
+ if (this.options.mode === 'date') {
550
+ let d = this.floorDate(new Date(this.options.minAllowedDate.getTime() + (i * this.oneDay)))
551
+ let monthYear = `${this.options.monthMap[d.getMonth()]} ${d.getFullYear()}`
552
+ if (!months[monthYear]) {
553
+ months[monthYear] = []
554
+ }
555
+ if (disabled.indexOf(d.getTime()) === -1) {
556
+ this.validDates.push(d.getTime())
557
+ }
558
+ months[monthYear].push({date: d, dayOfMonth: d.getDate(), dayOfWeek: d.getDay(), id: d.getTime(), disabled: disabled.indexOf(d.getTime()) !== -1})
421
559
  }
422
- months[monthYear].push({date: d, dayOfMonth: d.getDate(), dayOfWeek: d.getDay(), id: d.getTime(), disabled: disabled.indexOf(d.getTime()) !== -1})
560
+ else if (this.options.mode === 'year') {
561
+ let d = this.options.minAllowedYear + i
562
+ yearList.push({year: d, id: d, disabled: disabled.indexOf(d) !== -1})
563
+ if (disabled.indexOf(d) === -1) {
564
+ this.validYears.push(d)
565
+ }
566
+ }
423
567
  }
424
568
  // 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) {
569
+ for (let i = 0; i < this.options.ranges[this.options.mode].length; i++) {
570
+ const r = this.options.ranges[this.options.mode][i]
571
+ if (this.options.mode === 'date') {
572
+ // check the first date
573
+ if (this.validDates.indexOf(r.range[0].getTime()) !== -1) {
574
+ r.disabled = false
575
+ }
576
+ else if (r.range[1]) {
577
+ // check the last date
578
+ if (this.validDates.indexOf(r.range[1].getTime()) !== -1) {
579
+ r.disabled = false
580
+ }
581
+ else {
582
+ // check the full range until a match is found
583
+ for (let i = r.range[0].getTime(); i <= r.range[1].getTime(); i += this.oneDay) {
584
+ let testDate = this.floorDate(new Date(i))
585
+ if (this.validDates.indexOf(testDate.getTime()) !== -1) {
586
+ r.disabled = false
587
+ break
588
+ }
589
+ }
590
+ }
591
+ }
592
+ }
593
+ else if (this.options.mode === 'year') {
594
+ if (this.validYears.indexOf(r.range[0]) !== -1) {
434
595
  r.disabled = false
435
596
  }
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
- }
597
+ else if (r.range[1]) {
598
+ if (this.validYears.indexOf(r.range[1]) !== -1) {
599
+ r.disabled = false
600
+ }
601
+ else {
602
+ // check the full range until a match is found
603
+ for (let i = r.range[0]; i <= r.range[1]; i++) {
604
+ if (this.validYears.indexOf(r.range[0] + i) !== -1) {
605
+ r.disabled = false
606
+ break
607
+ }
608
+ }
444
609
  }
445
- }
446
- }
610
+ }
611
+ }
447
612
  }
448
613
  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) {
614
+ if (this.options.mode === 'date') {
458
615
  html += `
459
- <div class='websy-dp-month-container'>
460
- <span id='${key.replace(/\s/g, '_')}'>${key}</span>
461
- <ul>
616
+ <ul class='websy-dp-days-header'>
462
617
  `
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('')
618
+ html += this.options.daysOfWeek.map(d => `<li>${d}</li>`).join('')
471
619
  html += `
472
- </ul>
473
- </div>
620
+ </ul>
621
+ <div id='${this.elementId}_dateList' class='websy-dp-date-list'>
474
622
  `
475
- }
476
- html += '</div>'
623
+ for (let key in months) {
624
+ html += `
625
+ <div class='websy-dp-month-container'>
626
+ <span id='${key.replace(/\s/g, '_')}'>${key}</span>
627
+ <ul>
628
+ `
629
+ if (months[key][0].dayOfWeek > 0) {
630
+ let paddedDays = []
631
+ for (let i = 0; i < months[key][0].dayOfWeek; i++) {
632
+ paddedDays.push(`<li>&nbsp;</li>`)
633
+ }
634
+ html += paddedDays.join('')
635
+ }
636
+ html += months[key].map(d => `<li id='${d.id}_date' class='websy-dp-date ${d.disabled === true ? 'websy-disabled-date' : ''}'>${d.dayOfMonth}</li>`).join('')
637
+ html += `
638
+ </ul>
639
+ </div>
640
+ `
641
+ }
642
+ html += '</div>'
643
+ }
644
+ else if (this.options.mode === 'year') {
645
+ if (this.options.sortDirection === 'desc') {
646
+ yearList.reverse()
647
+ }
648
+ html += `<div id='${this.elementId}_dateList' class='websy-dp-date-list'><ul>`
649
+ 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('')
650
+ html += `</ul></div>`
651
+ }
477
652
  return html
478
653
  }
479
654
  renderRanges () {
480
- return this.options.ranges.map((r, i) => `
655
+ return this.options.ranges[this.options.mode].map((r, i) => `
481
656
  <li data-index='${i}' class='websy-date-picker-range ${i === this.selectedRange ? 'active' : ''} ${r.disabled === true ? 'websy-disabled-range' : ''}'>${r.label}</li>
482
- `).join('')
657
+ `).join('') + `<li data-index='-1' class='websy-date-picker-range ${this.selectedRange === -1 ? 'active' : ''}'>Custom</li>`
483
658
  }
484
659
  scrollRangeIntoView () {
485
660
  if (this.selectedRangeDates[0]) {
486
- const el = document.getElementById(`${this.selectedRangeDates[0].getTime()}_date`)
661
+ let el
662
+ if (this.options.mode === 'date') {
663
+ el = document.getElementById(`${this.selectedRangeDates[0].getTime()}_date`)
664
+ }
665
+ else if (this.options.mode === 'year') {
666
+ if (this.options.sortDirection === 'desc') {
667
+ el = document.getElementById(`${this.selectedRangeDates[this.selectedRangeDates.length - 1]}_year`)
668
+ }
669
+ else {
670
+ el = document.getElementById(`${this.selectedRangeDates[0]}_year`)
671
+ }
672
+ }
487
673
  const parentEl = document.getElementById(`${this.elementId}_dateList`)
488
674
  if (el && parentEl) {
489
675
  parentEl.scrollTo(0, el.offsetTop)
@@ -495,23 +681,38 @@ class WebsyDatePicker {
495
681
  this.currentselection.push(timestamp)
496
682
  }
497
683
  else {
498
- if (timestamp > this.currentselection[0]) {
499
- this.currentselection.push(timestamp)
684
+ if (this.dragging === true) {
685
+ this.currentselection = [this.mouseDownId]
686
+ if (timestamp > this.currentselection[0]) {
687
+ this.currentselection.push(timestamp)
688
+ }
689
+ else {
690
+ this.currentselection.splice(0, 0, timestamp)
691
+ }
692
+ this.customRangeSelected = true
500
693
  }
501
694
  else {
502
- this.currentselection.splice(0, 0, timestamp)
503
- }
695
+ this.currentselection.push(timestamp)
696
+ this.currentselection.sort((a, b) => a - b)
697
+ this.customRangeSelected = false
698
+ }
504
699
  }
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 = []
700
+ if (this.options.mode === 'date') {
701
+ this.selectedRangeDates = [new Date(this.currentselection[0]), new Date(this.currentselection[1] || this.currentselection[0])]
508
702
  }
703
+ else if (this.options.mode === 'year') {
704
+ this.selectedRangeDates = [this.currentselection[0], this.currentselection[1] || this.currentselection[0]]
705
+ }
706
+ // if (this.currentselection.length === 2) {
707
+ // this.currentselection = []
708
+ // }
509
709
  this.selectedRange = -1
510
710
  this.highlightRange()
511
711
  }
512
712
  selectRange (index) {
513
- if (this.options.ranges[index]) {
514
- this.selectedRangeDates = [...this.options.ranges[index].range]
713
+ if (this.options.ranges[this.options.mode][index]) {
714
+ this.selectedRangeDates = [...this.options.ranges[this.options.mode][index].range]
715
+ this.currentselection = [...this.options.ranges[this.options.mode][index].range]
515
716
  this.selectedRange = +index
516
717
  this.highlightRange()
517
718
  this.close(true)
@@ -520,28 +721,60 @@ class WebsyDatePicker {
520
721
  selectCustomRange (range) {
521
722
  this.selectedRange = -1
522
723
  this.selectedRangeDates = range
724
+ // check if the custom range matches a configured range
725
+ for (let i = 0; i < this.options.ranges[this.options.mode].length; i++) {
726
+ if (this.options.ranges[this.options.mode][i].range.length === 1) {
727
+ if (this.options.ranges[this.options.mode][i].range[0] === range[0]) {
728
+ this.selectedRange = i
729
+ break
730
+ }
731
+ }
732
+ else if (this.options.ranges[this.options.mode][i].range.length === 2) {
733
+ if (this.options.ranges[this.options.mode][i].range[0] === range[0] && this.options.ranges[this.options.mode][i].range[1] === range[1]) {
734
+ this.selectedRange = i
735
+ break
736
+ }
737
+ }
738
+ }
523
739
  this.highlightRange()
524
740
  this.updateRange()
525
741
  }
526
742
  setDateBounds (range) {
527
- if (this.options.ranges[0].label === 'All Dates') {
528
- this.options.ranges[0].range = [range[0], range[1] || range[0]]
743
+ if (['All Dates', 'All Years'].indexOf(this.options.ranges[this.options.mode][0].label) !== -1) {
744
+ this.options.ranges[this.options.mode][0].range = [range[0], range[1] || range[0]]
529
745
  }
530
- this.options.minAllowedDate = range[0]
531
- this.options.maxAllowedDate = range[1] || range[0]
746
+ if (this.options.mode === 'date') {
747
+ this.options.minAllowedDate = range[0]
748
+ this.options.maxAllowedDate = range[1] || range[0]
749
+ }
750
+ else if (this.options.mode === 'year') {
751
+ this.options.minAllowedYear = range[0]
752
+ this.options.maxAllowedYear = range[1] || range[0]
753
+ }
532
754
  }
533
755
  updateRange () {
534
756
  let range
535
757
  if (this.selectedRange === -1) {
536
- let start = this.selectedRangeDates[0].toLocaleDateString()
758
+ const list = (this.currentselection.length > 0 ? this.currentselection : this.selectedRangeDates).map(d => {
759
+ if (this.options.mode === 'date') {
760
+ return d.toLocaleDateString()
761
+ }
762
+ else if (this.options.mode === 'year') {
763
+ return d
764
+ }
765
+ })
766
+ let start = list[0]
537
767
  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}` }
768
+ if (this.customRangeSelected === true) {
769
+ end = ` - ${list[list.length - 1]}`
770
+ }
771
+ else {
772
+ start = `${list.length} selected`
773
+ }
774
+ range = { label: `${start}${end}` }
542
775
  }
543
776
  else {
544
- range = this.options.ranges[this.selectedRange]
777
+ range = this.options.ranges[this.options.mode][this.selectedRange]
545
778
  }
546
779
  const el = document.getElementById(this.elementId)
547
780
  const labelEl = document.getElementById(`${this.elementId}_selectedRange`)
@@ -591,7 +824,44 @@ class WebsyDropdown {
591
824
  el.addEventListener('click', this.handleClick.bind(this))
592
825
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
593
826
  el.addEventListener('mouseout', this.handleMouseOut.bind(this))
594
- el.addEventListener('mousemove', this.handleMouseMove.bind(this))
827
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
828
+ const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
829
+ const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
830
+ let html = `
831
+ <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
832
+ <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
833
+ <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
834
+ <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
835
+ <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
836
+ <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>
837
+ `
838
+ if (this.options.allowClear === true) {
839
+ html += `
840
+ <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>
841
+ `
842
+ }
843
+ html += `
844
+ </div>
845
+ <div id='${this.elementId}_mask' class='websy-dropdown-mask'></div>
846
+ <div id='${this.elementId}_content' class='websy-dropdown-content'>
847
+ `
848
+ if (this.options.disableSearch !== true) {
849
+ html += `
850
+ <input id='${this.elementId}_search' class='websy-dropdown-search' placeholder='${this.options.searchPlaceholder || 'Search'}'>
851
+ `
852
+ }
853
+ html += `
854
+ <div id='${this.elementId}_itemsContainer' class='websy-dropdown-items'>
855
+ <ul id='${this.elementId}_items'>
856
+ </ul>
857
+ </div><!--
858
+ --><div class='websy-dropdown-custom'></div>
859
+ </div>
860
+ </div>
861
+ `
862
+ el.innerHTML = html
863
+ const scrollEl = document.getElementById(`${this.elementId}_itemsContainer`)
864
+ scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
595
865
  this.render()
596
866
  }
597
867
  else {
@@ -616,6 +886,9 @@ class WebsyDropdown {
616
886
  }
617
887
  get data () {
618
888
  return this.options.items
889
+ }
890
+ appendRows () {
891
+
619
892
  }
620
893
  clearSelected () {
621
894
  this.selectedItems = []
@@ -724,6 +997,13 @@ class WebsyDropdown {
724
997
  clearTimeout(this.tooltipTimeoutFn)
725
998
  }
726
999
  }
1000
+ handleScroll (event) {
1001
+ if (event.target.classList.contains('websy-dropdown-items')) {
1002
+ if (this.options.onScroll) {
1003
+ this.options.onScroll(event)
1004
+ }
1005
+ }
1006
+ }
727
1007
  open (options, override = false) {
728
1008
  const maskEl = document.getElementById(`${this.elementId}_mask`)
729
1009
  const contentEl = document.getElementById(`${this.elementId}_content`)
@@ -744,42 +1024,42 @@ class WebsyDropdown {
744
1024
  console.log('No element Id provided for Websy Dropdown')
745
1025
  return
746
1026
  }
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
1027
+ // const el = document.getElementById(this.elementId)
1028
+ // const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1029
+ // const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1030
+ // let html = `
1031
+ // <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1032
+ // <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1033
+ // <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
1034
+ // <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1035
+ // <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1036
+ // <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>
1037
+ // `
1038
+ // if (this.options.allowClear === true) {
1039
+ // html += `
1040
+ // <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>
1041
+ // `
1042
+ // }
1043
+ // html += `
1044
+ // </div>
1045
+ // <div id='${this.elementId}_mask' class='websy-dropdown-mask'></div>
1046
+ // <div id='${this.elementId}_content' class='websy-dropdown-content'>
1047
+ // `
1048
+ // if (this.options.disableSearch !== true) {
1049
+ // html += `
1050
+ // <input id='${this.elementId}_search' class='websy-dropdown-search' placeholder='${this.options.searchPlaceholder || 'Search'}'>
1051
+ // `
1052
+ // }
1053
+ // html += `
1054
+ // <div class='websy-dropdown-items'>
1055
+ // <ul id='${this.elementId}_items'>
1056
+ // </ul>
1057
+ // </div><!--
1058
+ // --><div class='websy-dropdown-custom'></div>
1059
+ // </div>
1060
+ // </div>
1061
+ // `
1062
+ // el.innerHTML = html
783
1063
  this.renderItems()
784
1064
  }
785
1065
  renderItems () {
@@ -829,9 +1109,11 @@ class WebsyDropdown {
829
1109
  }
830
1110
  if (labelEl) {
831
1111
  if (this.selectedItems.length === 1) {
832
- labelEl.innerHTML = item.label
833
- labelEl.setAttribute('data-info', item.label)
834
- inputEl.value = item.value
1112
+ if (item) {
1113
+ labelEl.innerHTML = item.label
1114
+ labelEl.setAttribute('data-info', item.label)
1115
+ inputEl.value = item.value
1116
+ }
835
1117
  }
836
1118
  else if (this.selectedItems.length > 1) {
837
1119
  if (this.options.showCompleteSelectedList === true) {
@@ -902,9 +1184,9 @@ class WebsyForm {
902
1184
  this.elementId = elementId
903
1185
  const el = document.getElementById(elementId)
904
1186
  if (el) {
905
- if (this.options.classes) {
906
- this.options.classes.forEach(c => el.classList.add(c))
907
- }
1187
+ // if (this.options.classes) {
1188
+ // this.options.classes.forEach(c => el.classList.add(c))
1189
+ // }
908
1190
  el.addEventListener('click', this.handleClick.bind(this))
909
1191
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
910
1192
  el.addEventListener('keydown', this.handleKeyDown.bind(this))
@@ -992,7 +1274,7 @@ class WebsyForm {
992
1274
  else {
993
1275
  components.forEach(c => {
994
1276
  if (typeof WebsyDesigns[c.component] !== 'undefined') {
995
- const comp = new WebsyDesigns[c.component](`${this.elementId}_input_${c.field}_component`, c.options)
1277
+ c.instance = new WebsyDesigns[c.component](`${this.elementId}_input_${c.field}_component`, c.options)
996
1278
  }
997
1279
  else {
998
1280
  // some user feedback here
@@ -1014,13 +1296,13 @@ class WebsyForm {
1014
1296
  let componentsToProcess = []
1015
1297
  if (el) {
1016
1298
  let html = `
1017
- <form id="${this.elementId}Form">
1299
+ <form id="${this.elementId}Form" class="${this.options.classes || ''}">
1018
1300
  `
1019
1301
  this.options.fields.forEach((f, i) => {
1020
1302
  if (f.component) {
1021
1303
  componentsToProcess.push(f)
1022
1304
  html += `
1023
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1305
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1024
1306
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1025
1307
  <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
1026
1308
  </div><!--
@@ -1028,7 +1310,7 @@ class WebsyForm {
1028
1310
  }
1029
1311
  else if (f.type === 'longtext') {
1030
1312
  html += `
1031
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1313
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1032
1314
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1033
1315
  <textarea
1034
1316
  id="${this.elementId}_input_${f.field}"
@@ -1042,7 +1324,7 @@ class WebsyForm {
1042
1324
  }
1043
1325
  else {
1044
1326
  html += `
1045
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1327
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1046
1328
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1047
1329
  <input
1048
1330
  id="${this.elementId}_input_${f.field}"
@@ -1052,6 +1334,7 @@ class WebsyForm {
1052
1334
  name="${f.field}"
1053
1335
  placeholder="${f.placeholder || ''}"
1054
1336
  value="${f.value || ''}"
1337
+ valueAsDate="${f.type === 'date' ? f.value : ''}"
1055
1338
  oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
1056
1339
  />
1057
1340
  </div><!--
@@ -1059,11 +1342,11 @@ class WebsyForm {
1059
1342
  }
1060
1343
  })
1061
1344
  html += `
1062
- --><button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
1345
+ --><button class="websy-btn submit ${this.options.submit.classes || ''}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
1063
1346
  `
1064
1347
  if (this.options.cancel) {
1065
1348
  html += `
1066
- --><button class="websy-btn cancel ${this.options.cancel.classes}">${this.options.cancel.text || 'Cancel'}</button>
1349
+ --><button class="websy-btn cancel ${this.options.cancel.classes || ''}">${this.options.cancel.text || 'Cancel'}</button>
1067
1350
  `
1068
1351
  }
1069
1352
  html += `
@@ -1284,9 +1567,6 @@ class WebsyNavigationMenu {
1284
1567
  html += this.renderBlock(this.options.items, 'main', 0)
1285
1568
  html += `</div>`
1286
1569
  el.innerHTML = html
1287
- if (this.options.navigator) {
1288
- this.options.navigator.registerElements(el)
1289
- }
1290
1570
  }
1291
1571
  }
1292
1572
  renderBlock (items, block, level = 0) {
@@ -1378,6 +1658,92 @@ class WebsyNavigationMenu {
1378
1658
  }
1379
1659
  }
1380
1660
 
1661
+ /* global WebsyDesigns */
1662
+ class Pager {
1663
+ constructor (elementId, options) {
1664
+ this.elementId = elementId
1665
+ const DEFAULTS = {
1666
+ pageSizePrefix: 'Show',
1667
+ pageSizeSuffix: 'rows',
1668
+ pageSizeOptions: [
1669
+ { label: '10', value: 10 },
1670
+ { label: '20', value: 20 },
1671
+ { label: '50', value: 50 },
1672
+ { label: '100', value: 100 }
1673
+ ],
1674
+ selectedPageSize: 20,
1675
+ pageLabel: 'Page',
1676
+ showPageSize: true,
1677
+ activePage: 0,
1678
+ pages: []
1679
+ }
1680
+ this.options = Object.assign({}, DEFAULTS, options)
1681
+ const el = document.getElementById(this.elementId)
1682
+ if (el) {
1683
+ let html = `
1684
+ <div class="websy-pager-container">
1685
+ `
1686
+ if (this.options.showPageSize === true) {
1687
+ html += `
1688
+ ${this.options.pageSizePrefix} <div id="${this.elementId}_pageSizeSelector" class="websy-page-selector"></div> ${this.options.pageSizeSuffix}
1689
+ `
1690
+ }
1691
+ html += `
1692
+ <ul id="${this.elementId}_pageList" class="websy-page-list"></ul>
1693
+ </div>
1694
+ `
1695
+ el.innerHTML = html
1696
+ el.addEventListener('click', this.handleClick.bind(this))
1697
+ if (this.options.showPageSize === true) {
1698
+ this.pageSizeSelector = new WebsyDesigns.Dropdown(`${this.elementId}_pageSizeSelector`, {
1699
+ selectedItems: [this.options.pageSizeOptions.indexOf(this.options.selectedPageSize)],
1700
+ items: this.pageSizeOptions.map(p => ({ label: p.toString(), value: p })),
1701
+ allowClear: false,
1702
+ disableSearch: true,
1703
+ onItemSelected: (selectedItem) => {
1704
+ if (this.options.onChangePageSize) {
1705
+ this.options.onChangePageSize(selectedItem.value)
1706
+ }
1707
+ }
1708
+ })
1709
+ }
1710
+ this.render()
1711
+ }
1712
+ }
1713
+ handleClick (event) {
1714
+ if (event.target.classList.contains('websy-page-num')) {
1715
+ const pageNum = +event.target.getAttribute('data-index')
1716
+ if (this.options.onSetPage) {
1717
+ this.options.onSetPage(this.options.pages[pageNum])
1718
+ }
1719
+ }
1720
+ }
1721
+ render () {
1722
+ const el = document.getElementById(`${this.elementId}_pageList`)
1723
+ if (el) {
1724
+ let pages = this.options.pages.map((item, index) => {
1725
+ return `<li data-index="${index}" class="websy-page-num ${(this.options.activePage === index) ? 'active' : ''}">${index + 1}</li>`
1726
+ })
1727
+ let startIndex = 0
1728
+ if (this.options.pages.length > 8) {
1729
+ startIndex = Math.max(0, this.options.activePage - 4)
1730
+ pages = pages.splice(startIndex, 10)
1731
+ if (startIndex > 0) {
1732
+ pages.splice(0, 0, `<li>${this.options.pageLabel}&nbsp;</li><li data-page="0" class="websy-page-num">First</li><li>...</li>`)
1733
+ }
1734
+ else {
1735
+ pages.splice(0, 0, `<li>${this.options.pageLabel}&nbsp;</li>`)
1736
+ }
1737
+ if (this.options.activePage < this.options.pages.length - 1) {
1738
+ pages.push('<li>...</li>')
1739
+ pages.push(`<li data-page="${this.options.pages.length - 1}" class="websy-page-num">Last</li>`)
1740
+ }
1741
+ }
1742
+ el.innerHTML = pages.join('')
1743
+ }
1744
+ }
1745
+ }
1746
+
1381
1747
  /* global WebsyDesigns Blob */
1382
1748
  class WebsyPDFButton {
1383
1749
  constructor (elementId, options) {
@@ -2853,6 +3219,9 @@ class WebsyTable {
2853
3219
  }
2854
3220
  if (c.backgroundColor) {
2855
3221
  style += `background-color: ${c.backgroundColor}; `
3222
+ if (!c.color) {
3223
+ style += `color: ${WebsyDesigns.Utils.getLightDark(c.backgroundColor)}; `
3224
+ }
2856
3225
  }
2857
3226
  if (c.color) {
2858
3227
  style += `color: ${c.color}; `
@@ -3145,35 +3514,558 @@ class WebsyTable {
3145
3514
  }
3146
3515
  }
3147
3516
 
3148
- /* global d3 include WebsyDesigns */
3149
- class WebsyChart {
3517
+ /* global WebsyDesigns */
3518
+ class WebsyTable2 {
3150
3519
  constructor (elementId, options) {
3151
3520
  const DEFAULTS = {
3152
- margin: {
3153
- top: 10,
3154
- left: 3,
3155
- bottom: 3,
3156
- right: 3,
3157
- axisBottom: 0,
3158
- axisLeft: 0,
3159
- axisRight: 0,
3160
- axisTop: 0,
3161
- legendBottom: 0,
3162
- legendLeft: 0,
3163
- legendRight: 0,
3164
- legendTop: 0
3165
- },
3166
- orientation: 'vertical',
3167
- colors: ['#5e4fa2', '#3288bd', '#66c2a5', '#abdda4', '#e6f598', '#fee08b', '#fdae61', '#f46d43', '#d53e4f', '#9e0142'],
3168
- transitionDuration: 650,
3169
- curveStyle: 'curveLinear',
3170
- lineWidth: 2,
3171
- forceZero: true,
3172
- fontSize: 14,
3173
- symbolSize: 20,
3174
- showTrackingLine: true,
3175
- showTooltip: true,
3176
- showLegend: false,
3521
+ pageSize: 20,
3522
+ paging: 'scroll',
3523
+ cellSize: 35,
3524
+ virtualScroll: false,
3525
+ leftColumns: 0
3526
+ }
3527
+ this.elementId = elementId
3528
+ this.options = Object.assign({}, DEFAULTS, options)
3529
+ this.rowCount = 0
3530
+ this.busy = false
3531
+ this.tooltipTimeoutFn = null
3532
+ this.data = []
3533
+ const el = document.getElementById(this.elementId)
3534
+ if (el) {
3535
+ let html = `
3536
+ <div id='${this.elementId}_tableContainer' class='websy-vis-table ${this.options.paging === 'pages' ? 'with-paging' : ''} ${this.options.virtualScroll === true ? 'with-virtual-scroll' : ''}'>
3537
+ <!--<div class="download-button">
3538
+ <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>
3539
+ </div>-->
3540
+ <table id="${this.elementId}_table">
3541
+ <thead id="${this.elementId}_head">
3542
+ </thead>
3543
+ <tbody id="${this.elementId}_body">
3544
+ </tbody>
3545
+ <tfoot id="${this.elementId}_foot">
3546
+ </tfoot>
3547
+ </table>
3548
+ <div id="${this.elementId}_errorContainer" class='websy-vis-error-container'>
3549
+ <div>
3550
+ <div id="${this.elementId}_errorTitle"></div>
3551
+ <div id="${this.elementId}_errorMessage"></div>
3552
+ </div>
3553
+ </div>
3554
+ <div id="${this.elementId}_vScrollContainer" class="websy-v-scroll-container">
3555
+ <div id="${this.elementId}_vScrollHandle" class="websy-scroll-handle websy-scroll-handle-y"></div>
3556
+ </div>
3557
+ <div id="${this.elementId}_hScrollContainer" class="websy-h-scroll-container">
3558
+ <div id="${this.elementId}_hScrollHandle" class="websy-scroll-handle websy-scroll-handle-x"></div>
3559
+ </div>
3560
+ <div id="${this.elementId}_dropdownContainer"></div>
3561
+ <div id="${this.elementId}_loadingContainer"></div>
3562
+ </div>
3563
+ `
3564
+ if (this.options.paging === 'pages') {
3565
+ html += `
3566
+ <div class="websy-table-paging-container">
3567
+ Show <div id="${this.elementId}_pageSizeSelector" class="websy-vis-page-selector"></div> rows
3568
+ <ul id="${this.elementId}_pageList" class="websy-vis-page-list"></ul>
3569
+ </div>
3570
+ `
3571
+ }
3572
+ let pageOptions = [10, 20, 50, 100, 200]
3573
+ el.innerHTML = html
3574
+ if (this.options.paging === 'pages') {
3575
+ this.pageSizeSelector = new WebsyDesigns.Dropdown(`${this.elementId}_pageSizeSelector`, {
3576
+ selectedItems: [pageOptions.indexOf(this.options.pageSize)],
3577
+ items: pageOptions.map(p => ({ label: p.toString(), value: p })),
3578
+ allowClear: false,
3579
+ disableSearch: true,
3580
+ onItemSelected: (selectedItem) => {
3581
+ if (this.options.onChangePageSize) {
3582
+ this.options.onChangePageSize(selectedItem.value)
3583
+ }
3584
+ }
3585
+ })
3586
+ }
3587
+ el.addEventListener('click', this.handleClick.bind(this))
3588
+ el.addEventListener('mouseout', this.handleMouseOut.bind(this))
3589
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
3590
+ el.addEventListener('mousedown', this.handleMouseDown.bind(this))
3591
+ el.addEventListener('mouseup', this.handleMouseUp.bind(this))
3592
+ document.addEventListener('mouseup', this.handleGlobalMouseUp.bind(this))
3593
+ const scrollEl = document.getElementById(`${this.elementId}_tableContainer`)
3594
+ scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
3595
+ this.loadingDialog = new WebsyDesigns.LoadingDialog(`${this.elementId}_loadingContainer`)
3596
+ this.render()
3597
+ }
3598
+ else {
3599
+ console.error(`No element found with ID ${this.elementId}`)
3600
+ }
3601
+ }
3602
+ appendRows (data) {
3603
+ this.hideError()
3604
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
3605
+ let bodyHTML = ''
3606
+ if (data) {
3607
+ bodyHTML += data.map((r, rowIndex) => {
3608
+ return '<tr>' + r.map((c, i) => {
3609
+ if (this.options.columns[i].show !== false) {
3610
+ let style = `height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px;`
3611
+ if (c.style) {
3612
+ style += c.style
3613
+ }
3614
+ if (this.options.columns[i].width) {
3615
+ style += `width: ${this.options.columns[i].width}; `
3616
+ }
3617
+ if (c.backgroundColor) {
3618
+ style += `background-color: ${c.backgroundColor}; `
3619
+ }
3620
+ if (c.color) {
3621
+ style += `color: ${c.color}; `
3622
+ }
3623
+ if (this.options.columns[i].showAsLink === true && c.value.trim() !== '') {
3624
+ return `
3625
+ <td
3626
+ data-row-index='${this.rowCount + rowIndex}'
3627
+ data-col-index='${i}'
3628
+ class='${this.options.columns[i].classes || ''}'
3629
+ style='${style}'
3630
+ colspan='${c.colspan || 1}'
3631
+ rowspan='${c.rowspan || 1}'
3632
+ >
3633
+ <a href='${c.value}' target='${this.options.columns[i].openInNewTab === true ? '_blank' : '_self'}'>${c.displayText || this.options.columns[i].linkText || c.value}</a>
3634
+ </td>
3635
+ `
3636
+ }
3637
+ else if ((this.options.columns[i].showAsNavigatorLink === true || this.options.columns[i].showAsRouterLink === true) && c.value.trim() !== '') {
3638
+ return `
3639
+ <td
3640
+ data-view='${c.value}'
3641
+ data-row-index='${this.rowCount + rowIndex}'
3642
+ data-col-index='${i}'
3643
+ class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
3644
+ style='${style}'
3645
+ colspan='${c.colspan || 1}'
3646
+ rowspan='${c.rowspan || 1}'
3647
+ >${c.displayText || this.options.columns[i].linkText || c.value}</td>
3648
+ `
3649
+ }
3650
+ else {
3651
+ let info = c.value
3652
+ if (this.options.columns[i].showAsImage === true) {
3653
+ c.value = `
3654
+ <img src='${c.value}'>
3655
+ `
3656
+ }
3657
+ return `
3658
+ <td
3659
+ data-info='${info}'
3660
+ data-row-index='${this.rowCount + rowIndex}'
3661
+ data-col-index='${i}'
3662
+ class='${this.options.columns[i].classes || ''}'
3663
+ style='${style}'
3664
+ colspan='${c.colspan || 1}'
3665
+ rowspan='${c.rowspan || 1}'
3666
+ >${c.value}</td>
3667
+ `
3668
+ }
3669
+ }
3670
+ }).join('') + '</tr>'
3671
+ }).join('')
3672
+ this.data = this.data.concat(data)
3673
+ this.rowCount = this.data.length
3674
+ }
3675
+ bodyEl.innerHTML += bodyHTML
3676
+ if (this.options.virtualScroll === true) {
3677
+ // get height of the thead
3678
+ if (this.options.paging !== 'pages') {
3679
+ const headEl = document.getElementById(`${this.elementId}_head`)
3680
+ const vScrollContainerEl = document.getElementById(`${this.elementId}_vScrollContainer`)
3681
+ vScrollContainerEl.style.top = `${headEl.clientHeight}px`
3682
+ }
3683
+ const hScrollContainerEl = document.getElementById(`${this.elementId}_hScrollContainer`)
3684
+ let left = 0
3685
+ const cells = bodyEl.querySelectorAll(`tr:first-of-type td`)
3686
+ for (let i = 0; i < this.options.leftColumns; i++) {
3687
+ left += cells[i].offsetWidth || cells[i].clientWidth
3688
+ }
3689
+ hScrollContainerEl.style.left = `${left}px`
3690
+ }
3691
+ }
3692
+ buildSearchIcon (columnIndex) {
3693
+ return `
3694
+ <div class="websy-table-search-icon" data-col-index="${columnIndex}">
3695
+ <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>
3696
+ </div>
3697
+ `
3698
+ }
3699
+ handleClick (event) {
3700
+ if (event.target.classList.contains('download-button')) {
3701
+ window.viewManager.dataExportController.exportData(this.options.model)
3702
+ }
3703
+ if (event.target.classList.contains('sortable-column')) {
3704
+ const colIndex = +event.target.getAttribute('data-index')
3705
+ const column = this.options.columns[colIndex]
3706
+ if (this.options.onSort) {
3707
+ this.options.onSort(event, column, colIndex)
3708
+ }
3709
+ else {
3710
+ this.internalSort(column, colIndex)
3711
+ }
3712
+ // const colIndex = +event.target.getAttribute('data-index')
3713
+ // const dimIndex = +event.target.getAttribute('data-dim-index')
3714
+ // const expIndex = +event.target.getAttribute('data-exp-index')
3715
+ // const reverse = event.target.getAttribute('data-reverse') === 'true'
3716
+ // const patchDefs = [{
3717
+ // qOp: 'replace',
3718
+ // qPath: '/qHyperCubeDef/qInterColumnSortOrder',
3719
+ // qValue: JSON.stringify([colIndex])
3720
+ // }]
3721
+ // patchDefs.push({
3722
+ // qOp: 'replace',
3723
+ // qPath: `/qHyperCubeDef/${dimIndex > -1 ? 'qDimensions' : 'qMeasures'}/${dimIndex > -1 ? dimIndex : expIndex}/qDef/qReverseSort`,
3724
+ // qValue: JSON.stringify(reverse)
3725
+ // })
3726
+ // this.options.model.applyPatches(patchDefs) // .then(() => this.render())
3727
+ }
3728
+ else if (event.target.classList.contains('websy-table-search-icon')) {
3729
+ // let field = event.target.getAttribute('data-field')
3730
+ // window.viewManager.views.global.objects[1].instance.show(field, { x: event.pageX, y: event.pageY }, () => {
3731
+ // event.target.classList.remove('active')
3732
+ // })
3733
+ const colIndex = +event.target.getAttribute('data-col-index')
3734
+ if (this.options.columns[colIndex].onSearch) {
3735
+ this.options.columns[colIndex].onSearch(event, this.options.columns[colIndex])
3736
+ }
3737
+ }
3738
+ else if (event.target.classList.contains('clickable')) {
3739
+ const colIndex = +event.target.getAttribute('data-col-index')
3740
+ const rowIndex = +event.target.getAttribute('data-row-index')
3741
+ if (this.options.onClick) {
3742
+ this.options.onClick(event, this.data[rowIndex][colIndex], this.data[rowIndex], this.options.columns[colIndex])
3743
+ }
3744
+ }
3745
+ else if (event.target.classList.contains('websy-page-num')) {
3746
+ const pageNum = +event.target.getAttribute('data-page')
3747
+ if (this.options.onSetPage) {
3748
+ this.options.onSetPage(pageNum)
3749
+ }
3750
+ }
3751
+ }
3752
+ handleMouseDown (event) {
3753
+ if (event.target.classList.contains('websy-scroll-handle')) {
3754
+ this.scrolling = true
3755
+ const el = document.getElementById(this.elementId)
3756
+ el.classList.add('scrolling')
3757
+ }
3758
+ if (event.target.classList.contains('websy-scroll-handle-x')) {
3759
+ const handleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
3760
+ this.handleXStart = handleEl.offsetLeft
3761
+ this.scrollXStart = event.clientX
3762
+ this.scrollDirection = 'X'
3763
+ }
3764
+ }
3765
+ handleGlobalMouseUp (event) {
3766
+ this.scrolling = false
3767
+ const el = document.getElementById(this.elementId)
3768
+ el.classList.remove('scrolling')
3769
+ }
3770
+ handleMouseUp (event) {
3771
+ this.scrolling = false
3772
+ const el = document.getElementById(this.elementId)
3773
+ el.classList.remove('scrolling')
3774
+ }
3775
+ handleMouseMove (event) {
3776
+ if (this.tooltipTimeoutFn) {
3777
+ event.target.classList.remove('websy-delayed-info')
3778
+ clearTimeout(this.tooltipTimeoutFn)
3779
+ }
3780
+ if (event.target.tagName === 'TD') {
3781
+ this.tooltipTimeoutFn = setTimeout(() => {
3782
+ event.target.classList.add('websy-delayed-info')
3783
+ }, 500)
3784
+ }
3785
+ if (this.scrolling === true && this.options.virtualScroll === true) {
3786
+ const tableContainerEl = document.getElementById(`${this.elementId}_tableContainer`)
3787
+ if (this.scrollDirection === 'X') {
3788
+ const handleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
3789
+ // console.log(this.handleXStart + handleEl.offsetWidth + (event.clientX - this.scrollXStart), this.columnParameters.scrollableWidth)
3790
+ let startPoint = 0
3791
+ if (this.handleXStart + (event.clientX - this.scrollXStart) < this.columnParameters.scrollableWidth - handleEl.offsetWidth) {
3792
+ handleEl.style.left = `${this.handleXStart + (event.clientX - this.scrollXStart)}px`
3793
+ startPoint = this.handleXStart + (event.clientX - this.scrollXStart)
3794
+ }
3795
+ else {
3796
+ startPoint = this.columnParameters.scrollableWidth - handleEl.offsetWidth
3797
+ }
3798
+ if (this.handleXStart + (event.clientX - this.scrollXStart) < 0) {
3799
+ handleEl.style.left = 0
3800
+ startPoint = 0
3801
+ }
3802
+ if (this.options.onScrollX) {
3803
+ this.options.onScrollX(startPoint)
3804
+ }
3805
+ }
3806
+ }
3807
+ }
3808
+ handleMouseOut (event) {
3809
+ if (this.tooltipTimeoutFn) {
3810
+ event.target.classList.remove('websy-delayed-info')
3811
+ clearTimeout(this.tooltipTimeoutFn)
3812
+ }
3813
+ }
3814
+ handleScroll (event) {
3815
+ if (this.options.onScroll && this.options.paging === 'scroll') {
3816
+ this.options.onScroll(event)
3817
+ }
3818
+ }
3819
+ hideError () {
3820
+ const el = document.getElementById(`${this.elementId}_tableContainer`)
3821
+ if (el) {
3822
+ el.classList.remove('has-error')
3823
+ }
3824
+ const tableEl = document.getElementById(`${this.elementId}_table`)
3825
+ tableEl.classList.remove('hidden')
3826
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3827
+ if (containerEl) {
3828
+ containerEl.classList.remove('active')
3829
+ }
3830
+ }
3831
+ hideLoading () {
3832
+ this.loadingDialog.hide()
3833
+ }
3834
+ internalSort (column, colIndex) {
3835
+ this.options.columns.forEach((c, i) => {
3836
+ c.activeSort = i === colIndex
3837
+ })
3838
+ if (column.sortFunction) {
3839
+ this.data = column.sortFunction(this.data, column)
3840
+ }
3841
+ else {
3842
+ let sortProp = 'value'
3843
+ let sortOrder = column.sort === 'asc' ? 'desc' : 'asc'
3844
+ column.sort = sortOrder
3845
+ let sortType = column.sortType || 'alphanumeric'
3846
+ if (column.sortProp) {
3847
+ sortProp = column.sortProp
3848
+ }
3849
+ this.data.sort((a, b) => {
3850
+ switch (sortType) {
3851
+ case 'numeric':
3852
+ if (sortOrder === 'asc') {
3853
+ return a[colIndex][sortProp] - b[colIndex][sortProp]
3854
+ }
3855
+ else {
3856
+ return b[colIndex][sortProp] - a[colIndex][sortProp]
3857
+ }
3858
+ default:
3859
+ if (sortOrder === 'asc') {
3860
+ return a[colIndex][sortProp] > b[colIndex][sortProp] ? 1 : -1
3861
+ }
3862
+ else {
3863
+ return a[colIndex][sortProp] < b[colIndex][sortProp] ? 1 : -1
3864
+ }
3865
+ }
3866
+ })
3867
+ }
3868
+ this.render(this.data)
3869
+ }
3870
+ render (data) {
3871
+ if (!this.options.columns) {
3872
+ return
3873
+ }
3874
+ this.hideError()
3875
+ this.data = []
3876
+ this.rowCount = 0
3877
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
3878
+ bodyEl.innerHTML = ''
3879
+ if (this.options.allowDownload === true) {
3880
+ // doesn't do anything yet
3881
+ const el = document.getElementById(this.elementId)
3882
+ if (el) {
3883
+ el.classList.add('allow-download')
3884
+ }
3885
+ else {
3886
+ el.classList.remove('allow-download')
3887
+ }
3888
+ }
3889
+ // let colGroupHTML = this.options.columns.map(c => `<col style="${c.width ? 'width: ' + c.width : ''}"></col>`)
3890
+ let headHTML = '<tr>' + this.options.columns.map((c, i) => {
3891
+ if (c.show !== false) {
3892
+ return `
3893
+ <th ${c.width ? 'style="width: ' + (c.width || 'auto') + ';"' : ''}>
3894
+ <div class ="tableHeader">
3895
+ <div class="leftSection">
3896
+ <div
3897
+ class="tableHeaderField ${['asc', 'desc'].indexOf(c.sort) !== -1 ? 'sortable-column' : ''}"
3898
+ data-index="${i}"
3899
+ data-sort="${c.sort}"
3900
+ >
3901
+ ${c.name}
3902
+ </div>
3903
+ </div>
3904
+ <div class="${c.activeSort ? c.sort + ' sortOrder' : ''}"></div>
3905
+ ${c.searchable === true ? this.buildSearchIcon(i) : ''}
3906
+ </div>
3907
+ </th>
3908
+ `
3909
+ }
3910
+ }).join('') + '</tr>'
3911
+ const headEl = document.getElementById(`${this.elementId}_head`)
3912
+ headEl.innerHTML = headHTML
3913
+ let dropdownHTML = ``
3914
+ this.options.columns.forEach((c, i) => {
3915
+ if (c.searchable && c.searchField) {
3916
+ dropdownHTML += `
3917
+ <div id="${this.elementId}_columnSearch_${i}" class="websy-modal-dropdown"></div>
3918
+ `
3919
+ }
3920
+ })
3921
+ const dropdownEl = document.getElementById(`${this.elementId}_dropdownContainer`)
3922
+ dropdownEl.innerHTML = dropdownHTML
3923
+ // const colGroupEl = document.getElementById(`${this.elementId}_cols`)
3924
+ // colGroupEl.innerHTML = colGroupHTML
3925
+ // let footHTML = '<tr>' + this.options.columns.map((c, i) => {
3926
+ // if (c.show !== false) {
3927
+ // return `
3928
+ // <th></th>
3929
+ // `
3930
+ // }
3931
+ // }).join('') + '</tr>'
3932
+ // const footEl = document.getElementById(`${this.elementId}_foot`)
3933
+ // footEl.innerHTML = footHTML
3934
+ if (this.options.paging === 'pages') {
3935
+ const pagingEl = document.getElementById(`${this.elementId}_pageList`)
3936
+ if (pagingEl) {
3937
+ let pages = (new Array(this.options.pageCount)).fill('').map((item, index) => {
3938
+ return `<li data-page="${index}" class="websy-page-num ${(this.options.pageNum === index) ? 'active' : ''}">${index + 1}</li>`
3939
+ })
3940
+ let startIndex = 0
3941
+ if (this.options.pageCount > 8) {
3942
+ startIndex = Math.max(0, this.options.pageNum - 4)
3943
+ pages = pages.splice(startIndex, 10)
3944
+ if (startIndex > 0) {
3945
+ pages.splice(0, 0, `<li>Page&nbsp;</li><li data-page="0" class="websy-page-num">First</li><li>...</li>`)
3946
+ }
3947
+ else {
3948
+ pages.splice(0, 0, '<li>Page&nbsp;</li>')
3949
+ }
3950
+ if (this.options.pageNum < this.options.pageCount - 1) {
3951
+ pages.push('<li>...</li>')
3952
+ pages.push(`<li data-page="${this.options.pageCount - 1}" class="websy-page-num">Last</li>`)
3953
+ }
3954
+ }
3955
+ pagingEl.innerHTML = pages.join('')
3956
+ }
3957
+ }
3958
+ if (data) {
3959
+ this.appendRows(data)
3960
+ }
3961
+ }
3962
+ showError (options) {
3963
+ const el = document.getElementById(`${this.elementId}_tableContainer`)
3964
+ if (el) {
3965
+ el.classList.add('has-error')
3966
+ }
3967
+ const tableEl = document.getElementById(`${this.elementId}_table`)
3968
+ tableEl.classList.add('hidden')
3969
+ const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
3970
+ if (containerEl) {
3971
+ containerEl.classList.add('active')
3972
+ }
3973
+ if (options.title) {
3974
+ const titleEl = document.getElementById(`${this.elementId}_errorTitle`)
3975
+ if (titleEl) {
3976
+ titleEl.innerHTML = options.title
3977
+ }
3978
+ }
3979
+ if (options.message) {
3980
+ const messageEl = document.getElementById(`${this.elementId}_errorMessage`)
3981
+ if (messageEl) {
3982
+ messageEl.innerHTML = options.message
3983
+ }
3984
+ }
3985
+ }
3986
+ setHorizontalScroll (options) {
3987
+ const el = document.getElementById(`${this.elementId}_hScrollHandle`)
3988
+ if (options.width) {
3989
+ el.style.width = `${options.width}px`
3990
+ }
3991
+ }
3992
+ setWidth (width) {
3993
+ const el = document.getElementById(`${this.elementId}_table`)
3994
+ if (el) {
3995
+ el.style.width = `${width}px`
3996
+ }
3997
+ }
3998
+ showLoading (options) {
3999
+ this.loadingDialog.show(options)
4000
+ }
4001
+ getColumnParameters (values) {
4002
+ const tableEl = document.getElementById(`${this.elementId}_table`)
4003
+ tableEl.style.tableLayout = 'auto'
4004
+ tableEl.style.width = 'auto'
4005
+ const bodyEl = document.getElementById(`${this.elementId}_body`)
4006
+ bodyEl.innerHTML = '<tr>' + values.map(c => `
4007
+ <td
4008
+ style='height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px;'
4009
+ >${c.value || '&nbsp;'}</td>
4010
+ `).join('') + '</tr>'
4011
+ // get height of the first data cell
4012
+ const cells = bodyEl.querySelectorAll(`tr:first-of-type td`)
4013
+ const tableContainerEl = document.getElementById(`${this.elementId}_tableContainer`)
4014
+ const cellHeight = cells[0].offsetHeight || cells[0].clientHeight
4015
+ const cellWidths = []
4016
+ let nonScrollableWidth = 0
4017
+ for (let i = 0; i < cells.length; i++) {
4018
+ if (i < this.options.leftColumns) {
4019
+ nonScrollableWidth += values[i].width || cells[i].offsetWidth || cells[i].clientWidth
4020
+ }
4021
+ cellWidths.push(values[i].width || cells[i].offsetWidth || cells[i].clientWidth)
4022
+ }
4023
+ // const cellWidth = firstDataCell.offsetWidth || firstDataCell.clientWidth
4024
+ // tableEl.style.width = ''
4025
+ this.columnParameters = {
4026
+ cellHeight,
4027
+ cellWidths,
4028
+ availableHeight: tableContainerEl.offsetHeight || tableContainerEl.clientHeight,
4029
+ availableWidth: tableContainerEl.offsetWidth || tableContainerEl.clientWidth,
4030
+ nonScrollableWidth,
4031
+ scrollableWidth: (tableContainerEl.offsetWidth || tableContainerEl.clientWidth) - nonScrollableWidth
4032
+ }
4033
+ bodyEl.innerHTML = ''
4034
+ tableEl.style.tableLayout = ''
4035
+ tableEl.style.width = ''
4036
+ return this.columnParameters
4037
+ }
4038
+ }
4039
+
4040
+ /* global d3 include WebsyDesigns */
4041
+ class WebsyChart {
4042
+ constructor (elementId, options) {
4043
+ const DEFAULTS = {
4044
+ margin: {
4045
+ top: 10,
4046
+ left: 3,
4047
+ bottom: 3,
4048
+ right: 3,
4049
+ axisBottom: 0,
4050
+ axisLeft: 0,
4051
+ axisRight: 0,
4052
+ axisTop: 0,
4053
+ legendBottom: 0,
4054
+ legendLeft: 0,
4055
+ legendRight: 0,
4056
+ legendTop: 0
4057
+ },
4058
+ orientation: 'vertical',
4059
+ colors: ['#5e4fa2', '#3288bd', '#66c2a5', '#abdda4', '#e6f598', '#fee08b', '#fdae61', '#f46d43', '#d53e4f', '#9e0142'],
4060
+ transitionDuration: 650,
4061
+ curveStyle: 'curveLinear',
4062
+ lineWidth: 2,
4063
+ forceZero: true,
4064
+ fontSize: 14,
4065
+ symbolSize: 20,
4066
+ showTrackingLine: true,
4067
+ showTooltip: true,
4068
+ showLegend: false,
3177
4069
  legendPosition: 'bottom',
3178
4070
  tooltipWidth: 200
3179
4071
  }
@@ -3429,7 +4321,7 @@ if (this.options.data[side].scale === 'Time') {
3429
4321
  }
3430
4322
  }
3431
4323
  this.tooltip.setHeight(this.plotHeight)
3432
- this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
4324
+ this.options.showTooltip && this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
3433
4325
  // }
3434
4326
  // else {
3435
4327
  // xPoint = x0
@@ -4011,7 +4903,7 @@ function getBarX (d, i) {
4011
4903
  }
4012
4904
  }
4013
4905
  else {
4014
- if (this.options.grouping === 'stacked') {
4906
+ if (this.options.grouping !== 'stacked') {
4015
4907
  return this[xAxis](this.parseX(d.x.value))
4016
4908
  }
4017
4909
  else {
@@ -4021,7 +4913,7 @@ function getBarX (d, i) {
4021
4913
  }
4022
4914
  function getBarY (d, i) {
4023
4915
  if (this.options.orientation === 'horizontal') {
4024
- if (this.options.grouping === 'stacked') {
4916
+ if (this.options.grouping !== 'stacked') {
4025
4917
  return this[xAxis](this.parseX(d.x.value))
4026
4918
  }
4027
4919
  else {
@@ -4804,7 +5696,9 @@ const WebsyDesigns = {
4804
5696
  WebsyRouter,
4805
5697
  Router: WebsyRouter,
4806
5698
  WebsyTable,
5699
+ WebsyTable2,
4807
5700
  Table: WebsyTable,
5701
+ Table2: WebsyTable2,
4808
5702
  WebsyChart,
4809
5703
  Chart: WebsyChart,
4810
5704
  WebsyChartTooltip,
@@ -4821,6 +5715,7 @@ const WebsyDesigns = {
4821
5715
  Utils: WebsyUtils,
4822
5716
  ButtonGroup,
4823
5717
  WebsySwitch: Switch,
5718
+ Pager,
4824
5719
  Switch
4825
5720
  }
4826
5721