@websy/websy-designs 0.0.114 → 0.0.118

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.
@@ -15,7 +15,9 @@
15
15
  WebsyMap
16
16
  WebsyKPI
17
17
  WebsyPDFButton
18
+ WebsyTemplate
18
19
  APIService
20
+ WebsyUtils
19
21
  */
20
22
 
21
23
  class WebsyPopupDialog {
@@ -325,6 +327,13 @@ class WebsyForm {
325
327
  this.render()
326
328
  }
327
329
  }
330
+ cancelForm () {
331
+ const formEl = document.getElementById(`${this.elementId}Form`)
332
+ formEl.reset()
333
+ if (this.options.cancelFn) {
334
+ this.options.cancelFn(this.elementId)
335
+ }
336
+ }
328
337
  checkRecaptcha () {
329
338
  return new Promise((resolve, reject) => {
330
339
  if (this.options.useRecaptcha === true) {
@@ -375,9 +384,13 @@ class WebsyForm {
375
384
  }
376
385
  }
377
386
  handleClick (event) {
387
+ event.preventDefault()
378
388
  if (event.target.classList.contains('submit')) {
379
389
  this.submitForm()
380
390
  }
391
+ else if (event.target.classList.contains('cancel')) {
392
+ this.cancelForm()
393
+ }
381
394
  }
382
395
  handleKeyDown (event) {
383
396
  if (event.key === 'enter') {
@@ -418,42 +431,56 @@ class WebsyForm {
418
431
  let html = `
419
432
  <form id="${this.elementId}Form">
420
433
  `
421
- this.options.fields.forEach(f => {
434
+ this.options.fields.forEach((f, i) => {
422
435
  if (f.component) {
423
436
  componentsToProcess.push(f)
424
437
  html += `
425
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
426
- <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
438
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
439
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
440
+ <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
441
+ </div><!--
427
442
  `
428
443
  }
429
444
  else if (f.type === 'longtext') {
430
445
  html += `
431
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
432
- <textarea
433
- id="${this.elementId}_input_${f.field}"
434
- ${f.required === true ? 'required' : ''}
435
- placeholder="${f.placeholder || ''}"
436
- name="${f.field}"
437
- class="websy-input websy-textarea ${f.classes}"
438
- ></textarea>
446
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
447
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
448
+ <textarea
449
+ id="${this.elementId}_input_${f.field}"
450
+ ${f.required === true ? 'required' : ''}
451
+ placeholder="${f.placeholder || ''}"
452
+ name="${f.field}"
453
+ class="websy-input websy-textarea"
454
+ ></textarea>
455
+ </div><!--
439
456
  `
440
457
  }
441
458
  else {
442
459
  html += `
443
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
444
- <input
445
- id="${this.elementId}_input_${f.field}"
446
- ${f.required === true ? 'required' : ''}
447
- type="${f.type || 'text'}"
448
- class="websy-input ${f.classes}"
449
- name="${f.field}"
450
- placeholder="${f.placeholder || ''}"
451
- value="${f.value || ''}"
452
- oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
453
- />
460
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
461
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
462
+ <input
463
+ id="${this.elementId}_input_${f.field}"
464
+ ${f.required === true ? 'required' : ''}
465
+ type="${f.type || 'text'}"
466
+ class="websy-input"
467
+ name="${f.field}"
468
+ placeholder="${f.placeholder || ''}"
469
+ value="${f.value || ''}"
470
+ oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
471
+ />
472
+ </div><!--
454
473
  `
455
474
  }
456
475
  })
476
+ html += `
477
+ --><button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
478
+ `
479
+ if (this.options.cancel) {
480
+ html += `
481
+ --><button class="websy-btn cancel ${this.options.cancel.classes}">${this.options.cancel.text || 'Cancel'}</button>
482
+ `
483
+ }
457
484
  html += `
458
485
  </form>
459
486
  <div id="${this.elementId}_validationFail" class="websy-validation-failure"></div>
@@ -463,9 +490,6 @@ class WebsyForm {
463
490
  <div id='${this.elementId}_recaptcha'></div>
464
491
  `
465
492
  }
466
- html += `
467
- <button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>
468
- `
469
493
  el.innerHTML = html
470
494
  this.processComponents(componentsToProcess, () => {
471
495
  if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
@@ -884,6 +908,7 @@ Date.prototype.floor = function () {
884
908
  return new Date(`${this.getMonth() + 1}/${this.getDate()}/${this.getFullYear()}`)
885
909
  }
886
910
 
911
+ /* global WebsyUtils */
887
912
  class WebsyDropdown {
888
913
  constructor (elementId, options) {
889
914
  const DEFAULTS = {
@@ -893,8 +918,10 @@ class WebsyDropdown {
893
918
  style: 'plain',
894
919
  items: [],
895
920
  label: '',
921
+ disabled: false,
896
922
  minSearchCharacters: 2,
897
- showCompleteSelectedList: false
923
+ showCompleteSelectedList: false,
924
+ closeAfterSelection: true
898
925
  }
899
926
  this.options = Object.assign({}, DEFAULTS, options)
900
927
  this.tooltipTimeoutFn = null
@@ -948,6 +975,7 @@ class WebsyDropdown {
948
975
  const contentEl = document.getElementById(`${this.elementId}_content`)
949
976
  maskEl.classList.remove('active')
950
977
  contentEl.classList.remove('active')
978
+ contentEl.classList.remove('on-top')
951
979
  const searchEl = document.getElementById(`${this.elementId}_search`)
952
980
  if (searchEl) {
953
981
  if (this.options.onCancelSearch) {
@@ -957,6 +985,9 @@ class WebsyDropdown {
957
985
  }
958
986
  }
959
987
  handleClick (event) {
988
+ if (this.options.disabled === true) {
989
+ return
990
+ }
960
991
  if (event.target.classList.contains('websy-dropdown-header')) {
961
992
  this.open()
962
993
  }
@@ -1044,6 +1075,9 @@ class WebsyDropdown {
1044
1075
  const contentEl = document.getElementById(`${this.elementId}_content`)
1045
1076
  maskEl.classList.add('active')
1046
1077
  contentEl.classList.add('active')
1078
+ if (WebsyUtils.getElementPos(contentEl).bottom > window.innerHeight) {
1079
+ contentEl.classList.add('on-top')
1080
+ }
1047
1081
  if (this.options.disableSearch !== true) {
1048
1082
  const searchEl = document.getElementById(`${this.elementId}_search`)
1049
1083
  if (searchEl) {
@@ -1057,12 +1091,13 @@ class WebsyDropdown {
1057
1091
  return
1058
1092
  }
1059
1093
  const el = document.getElementById(this.elementId)
1060
- const headerValue = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1094
+ const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1095
+ const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1061
1096
  let html = `
1062
- <div class='websy-dropdown-container ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1097
+ <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1063
1098
  <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1064
1099
  <span id='${this.elementId}_headerLabel' class='websy-dropdown-header-label'>${this.options.label}</span>
1065
- <span data-info='${headerValue}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerValue}</span>
1100
+ <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1066
1101
  <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1067
1102
  <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>
1068
1103
  `
@@ -1142,19 +1177,21 @@ class WebsyDropdown {
1142
1177
  if (this.selectedItems.length === 1) {
1143
1178
  labelEl.innerHTML = item.label
1144
1179
  labelEl.setAttribute('data-info', item.label)
1145
- inputEl.value = item.label
1180
+ inputEl.value = item.value
1146
1181
  }
1147
1182
  else if (this.selectedItems.length > 1) {
1148
1183
  if (this.options.showCompleteSelectedList === true) {
1149
- let selectedValues = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1150
- labelEl.innerHTML = selectedValues
1151
- labelEl.setAttribute('data-info', selectedValues)
1184
+ let selectedLabels = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1185
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1186
+ labelEl.innerHTML = selectedLabels
1187
+ labelEl.setAttribute('data-info', selectedLabels)
1152
1188
  inputEl.value = selectedValues
1153
1189
  }
1154
1190
  else {
1191
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1155
1192
  labelEl.innerHTML = `${this.selectedItems.length} selected`
1156
1193
  labelEl.setAttribute('data-info', '')
1157
- inputEl.value = this.selectedItems.join(this.options.multiValueDelimiter)
1194
+ inputEl.value = selectedValues
1158
1195
  }
1159
1196
  }
1160
1197
  else {
@@ -1182,7 +1219,9 @@ class WebsyDropdown {
1182
1219
  if (item && this.options.onItemSelected) {
1183
1220
  this.options.onItemSelected(item, this.selectedItems, this.options.items)
1184
1221
  }
1185
- this.close()
1222
+ if (this.options.closeAfterSelection === true) {
1223
+ this.close()
1224
+ }
1186
1225
  }
1187
1226
  }
1188
1227
 
@@ -1390,6 +1429,149 @@ class WebsyResultList {
1390
1429
  }
1391
1430
  }
1392
1431
 
1432
+ /* global WebsyDesigns */
1433
+ class WebsyTemplate {
1434
+ constructor (elementId, options) {
1435
+ const DEFAULTS = {
1436
+ listeners: {
1437
+ click: {}
1438
+ }
1439
+ }
1440
+ this.options = Object.assign({}, DEFAULTS, options)
1441
+ this.elementId = elementId
1442
+ this.templateService = new WebsyDesigns.APIService('')
1443
+ if (!elementId) {
1444
+ console.log('No element Id provided for Websy Template')
1445
+ return
1446
+ }
1447
+ const el = document.getElementById(elementId)
1448
+ if (el) {
1449
+ el.addEventListener('click', this.handleClick.bind(this))
1450
+ }
1451
+ if (typeof options.template === 'object' && options.template.url) {
1452
+ this.templateService.get(options.template.url).then(templateString => {
1453
+ this.options.template = templateString
1454
+ this.render()
1455
+ })
1456
+ }
1457
+ else {
1458
+ this.render()
1459
+ }
1460
+ }
1461
+ buildHTML () {
1462
+ let html = ``
1463
+ if (this.options.template) {
1464
+ let template = this.options.template
1465
+ // find conditional elements
1466
+ let ifMatches = [...template.matchAll(/<\s*if[^>]*>([\s\S]*?)<\s*\/\s*if>/g)]
1467
+ ifMatches.forEach(m => {
1468
+ // get the condition
1469
+ if (m[0] && m.index > -1) {
1470
+ let conditionMatch = m[0].match(/(\scondition=["|']\w.+)["|']/g)
1471
+ if (conditionMatch && conditionMatch[0]) {
1472
+ let c = conditionMatch[0].trim().replace('condition=', '')
1473
+ if (c.split('')[0] === '"') {
1474
+ c = c.replace(/"/g, '')
1475
+ }
1476
+ else if (c.split('')[0] === '\'') {
1477
+ c = c.replace(/'/g, '')
1478
+ }
1479
+ let parts = []
1480
+ let polarity = true
1481
+ if (c.indexOf('===') !== -1) {
1482
+ parts = c.split('===')
1483
+ }
1484
+ else if (c.indexOf('!==') !== -1) {
1485
+ parts = c.split('!==')
1486
+ polarity = false
1487
+ }
1488
+ else if (c.indexOf('==') !== -1) {
1489
+ parts = c.split('==')
1490
+ }
1491
+ else if (c.indexOf('!=') !== -1) {
1492
+ parts = c.split('!=')
1493
+ polarity = false
1494
+ }
1495
+ let removeAll = true
1496
+ if (parts.length === 2) {
1497
+ if (!isNaN(parts[1])) {
1498
+ parts[1] = +parts[1]
1499
+ }
1500
+ if (parts[1] === 'true') {
1501
+ parts[1] = true
1502
+ }
1503
+ if (parts[1] === 'false') {
1504
+ parts[1] = false
1505
+ }
1506
+ if (typeof parts[1] === 'string') {
1507
+ if (parts[1].indexOf('"') !== -1) {
1508
+ parts[1] = parts[1].replace(/"/g, '')
1509
+ }
1510
+ else if (parts[1].indexOf('\'') !== -1) {
1511
+ parts[1] = parts[1].replace(/'/g, '')
1512
+ }
1513
+ }
1514
+ if (polarity === true) {
1515
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] === parts[1]) {
1516
+ // remove the <if> tags
1517
+ removeAll = false
1518
+ }
1519
+ else if (parts[0] === parts[1]) {
1520
+ removeAll = false
1521
+ }
1522
+ }
1523
+ else if (polarity === false) {
1524
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] !== parts[1]) {
1525
+ // remove the <if> tags
1526
+ removeAll = false
1527
+ }
1528
+ }
1529
+ }
1530
+ if (removeAll === true) {
1531
+ // remove the whole markup
1532
+ template = template.replace(m[0], '')
1533
+ }
1534
+ else {
1535
+ // remove the <if> tags
1536
+ let newMarkup = m[0]
1537
+ newMarkup = newMarkup.replace('</if>', '').replace(/<\s*if[^>]*>/g, '')
1538
+ template = template.replace(m[0], newMarkup)
1539
+ }
1540
+ }
1541
+ }
1542
+ })
1543
+ let tagMatches = [...template.matchAll(/(\sdata-event=["|']\w.+)["|']/g)]
1544
+ tagMatches.forEach(m => {
1545
+ if (m[0] && m.index > -1) {
1546
+ template = template.replace(m[0], `${m[0]}`)
1547
+ }
1548
+ })
1549
+ for (let key in this.options.data) {
1550
+ let rg = new RegExp(`{${key}}`, 'gm')
1551
+ if (rg) {
1552
+ template = template.replace(rg, this.options.data[key])
1553
+ }
1554
+ }
1555
+ html = template
1556
+ }
1557
+ return html
1558
+ }
1559
+ handleClick (event) {
1560
+ //
1561
+ }
1562
+ render () {
1563
+ this.resize()
1564
+ }
1565
+ resize () {
1566
+ const html = this.buildHTML()
1567
+ const el = document.getElementById(this.elementId)
1568
+ el.innerHTML = html.replace(/\n/g, '')
1569
+ if (this.options.readyCallbackFn) {
1570
+ this.options.readyCallbackFn()
1571
+ }
1572
+ }
1573
+ }
1574
+
1393
1575
  class WebsyPubSub {
1394
1576
  constructor (elementId, options) {
1395
1577
  this.options = Object.assign({}, options)
@@ -1888,7 +2070,7 @@ class APIService {
1888
2070
  if (id) {
1889
2071
  query.push(`id:${id}`)
1890
2072
  }
1891
- return `${this.baseUrl}/${entity}${query.length > 0 ? `?where=${query.join(';')}` : ''}`
2073
+ return `${this.baseUrl}/${entity}${query.length > 0 ? `${entity.indexOf('?') === -1 ? '?' : '&'}where=${query.join(';')}` : ''}`
1892
2074
  }
1893
2075
  delete (entity, id) {
1894
2076
  const url = this.buildUrl(entity, id)
@@ -3493,6 +3675,29 @@ class WebsyChartTooltip {
3493
3675
  }
3494
3676
  }
3495
3677
 
3678
+ const WebsyUtils = {
3679
+ createIdentity: (size = 6) => {
3680
+ let text = ''
3681
+ let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
3682
+
3683
+ for (let i = 0; i < size; i++) {
3684
+ text += possible.charAt(Math.floor(Math.random() * possible.length))
3685
+ }
3686
+ return text
3687
+ },
3688
+ getElementPos: el => {
3689
+ const rect = el.getBoundingClientRect()
3690
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
3691
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop
3692
+ return {
3693
+ top: rect.top + scrollTop,
3694
+ left: rect.left + scrollLeft,
3695
+ bottom: rect.top + scrollTop + el.clientHeight,
3696
+ right: rect.left + scrollLeft + el.clientWidth
3697
+ }
3698
+ }
3699
+ }
3700
+
3496
3701
 
3497
3702
  const WebsyDesigns = {
3498
3703
  WebsyPopupDialog,
@@ -3502,6 +3707,7 @@ const WebsyDesigns = {
3502
3707
  WebsyDatePicker,
3503
3708
  WebsyDropdown,
3504
3709
  WebsyResultList,
3710
+ WebsyTemplate,
3505
3711
  WebsyPubSub,
3506
3712
  WebsyRouter,
3507
3713
  WebsyTable,
@@ -3511,7 +3717,8 @@ const WebsyDesigns = {
3511
3717
  WebsyKPI,
3512
3718
  WebsyPDFButton,
3513
3719
  PDFButton: WebsyPDFButton,
3514
- APIService
3720
+ APIService,
3721
+ WebsyUtils
3515
3722
  }
3516
3723
 
3517
3724
  const GlobalPubSub = new WebsyPubSub('empty', {})