@websy/websy-designs 0.0.116 → 0.0.120

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 {
@@ -156,8 +158,10 @@ class WebsyLoadingDialog {
156
158
  class WebsyNavigationMenu {
157
159
  constructor (elementId, options) {
158
160
  this.options = Object.assign({}, {
161
+ collapsable: false,
159
162
  orientation: 'horizontal',
160
- parentMap: {}
163
+ parentMap: {},
164
+ childIndentation: 10
161
165
  }, options)
162
166
  if (!elementId) {
163
167
  console.log('No element Id provided for Websy Menu')
@@ -196,15 +200,19 @@ class WebsyNavigationMenu {
196
200
  const el = document.getElementById(this.elementId)
197
201
  if (el) {
198
202
  let html = ``
199
- if (this.options.logo) {
203
+ if (this.options.collapsable === true) {
200
204
  html += `
201
205
  <div id='${this.elementId}_menuIcon' class='websy-menu-icon'>
202
- <svg viewbox="0 0 40 40" width="40" height="40">
203
- <rect x="0" y="0" width="40" height="4" rx="2"></rect>
204
- <rect x="0" y="12" width="40" height="4" rx="2"></rect>
205
- <rect x="0" y="24" width="40" height="4" rx="2"></rect>
206
+ <svg viewbox="0 0 40 40" width="30" height="40">
207
+ <rect x="0" y="0" width="30" height="4" rx="2"></rect>
208
+ <rect x="0" y="12" width="30" height="4" rx="2"></rect>
209
+ <rect x="0" y="24" width="30" height="4" rx="2"></rect>
206
210
  </svg>
207
- </div>
211
+ </div>
212
+ `
213
+ }
214
+ if (this.options.logo) {
215
+ html += `
208
216
  <div
209
217
  class='logo ${(this.options.logo.classes && this.options.logo.classes.join(' ')) || ''}'
210
218
  ${this.options.logo.attributes && this.options.logo.attributes.join(' ')}
@@ -240,10 +248,11 @@ class WebsyNavigationMenu {
240
248
  <li class='websy-${this.options.orientation}-list-item'>
241
249
  <div class='websy-menu-header ${items[i].classes && items[i].classes.join(' ')} ${selected} ${active}'
242
250
  id='${this.elementId}_${currentBlock}_label'
243
- data-id='${currentBlock}'
251
+ data-id='${currentBlock}'
252
+ data-menu-id='${this.elementId}_${currentBlock}_list'
244
253
  data-popout-id='${level > 1 ? block : currentBlock}'
245
254
  data-text='${items[i].text}'
246
- style='padding-left: ${level * this.options.menuHPadding}px'
255
+ style='padding-left: ${level * this.options.childIndentation}px'
247
256
  ${items[i].attributes && items[i].attributes.join(' ')}
248
257
  >
249
258
  `
@@ -278,6 +287,9 @@ class WebsyNavigationMenu {
278
287
  }
279
288
  html += `</ul>`
280
289
  return html
290
+ }
291
+ toggleOpen () {
292
+
281
293
  }
282
294
  toggleMobileMenu (method) {
283
295
  if (typeof method === 'undefined') {
@@ -325,6 +337,13 @@ class WebsyForm {
325
337
  this.render()
326
338
  }
327
339
  }
340
+ cancelForm () {
341
+ const formEl = document.getElementById(`${this.elementId}Form`)
342
+ formEl.reset()
343
+ if (this.options.cancelFn) {
344
+ this.options.cancelFn(this.elementId)
345
+ }
346
+ }
328
347
  checkRecaptcha () {
329
348
  return new Promise((resolve, reject) => {
330
349
  if (this.options.useRecaptcha === true) {
@@ -375,9 +394,13 @@ class WebsyForm {
375
394
  }
376
395
  }
377
396
  handleClick (event) {
397
+ event.preventDefault()
378
398
  if (event.target.classList.contains('submit')) {
379
399
  this.submitForm()
380
400
  }
401
+ else if (event.target.classList.contains('cancel')) {
402
+ this.cancelForm()
403
+ }
381
404
  }
382
405
  handleKeyDown (event) {
383
406
  if (event.key === 'enter') {
@@ -418,42 +441,56 @@ class WebsyForm {
418
441
  let html = `
419
442
  <form id="${this.elementId}Form">
420
443
  `
421
- this.options.fields.forEach(f => {
444
+ this.options.fields.forEach((f, i) => {
422
445
  if (f.component) {
423
446
  componentsToProcess.push(f)
424
447
  html += `
425
- ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
426
- <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
448
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
449
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
450
+ <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
451
+ </div><!--
427
452
  `
428
453
  }
429
454
  else if (f.type === 'longtext') {
430
455
  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>
456
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
457
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
458
+ <textarea
459
+ id="${this.elementId}_input_${f.field}"
460
+ ${f.required === true ? 'required' : ''}
461
+ placeholder="${f.placeholder || ''}"
462
+ name="${f.field}"
463
+ class="websy-input websy-textarea"
464
+ ></textarea>
465
+ </div><!--
439
466
  `
440
467
  }
441
468
  else {
442
469
  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
- />
470
+ ${i > 0 ? '-->' : ''}<div class='${f.classes}'>
471
+ ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}
472
+ <input
473
+ id="${this.elementId}_input_${f.field}"
474
+ ${f.required === true ? 'required' : ''}
475
+ type="${f.type || 'text'}"
476
+ class="websy-input"
477
+ name="${f.field}"
478
+ placeholder="${f.placeholder || ''}"
479
+ value="${f.value || ''}"
480
+ oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
481
+ />
482
+ </div><!--
454
483
  `
455
484
  }
456
485
  })
486
+ html += `
487
+ --><button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>${this.options.cancel ? '<!--' : ''}
488
+ `
489
+ if (this.options.cancel) {
490
+ html += `
491
+ --><button class="websy-btn cancel ${this.options.cancel.classes}">${this.options.cancel.text || 'Cancel'}</button>
492
+ `
493
+ }
457
494
  html += `
458
495
  </form>
459
496
  <div id="${this.elementId}_validationFail" class="websy-validation-failure"></div>
@@ -463,9 +500,6 @@ class WebsyForm {
463
500
  <div id='${this.elementId}_recaptcha'></div>
464
501
  `
465
502
  }
466
- html += `
467
- <button class="websy-btn submit ${this.options.submit.classes}">${this.options.submit.text || 'Save'}</button>
468
- `
469
503
  el.innerHTML = html
470
504
  this.processComponents(componentsToProcess, () => {
471
505
  if (this.options.useRecaptcha === true && typeof grecaptcha !== 'undefined') {
@@ -884,6 +918,7 @@ Date.prototype.floor = function () {
884
918
  return new Date(`${this.getMonth() + 1}/${this.getDate()}/${this.getFullYear()}`)
885
919
  }
886
920
 
921
+ /* global WebsyUtils */
887
922
  class WebsyDropdown {
888
923
  constructor (elementId, options) {
889
924
  const DEFAULTS = {
@@ -893,8 +928,10 @@ class WebsyDropdown {
893
928
  style: 'plain',
894
929
  items: [],
895
930
  label: '',
931
+ disabled: false,
896
932
  minSearchCharacters: 2,
897
- showCompleteSelectedList: false
933
+ showCompleteSelectedList: false,
934
+ closeAfterSelection: true
898
935
  }
899
936
  this.options = Object.assign({}, DEFAULTS, options)
900
937
  this.tooltipTimeoutFn = null
@@ -948,6 +985,7 @@ class WebsyDropdown {
948
985
  const contentEl = document.getElementById(`${this.elementId}_content`)
949
986
  maskEl.classList.remove('active')
950
987
  contentEl.classList.remove('active')
988
+ contentEl.classList.remove('on-top')
951
989
  const searchEl = document.getElementById(`${this.elementId}_search`)
952
990
  if (searchEl) {
953
991
  if (this.options.onCancelSearch) {
@@ -957,6 +995,9 @@ class WebsyDropdown {
957
995
  }
958
996
  }
959
997
  handleClick (event) {
998
+ if (this.options.disabled === true) {
999
+ return
1000
+ }
960
1001
  if (event.target.classList.contains('websy-dropdown-header')) {
961
1002
  this.open()
962
1003
  }
@@ -1044,6 +1085,9 @@ class WebsyDropdown {
1044
1085
  const contentEl = document.getElementById(`${this.elementId}_content`)
1045
1086
  maskEl.classList.add('active')
1046
1087
  contentEl.classList.add('active')
1088
+ if (WebsyUtils.getElementPos(contentEl).bottom > window.innerHeight) {
1089
+ contentEl.classList.add('on-top')
1090
+ }
1047
1091
  if (this.options.disableSearch !== true) {
1048
1092
  const searchEl = document.getElementById(`${this.elementId}_search`)
1049
1093
  if (searchEl) {
@@ -1057,12 +1101,13 @@ class WebsyDropdown {
1057
1101
  return
1058
1102
  }
1059
1103
  const el = document.getElementById(this.elementId)
1060
- const headerValue = this.selectedItems.map(s => this.options.items[s].label).join(this.options.multiValueDelimiter)
1104
+ const headerLabel = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1105
+ const headerValue = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1061
1106
  let html = `
1062
- <div class='websy-dropdown-container ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1107
+ <div class='websy-dropdown-container ${this.options.disabled ? 'disabled' : ''} ${this.options.disableSearch !== true ? 'with-search' : ''}'>
1063
1108
  <div id='${this.elementId}_header' class='websy-dropdown-header ${this.selectedItems.length === 1 ? 'one-selected' : ''} ${this.options.allowClear === true ? 'allow-clear' : ''}'>
1064
1109
  <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>
1110
+ <span data-info='${headerLabel}' class='websy-dropdown-header-value' id='${this.elementId}_selectedItems'>${headerLabel}</span>
1066
1111
  <input class='dropdown-input' id='${this.elementId}_input' name='${this.options.field || this.options.label}' value='${headerValue}'>
1067
1112
  <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
1113
  `
@@ -1142,19 +1187,21 @@ class WebsyDropdown {
1142
1187
  if (this.selectedItems.length === 1) {
1143
1188
  labelEl.innerHTML = item.label
1144
1189
  labelEl.setAttribute('data-info', item.label)
1145
- inputEl.value = item.label
1190
+ inputEl.value = item.value
1146
1191
  }
1147
1192
  else if (this.selectedItems.length > 1) {
1148
1193
  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)
1194
+ let selectedLabels = this.selectedItems.map(s => this.options.items[s].label || this.options.items[s].value).join(this.options.multiValueDelimiter)
1195
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1196
+ labelEl.innerHTML = selectedLabels
1197
+ labelEl.setAttribute('data-info', selectedLabels)
1152
1198
  inputEl.value = selectedValues
1153
1199
  }
1154
1200
  else {
1201
+ let selectedValues = this.selectedItems.map(s => this.options.items[s].value || this.options.items[s].label).join(this.options.multiValueDelimiter)
1155
1202
  labelEl.innerHTML = `${this.selectedItems.length} selected`
1156
1203
  labelEl.setAttribute('data-info', '')
1157
- inputEl.value = this.selectedItems.join(this.options.multiValueDelimiter)
1204
+ inputEl.value = selectedValues
1158
1205
  }
1159
1206
  }
1160
1207
  else {
@@ -1182,7 +1229,9 @@ class WebsyDropdown {
1182
1229
  if (item && this.options.onItemSelected) {
1183
1230
  this.options.onItemSelected(item, this.selectedItems, this.options.items)
1184
1231
  }
1185
- this.close()
1232
+ if (this.options.closeAfterSelection === true) {
1233
+ this.close()
1234
+ }
1186
1235
  }
1187
1236
  }
1188
1237
 
@@ -1390,6 +1439,149 @@ class WebsyResultList {
1390
1439
  }
1391
1440
  }
1392
1441
 
1442
+ /* global WebsyDesigns */
1443
+ class WebsyTemplate {
1444
+ constructor (elementId, options) {
1445
+ const DEFAULTS = {
1446
+ listeners: {
1447
+ click: {}
1448
+ }
1449
+ }
1450
+ this.options = Object.assign({}, DEFAULTS, options)
1451
+ this.elementId = elementId
1452
+ this.templateService = new WebsyDesigns.APIService('')
1453
+ if (!elementId) {
1454
+ console.log('No element Id provided for Websy Template')
1455
+ return
1456
+ }
1457
+ const el = document.getElementById(elementId)
1458
+ if (el) {
1459
+ el.addEventListener('click', this.handleClick.bind(this))
1460
+ }
1461
+ if (typeof options.template === 'object' && options.template.url) {
1462
+ this.templateService.get(options.template.url).then(templateString => {
1463
+ this.options.template = templateString
1464
+ this.render()
1465
+ })
1466
+ }
1467
+ else {
1468
+ this.render()
1469
+ }
1470
+ }
1471
+ buildHTML () {
1472
+ let html = ``
1473
+ if (this.options.template) {
1474
+ let template = this.options.template
1475
+ // find conditional elements
1476
+ let ifMatches = [...template.matchAll(/<\s*if[^>]*>([\s\S]*?)<\s*\/\s*if>/g)]
1477
+ ifMatches.forEach(m => {
1478
+ // get the condition
1479
+ if (m[0] && m.index > -1) {
1480
+ let conditionMatch = m[0].match(/(\scondition=["|']\w.+)["|']/g)
1481
+ if (conditionMatch && conditionMatch[0]) {
1482
+ let c = conditionMatch[0].trim().replace('condition=', '')
1483
+ if (c.split('')[0] === '"') {
1484
+ c = c.replace(/"/g, '')
1485
+ }
1486
+ else if (c.split('')[0] === '\'') {
1487
+ c = c.replace(/'/g, '')
1488
+ }
1489
+ let parts = []
1490
+ let polarity = true
1491
+ if (c.indexOf('===') !== -1) {
1492
+ parts = c.split('===')
1493
+ }
1494
+ else if (c.indexOf('!==') !== -1) {
1495
+ parts = c.split('!==')
1496
+ polarity = false
1497
+ }
1498
+ else if (c.indexOf('==') !== -1) {
1499
+ parts = c.split('==')
1500
+ }
1501
+ else if (c.indexOf('!=') !== -1) {
1502
+ parts = c.split('!=')
1503
+ polarity = false
1504
+ }
1505
+ let removeAll = true
1506
+ if (parts.length === 2) {
1507
+ if (!isNaN(parts[1])) {
1508
+ parts[1] = +parts[1]
1509
+ }
1510
+ if (parts[1] === 'true') {
1511
+ parts[1] = true
1512
+ }
1513
+ if (parts[1] === 'false') {
1514
+ parts[1] = false
1515
+ }
1516
+ if (typeof parts[1] === 'string') {
1517
+ if (parts[1].indexOf('"') !== -1) {
1518
+ parts[1] = parts[1].replace(/"/g, '')
1519
+ }
1520
+ else if (parts[1].indexOf('\'') !== -1) {
1521
+ parts[1] = parts[1].replace(/'/g, '')
1522
+ }
1523
+ }
1524
+ if (polarity === true) {
1525
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] === parts[1]) {
1526
+ // remove the <if> tags
1527
+ removeAll = false
1528
+ }
1529
+ else if (parts[0] === parts[1]) {
1530
+ removeAll = false
1531
+ }
1532
+ }
1533
+ else if (polarity === false) {
1534
+ if (typeof this.options.data[parts[0]] !== 'undefined' && this.options.data[parts[0]] !== parts[1]) {
1535
+ // remove the <if> tags
1536
+ removeAll = false
1537
+ }
1538
+ }
1539
+ }
1540
+ if (removeAll === true) {
1541
+ // remove the whole markup
1542
+ template = template.replace(m[0], '')
1543
+ }
1544
+ else {
1545
+ // remove the <if> tags
1546
+ let newMarkup = m[0]
1547
+ newMarkup = newMarkup.replace('</if>', '').replace(/<\s*if[^>]*>/g, '')
1548
+ template = template.replace(m[0], newMarkup)
1549
+ }
1550
+ }
1551
+ }
1552
+ })
1553
+ let tagMatches = [...template.matchAll(/(\sdata-event=["|']\w.+)["|']/g)]
1554
+ tagMatches.forEach(m => {
1555
+ if (m[0] && m.index > -1) {
1556
+ template = template.replace(m[0], `${m[0]}`)
1557
+ }
1558
+ })
1559
+ for (let key in this.options.data) {
1560
+ let rg = new RegExp(`{${key}}`, 'gm')
1561
+ if (rg) {
1562
+ template = template.replace(rg, this.options.data[key])
1563
+ }
1564
+ }
1565
+ html = template
1566
+ }
1567
+ return html
1568
+ }
1569
+ handleClick (event) {
1570
+ //
1571
+ }
1572
+ render () {
1573
+ this.resize()
1574
+ }
1575
+ resize () {
1576
+ const html = this.buildHTML()
1577
+ const el = document.getElementById(this.elementId)
1578
+ el.innerHTML = html.replace(/\n/g, '')
1579
+ if (this.options.readyCallbackFn) {
1580
+ this.options.readyCallbackFn()
1581
+ }
1582
+ }
1583
+ }
1584
+
1393
1585
  class WebsyPubSub {
1394
1586
  constructor (elementId, options) {
1395
1587
  this.options = Object.assign({}, options)
@@ -1888,7 +2080,7 @@ class APIService {
1888
2080
  if (id) {
1889
2081
  query.push(`id:${id}`)
1890
2082
  }
1891
- return `${this.baseUrl}/${entity}${query.length > 0 ? `?where=${query.join(';')}` : ''}`
2083
+ return `${this.baseUrl}/${entity}${query.length > 0 ? `${entity.indexOf('?') === -1 ? '?' : '&'}where=${query.join(';')}` : ''}`
1892
2084
  }
1893
2085
  delete (entity, id) {
1894
2086
  const url = this.buildUrl(entity, id)
@@ -2180,19 +2372,47 @@ class WebsyTable {
2180
2372
  bodyHTML += data.map((r, rowIndex) => {
2181
2373
  return '<tr>' + r.map((c, i) => {
2182
2374
  if (this.options.columns[i].show !== false) {
2375
+ let style = ''
2376
+ if (this.options.columns[i].width) {
2377
+ style += `width: ${this.options.columns[i].width}; `
2378
+ }
2379
+ if (c.backgroundColor) {
2380
+ style += `background-color: ${c.backgroundColor}; `
2381
+ }
2382
+ if (c.color) {
2383
+ style += `color: ${c.color}; `
2384
+ }
2183
2385
  if (this.options.columns[i].showAsLink === true && c.value.trim() !== '') {
2184
2386
  return `
2185
- <td data-row-index='${this.rowCount + rowIndex}' data-col-index='${i}' class='${this.options.columns[i].classes || ''}' ${this.options.columns[i].width ? 'style="width: ' + this.options.columns[i].width + '"' : ''}><a href='${c.value}' target='${this.options.columns[i].openInNewTab === true ? '_blank' : '_self'}'>${this.options.columns[i].linkText || c.value}</a></td>
2387
+ <td
2388
+ data-row-index='${this.rowCount + rowIndex}'
2389
+ data-col-index='${i}'
2390
+ class='${this.options.columns[i].classes || ''}'
2391
+ style='${style}'
2392
+ >
2393
+ <a href='${c.value}' target='${this.options.columns[i].openInNewTab === true ? '_blank' : '_self'}'>${this.options.columns[i].linkText || c.value}</a>
2394
+ </td>
2186
2395
  `
2187
2396
  }
2188
2397
  else if (this.options.columns[i].showAsNavigatorLink === true && c.value.trim() !== '') {
2189
2398
  return `
2190
- <td data-view='${c.value}' data-row-index='${this.rowCount + rowIndex}' data-col-index='${i}' class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}' ${this.options.columns[i].width ? 'style="width: ' + this.options.columns[i].width + '"' : ''}>${this.options.columns[i].linkText || c.value}</td>
2399
+ <td
2400
+ data-view='${c.value}'
2401
+ data-row-index='${this.rowCount + rowIndex}'
2402
+ data-col-index='${i}'
2403
+ class='trigger-item ${this.options.columns[i].clickable === true ? 'clickable' : ''} ${this.options.columns[i].classes || ''}'
2404
+ style='${style}'
2405
+ >${this.options.columns[i].linkText || c.value}</td>
2191
2406
  `
2192
2407
  }
2193
2408
  else {
2194
2409
  return `
2195
- <td data-info='${c.value}' data-row-index='${this.rowCount + rowIndex}' data-col-index='${i}' class='${this.options.columns[i].classes || ''}' ${this.options.columns[i].width ? 'style="width: ' + (this.options.columns[i].width || 'auto') + '"' : ''}>${c.value}</td>
2410
+ <td
2411
+ data-info='${c.value}'
2412
+ data-row-index='${this.rowCount + rowIndex}'
2413
+ data-col-index='${i}'
2414
+ class='${this.options.columns[i].classes || ''}'
2415
+ style='${style}'>${c.value}</td>
2196
2416
  `
2197
2417
  }
2198
2418
  }
@@ -2557,6 +2777,7 @@ this.plotArea = this.svg.append('g')
2557
2777
  this.areaLayer = this.svg.append('g')
2558
2778
  this.lineLayer = this.svg.append('g')
2559
2779
  this.barLayer = this.svg.append('g')
2780
+ this.labelLayer = this.svg.append('g')
2560
2781
  this.symbolLayer = this.svg.append('g')
2561
2782
  this.trackingLineLayer = this.svg.append('g')
2562
2783
  this.trackingLineLayer.append('line').attr('class', 'tracking-line')
@@ -2732,6 +2953,8 @@ else {
2732
2953
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2733
2954
  this.barLayer
2734
2955
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2956
+ this.labelLayer
2957
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2735
2958
  this.symbolLayer
2736
2959
  .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
2737
2960
  this.trackingLineLayer
@@ -2924,6 +3147,7 @@ else {
2924
3147
  series.color = this.options.colors[index % this.options.colors.length]
2925
3148
  }
2926
3149
  this[`render${series.type || 'bar'}`](series, index)
3150
+ this.renderLabels(series, index)
2927
3151
  })
2928
3152
  }
2929
3153
  }
@@ -3050,6 +3274,76 @@ bars
3050
3274
  return `bar bar_${series.key}`
3051
3275
  })
3052
3276
 
3277
+ }
3278
+ renderLabels (series, index) {
3279
+ /* global series index d3 */
3280
+ let xAxis = 'bottomAxis'
3281
+ let yAxis = 'leftAxis'
3282
+ let that = this
3283
+ if (this.options.orientation === 'horizontal') {
3284
+ xAxis = 'leftAxis'
3285
+ yAxis = 'bottomAxis'
3286
+ }
3287
+ if (this.options.showLabels) {
3288
+ // need to add logic to handle positioning options
3289
+ // e.g. Inside, Outide, Auto (this will also affect the available plot space)
3290
+ // We currently only support 'Auto'
3291
+ let labels = this.labelLayer.selectAll(`.label_${series.key}`).data(series.data)
3292
+ labels
3293
+ .exit()
3294
+ .transition(this.transition)
3295
+ .style('stroke-opacity', 1e-6)
3296
+ .remove()
3297
+ labels
3298
+ .attr('x', getLabelX.bind(this))
3299
+ .attr('y', getLabelY.bind(this))
3300
+ .attr('class', `.label_${series.key}`)
3301
+ .style('font-size', `${this.options.labelSize || this.options.fontSize}px`)
3302
+ .transition(this.transition)
3303
+ .text(d => d.y.label || d.y.value)
3304
+
3305
+ labels
3306
+ .enter()
3307
+ .append('text')
3308
+ .attr('class', `.label_${series.key}`)
3309
+ .attr('x', getLabelX.bind(this))
3310
+ .attr('y', getLabelY.bind(this))
3311
+ .attr('alignment-baseline', 'central')
3312
+ .attr('text-anchor', this.options.orientation === 'horizontal' ? 'left' : 'middle')
3313
+ .style('font-size', `${this.options.labelSize || this.options.fontSize}px`)
3314
+ .text(d => d.y.label || d.y.value)
3315
+ .each(function (d, i) {
3316
+ if (that.options.orientation === 'horizontal') {
3317
+ if (that.plotWidth - getLabelX.call(that, d) < this.getComputedTextLength()) {
3318
+ this.setAttribute('text-anchor', 'end')
3319
+ this.setAttribute('x', +(this.getAttribute('x')) - 8)
3320
+ }
3321
+ }
3322
+ else {
3323
+ if (that.plotheight - getLabelX.call(that, d) < (that.options.labelSize || that.options.fontSize)) {
3324
+ this.setAttribute('y', +(this.getAttribute('y')) + 8)
3325
+ }
3326
+ }
3327
+ })
3328
+ }
3329
+
3330
+ function getLabelX (d) {
3331
+ if (this.options.orientation === 'horizontal') {
3332
+ return this[yAxis](isNaN(d.y.value) ? 0 : d.y.value) + 4
3333
+ }
3334
+ else {
3335
+ return this[xAxis](this.parseX(d.x.value)) + (this[xAxis].bandwidth() / 2)
3336
+ }
3337
+ }
3338
+ function getLabelY (d) {
3339
+ if (this.options.orientation === 'horizontal') {
3340
+ return this[xAxis](this.parseX(d.x.value)) + (this[xAxis].bandwidth() / 2)
3341
+ }
3342
+ else {
3343
+ return this[yAxis](isNaN(d.y.value) ? 0 : d.y.value) - 4
3344
+ }
3345
+ }
3346
+
3053
3347
  }
3054
3348
  renderline (series, index) {
3055
3349
  /* global series index d3 */
@@ -3135,7 +3429,7 @@ symbols
3135
3429
  .transition(this.transition)
3136
3430
  .attr('fill', 'white')
3137
3431
  .attr('stroke', series.color)
3138
- .attr('transform', d => { return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](d.y.value)})` })
3432
+ .attr('transform', d => { return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](isNaN(d.y.value) ? 0 : d.y.value)})` })
3139
3433
  // Enter
3140
3434
  symbols.enter()
3141
3435
  .append('path')
@@ -3145,7 +3439,7 @@ symbols.enter()
3145
3439
  .attr('stroke', series.color)
3146
3440
  .attr('class', d => { return `symbol symbol_${series.key}` })
3147
3441
  .attr('transform', d => {
3148
- return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](d.y.value)})`
3442
+ return `translate(${this[xAxis](this.parseX(d.x.value))}, ${this[yAxis](isNaN(d.y.value) ? 0 : d.y.value)})`
3149
3443
  })
3150
3444
 
3151
3445
  }
@@ -3159,8 +3453,10 @@ if (el) {
3159
3453
  .attr('width', this.width)
3160
3454
  .attr('height', this.height)
3161
3455
  // Define the plot height
3456
+ // this.plotWidth = this.width - this.options.margin.left - this.options.margin.right - this.options.margin.axisLeft - this.options.margin.axisRight
3457
+ // this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom
3162
3458
  this.plotWidth = this.width - this.options.margin.left - this.options.margin.right - this.options.margin.axisLeft - this.options.margin.axisRight
3163
- this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom
3459
+ this.plotHeight = this.height - this.options.margin.top - this.options.margin.bottom - this.options.margin.axisBottom - this.options.margin.axisTop
3164
3460
  // establish the space needed for the various axes
3165
3461
  this.longestRight = 5
3166
3462
  this.longestBottom = 5
@@ -3190,24 +3486,54 @@ if (el) {
3190
3486
  }
3191
3487
  }
3192
3488
  // Translate the layers
3489
+ // this.leftAxisLayer
3490
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3491
+ // this.rightAxisLayer
3492
+ // .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3493
+ // this.bottomAxisLayer
3494
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.plotHeight})`)
3495
+ // this.plotArea
3496
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3497
+ // this.areaLayer
3498
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3499
+ // this.lineLayer
3500
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3501
+ // this.barLayer
3502
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3503
+ // this.labelLayer
3504
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3505
+ // this.symbolLayer
3506
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3507
+ // this.trackingLineLayer
3508
+ // .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3193
3509
  this.leftAxisLayer
3194
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3510
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3195
3511
  this.rightAxisLayer
3196
- .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3512
+ .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3197
3513
  this.bottomAxisLayer
3198
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.plotHeight})`)
3514
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight})`)
3515
+ this.leftAxisLabel
3516
+ .attr('transform', `translate(${this.options.margin.left}, ${this.options.margin.top + this.options.margin.axisTop})`)
3517
+ this.rightAxisLabel
3518
+ .attr('transform', `translate(${this.options.margin.left + this.plotWidth + this.options.margin.axisLeft + this.options.margin.axisRight}, ${this.options.margin.top + this.options.margin.axisTop})`)
3519
+ this.bottomAxisLabel
3520
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop + this.plotHeight})`)
3199
3521
  this.plotArea
3200
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3522
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3201
3523
  this.areaLayer
3202
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3524
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3203
3525
  this.lineLayer
3204
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3526
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3205
3527
  this.barLayer
3206
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3528
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3529
+ this.labelLayer
3530
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3207
3531
  this.symbolLayer
3208
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3532
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3209
3533
  this.trackingLineLayer
3210
- .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top})`)
3534
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3535
+ this.eventLayer
3536
+ .attr('transform', `translate(${this.options.margin.left + this.options.margin.axisLeft}, ${this.options.margin.top + this.options.margin.axisTop})`)
3211
3537
  }
3212
3538
 
3213
3539
  }
@@ -3493,6 +3819,29 @@ class WebsyChartTooltip {
3493
3819
  }
3494
3820
  }
3495
3821
 
3822
+ const WebsyUtils = {
3823
+ createIdentity: (size = 6) => {
3824
+ let text = ''
3825
+ let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
3826
+
3827
+ for (let i = 0; i < size; i++) {
3828
+ text += possible.charAt(Math.floor(Math.random() * possible.length))
3829
+ }
3830
+ return text
3831
+ },
3832
+ getElementPos: el => {
3833
+ const rect = el.getBoundingClientRect()
3834
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
3835
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop
3836
+ return {
3837
+ top: rect.top + scrollTop,
3838
+ left: rect.left + scrollLeft,
3839
+ bottom: rect.top + scrollTop + el.clientHeight,
3840
+ right: rect.left + scrollLeft + el.clientWidth
3841
+ }
3842
+ }
3843
+ }
3844
+
3496
3845
 
3497
3846
  const WebsyDesigns = {
3498
3847
  WebsyPopupDialog,
@@ -3502,6 +3851,7 @@ const WebsyDesigns = {
3502
3851
  WebsyDatePicker,
3503
3852
  WebsyDropdown,
3504
3853
  WebsyResultList,
3854
+ WebsyTemplate,
3505
3855
  WebsyPubSub,
3506
3856
  WebsyRouter,
3507
3857
  WebsyTable,
@@ -3511,7 +3861,8 @@ const WebsyDesigns = {
3511
3861
  WebsyKPI,
3512
3862
  WebsyPDFButton,
3513
3863
  PDFButton: WebsyPDFButton,
3514
- APIService
3864
+ APIService,
3865
+ WebsyUtils
3515
3866
  }
3516
3867
 
3517
3868
  const GlobalPubSub = new WebsyPubSub('empty', {})