@websy/websy-designs 1.1.12 → 1.2.1

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.
@@ -11,6 +11,7 @@
11
11
  WebsyResultList
12
12
  WebsyTable
13
13
  WebsyTable2
14
+ WebsyIcons
14
15
  WebsyChart
15
16
  WebsyChartTooltip
16
17
  WebsyLegend
@@ -23,6 +24,8 @@
23
24
  ButtonGroup
24
25
  WebsyUtils
25
26
  WebsyCarousel
27
+ WebsyLogin
28
+ WebsySignup
26
29
  Pager
27
30
  */
28
31
 
@@ -90,7 +93,7 @@ class APIService {
90
93
  }
91
94
  xhr.withCredentials = true
92
95
  xhr.onload = () => {
93
- if (xhr.status === 401 || xhr.status === 403) {
96
+ if (xhr.status === 401) { // || xhr.status === 403) {
94
97
  if (ENV && ENV.AUTH_REDIRECT) {
95
98
  window.location = ENV.AUTH_REDIRECT
96
99
  }
@@ -206,7 +209,9 @@ class WebsyCarousel {
206
209
  currentFrame: 0,
207
210
  frameDuration: 4000,
208
211
  showFrameSelector: true,
209
- showPrevNext: true
212
+ showPrevNext: true,
213
+ autoPlay: true,
214
+ frames: []
210
215
  }
211
216
  this.playTimeoutFn = null
212
217
  this.options = Object.assign({}, DEFAULTS, options)
@@ -244,12 +249,7 @@ class WebsyCarousel {
244
249
  this.options.currentFrame++
245
250
  }
246
251
  this.showFrame(prevFrameIndex, this.options.currentFrame)
247
- this.play()
248
- // document.getElementById(`${this.elementId}_frame_${this.options.currentFrame}`)
249
- // .style.transform = `translateX(-100%)`
250
- // if (`${this.options.currentFrame === this.options.frames.length - 1}`) {
251
- // document.getElementById`${this.elementId}_frame_${this.options.currentFrame}`.style.transform = `translateX('-100%')`
252
- // }
252
+ this.play()
253
253
  }
254
254
  pause () {
255
255
  if (this.playTimeoutFn) {
@@ -257,6 +257,9 @@ class WebsyCarousel {
257
257
  }
258
258
  }
259
259
  play () {
260
+ if (this.options.autoPlay !== true) {
261
+ return
262
+ }
260
263
  this.playTimeoutFn = setTimeout(() => {
261
264
  let prevFrameIndex = this.options.currentFrame
262
265
  if (this.options.currentFrame === this.options.frames.length - 1) {
@@ -279,9 +282,7 @@ class WebsyCarousel {
279
282
  this.options.currentFrame--
280
283
  }
281
284
  this.showFrame(prevFrameIndex, this.options.currentFrame)
282
- this.play()
283
- // document.getElementById(`${this.elementId}_frame_${this.options.currentFrame}`)
284
- // .style.transform = `translateX(100%)`
285
+ this.play()
285
286
  }
286
287
 
287
288
  render (options) {
@@ -297,7 +298,7 @@ class WebsyCarousel {
297
298
  `
298
299
  this.options.frames.forEach((frame, frameIndex) => {
299
300
  html += `
300
- <div id="${this.elementId}_frame_${frameIndex}" class="websy-frame-container animate" style="transform: translateX(${frameIndex === 0 ? '0' : '100%'})">
301
+ <div id="${this.elementId}_frame_${frameIndex}" class="websy-frame-container animate" style="transform: translateX(${frameIndex === 0 ? '0' : '101%'})">
301
302
  `
302
303
  frame.images.forEach(image => {
303
304
  html += `
@@ -314,7 +315,7 @@ class WebsyCarousel {
314
315
  })
315
316
  html += `</div>`
316
317
  })
317
- if (this.options.showFrameSelector === true) {
318
+ if (this.options.showFrameSelector === true && this.options.frames.length > 1) {
318
319
  html += `<div class="websy-btn-parent">`
319
320
  this.options.frames.forEach((frame, frameIndex) => {
320
321
  html += `
@@ -326,7 +327,7 @@ class WebsyCarousel {
326
327
  })
327
328
  html += `</div>`
328
329
  }
329
- if (this.options.showPrevNext === true) {
330
+ if (this.options.showPrevNext === true && this.options.frames.length > 1) {
330
331
  html += `
331
332
  <svg xmlns="http://www.w3.org/2000/svg" class="websy-prev-arrow"
332
333
  viewBox="0 0 512 512">
@@ -350,15 +351,15 @@ class WebsyCarousel {
350
351
  }
351
352
 
352
353
  showFrame (prevFrameIndex, currFrameIndex) {
353
- let prevTranslateX = prevFrameIndex > currFrameIndex ? '100%' : '-100%'
354
- let nextTranslateX = prevFrameIndex < currFrameIndex ? '100%' : '-100%'
354
+ let prevTranslateX = prevFrameIndex > currFrameIndex ? '101%' : '-101%'
355
+ let nextTranslateX = prevFrameIndex < currFrameIndex ? '101%' : '-101%'
355
356
  if (currFrameIndex === 0 && prevFrameIndex === this.options.frames.length - 1) {
356
- prevTranslateX = '-100%'
357
- nextTranslateX = '100%'
357
+ prevTranslateX = '-101%'
358
+ nextTranslateX = '101%'
358
359
  }
359
360
  else if (prevFrameIndex === 0 && currFrameIndex === this.options.frames.length - 1) {
360
- prevTranslateX = '100%'
361
- nextTranslateX = '-100%'
361
+ prevTranslateX = '101%'
362
+ nextTranslateX = '-101%'
362
363
  }
363
364
  const prevF = document.getElementById(
364
365
  `${this.elementId}_frame_${prevFrameIndex}`)
@@ -393,6 +394,7 @@ class WebsyDatePicker {
393
394
  this.shiftPressed = false
394
395
  const DEFAULTS = {
395
396
  defaultRange: 0,
397
+ allowClear: true,
396
398
  minAllowedDate: this.floorDate(new Date(new Date((new Date().setFullYear(new Date().getFullYear() - 1))).setDate(1))),
397
399
  maxAllowedDate: this.floorDate(new Date((new Date()))),
398
400
  minAllowedYear: 1970,
@@ -487,9 +489,16 @@ class WebsyDatePicker {
487
489
  let html = `
488
490
  <div class='websy-date-picker-container'>
489
491
  <span class='websy-dropdown-header-label'>${this.options.label || 'Date'}</span>
490
- <div class='websy-date-picker-header'>
492
+ <div id="${this.elementId}_header" class='websy-date-picker-header ${this.options.allowClear === true ? 'allow-clear' : ''}'>
491
493
  <span id='${this.elementId}_selectedRange'>${this.options.ranges[this.options.mode][this.selectedRange].label}</span>
492
494
  <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>
495
+ `
496
+ if (this.options.allowClear === true) {
497
+ html += `
498
+ <svg class='clear-selection' 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>
499
+ `
500
+ }
501
+ html += `
493
502
  </div>
494
503
  <div id='${this.elementId}_mask' class='websy-date-picker-mask'></div>
495
504
  <div id='${this.elementId}_content' class='websy-date-picker-content'>
@@ -521,6 +530,10 @@ class WebsyDatePicker {
521
530
  close (confirm) {
522
531
  const maskEl = document.getElementById(`${this.elementId}_mask`)
523
532
  const contentEl = document.getElementById(`${this.elementId}_content`)
533
+ const el = document.getElementById(this.elementId)
534
+ if (el) {
535
+ el.style.zIndex = ''
536
+ }
524
537
  maskEl.classList.remove('active')
525
538
  contentEl.classList.remove('active')
526
539
  if (confirm === true) {
@@ -576,9 +589,12 @@ class WebsyDatePicker {
576
589
  else if (event.target.classList.contains('websy-dp-cancel')) {
577
590
  this.close()
578
591
  }
592
+ else if (event.target.classList.contains('clear-selection')) {
593
+ this.selectRange(0)
594
+ this.updateRange(0)
595
+ }
579
596
  }
580
- handleKeyDown (event) {
581
- console.log('key down', event)
597
+ handleKeyDown (event) {
582
598
  if (event.key === 'Shift') {
583
599
  this.dragging = true
584
600
  this.shiftPressed = true
@@ -638,13 +654,14 @@ class WebsyDatePicker {
638
654
  if (this.selectedRange === 0) {
639
655
  return
640
656
  }
641
- if (this.customRangeSelected === true) {
657
+ if (this.customRangeSelected === true) {
658
+ console.log('if date selection', this.currentselection)
642
659
  let diff
643
660
  if (this.options.mode === 'date') {
644
661
  diff = Math.floor((this.selectedRangeDates[this.selectedRangeDates.length - 1].getTime() - this.selectedRangeDates[0].getTime()) / this.oneDay)
645
- if (this.selectedRangeDates[0].getMonth() !== this.selectedRangeDates[this.selectedRangeDates.length - 1].getMonth()) {
646
- diff += 1
647
- }
662
+ // if (this.selectedRangeDates[0].getMonth() !== this.selectedRangeDates[this.selectedRangeDates.length - 1].getMonth()) {
663
+ // diff += 1
664
+ // }
648
665
  }
649
666
  else if (this.options.mode === 'year') {
650
667
  diff = this.selectedRangeDates[this.selectedRangeDates.length - 1] - this.selectedRangeDates[0]
@@ -685,7 +702,7 @@ class WebsyDatePicker {
685
702
  }
686
703
  }
687
704
  }
688
- else {
705
+ else {
689
706
  this.currentselection.forEach(d => {
690
707
  let dateEl
691
708
  if (this.options.mode === 'date') {
@@ -703,6 +720,10 @@ class WebsyDatePicker {
703
720
  open (options, override = false) {
704
721
  const maskEl = document.getElementById(`${this.elementId}_mask`)
705
722
  const contentEl = document.getElementById(`${this.elementId}_content`)
723
+ const el = document.getElementById(this.elementId)
724
+ if (el) {
725
+ el.style.zIndex = 999
726
+ }
706
727
  maskEl.classList.add('active')
707
728
  contentEl.classList.add('active')
708
729
  this.priorSelectedDates = [...this.selectedRangeDates]
@@ -921,6 +942,15 @@ class WebsyDatePicker {
921
942
  this.selectedRangeDates = [...this.options.ranges[this.options.mode][index].range]
922
943
  this.currentselection = [...this.options.ranges[this.options.mode][index].range]
923
944
  this.selectedRange = +index
945
+ const el = document.getElementById(`${this.elementId}_header`)
946
+ if (el) {
947
+ if (this.selectedRange === 0) {
948
+ el.classList.remove('range-selected')
949
+ }
950
+ else {
951
+ el.classList.add('range-selected')
952
+ }
953
+ }
924
954
  this.highlightRange()
925
955
  this.close(true)
926
956
  }
@@ -1112,6 +1142,10 @@ class WebsyDropdown {
1112
1142
  const maskEl = document.getElementById(`${this.elementId}_mask`)
1113
1143
  const contentEl = document.getElementById(`${this.elementId}_content`)
1114
1144
  const scrollEl = document.getElementById(`${this.elementId}_itemsContainer`)
1145
+ const el = document.getElementById(this.elementId)
1146
+ if (el) {
1147
+ el.style.zIndex = ''
1148
+ }
1115
1149
  scrollEl.scrollTop = 0
1116
1150
  maskEl.classList.remove('active')
1117
1151
  contentEl.classList.remove('active')
@@ -1227,6 +1261,10 @@ class WebsyDropdown {
1227
1261
  open (options, override = false) {
1228
1262
  const maskEl = document.getElementById(`${this.elementId}_mask`)
1229
1263
  const contentEl = document.getElementById(`${this.elementId}_content`)
1264
+ const el = document.getElementById(this.elementId)
1265
+ if (el) {
1266
+ el.style.zIndex = 999
1267
+ }
1230
1268
  maskEl.classList.add('active')
1231
1269
  contentEl.classList.add('active')
1232
1270
  if (WebsyUtils.getElementPos(contentEl).bottom > window.innerHeight) {
@@ -1389,8 +1427,10 @@ class WebsyForm {
1389
1427
  constructor (elementId, options) {
1390
1428
  const defaults = {
1391
1429
  submit: { text: 'Save', classes: '' },
1430
+ useRecaptcha: false,
1392
1431
  clearAfterSave: false,
1393
1432
  fields: [],
1433
+ mode: 'add',
1394
1434
  onSuccess: function (data) {},
1395
1435
  onError: function (err) { console.log('Error submitting form data:', err) }
1396
1436
  }
@@ -1426,19 +1466,25 @@ class WebsyForm {
1426
1466
  checkRecaptcha () {
1427
1467
  return new Promise((resolve, reject) => {
1428
1468
  if (this.options.useRecaptcha === true) {
1429
- if (this.recaptchaValue) {
1430
- this.apiService.add('/google/checkrecaptcha', JSON.stringify({grecaptcharesponse: this.recaptchaValue})).then(response => {
1431
- if (response.success && response.success === true) {
1432
- resolve(true)
1433
- }
1434
- else {
1435
- reject(false)
1436
- }
1469
+ // if (this.recaptchaValue) {
1470
+ grecaptcha.ready(() => {
1471
+ grecaptcha.execute(ENVIRONMENT.RECAPTCHA_KEY, { action: 'submit' }).then(token => {
1472
+ this.apiService.add('google/checkrecaptcha', {grecaptcharesponse: token}).then(response => {
1473
+ if (response.success && response.success === true) {
1474
+ resolve(true)
1475
+ }
1476
+ else {
1477
+ reject(false)
1478
+ }
1479
+ })
1480
+ }, err => {
1481
+ reject(err)
1437
1482
  })
1438
- }
1439
- else {
1440
- reject(false)
1441
- }
1483
+ })
1484
+ // }
1485
+ // else {
1486
+ // reject(false)
1487
+ // }
1442
1488
  }
1443
1489
  else {
1444
1490
  resolve(true)
@@ -1519,7 +1565,7 @@ class WebsyForm {
1519
1565
  let componentsToProcess = []
1520
1566
  if (el) {
1521
1567
  let html = `
1522
- <form id="${this.elementId}Form" class="${this.options.classes || ''}">
1568
+ <form id="${this.elementId}Form" class="websy-form ${this.options.classes || ''}">
1523
1569
  `
1524
1570
  this.options.fields.forEach((f, i) => {
1525
1571
  if (f.component) {
@@ -1540,6 +1586,7 @@ class WebsyForm {
1540
1586
  ${f.required === true ? 'required' : ''}
1541
1587
  placeholder="${f.placeholder || ''}"
1542
1588
  name="${f.field}"
1589
+ ${(f.attributes || []).join(' ')}
1543
1590
  class="websy-input websy-textarea"
1544
1591
  ></textarea>
1545
1592
  </div><!--
@@ -1554,6 +1601,7 @@ class WebsyForm {
1554
1601
  ${f.required === true ? 'required' : ''}
1555
1602
  type="${f.type || 'text'}"
1556
1603
  class="websy-input"
1604
+ ${(f.attributes || []).join(' ')}
1557
1605
  name="${f.field}"
1558
1606
  placeholder="${f.placeholder || ''}"
1559
1607
  value="${f.value || ''}"
@@ -1584,7 +1632,7 @@ class WebsyForm {
1584
1632
  el.innerHTML = html
1585
1633
  this.processComponents(componentsToProcess, () => {
1586
1634
  if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
1587
- this.recaptchaReady()
1635
+ // this.recaptchaReady()
1588
1636
  }
1589
1637
  })
1590
1638
  }
@@ -1601,7 +1649,14 @@ class WebsyForm {
1601
1649
  data[key] = value
1602
1650
  })
1603
1651
  if (this.options.url) {
1604
- this.apiService.add(this.options.url, data).then(result => {
1652
+ let params = [
1653
+ this.options.url
1654
+ ]
1655
+ if (this.options.mode === 'update') {
1656
+ params.push(this.options.id)
1657
+ }
1658
+ params.push(data)
1659
+ this.apiService[this.options.mode](...params).then(result => {
1605
1660
  if (this.options.clearAfterSave === true) {
1606
1661
  // this.render()
1607
1662
  formEl.reset()
@@ -1632,6 +1687,46 @@ class WebsyForm {
1632
1687
  }
1633
1688
  }
1634
1689
 
1690
+ /* global include */
1691
+ const WebsyIcons = {
1692
+ 'search-icon': `
1693
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
1694
+ viewBox="0 0 500 500" xml:space="preserve">
1695
+ <path d="M481.4,468.6c-17.2-17.2-34.4-34.4-51.6-51.6c-27.4-27.4-54.8-54.8-82.2-82.2c-4.8-4.8-9.5-9.5-14.3-14.3
1696
+ c29.4-32.5,47.4-75.5,47.4-122.7C380.7,97,298.7,15,197.9,15S15,97,15,197.9s82,182.9,182.9,182.9c47.2,0,90.3-18,122.7-47.4
1697
+ c15.7,15.7,31.4,31.4,47.1,47.1c27.4,27.4,54.8,54.8,82.2,82.2c6.3,6.3,12.5,12.5,18.8,18.8C476.8,489.6,489.6,476.8,481.4,468.6z
1698
+ M35,197.9C35,108.1,108.1,35,197.9,35s162.9,73.1,162.9,162.9s-73.1,162.9-162.9,162.9S35,287.7,35,197.9z"/>
1699
+ </svg>
1700
+
1701
+ `,
1702
+ 'bag-icon': `
1703
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
1704
+ viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
1705
+ <path d="M456.6,472.3H43.4c-5.3,0-10.2-2.1-13.7-6c-3.6-3.9-5.2-9.2-4.5-14.4l37-285.4c1.2-9,9-15.9,18.2-15.9h339.2
1706
+ c9.2,0,17,6.8,18.2,15.8l37,285.4c0.7,5.2-1,10.5-4.5,14.4l0,0C466.8,470.1,461.9,472.3,456.6,472.3z M46.5,451.2h407l-36.3-279.6
1707
+ H82.8L46.5,451.2z"/>
1708
+ <g>
1709
+ <path d="M361.3,157.1C357.3,94.8,308.4,46,249.9,46c-28,0-54.8,11.1-75.4,31.4c-20.7,20.3-33.5,47.9-35.9,77.8l-21.5-1.6
1710
+ c2.8-34.8,17.7-67.1,42.1-91C183.9,38.3,216.1,25,249.9,25c34.2,0,66.6,13.6,91.5,38.3c24.5,24.3,39.2,57.2,41.5,92.5L361.3,157.1z
1711
+ "/>
1712
+ </g>
1713
+ </svg>
1714
+
1715
+ `,
1716
+ 'user-icon': `
1717
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
1718
+ viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
1719
+ <g>
1720
+ <path d="M248,260.5c-62,0-112.5-52.8-112.5-117.7S186,25,248,25s112.5,52.8,112.5,117.7S310,260.5,248,260.5z M248,45.9
1721
+ c-51,0-92.5,43.4-92.5,96.8s41.5,96.8,92.5,96.8c51,0,92.5-43.4,92.5-96.8S299,45.9,248,45.9z"/>
1722
+ </g>
1723
+ <path d="M45,475C45,475,45,475,45,475c0-118.3,92-214.5,205-214.5c113,0,205,96.2,205,214.5c0,0,0,0,0,0h20c0,0,0,0,0,0
1724
+ c0-62.9-23.4-122-65.9-166.5c-42.5-44.5-99-69-159.1-69s-116.6,24.5-159.1,69C48.4,353,25,412.1,25,475c0,0,0,0,0,0H45z"/>
1725
+ </svg>
1726
+
1727
+ `
1728
+ }
1729
+
1635
1730
  class WebsyLoadingDialog {
1636
1731
  constructor (elementId, options) {
1637
1732
  this.options = Object.assign({}, options)
@@ -1684,6 +1779,54 @@ class WebsyLoadingDialog {
1684
1779
  }
1685
1780
  }
1686
1781
 
1782
+ /* global WebsyDesigns ENVIRONMENT */
1783
+ class WebsyLogin {
1784
+ constructor (elementId, options) {
1785
+ const DEFAULTS = {
1786
+ loginType: 'email',
1787
+ classes: [],
1788
+ url: 'auth/login'
1789
+ }
1790
+ this.elementId = elementId
1791
+ this.options = Object.assign({}, DEFAULTS, options)
1792
+ const el = document.getElementById(this.elementId)
1793
+ if (el) {
1794
+ const formOptions = {
1795
+ useRecaptcha: this.options.useRecaptcha || ENVIRONMENT.useRecaptcha || false,
1796
+ submit: {
1797
+ text: this.options.buttonText || 'Log in',
1798
+ classes: (this.options.buttonClasses || []).join(' ') || ''
1799
+ },
1800
+ submitFn: this.submitForm.bind(this),
1801
+ fields: [
1802
+ {
1803
+ label: this.options.loginType === 'email' ? 'Email' : 'Username',
1804
+ placeholder: `Enter your ${this.options.loginType === 'email' ? 'email address' : 'Username'}`,
1805
+ field: this.options.loginType,
1806
+ type: this.options.loginType,
1807
+ required: true
1808
+ },
1809
+ {
1810
+ label: 'Password',
1811
+ placeholder: 'Enter your password',
1812
+ field: this.options.passwordField || 'password',
1813
+ type: 'password',
1814
+ required: true
1815
+ }
1816
+ ]
1817
+ }
1818
+ this.loginForm = new WebsyDesigns.WebsyForm(this.elementId, Object.assign({}, this.options, formOptions))
1819
+ }
1820
+ else {
1821
+ console.error(`No element with ID ${this.elementId} found for WebsyLogin component.`)
1822
+ }
1823
+ }
1824
+ submitForm (data, b, c) {
1825
+ console.log(data)
1826
+ console.log(b, c)
1827
+ }
1828
+ }
1829
+
1687
1830
  /* global */
1688
1831
  class WebsyNavigationMenu {
1689
1832
  constructor (elementId, options) {
@@ -1810,7 +1953,7 @@ class WebsyNavigationMenu {
1810
1953
  items[i].classes = items[i].classes.join(' ')
1811
1954
  }
1812
1955
  html += `
1813
- <li class='websy-${this.options.orientation}-list-item'>
1956
+ <li class='websy-${this.options.orientation}-list-item ${items[i].alwaysOpen === true ? 'always-open' : ''}'>
1814
1957
  <div class='websy-menu-header ${items[i].classes || ''} ${selected} ${active}'
1815
1958
  id='${blockId}'
1816
1959
  data-id='${currentBlock}'
@@ -2129,7 +2272,9 @@ class WebsyPDFButton {
2129
2272
  class WebsyPopupDialog {
2130
2273
  constructor (elementId, options) {
2131
2274
  this.DEFAULTS = {
2132
- buttons: []
2275
+ buttons: [],
2276
+ classes: [],
2277
+ style: ''
2133
2278
  }
2134
2279
  this.options = Object.assign({}, this.DEFAULTS, options)
2135
2280
  if (!elementId) {
@@ -2181,7 +2326,7 @@ class WebsyPopupDialog {
2181
2326
  }
2182
2327
  html += `
2183
2328
  <div class='websy-popup-dialog-container'>
2184
- <div class='websy-popup-dialog'>
2329
+ <div class='websy-popup-dialog ${this.options.classes.join(' ')}' style='${this.options.style}'>
2185
2330
  `
2186
2331
  if (this.options.title) {
2187
2332
  html += `<h1>${this.options.title}</h1>`
@@ -2496,8 +2641,7 @@ class WebsyRouter {
2496
2641
  addGroup (group) {
2497
2642
  if (!this.groups[group]) {
2498
2643
  const els = document.querySelectorAll(`.websy-view[data-group="${group}"]`)
2499
- if (els) {
2500
- console.log('els', els)
2644
+ if (els) {
2501
2645
  this.getClosestParent(els[0], parent => {
2502
2646
  this.groups[group] = {
2503
2647
  activeView: '',
@@ -2902,8 +3046,10 @@ class WebsyRouter {
2902
3046
  if (popped === false) {
2903
3047
  let historyUrl = inputPath
2904
3048
  if (this.options.urlPrefix) {
2905
- historyUrl = `/${this.options.urlPrefix}/${historyUrl}`
2906
- inputPath = `/${this.options.urlPrefix}/${inputPath}`
3049
+ historyUrl = historyUrl === '/' ? '' : `/${historyUrl}`
3050
+ inputPath = inputPath === '/' ? '' : `/${inputPath}`
3051
+ historyUrl = (`/${this.options.urlPrefix}${historyUrl}`).replace(/\/\//g, '/')
3052
+ inputPath = (`/${this.options.urlPrefix}${inputPath}`).replace(/\/\//g, '/')
2907
3053
  }
2908
3054
  if (this.currentParams && this.currentParams.path) {
2909
3055
  historyUrl += `?${this.currentParams.path}`
@@ -2998,6 +3144,57 @@ class WebsyRouter {
2998
3144
  }
2999
3145
  }
3000
3146
 
3147
+ /* global WebsyDesigns ENVIRONMENT */
3148
+ class WebsySignup {
3149
+ constructor (elementId, options) {
3150
+ const DEFAULTS = {
3151
+ loginType: 'email',
3152
+ classes: [],
3153
+ url: 'auth/signup'
3154
+ }
3155
+ this.elementId = elementId
3156
+ this.options = Object.assign({}, DEFAULTS, options)
3157
+ if (!this.options.fields) {
3158
+ this.options.fields = [
3159
+ {
3160
+ label: this.options.loginType === 'email' ? 'Email' : 'Username',
3161
+ placeholder: `Enter ${this.options.loginType === 'email' ? 'your email address' : 'your chosen Username'}`,
3162
+ field: this.options.loginType,
3163
+ type: this.options.loginType,
3164
+ required: true
3165
+ },
3166
+ {
3167
+ label: 'Password',
3168
+ placeholder: 'Enter your password',
3169
+ field: this.options.passwordField || 'password',
3170
+ type: 'password',
3171
+ required: true
3172
+ }
3173
+ ]
3174
+ }
3175
+ const el = document.getElementById(this.elementId)
3176
+ if (el) {
3177
+ const formOptions = {
3178
+ useRecaptcha: this.options.useRecaptcha || ENVIRONMENT.useRecaptcha || false,
3179
+ submit: {
3180
+ text: this.options.buttonText || 'Sign up',
3181
+ classes: (this.options.buttonClasses || []).join(' ') || ''
3182
+ },
3183
+ submitFn: this.submitForm.bind(this),
3184
+ fields: this.options.fields
3185
+ }
3186
+ this.signupForm = new WebsyDesigns.WebsyForm(this.elementId, Object.assign({}, this.options, formOptions))
3187
+ }
3188
+ else {
3189
+ console.error(`No element with ID ${this.elementId} found for WebsyLogin component.`)
3190
+ }
3191
+ }
3192
+ submitForm (data, b, c) {
3193
+ console.log(data)
3194
+ console.log(b, c)
3195
+ }
3196
+ }
3197
+
3001
3198
  /* global */
3002
3199
  class Switch {
3003
3200
  constructor (elementId, options) {
@@ -3241,6 +3438,21 @@ const WebsyUtils = {
3241
3438
  }
3242
3439
  return (red * 0.299 + green * 0.587 + blue * 0.114) > 186 ? darkColor : lightColor
3243
3440
  },
3441
+ measureText (text, rotation = 0, fontSize = '12px') {
3442
+ if (!isNaN(fontSize)) {
3443
+ fontSize = `${fontSize}px`
3444
+ }
3445
+ let html = `<div style='display: inline-block; width: auto; font-size: ${fontSize}'>${text}</div>`
3446
+ const el = document.createElement('div')
3447
+ el.style.position = 'absolute'
3448
+ el.style.visibility = 'hidden'
3449
+ el.style.transform = `rotate(${rotation}deg)`
3450
+ el.innerHTML = html
3451
+ document.body.appendChild(el)
3452
+ let w = el.getBoundingClientRect()
3453
+ el.remove()
3454
+ return w
3455
+ },
3244
3456
  parseUrlParams: () => {
3245
3457
  let queryString = window.location.search.replace('?', '')
3246
3458
  const params = {}
@@ -3481,7 +3693,7 @@ class WebsyTable {
3481
3693
  data-view='${c.value}'
3482
3694
  data-row-index='${this.rowCount + rowIndex}'
3483
3695
  data-col-index='${i}'
3484
- class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
3696
+ class='websy-trigger trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
3485
3697
  style='${style}'
3486
3698
  colspan='${c.colspan || 1}'
3487
3699
  rowspan='${c.rowspan || 1}'
@@ -3565,19 +3777,26 @@ class WebsyTable {
3565
3777
  event.target.classList.remove('active')
3566
3778
  })
3567
3779
  }
3568
- else if (event.target.classList.contains('clickable')) {
3569
- const colIndex = +event.target.getAttribute('data-col-index')
3570
- const rowIndex = +event.target.getAttribute('data-row-index')
3571
- if (this.options.onClick) {
3572
- this.options.onClick(event, this.data[rowIndex][colIndex], this.data[rowIndex], this.options.columns[colIndex])
3573
- }
3574
- }
3780
+ // else if (event.target.classList.contains('clickable')) {
3781
+ // const colIndex = +event.target.getAttribute('data-col-index')
3782
+ // const rowIndex = +event.target.getAttribute('data-row-index')
3783
+ // if (this.options.onClick) {
3784
+ // this.options.onClick(event, this.data[rowIndex][colIndex], this.data[rowIndex], this.options.columns[colIndex])
3785
+ // }
3786
+ // }
3575
3787
  else if (event.target.classList.contains('websy-page-num')) {
3576
3788
  const pageNum = +event.target.getAttribute('data-page')
3577
3789
  if (this.options.onSetPage) {
3578
3790
  this.options.onSetPage(pageNum)
3579
3791
  }
3580
3792
  }
3793
+ else {
3794
+ const colIndex = +event.target.getAttribute('data-col-index')
3795
+ const rowIndex = +event.target.getAttribute('data-row-index')
3796
+ if (this.options.onClick) {
3797
+ this.options.onClick(event, { cell: this.data[rowIndex][colIndex], row: this.data[rowIndex], column: this.options.columns[colIndex], colIndex, rowIndex })
3798
+ }
3799
+ }
3581
3800
  }
3582
3801
  handleMouseMove (event) {
3583
3802
  if (this.tooltipTimeoutFn) {
@@ -3878,7 +4097,7 @@ class WebsyTable2 {
3878
4097
  data-view='${c.value}'
3879
4098
  data-row-index='${this.rowCount + rowIndex}'
3880
4099
  data-col-index='${i}'
3881
- class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
4100
+ class='websy-trigger trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
3882
4101
  style='${style}'
3883
4102
  colspan='${c.colspan || 1}'
3884
4103
  rowspan='${c.rowspan || 1}'
@@ -3986,6 +4205,18 @@ class WebsyTable2 {
3986
4205
  this.options.onSetPage(pageNum)
3987
4206
  }
3988
4207
  }
4208
+ else if (event.target.classList.contains('websy-h-scroll-container')) {
4209
+ console.log('scroll handle clicked', event)
4210
+ let clickX = event.clientX
4211
+ let elX = event.target.getBoundingClientRect().left
4212
+ const handleEl = document.getElementById(`${this.elementId}_hScrollHandle`)
4213
+ let startPoint = clickX - elX - (handleEl.clientWidth / 2)
4214
+ startPoint = Math.max(0, Math.min(startPoint, event.target.clientWidth - handleEl.clientWidth))
4215
+ handleEl.style.left = `${startPoint}px`
4216
+ if (this.options.onScrollX) {
4217
+ this.options.onScrollX(startPoint)
4218
+ }
4219
+ }
3989
4220
  }
3990
4221
  handleMouseDown (event) {
3991
4222
  if (event.target.classList.contains('websy-scroll-handle')) {
@@ -4127,8 +4358,15 @@ class WebsyTable2 {
4127
4358
  // let colGroupHTML = this.options.columns.map(c => `<col style="${c.width ? 'width: ' + c.width : ''}"></col>`)
4128
4359
  let headHTML = '<tr>' + this.options.columns.map((c, i) => {
4129
4360
  if (c.show !== false) {
4361
+ let style = ''
4362
+ if (c.style) {
4363
+ style += c.style
4364
+ }
4365
+ if (c.width) {
4366
+ style += `width: ${c.width || 'auto'}; `
4367
+ }
4130
4368
  return `
4131
- <th ${c.width ? 'style="width: ' + (c.width || 'auto') + ';"' : ''}>
4369
+ <th style="${style}">
4132
4370
  <div class ="tableHeader">
4133
4371
  <div class="leftSection">
4134
4372
  <div
@@ -4245,7 +4483,7 @@ class WebsyTable2 {
4245
4483
  const bodyEl = document.getElementById(`${this.elementId}_body`)
4246
4484
  bodyEl.innerHTML = '<tr>' + values.map(c => `
4247
4485
  <td
4248
- style='height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px;'
4486
+ style='height: ${this.options.cellSize}px; line-height: ${this.options.cellSize}px; padding: 10px 5px;'
4249
4487
  >${c.value || '&nbsp;'}</td>
4250
4488
  `).join('') + '</tr>'
4251
4489
  // get height of the first data cell
@@ -4253,12 +4491,20 @@ class WebsyTable2 {
4253
4491
  const tableContainerEl = document.getElementById(`${this.elementId}_tableContainer`)
4254
4492
  const cellHeight = cells[0].offsetHeight || cells[0].clientHeight
4255
4493
  const cellWidths = []
4494
+ let accWidth = 0
4256
4495
  let nonScrollableWidth = 0
4257
4496
  for (let i = 0; i < cells.length; i++) {
4258
4497
  if (i < this.options.leftColumns) {
4259
4498
  nonScrollableWidth += values[i].width || cells[i].offsetWidth || cells[i].clientWidth
4260
4499
  }
4261
4500
  cellWidths.push(values[i].width || cells[i].offsetWidth || cells[i].clientWidth)
4501
+ accWidth += values[i].width || cells[i].offsetWidth || cells[i].clientWidth
4502
+ }
4503
+ // if the table doesn't fill the available space we adjust the space so that the columns grow
4504
+ if (accWidth < (tableContainerEl.offsetWidth || tableContainerEl.clientWidth) - nonScrollableWidth) {
4505
+ for (let i = this.options.leftColumns; i < cellWidths.length; i++) {
4506
+ cellWidths[i] = ((tableContainerEl.offsetWidth || tableContainerEl.clientWidth) - nonScrollableWidth) / (cellWidths.length - this.options.leftColumns)
4507
+ }
4262
4508
  }
4263
4509
  // const cellWidth = firstDataCell.offsetWidth || firstDataCell.clientWidth
4264
4510
  // tableEl.style.width = ''
@@ -4295,6 +4541,7 @@ class WebsyChart {
4295
4541
  legendRight: 0,
4296
4542
  legendTop: 0
4297
4543
  },
4544
+ axis: {},
4298
4545
  orientation: 'vertical',
4299
4546
  colors: ['#5e4fa2', '#3288bd', '#66c2a5', '#abdda4', '#e6f598', '#fee08b', '#fdae61', '#f46d43', '#d53e4f', '#9e0142'],
4300
4547
  transitionDuration: 650,
@@ -4619,7 +4866,7 @@ this.render()
4619
4866
 
4620
4867
  }
4621
4868
  render (options) {
4622
- /* global d3 options */
4869
+ /* global d3 options WebsyUtils */
4623
4870
  if (typeof options !== 'undefined') {
4624
4871
  this.options = Object.assign({}, this.options, options)
4625
4872
  }
@@ -4718,9 +4965,9 @@ else {
4718
4965
  this.options.data.bottom.min = this.options.data.bottom.data[0].value
4719
4966
  }
4720
4967
  if (this.options.data.bottom && typeof this.options.data.bottom.max !== 'undefined') {
4721
- this.longestBottom = this.options.data.bottom.max.toString().length
4968
+ this.longestBottom = this.options.data.bottom.max.toString()
4722
4969
  if (this.options.data.bottom.formatter) {
4723
- this.longestBottom = this.options.data.bottom.formatter(this.options.data.bottom.max).toString().length
4970
+ this.longestBottom = this.options.data.bottom.formatter(this.options.data.bottom.max).toString()
4724
4971
  }
4725
4972
  }
4726
4973
  if (this.options.data.left && this.options.data.left.data && this.options.data.left.max === 'undefined') {
@@ -4734,9 +4981,9 @@ else {
4734
4981
  this.options.data.left.min = this.options.data.left.data.reduce((a, b) => a.length < b.value.length ? a : b.value, this.options.data.left.max)
4735
4982
  }
4736
4983
  if (this.options.data.left && typeof this.options.data.left.max !== 'undefined') {
4737
- this.longestLeft = this.options.data.left.max.toString().length
4984
+ this.longestLeft = this.options.data.left.max.toString()
4738
4985
  if (this.options.data.left.formatter) {
4739
- this.longestLeft = this.options.data.left.formatter(this.options.data.left.max).toString().length
4986
+ this.longestLeft = this.options.data.left.formatter(this.options.data.left.max).toString()
4740
4987
  }
4741
4988
  }
4742
4989
  if (this.options.data.right && this.options.data.right.data && this.options.data.right.max === 'undefined') {
@@ -4744,15 +4991,21 @@ else {
4744
4991
  this.options.data.right.max = d3.max(this.options.data.right.data)
4745
4992
  }
4746
4993
  if (this.options.data.right && typeof this.options.data.right.max !== 'undefined') {
4747
- this.longestRight = this.options.data.right.max.toString().length
4994
+ this.longestRight = this.options.data.right.max.toString()
4748
4995
  if (this.options.data.right.formatter) {
4749
- this.longestRight = this.options.data.right.formatter(this.options.data.right.max).toString().length
4996
+ this.longestRight = this.options.data.right.formatter(this.options.data.right.max).toString()
4750
4997
  }
4751
4998
  }
4752
4999
  // establish the space needed for the various axes
4753
- this.options.margin.axisLeft = this.longestLeft * ((this.options.data.left && this.options.data.left.fontSize) || this.options.fontSize) * 0.7
4754
- this.options.margin.axisRight = this.longestRight * ((this.options.data.right && this.options.data.right.fontSize) || this.options.fontSize) * 0.7
4755
- this.options.margin.axisBottom = ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize) + 10
5000
+ // this.options.margin.axisLeft = this.longestLeft * ((this.options.data.left && this.options.data.left.fontSize) || this.options.fontSize) * 0.7
5001
+ // this.options.margin.axisRight = this.longestRight * ((this.options.data.right && this.options.data.right.fontSize) || this.options.fontSize) * 0.7
5002
+ // this.options.margin.axisBottom = ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize) + 10
5003
+ let longestLeftBounds = WebsyUtils.measureText(this.longestLeft, 0, ((this.options.data.left && this.options.data.left.fontSize) || this.options.fontSize))
5004
+ let longestRightBounds = WebsyUtils.measureText(this.longestRight, 0, ((this.options.data.right && this.options.data.right.fontSize) || this.options.fontSize))
5005
+ let longestBottomBounds = WebsyUtils.measureText(this.longestBottom, ((this.options.data.bottom && this.options.data.bottom.rotate) || 0), ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize))
5006
+ this.options.margin.axisLeft = longestLeftBounds.width
5007
+ this.options.margin.axisRight = longestRightBounds.width
5008
+ this.options.margin.axisBottom = longestBottomBounds.height + 10
4756
5009
  this.options.margin.axisTop = 0
4757
5010
  // adjust axis margins based on title options
4758
5011
  if (this.options.data.left && this.options.data.left.showTitle === true) {
@@ -4771,11 +5024,20 @@ else {
4771
5024
  this.options.margin.axisTop += (this.options.data.right.titleFontSize || 10) + 10
4772
5025
  }
4773
5026
  }
4774
- if (this.options.data.bottom.rotate) {
4775
- // this.options.margin.bottom = this.longestBottom * ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize)
4776
- this.options.margin.axisBottom = this.longestBottom * ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize) * 0.4
4777
- // this.options.margin.bottom = this.options.margin.bottom * (1 + this.options.data.bottom.rotate / 100)
4778
- }
5027
+ if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) === 0 && this.options.axis.hideBottom !== true) {
5028
+ this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width / 2)
5029
+ }
5030
+ else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) < 0 && this.options.axis.hideBottom !== true) {
5031
+ this.options.margin.axisLeft = Math.max(this.options.margin.axisLeft, longestBottomBounds.width)
5032
+ }
5033
+ else if (((this.options.data.bottom && this.options.data.bottom.rotate) || 0) > 0 && this.options.axis.hideBottom !== true) {
5034
+ this.options.margin.axisRight = Math.max(this.options.margin.axisRight, longestBottomBounds.width)
5035
+ }
5036
+ // if (this.options.data.bottom.rotate) {
5037
+ // // this.options.margin.bottom = this.longestBottom * ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize)
5038
+ // this.options.margin.axisBottom = this.longestBottom * ((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize) * 0.4
5039
+ // // this.options.margin.bottom = this.options.margin.bottom * (1 + this.options.data.bottom.rotate / 100)
5040
+ // }
4779
5041
  // hide the margin if necessary
4780
5042
  if (this.options.axis) {
4781
5043
  if (this.options.axis.hideAll === true) {
@@ -4910,17 +5172,18 @@ else {
4910
5172
  let bAxisFunc = d3.axisBottom(this.bottomAxis)
4911
5173
  // .ticks(this.options.data.bottom.ticks || Math.min(this.options.data.bottom.data.length, 5))
4912
5174
  .ticks(tickDefinition)
4913
- console.log('tickDefinition', tickDefinition)
4914
- console.log(bAxisFunc)
5175
+ // console.log('tickDefinition', tickDefinition)
5176
+ // console.log(bAxisFunc)
4915
5177
  if (this.options.data.bottom.formatter) {
4916
5178
  bAxisFunc.tickFormat(d => this.options.data.bottom.formatter(d))
4917
5179
  }
4918
5180
  this.bottomAxisLayer.call(bAxisFunc)
4919
- console.log(this.bottomAxisLayer.ticks)
5181
+ // console.log(this.bottomAxisLayer.ticks)
4920
5182
  if (this.options.data.bottom.rotate) {
4921
5183
  this.bottomAxisLayer.selectAll('text')
4922
- .attr('transform', `rotate(${this.options.data.bottom.rotate})`)
4923
- .style('text-anchor', 'end')
5184
+ .attr('transform', `rotate(${((this.options.data.bottom && this.options.data.bottom.rotate) || 0)})`)
5185
+ .style('text-anchor', `${((this.options.data.bottom && this.options.data.bottom.rotate) || 0) === 0 ? 'middle' : 'end'}`)
5186
+ .style('transform-origin', ((this.options.data.bottom && this.options.data.bottom.rotate) || 0) === 0 ? '0 0' : `0 ${((this.options.data.bottom && this.options.data.bottom.fontSize) || this.options.fontSize)}px`)
4924
5187
  }
4925
5188
  }
4926
5189
  // Configure the left axis
@@ -5962,7 +6225,14 @@ const WebsyDesigns = {
5962
6225
  ButtonGroup,
5963
6226
  WebsySwitch: Switch,
5964
6227
  Pager,
5965
- Switch
6228
+ Switch,
6229
+ Carousel: WebsyCarousel,
6230
+ WebsyIcons,
6231
+ Icons: WebsyIcons,
6232
+ WebsyLogin,
6233
+ Login: WebsyLogin,
6234
+ WebsySignup,
6235
+ Signup: WebsySignup
5966
6236
  }
5967
6237
 
5968
6238
  WebsyDesigns.service = new WebsyDesigns.APIService('')
@@ -5970,14 +6240,15 @@ WebsyDesigns.service = new WebsyDesigns.APIService('')
5970
6240
  const GlobalPubSub = new WebsyPubSub('empty', {})
5971
6241
 
5972
6242
  function recaptchaReadyCallBack () {
6243
+ console.log('recaptchaready')
5973
6244
  GlobalPubSub.publish('recaptchaready')
5974
6245
  }
5975
6246
 
5976
6247
  // need a way of initializing these based on environment variables
5977
- function useGoogleRecaptcha () {
6248
+ function useGoogleRecaptcha (key) {
5978
6249
  const rcs = document.createElement('script')
5979
- rcs.src = '//www.google.com/recaptcha/api.js?onload=recaptchaReadyCallBack'
5980
- document.getElementsByTagName('body')[0].appendChild(rcs)
6250
+ rcs.src = `//www.google.com/recaptcha/api.js?render=${key}`
6251
+ document.body.appendChild(rcs)
5981
6252
  }
5982
6253
 
5983
6254
  function usePayPal () {