@websy/websy-designs 1.0.2 → 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))
@@ -967,12 +1249,13 @@ class WebsyForm {
967
1249
  el.innerHTML = msg
968
1250
  }
969
1251
  }
970
- handleClick (event) {
971
- event.preventDefault()
1252
+ handleClick (event) {
972
1253
  if (event.target.classList.contains('submit')) {
1254
+ event.preventDefault()
973
1255
  this.submitForm()
974
1256
  }
975
1257
  else if (event.target.classList.contains('cancel')) {
1258
+ event.preventDefault()
976
1259
  this.cancelForm()
977
1260
  }
978
1261
  }
@@ -991,7 +1274,7 @@ class WebsyForm {
991
1274
  else {
992
1275
  components.forEach(c => {
993
1276
  if (typeof WebsyDesigns[c.component] !== 'undefined') {
994
- 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)
995
1278
  }
996
1279
  else {
997
1280
  // some user feedback here
@@ -1013,13 +1296,13 @@ class WebsyForm {
1013
1296
  let componentsToProcess = []
1014
1297
  if (el) {
1015
1298
  let html = `
1016
- <form id="${this.elementId}Form">
1299
+ <form id="${this.elementId}Form" class="${this.options.classes || ''}">
1017
1300
  `
1018
1301
  this.options.fields.forEach((f, i) => {
1019
1302
  if (f.component) {
1020
1303
  componentsToProcess.push(f)
1021
1304
  html += `
1022
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1305
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1023
1306
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1024
1307
  <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
1025
1308
  </div><!--
@@ -1027,7 +1310,7 @@ class WebsyForm {
1027
1310
  }
1028
1311
  else if (f.type === 'longtext') {
1029
1312
  html += `
1030
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1313
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1031
1314
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1032
1315
  <textarea
1033
1316
  id="${this.elementId}_input_${f.field}"
@@ -1041,7 +1324,7 @@ class WebsyForm {
1041
1324
  }
1042
1325
  else {
1043
1326
  html += `
1044
- ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
1327
+ ${i > 0 ? '-->' : ''}<div class='${f.classes || ''}'>
1045
1328
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
1046
1329
  <input
1047
1330
  id="${this.elementId}_input_${f.field}"
@@ -1051,6 +1334,7 @@ class WebsyForm {
1051
1334
  name="${f.field}"
1052
1335
  placeholder="${f.placeholder || ''}"
1053
1336
  value="${f.value || ''}"
1337
+ valueAsDate="${f.type === 'date' ? f.value : ''}"
1054
1338
  oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
1055
1339
  />
1056
1340
  </div><!--
@@ -1058,11 +1342,11 @@ class WebsyForm {
1058
1342
  }
1059
1343
  })
1060
1344
  html += `
1061
- --><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 ? '<!--' : ''}
1062
1346
  `
1063
1347
  if (this.options.cancel) {
1064
1348
  html += `
1065
- --><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>
1066
1350
  `
1067
1351
  }
1068
1352
  html += `
@@ -1283,9 +1567,6 @@ class WebsyNavigationMenu {
1283
1567
  html += this.renderBlock(this.options.items, 'main', 0)
1284
1568
  html += `</div>`
1285
1569
  el.innerHTML = html
1286
- if (this.options.navigator) {
1287
- this.options.navigator.registerElements(el)
1288
- }
1289
1570
  }
1290
1571
  }
1291
1572
  renderBlock (items, block, level = 0) {
@@ -1377,6 +1658,92 @@ class WebsyNavigationMenu {
1377
1658
  }
1378
1659
  }
1379
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
+
1380
1747
  /* global WebsyDesigns Blob */
1381
1748
  class WebsyPDFButton {
1382
1749
  constructor (elementId, options) {
@@ -2260,18 +2627,7 @@ class WebsyRouter {
2260
2627
  groupActiveView = this.groups[group].activeView
2261
2628
  }
2262
2629
  this.previousPath = this.groups[group].activeView
2263
- }
2264
- if (toggle === true) {
2265
- if (this.previousPath !== '') {
2266
- this.hideView(this.previousPath, group)
2267
- }
2268
- }
2269
- else {
2270
- this.hideView(this.previousView, group)
2271
2630
  }
2272
- if (toggle === true && newPath === groupActiveView) {
2273
- return
2274
- }
2275
2631
  if (group && this.groups[group] && group !== this.options.defaultGroup) {
2276
2632
  this.groups[group].activeView = newPath
2277
2633
  }
@@ -2287,6 +2643,17 @@ class WebsyRouter {
2287
2643
  if (this.currentViewMain === '/') {
2288
2644
  this.currentViewMain = this.options.defaultView
2289
2645
  }
2646
+ if (toggle === true) {
2647
+ if (this.previousPath !== '') {
2648
+ this.hideView(this.previousPath, group)
2649
+ }
2650
+ }
2651
+ else {
2652
+ this.hideView(this.previousView, group)
2653
+ }
2654
+ if (toggle === true && newPath === groupActiveView) {
2655
+ return
2656
+ }
2290
2657
  if (toggle === false) {
2291
2658
  this.showView(this.currentView, this.currentParams)
2292
2659
  }
@@ -2768,7 +3135,8 @@ const WebsyUtils = {
2768
3135
  class WebsyTable {
2769
3136
  constructor (elementId, options) {
2770
3137
  const DEFAULTS = {
2771
- pageSize: 20
3138
+ pageSize: 20,
3139
+ paging: 'scroll'
2772
3140
  }
2773
3141
  this.elementId = elementId
2774
3142
  this.options = Object.assign({}, DEFAULTS, options)
@@ -2778,8 +3146,8 @@ class WebsyTable {
2778
3146
  this.data = []
2779
3147
  const el = document.getElementById(this.elementId)
2780
3148
  if (el) {
2781
- el.innerHTML = `
2782
- <div id='${this.elementId}_tableContainer' class='websy-vis-table'>
3149
+ let html = `
3150
+ <div id='${this.elementId}_tableContainer' class='websy-vis-table ${this.options.paging === 'pages' ? 'with-paging' : ''}'>
2783
3151
  <!--<div class="download-button">
2784
3152
  <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>
2785
3153
  </div>-->
@@ -2790,7 +3158,7 @@ class WebsyTable {
2790
3158
  </tbody>
2791
3159
  <tfoot id="${this.elementId}_foot">
2792
3160
  </tfoot>
2793
- </table>
3161
+ </table>
2794
3162
  <div id="${this.elementId}_errorContainer" class='websy-vis-error-container'>
2795
3163
  <div>
2796
3164
  <div id="${this.elementId}_errorTitle"></div>
@@ -2799,7 +3167,30 @@ class WebsyTable {
2799
3167
  </div>
2800
3168
  <div id="${this.elementId}_loadingContainer"></div>
2801
3169
  </div>
2802
- `
3170
+ `
3171
+ if (this.options.paging === 'pages') {
3172
+ html += `
3173
+ <div class="websy-table-paging-container">
3174
+ Show <div id="${this.elementId}_pageSizeSelector" class="websy-vis-page-selector"></div> rows
3175
+ <ul id="${this.elementId}_pageList" class="websy-vis-page-list"></ul>
3176
+ </div>
3177
+ `
3178
+ }
3179
+ let pageOptions = [10, 20, 50, 100, 200]
3180
+ el.innerHTML = html
3181
+ if (this.options.paging === 'pages') {
3182
+ this.pageSizeSelector = new WebsyDesigns.Dropdown(`${this.elementId}_pageSizeSelector`, {
3183
+ selectedItems: [pageOptions.indexOf(this.options.pageSize)],
3184
+ items: pageOptions.map(p => ({ label: p.toString(), value: p })),
3185
+ allowClear: false,
3186
+ disableSearch: true,
3187
+ onItemSelected: (selectedItem) => {
3188
+ if (this.options.onChangePageSize) {
3189
+ this.options.onChangePageSize(selectedItem.value)
3190
+ }
3191
+ }
3192
+ })
3193
+ }
2803
3194
  el.addEventListener('click', this.handleClick.bind(this))
2804
3195
  el.addEventListener('mouseout', this.handleMouseOut.bind(this))
2805
3196
  el.addEventListener('mousemove', this.handleMouseMove.bind(this))
@@ -2828,6 +3219,9 @@ class WebsyTable {
2828
3219
  }
2829
3220
  if (c.backgroundColor) {
2830
3221
  style += `background-color: ${c.backgroundColor}; `
3222
+ if (!c.color) {
3223
+ style += `color: ${WebsyDesigns.Utils.getLightDark(c.backgroundColor)}; `
3224
+ }
2831
3225
  }
2832
3226
  if (c.color) {
2833
3227
  style += `color: ${c.color}; `
@@ -2943,6 +3337,12 @@ class WebsyTable {
2943
3337
  this.options.onClick(event, this.data[rowIndex][colIndex], this.data[rowIndex], this.options.columns[colIndex])
2944
3338
  }
2945
3339
  }
3340
+ else if (event.target.classList.contains('websy-page-num')) {
3341
+ const pageNum = +event.target.getAttribute('data-page')
3342
+ if (this.options.onSetPage) {
3343
+ this.options.onSetPage(pageNum)
3344
+ }
3345
+ }
2946
3346
  }
2947
3347
  handleMouseMove (event) {
2948
3348
  if (this.tooltipTimeoutFn) {
@@ -2962,9 +3362,9 @@ class WebsyTable {
2962
3362
  }
2963
3363
  }
2964
3364
  handleScroll (event) {
2965
- if (this.options.onScroll) {
3365
+ if (this.options.onScroll && this.options.paging === 'scroll') {
2966
3366
  this.options.onScroll(event)
2967
- }
3367
+ }
2968
3368
  }
2969
3369
  hideError () {
2970
3370
  const containerEl = document.getElementById(`${this.elementId}_errorContainer`)
@@ -3053,15 +3453,39 @@ class WebsyTable {
3053
3453
  }).join('') + '</tr>'
3054
3454
  const headEl = document.getElementById(`${this.elementId}_head`)
3055
3455
  headEl.innerHTML = headHTML
3056
- let footHTML = '<tr>' + this.options.columns.map((c, i) => {
3057
- if (c.show !== false) {
3058
- return `
3059
- <th></th>
3060
- `
3456
+ // let footHTML = '<tr>' + this.options.columns.map((c, i) => {
3457
+ // if (c.show !== false) {
3458
+ // return `
3459
+ // <th></th>
3460
+ // `
3461
+ // }
3462
+ // }).join('') + '</tr>'
3463
+ // const footEl = document.getElementById(`${this.elementId}_foot`)
3464
+ // footEl.innerHTML = footHTML
3465
+ if (this.options.paging === 'pages') {
3466
+ const pagingEl = document.getElementById(`${this.elementId}_pageList`)
3467
+ if (pagingEl) {
3468
+ let pages = (new Array(this.options.pageCount)).fill('').map((item, index) => {
3469
+ return `<li data-page="${index}" class="websy-page-num ${(this.options.pageNum === index) ? 'active' : ''}">${index + 1}</li>`
3470
+ })
3471
+ let startIndex = 0
3472
+ if (this.options.pageCount > 8) {
3473
+ startIndex = Math.max(0, this.options.pageNum - 4)
3474
+ pages = pages.splice(startIndex, 10)
3475
+ if (startIndex > 0) {
3476
+ pages.splice(0, 0, `<li>Page&nbsp;</li><li data-page="0" class="websy-page-num">First</li><li>...</li>`)
3477
+ }
3478
+ else {
3479
+ pages.splice(0, 0, '<li>Page&nbsp;</li>')
3480
+ }
3481
+ if (this.options.pageNum < this.options.pageCount - 1) {
3482
+ pages.push('<li>...</li>')
3483
+ pages.push(`<li data-page="${this.options.pageCount - 1}" class="websy-page-num">Last</li>`)
3484
+ }
3485
+ }
3486
+ pagingEl.innerHTML = pages.join('')
3061
3487
  }
3062
- }).join('') + '</tr>'
3063
- const footEl = document.getElementById(`${this.elementId}_foot`)
3064
- footEl.innerHTML = footHTML
3488
+ }
3065
3489
  if (data) {
3066
3490
  // this.data = this.data.concat(data)
3067
3491
  this.appendRows(data)
@@ -3090,6 +3514,529 @@ class WebsyTable {
3090
3514
  }
3091
3515
  }
3092
3516
 
3517
+ /* global WebsyDesigns */
3518
+ class WebsyTable2 {
3519
+ constructor (elementId, options) {
3520
+ const DEFAULTS = {
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
+
3093
4040
  /* global d3 include WebsyDesigns */
3094
4041
  class WebsyChart {
3095
4042
  constructor (elementId, options) {
@@ -3374,7 +4321,7 @@ if (this.options.data[side].scale === 'Time') {
3374
4321
  }
3375
4322
  }
3376
4323
  this.tooltip.setHeight(this.plotHeight)
3377
- this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
4324
+ this.options.showTooltip && this.tooltip.show(tooltipTitle, tooltipHTML, posOptions)
3378
4325
  // }
3379
4326
  // else {
3380
4327
  // xPoint = x0
@@ -3956,7 +4903,7 @@ function getBarX (d, i) {
3956
4903
  }
3957
4904
  }
3958
4905
  else {
3959
- if (this.options.grouping === 'stacked') {
4906
+ if (this.options.grouping !== 'stacked') {
3960
4907
  return this[xAxis](this.parseX(d.x.value))
3961
4908
  }
3962
4909
  else {
@@ -3966,7 +4913,7 @@ function getBarX (d, i) {
3966
4913
  }
3967
4914
  function getBarY (d, i) {
3968
4915
  if (this.options.orientation === 'horizontal') {
3969
- if (this.options.grouping === 'stacked') {
4916
+ if (this.options.grouping !== 'stacked') {
3970
4917
  return this[xAxis](this.parseX(d.x.value))
3971
4918
  }
3972
4919
  else {
@@ -4749,7 +5696,9 @@ const WebsyDesigns = {
4749
5696
  WebsyRouter,
4750
5697
  Router: WebsyRouter,
4751
5698
  WebsyTable,
5699
+ WebsyTable2,
4752
5700
  Table: WebsyTable,
5701
+ Table2: WebsyTable2,
4753
5702
  WebsyChart,
4754
5703
  Chart: WebsyChart,
4755
5704
  WebsyChartTooltip,
@@ -4766,6 +5715,7 @@ const WebsyDesigns = {
4766
5715
  Utils: WebsyUtils,
4767
5716
  ButtonGroup,
4768
5717
  WebsySwitch: Switch,
5718
+ Pager,
4769
5719
  Switch
4770
5720
  }
4771
5721