@websy/websy-designs 0.0.117 → 0.0.121

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