@websy/websy-designs 0.0.99 → 0.0.103

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.
@@ -356,6 +356,18 @@ class WebsyForm {
356
356
  }
357
357
  this.render()
358
358
  }
359
+ confirmValidation () {
360
+ const el = document.getElementById(`${this.elementId}_validationFail`)
361
+ if (el) {
362
+ el.innerHTML = ''
363
+ }
364
+ }
365
+ failValidation (msg) {
366
+ const el = document.getElementById(`${this.elementId}_validationFail`)
367
+ if (el) {
368
+ el.innerHTML = msg
369
+ }
370
+ }
359
371
  handleClick (event) {
360
372
  if (event.target.classList.contains('submit')) {
361
373
  this.submitForm()
@@ -368,6 +380,21 @@ class WebsyForm {
368
380
  }
369
381
  handleKeyUp (event) {
370
382
 
383
+ }
384
+ processComponents (components, callbackFn) {
385
+ if (components.length === 0) {
386
+ callbackFn()
387
+ }
388
+ else {
389
+ components.forEach(c => {
390
+ if (typeof WebsyDesigns[c.component] !== 'undefined') {
391
+ const comp = new WebsyDesigns[c.component](`${this.elementId}_input_${c.field}_component`, c.options)
392
+ }
393
+ else {
394
+ // some user feedback here
395
+ }
396
+ })
397
+ }
371
398
  }
372
399
  recaptchaReady () {
373
400
  const el = document.getElementById(`${this.elementId}_recaptcha`)
@@ -380,12 +407,20 @@ class WebsyForm {
380
407
  }
381
408
  render (update, data) {
382
409
  const el = document.getElementById(this.elementId)
410
+ let componentsToProcess = []
383
411
  if (el) {
384
412
  let html = `
385
413
  <form id="${this.elementId}Form">
386
414
  `
387
415
  this.options.fields.forEach(f => {
388
- if (f.type === 'longtext') {
416
+ if (f.component) {
417
+ componentsToProcess.push(f)
418
+ html += `
419
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
420
+ <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
421
+ `
422
+ }
423
+ else if (f.type === 'longtext') {
389
424
  html += `
390
425
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
391
426
  <textarea
@@ -415,6 +450,7 @@ class WebsyForm {
415
450
  })
416
451
  html += `
417
452
  </form>
453
+ <div id="${this.elementId}_validationFail" class="websy-validation-failure"></div>
418
454
  `
419
455
  if (this.options.useRecaptcha === true) {
420
456
  html += `
@@ -425,9 +461,11 @@ class WebsyForm {
425
461
  <button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>
426
462
  `
427
463
  el.innerHTML = html
428
- if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
429
- this.recaptchaReady()
430
- }
464
+ this.processComponents(componentsToProcess, () => {
465
+ if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
466
+ this.recaptchaReady()
467
+ }
468
+ })
431
469
  }
432
470
  }
433
471
  submitForm () {
@@ -454,11 +492,12 @@ class WebsyForm {
454
492
  })
455
493
  }
456
494
  else if (this.options.submitFn) {
457
- this.options.submitFn(data)
458
- if (this.options.clearAfterSave === true) {
459
- // this.render()
460
- formEl.reset()
461
- }
495
+ this.options.submitFn(data, () => {
496
+ if (this.options.clearAfterSave === true) {
497
+ // this.render()
498
+ formEl.reset()
499
+ }
500
+ })
462
501
  }
463
502
  }
464
503
  else {
@@ -479,8 +518,8 @@ class WebsyDatePicker {
479
518
  this.validDates = []
480
519
  const DEFAULTS = {
481
520
  defaultRange: 0,
482
- minAllowedDate: floorDate(new Date(new Date((new Date().setFullYear(new Date().getFullYear() - 5))).setDate(1))),
483
- maxAllowedDate: floorDate(new Date((new Date().setFullYear(new Date().getFullYear() + 1)))),
521
+ minAllowedDate: this.floorDate(new Date(new Date((new Date().setFullYear(new Date().getFullYear() - 1))).setDate(1))),
522
+ maxAllowedDate: this.floorDate(new Date((new Date()))),
484
523
  daysOfWeek: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
485
524
  monthMap: {
486
525
  0: 'Jan',
@@ -505,31 +544,31 @@ class WebsyDatePicker {
505
544
  },
506
545
  {
507
546
  label: 'Today',
508
- range: [floorDate(new Date())]
547
+ range: [this.floorDate(new Date())]
509
548
  },
510
549
  {
511
550
  label: 'Yesterday',
512
- range: [floorDate(new Date().setDate(new Date().getDate() - 1))]
551
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 1))]
513
552
  },
514
553
  {
515
554
  label: 'Last 7 Days',
516
- range: [floorDate(new Date().setDate(new Date().getDate() - 6)), floorDate(new Date())]
555
+ range: [this.floorDate(new Date().setDate(new Date().getDate() - 6)), this.floorDate(new Date())]
517
556
  },
518
557
  {
519
558
  label: 'This Month',
520
- range: [floorDate(new Date().setDate(1)), floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() + 1) - this.oneDay)]
559
+ range: [this.floorDate(new Date().setDate(1)), this.floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() + 1) - this.oneDay)]
521
560
  },
522
561
  {
523
562
  label: 'Last Month',
524
- range: [floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth() - 1)), floorDate(new Date(new Date().setDate(1)).setMonth(new Date().getMonth()) - this.oneDay)]
563
+ 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)]
525
564
  },
526
565
  {
527
566
  label: 'This Year',
528
- range: [floorDate(new Date(`1/1/${new Date().getFullYear()}`)), floorDate(new Date(`12/31/${new Date().getFullYear()}`))]
567
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear()}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear()}`))]
529
568
  },
530
569
  {
531
570
  label: 'Last Year',
532
- range: [floorDate(new Date(`1/1/${new Date().getFullYear() - 1}`)), floorDate(new Date(`12/31/${new Date().getFullYear() - 1}`))]
571
+ range: [this.floorDate(new Date(`1/1/${new Date().getFullYear() - 1}`)), this.floorDate(new Date(`12/31/${new Date().getFullYear() - 1}`))]
533
572
  }
534
573
  ]
535
574
  this.options = Object.assign({}, DEFAULTS, options)
@@ -571,13 +610,7 @@ class WebsyDatePicker {
571
610
  }
572
611
  else {
573
612
  console.log('No element found with Id', elementId)
574
- }
575
- function floorDate (d) {
576
- if (typeof d === 'number') {
577
- d = new Date(d)
578
- }
579
- return new Date(d.setHours(0, 0, 0))
580
- }
613
+ }
581
614
  }
582
615
  close (confirm) {
583
616
  const maskEl = document.getElementById(`${this.elementId}_mask`)
@@ -595,6 +628,12 @@ class WebsyDatePicker {
595
628
  this.selectedRange = this.priorSelectedRange
596
629
  }
597
630
  }
631
+ floorDate (d) {
632
+ if (typeof d === 'number') {
633
+ d = new Date(d)
634
+ }
635
+ return new Date(d.setHours(0, 0, 0, 0))
636
+ }
598
637
  handleClick (event) {
599
638
  if (event.target.classList.contains('websy-date-picker-header')) {
600
639
  this.open()
@@ -640,7 +679,7 @@ class WebsyDatePicker {
640
679
  daysDiff += 1
641
680
  }
642
681
  for (let i = 0; i < daysDiff + 1; i++) {
643
- let d = new Date(this.selectedRangeDates[0].getTime() + (i * this.oneDay)).floor()
682
+ let d = this.floorDate(new Date(this.selectedRangeDates[0].getTime() + (i * this.oneDay)))
644
683
  const dateEl = document.getElementById(`${d.getTime()}_date`)
645
684
  if (dateEl) {
646
685
  dateEl.classList.add('selected')
@@ -679,6 +718,7 @@ class WebsyDatePicker {
679
718
  }
680
719
  renderDates (disabledDates) {
681
720
  let disabled = []
721
+ this.validDates = []
682
722
  if (disabledDates) {
683
723
  disabled = disabledDates.map(d => d.getTime())
684
724
  }
@@ -687,8 +727,7 @@ class WebsyDatePicker {
687
727
  let daysDiff = Math.ceil((this.options.maxAllowedDate.getTime() - this.options.minAllowedDate.getTime()) / this.oneDay) + 1
688
728
  let months = {}
689
729
  for (let i = 0; i < daysDiff; i++) {
690
- let d = new Date(this.options.minAllowedDate.getTime() + (i * this.oneDay)).floor()
691
- d.setHours(0)
730
+ let d = this.floorDate(new Date(this.options.minAllowedDate.getTime() + (i * this.oneDay)))
692
731
  let monthYear = `${this.options.monthMap[d.getMonth()]} ${d.getFullYear()}`
693
732
  if (!months[monthYear]) {
694
733
  months[monthYear] = []
@@ -710,13 +749,16 @@ class WebsyDatePicker {
710
749
  if (this.validDates.indexOf(r.range[1].getTime()) !== -1) {
711
750
  r.disabled = false
712
751
  }
713
- // check the full range until a match is found
714
- for (let i = r.range[0].getTime(); i < r.range[1].getTime(); i += (24 * 60 * 60 * 1000)) {
715
- if (this.validDates.indexOf(r.range[1].getTime()) !== -1) {
716
- r.disabled = false
717
- break
718
- }
719
- }
752
+ else {
753
+ // check the full range until a match is found
754
+ for (let i = r.range[0].getTime(); i <= r.range[1].getTime(); i += this.oneDay) {
755
+ let testDate = this.floorDate(new Date(i))
756
+ if (this.validDates.indexOf(testDate.getTime()) !== -1) {
757
+ r.disabled = false
758
+ break
759
+ }
760
+ }
761
+ }
720
762
  }
721
763
  }
722
764
  let html = ''
@@ -840,14 +882,17 @@ class WebsyDropdown {
840
882
  constructor (elementId, options) {
841
883
  const DEFAULTS = {
842
884
  multiSelect: false,
885
+ multiValueDelimiter: ',',
843
886
  allowClear: true,
844
887
  style: 'plain',
845
888
  items: [],
846
889
  label: '',
847
- minSearchCharacters: 2
890
+ minSearchCharacters: 2,
891
+ showCompleteSelectedList: false
848
892
  }
849
893
  this.options = Object.assign({}, DEFAULTS, options)
850
- this.selectedItems = []
894
+ this.tooltipTimeoutFn = null
895
+ this.selectedItems = this.options.selectedItems || []
851
896
  if (!elementId) {
852
897
  console.log('No element Id provided')
853
898
  return
@@ -857,6 +902,8 @@ class WebsyDropdown {
857
902
  this.elementId = elementId
858
903
  el.addEventListener('click', this.handleClick.bind(this))
859
904
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
905
+ el.addEventListener('mouseout', this.handleMouseOut.bind(this))
906
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
860
907
  this.render()
861
908
  }
862
909
  else {
@@ -945,6 +992,36 @@ class WebsyDropdown {
945
992
  }
946
993
  }
947
994
  }
995
+ handleMouseMove (event) {
996
+ if (this.tooltipTimeoutFn) {
997
+ event.target.classList.remove('websy-delayed')
998
+ event.target.classList.remove('websy-delayed-info')
999
+ if (event.target.children[1]) {
1000
+ event.target.children[1].classList.remove('websy-delayed-info')
1001
+ }
1002
+ clearTimeout(this.tooltipTimeoutFn)
1003
+ }
1004
+ if (event.target.tagName === 'LI') {
1005
+ this.tooltipTimeoutFn = setTimeout(() => {
1006
+ event.target.classList.add('websy-delayed')
1007
+ }, 500)
1008
+ }
1009
+ if (event.target.classList.contains('websy-dropdown-header') && event.target.children[1]) {
1010
+ this.tooltipTimeoutFn = setTimeout(() => {
1011
+ event.target.children[1].classList.add('websy-delayed-info')
1012
+ }, 500)
1013
+ }
1014
+ }
1015
+ handleMouseOut (event) {
1016
+ if (this.tooltipTimeoutFn) {
1017
+ event.target.classList.remove('websy-delayed')
1018
+ event.target.classList.remove('websy-delayed-info')
1019
+ if (event.target.children[1]) {
1020
+ event.target.children[1].classList.remove('websy-delayed-info')
1021
+ }
1022
+ clearTimeout(this.tooltipTimeoutFn)
1023
+ }
1024
+ }
948
1025
  open (options, override = false) {
949
1026
  const maskEl = document.getElementById(`${this.elementId}_mask`)
950
1027
  const contentEl = document.getElementById(`${this.elementId}_content`)
@@ -963,11 +1040,13 @@ class WebsyDropdown {
963
1040
  return
964
1041
  }
965
1042
  const el = document.getElementById(this.elementId)
1043
+ const headerValue = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
966
1044
  let html = `
967
1045
  <div class='websy-dropdown-container ${this.options.disableSearch !== true ? 'with-search' : ''}'>
968
1046
  <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
969
1047
  <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
970
- <span class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${this.selectedItems.map(s => this.options.items[s].label).join(',')}</span>
1048
+ <span data-info='${headerValue}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerValue}</span>
1049
+ <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
971
1050
  <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>
972
1051
  `
973
1052
  if (this.options.allowClear === true) {
@@ -1016,6 +1095,7 @@ class WebsyDropdown {
1016
1095
  const headerEl = document.getElementById(`${this.elementId}_header`)
1017
1096
  const headerLabelEl = document.getElementById(`${this.elementId}_headerLabel`)
1018
1097
  const labelEl = document.getElementById(`${this.elementId}_selectedItems`)
1098
+ const inputEl = document.getElementById(`${this.elementId}_input`)
1019
1099
  const itemEls = el.querySelectorAll(`.websy-dropdown-item`)
1020
1100
  for (let i = 0; i < itemEls.length; i++) {
1021
1101
  itemEls[i].classList.remove('active')
@@ -1033,18 +1113,37 @@ class WebsyDropdown {
1033
1113
  headerEl.classList.add('one-selected')
1034
1114
  }
1035
1115
  else if (this.selectedItems.length > 1) {
1036
- headerEl.classList.add('multi-selected')
1116
+ if (this.options.showCompleteSelectedList === true) {
1117
+ headerEl.classList.add('one-selected')
1118
+ }
1119
+ else {
1120
+ headerEl.classList.add('multi-selected')
1121
+ }
1037
1122
  }
1038
1123
  }
1039
1124
  if (labelEl) {
1040
1125
  if (this.selectedItems.length === 1) {
1041
- labelEl.innerHTML = item.label
1126
+ labelEl.innerHTML = item.label
1127
+ labelEl.setAttribute('data-info', item.label)
1128
+ inputEl.value = item.label
1042
1129
  }
1043
1130
  else if (this.selectedItems.length > 1) {
1044
- labelEl.innerHTML = `${this.selectedItems.length} selected`
1131
+ if (this.options.showCompleteSelectedList === true) {
1132
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1133
+ labelEl.innerHTML = selectedValues
1134
+ labelEl.setAttribute('data-info', selectedValues)
1135
+ inputEl.value = selectedValues
1136
+ }
1137
+ else {
1138
+ labelEl.innerHTML = `${this.selectedItems.length} selected`
1139
+ labelEl.setAttribute('data-info', '')
1140
+ inputEl.value = this.selectedItems.join(this.options.multiValueDelimiter)
1141
+ }
1045
1142
  }
1046
1143
  else {
1047
1144
  labelEl.innerHTML = ''
1145
+ labelEl.setAttribute('data-info', '')
1146
+ inputEl.value = ''
1048
1147
  }
1049
1148
  }
1050
1149
  }
@@ -1363,7 +1462,7 @@ class APIService {
1363
1462
  xhr.withCredentials = true
1364
1463
  console.log('using this')
1365
1464
  xhr.onload = () => {
1366
- if (xhr.status === 401) {
1465
+ if (xhr.status === 401 || xhr.status === 403) {
1367
1466
  if (ENV && ENV.AUTH_REDIRECT) {
1368
1467
  window.location = ENV.AUTH_REDIRECT
1369
1468
  }
@@ -1589,6 +1688,7 @@ class WebsyTable {
1589
1688
  this.options = Object.assign({}, DEFAULTS, options)
1590
1689
  this.rowCount = 0
1591
1690
  this.busy = false
1691
+ this.tooltipTimeoutFn = null
1592
1692
  this.data = []
1593
1693
  const el = document.getElementById(this.elementId)
1594
1694
  if (el) {
@@ -1606,6 +1706,8 @@ class WebsyTable {
1606
1706
  </div>
1607
1707
  `
1608
1708
  el.addEventListener('click', this.handleClick.bind(this))
1709
+ el.addEventListener('mouseout', this.handleMouseOut.bind(this))
1710
+ el.addEventListener('mousemove', this.handleMouseMove.bind(this))
1609
1711
  const scrollEl = document.getElementById(`${this.elementId}_tableContainer`)
1610
1712
  scrollEl.addEventListener('scroll', this.handleScroll.bind(this))
1611
1713
  this.render()
@@ -1632,7 +1734,7 @@ class WebsyTable {
1632
1734
  }
1633
1735
  else {
1634
1736
  return `
1635
- <td class='${this.options.columns[i].classes || ''}' ${this.options.columns[i].width ? 'style="width: ' + (this.options.columns[i].width || 'auto') + '"' : ''}>${c.value}</td>
1737
+ <td data-info='${c.value}' class='${this.options.columns[i].classes || ''}' ${this.options.columns[i].width ? 'style="width: ' + (this.options.columns[i].width || 'auto') + '"' : ''}>${c.value}</td>
1636
1738
  `
1637
1739
  }
1638
1740
  }
@@ -1669,7 +1771,7 @@ class WebsyTable {
1669
1771
  this.options.onSort(event, column, colIndex)
1670
1772
  }
1671
1773
  else {
1672
- this.internalSort()
1774
+ this.internalSort(column, colIndex)
1673
1775
  }
1674
1776
  // const colIndex = +event.target.getAttribute('data-index')
1675
1777
  // const dimIndex = +event.target.getAttribute('data-dim-index')
@@ -1701,13 +1803,63 @@ class WebsyTable {
1701
1803
  }
1702
1804
  }
1703
1805
  }
1806
+ handleMouseMove (event) {
1807
+ if (this.tooltipTimeoutFn) {
1808
+ event.target.classList.remove('websy-delayed-info')
1809
+ clearTimeout(this.tooltipTimeoutFn)
1810
+ }
1811
+ if (event.target.tagName === 'TD') {
1812
+ this.tooltipTimeoutFn = setTimeout(() => {
1813
+ event.target.classList.add('websy-delayed-info')
1814
+ }, 500)
1815
+ }
1816
+ }
1817
+ handleMouseOut (event) {
1818
+ if (this.tooltipTimeoutFn) {
1819
+ event.target.classList.remove('websy-delayed-info')
1820
+ clearTimeout(this.tooltipTimeoutFn)
1821
+ }
1822
+ }
1704
1823
  handleScroll (event) {
1705
1824
  if (this.options.onScroll) {
1706
1825
  this.options.onScroll(event)
1707
1826
  }
1708
1827
  }
1709
- internalSort () {
1710
-
1828
+ internalSort (column, colIndex) {
1829
+ this.options.columns.forEach((c, i) => {
1830
+ c.activeSort = i === colIndex
1831
+ })
1832
+ if (column.sortFunction) {
1833
+ this.data = column.sortFunction(this.data, column)
1834
+ }
1835
+ else {
1836
+ let sortProp = 'value'
1837
+ let sortOrder = column.sort === 'asc' ? 'desc' : 'asc'
1838
+ column.sort = sortOrder
1839
+ let sortType = column.sortType || 'alphanumeric'
1840
+ if (column.sortProp) {
1841
+ sortProp = column.sortProp
1842
+ }
1843
+ this.data.sort((a, b) => {
1844
+ switch (sortType) {
1845
+ case 'numeric':
1846
+ if (sortOrder === 'asc') {
1847
+ return a[colIndex][sortProp] - b[colIndex][sortProp]
1848
+ }
1849
+ else {
1850
+ return b[colIndex][sortProp] - a[colIndex][sortProp]
1851
+ }
1852
+ default:
1853
+ if (sortOrder === 'asc') {
1854
+ return a[colIndex][sortProp] > b[colIndex][sortProp] ? 1 : -1
1855
+ }
1856
+ else {
1857
+ return a[colIndex][sortProp] < b[colIndex][sortProp] ? 1 : -1
1858
+ }
1859
+ }
1860
+ })
1861
+ }
1862
+ this.render(this.data)
1711
1863
  }
1712
1864
  render (data) {
1713
1865
  if (!this.options.columns) {
@@ -1750,7 +1902,7 @@ class WebsyTable {
1750
1902
  const headEl = document.getElementById(`${this.elementId}_head`)
1751
1903
  headEl.innerHTML = headHTML
1752
1904
  if (data) {
1753
- this.data = this.data.concat(data)
1905
+ // this.data = this.data.concat(data)
1754
1906
  this.appendRows(data)
1755
1907
  }
1756
1908
  }
@@ -2765,6 +2917,9 @@ class WebsyMap {
2765
2917
  this.map.fitBounds(g.getBounds())
2766
2918
  this.map.invalidateSize()
2767
2919
  }
2920
+ else if (this.geo) {
2921
+ this.map.fitBounds(this.geo.getBounds())
2922
+ }
2768
2923
  else if (this.options.center) {
2769
2924
  this.map.setView(this.options.center, this.options.zoom || null)
2770
2925
  }