@websy/websy-designs 1.10.7 → 1.11.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.
@@ -0,0 +1,21 @@
1
+ const bCrypt = require('bcrypt-nodejs')
2
+ const md5 = require('md5')
3
+
4
+ class AuthHelper {
5
+ constructor (dbHelper, options) {
6
+ this.dbHelper = dbHelper
7
+ const DEFAULTS = {
8
+ loginType: 'email'
9
+ }
10
+ this.options = Object.assign({}, DEFAULTS, options)
11
+ // console.log(this.options)
12
+ }
13
+ isLoggedIn (req, res, next) {
14
+ next()
15
+ }
16
+ checkPermissions (req, res, next) {
17
+ next()
18
+ }
19
+ }
20
+
21
+ module.exports = AuthHelper
@@ -221,6 +221,9 @@ class PGHelper {
221
221
  let updates = []
222
222
  for (let key in data) {
223
223
  if (this.updateIgnores.indexOf(key) === -1) {
224
+ if (typeof data[key] === 'string') {
225
+ data[key] = data[key].replace(/''/gm, `'`).replace(/'/gm, `''`).replace(/\\\\/gm, '\\')
226
+ }
224
227
  updates.push(`${key} = ${(data[key] === null ? data[key] : `'${data[key]}'`)}`)
225
228
  }
226
229
  }
@@ -269,9 +272,21 @@ class PGHelper {
269
272
  }
270
273
  else {
271
274
  delete row[(this.options.entityConfig[entity] && this.options.entityConfig[entity].idColumn) || 'id']
275
+ let sqlValues = Object.values(row).map(d => {
276
+ if (d === null) {
277
+ return d
278
+ }
279
+ else {
280
+ if (typeof d === 'string') {
281
+ d = d.replace(/'/g, `''`)
282
+ }
283
+ return `'${d}'`
284
+ // (d === null ? `${d}` : `'${d.replace(/'/)}'`)
285
+ }
286
+ }).join(',')
272
287
  sql += `
273
288
  INSERT INTO ${entity} (${Object.keys(row).join(',')})
274
- VALUES (${Object.values(row).map(d => (d === null ? `${d}` : `'${d}'`)).join(',')})
289
+ VALUES (${sqlValues})
275
290
  RETURNING ${(this.options.entityConfig[entity] && this.options.entityConfig[entity].idColumn) || 'id'};
276
291
  `
277
292
  }
@@ -24,10 +24,12 @@ module.exports = function (options) {
24
24
  process.env.wdRoot = __dirname
25
25
  let version = options.version || 'v1'
26
26
  process.env.WD_VERSION = version
27
- app.use(bodyParser.json({limit: '5mb'}))
28
- app.use(bodyParser.urlencoded({limit: '5mb', extended: true}))
29
- app.use(bodyParser.raw({limit: '5mb'}))
27
+ console.log('max body size is', options.maxBodySize)
28
+ app.use(bodyParser.json({limit: options.maxBodySize || '5mb'}))
29
+ app.use(bodyParser.urlencoded({limit: options.maxBodySize || '5mb', extended: true}))
30
+ app.use(bodyParser.raw({limit: options.maxBodySize || '5mb'}))
30
31
  const AuthHelper = require(`./helpers/${version}/authHelper`)
32
+ const NoAuthHelper = require(`./helpers/${version}/noAuthHelper`)
31
33
  const allowCrossDomain = (req, res, next) => {
32
34
  // console.log(req.url);
33
35
  // const allowedOrigins = ['https://www.google.com', 'http://localhost:4000', 'https://localhost:4000', 'http://ec2-3-92-185-52.compute-1.amazonaws.com', 'https://ec2-3-92-185-52.compute-1.amazonaws.com']
@@ -128,6 +130,9 @@ module.exports = function (options) {
128
130
  }
129
131
  app.use('/auth', require(`./routes/${version}/auth`)(dbHelper, options.dbEngine, app, options.strategy))
130
132
  }
133
+ else {
134
+ app.authHelper = new NoAuthHelper()
135
+ }
131
136
  const protectedRoutes = function (req, res, next) {
132
137
  let secureRoutes = true
133
138
  if (process.env.SECURE_ROUTES) {
@@ -1909,6 +1909,7 @@ class WebsyDropdown {
1909
1909
  const headerPos = WebsyUtils.getElementPos(headerEl)
1910
1910
  const contentPos = WebsyUtils.getElementPos(contentEl)
1911
1911
  if (this.options.style === 'plain' && headerPos.width > 0 && headerPos.height > 0) {
1912
+ contentEl.style.left = 'unset'
1912
1913
  contentEl.style.right = `calc(100vw - ${headerPos.right}px)`
1913
1914
  contentEl.style.width = `${Math.max(this.options.minWidth, headerEl.clientWidth)}px`
1914
1915
  if (headerPos.bottom + contentPos.height > window.innerHeight) {
@@ -1921,6 +1922,7 @@ class WebsyDropdown {
1921
1922
  }
1922
1923
  else if (this.options.style === 'plain' && headerPos.width === 0 && headerPos.height === 0) {
1923
1924
  const targetPos = WebsyUtils.getElementPos(event.target)
1925
+ contentEl.style.left = 'unset'
1924
1926
  contentEl.style.right = `calc(100vw - ${targetPos.right}px)`
1925
1927
  contentEl.style.width = `${Math.max(this.options.minWidth, targetPos.width)}px`
1926
1928
  }
@@ -2006,7 +2008,8 @@ class WebsyDropdown {
2006
2008
  }
2007
2009
  get value () {
2008
2010
  if (this.selectedItems && this.selectedItems.length > 0) {
2009
- return this.selectedItems.map((d, i) => this.options.items[+d])
2011
+ // return this.selectedItems.map((d, i) => this.options.items[+d])
2012
+ return this.selectedItems.map((d, i) => this._originalData[+d])
2010
2013
  }
2011
2014
  return []
2012
2015
  }
@@ -2486,7 +2489,7 @@ class WebsyForm {
2486
2489
  if (f.component) {
2487
2490
  componentsToProcess.push(f)
2488
2491
  html += `
2489
- ${i > 0 ? '-->' : ''}<div id='${this.elementId}_${f.field}_inputContainer' style='${f.style || ''}' class='websy-input-container ${f.classes ? f.classes.join(' ') : ''}'>
2492
+ ${i > 0 ? '-->' : ''}<div id='${this.elementId}_${f.field}_inputContainer' style='${f.style || ''}' class='websy-input-container ${f.classes ? f.classes.join(' ') : ''} ${f.component === 'MediaUpload' ? 'media-upload' : ''}'>
2490
2493
  ${f.label ? `<label for="${f.field}">${f.label}</label>` : ''}${f.required === true ? '<span class="websy-form-required-value">*</span>' : ''}
2491
2494
  <div id='${this.elementId}_input_${f.field}_component' class='form-component'></div>
2492
2495
  <span id='${this.elementId}_${f.field}_error' class='websy-form-validation-error'></span>
@@ -2506,7 +2509,7 @@ class WebsyForm {
2506
2509
  name="${f.field}"
2507
2510
  ${(f.attributes || []).join(' ')}
2508
2511
  class="websy-input websy-textarea"
2509
- ></textarea>
2512
+ >${f.value || ''}</textarea>
2510
2513
  <span id='${this.elementId}_${f.field}_error' class='websy-form-validation-error'></span>
2511
2514
  </div><!--
2512
2515
  `
@@ -2525,7 +2528,7 @@ class WebsyForm {
2525
2528
  ${(f.attributes || []).join(' ')}
2526
2529
  name="${f.field}"
2527
2530
  placeholder="${f.placeholder || ''}"
2528
- value="${f.value || ''}"
2531
+ value="${f.type === 'date' ? '' : f.value || ''}"
2529
2532
  valueAsDate="${f.type === 'date' ? f.value : ''}"
2530
2533
  oninvalidx="this.setCustomValidity('${f.invalidMessage || 'Please fill in this field.'}')"
2531
2534
  />
@@ -2573,6 +2576,9 @@ class WebsyForm {
2573
2576
  if (this.fieldMap[field].type === 'checkbox') {
2574
2577
  el.checked = value
2575
2578
  }
2579
+ if (this.fieldMap[field].type === 'date') {
2580
+ el.valueAsDate = value
2581
+ }
2576
2582
  }
2577
2583
  else {
2578
2584
  console.error(`Input for ${field} does not exist in form.`)
@@ -2717,10 +2723,12 @@ class MultiForm {
2717
2723
  constructor (elementId, options) {
2718
2724
  this.elementId = elementId
2719
2725
  const DEFAULTS = {
2720
- addButton: `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 512 512"><line x1="256" y1="112" x2="256" y2="400" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="400" y1="256" x2="112" y2="256" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>`,
2721
- deleteButton: `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 512 512"><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>`,
2726
+ addIcon: `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 512 512"><line x1="256" y1="112" x2="256" y2="400" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="400" y1="256" x2="112" y2="256" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>`,
2727
+ deleteIcon: `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 512 512"><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>`,
2722
2728
  allowAdd: true,
2723
- allowDelete: true
2729
+ allowDelete: true,
2730
+ addLabel: '',
2731
+ deleteLabel: ''
2724
2732
  }
2725
2733
  this.options = Object.assign({}, DEFAULTS, options)
2726
2734
  this.formData = []
@@ -2729,7 +2737,12 @@ class MultiForm {
2729
2737
  const el = document.getElementById(elementId)
2730
2738
  if (el) {
2731
2739
  el.addEventListener('click', this.handleClick.bind(this))
2732
- el.innerHTML = `<div id='${elementId}_container' class='websy-multi-form-container'></div>`
2740
+ el.innerHTML = `
2741
+ <div id='${elementId}_container' class='websy-multi-form-container'></div>
2742
+ <button id='${this.elementId}_addButton' class='websy-multi-form-add'>
2743
+ ${this.options.addIcon}${this.options.addLabel}
2744
+ </button>
2745
+ `
2733
2746
  }
2734
2747
  this.render()
2735
2748
  }
@@ -2738,24 +2751,28 @@ class MultiForm {
2738
2751
  this.render()
2739
2752
  }
2740
2753
  addEntry () {
2741
- const el = document.getElementById(`${this.elementId}_container`)
2742
- let newId = WebsyDesigns.Utils.createIdentity()
2743
- const newFormEl = document.createElement('div')
2744
- newFormEl.id = `${this.elementId}_${newId}_formContainer`
2745
- newFormEl.classList.add('websy-multi-form-form-container')
2746
- newFormEl.innerHTML = `
2747
- <div id='${this.elementId}_${newId}_form' class='websy-multi-form-form'>
2748
- </div>
2749
- <button id='${this.elementId}_${newId}_deleteButton' data-formid='${newId}' class='hidden websy-multi-form-delete'>
2750
- ${this.options.deleteButton}
2751
- </button>
2752
- <button id='${this.elementId}_${newId}_addButton' data-formid='${newId}' class='websy-multi-form-add'>
2753
- ${this.options.addButton}
2754
- </button>
2755
- `
2756
- el.appendChild(newFormEl)
2757
- let formOptions = Object.assign({}, this.options, { fields: [...this.options.fields.map(f => Object.assign({}, f))] })
2758
- this.forms.push(new WebsyDesigns.Form(`${this.elementId}_${newId}_form`, formOptions))
2754
+ const addEl = document.getElementById(`${this.elementId}_addButton`)
2755
+ if (typeof this.options.maxRows === 'undefined' || this.forms.length < this.options.maxRows) {
2756
+ const el = document.getElementById(`${this.elementId}_container`)
2757
+ let newId = WebsyDesigns.Utils.createIdentity()
2758
+ const newFormEl = document.createElement('div')
2759
+ newFormEl.id = `${this.elementId}_${newId}_formContainer`
2760
+ newFormEl.classList.add('websy-multi-form-form-container')
2761
+ let html = `
2762
+ <div id='${this.elementId}_${newId}_form' class='websy-multi-form-form'>
2763
+ </div>
2764
+ <button id='${this.elementId}_${newId}_deleteButton' data-formid='${newId}' class='websy-multi-form-delete'>
2765
+ ${this.options.deleteIcon}${this.options.deleteLabel}
2766
+ </button>
2767
+ `
2768
+ newFormEl.innerHTML = html
2769
+ el.appendChild(newFormEl)
2770
+ let formOptions = Object.assign({}, this.options, { fields: [...this.options.fields.map(f => Object.assign({}, f))] })
2771
+ this.forms.push(new WebsyDesigns.Form(`${this.elementId}_${newId}_form`, formOptions))
2772
+ if (addEl) {
2773
+ addEl.style.display = this.forms.length < this.options.maxRows ? 'flex' : 'none'
2774
+ }
2775
+ }
2759
2776
  }
2760
2777
  clear () {
2761
2778
  this.formData = []
@@ -2767,12 +2784,7 @@ class MultiForm {
2767
2784
  }
2768
2785
  }
2769
2786
  get data () {
2770
- const d = this.forms.map(f => (f.data))
2771
- console.log('forms data', d)
2772
- if (this.options.allowAdd !== false) {
2773
- // we don't return the last form
2774
- d.pop()
2775
- }
2787
+ const d = this.forms.map(f => (f.data))
2776
2788
  return d
2777
2789
  }
2778
2790
  set data (d) {
@@ -2784,16 +2796,6 @@ class MultiForm {
2784
2796
  }
2785
2797
  handleClick (event) {
2786
2798
  if (event.target.classList.contains('websy-multi-form-add')) {
2787
- let id = event.target.getAttribute('data-formid')
2788
- // hide add button and show delete button
2789
- const addButtonEl = document.getElementById(`${this.elementId}_${id}_addButton`)
2790
- if (addButtonEl) {
2791
- addButtonEl.classList.add('hidden')
2792
- }
2793
- const deleteButtonEl = document.getElementById(`${this.elementId}_${id}_deleteButton`)
2794
- if (deleteButtonEl) {
2795
- deleteButtonEl.classList.remove('hidden')
2796
- }
2797
2799
  // add new form
2798
2800
  if (this.options.allowAdd === true) {
2799
2801
  this.addEntry()
@@ -2818,6 +2820,10 @@ class MultiForm {
2818
2820
  if (el) {
2819
2821
  el.remove()
2820
2822
  }
2823
+ const addEl = document.getElementById(`${this.elementId}_addButton`)
2824
+ if (addEl) {
2825
+ addEl.style.display = (typeof this.options.maxRows === 'undefined' || this.forms.length < this.options.maxRows) ? 'flex' : 'none'
2826
+ }
2821
2827
  // delete form element based on id
2822
2828
  }
2823
2829
  }
@@ -2837,7 +2843,7 @@ class MultiForm {
2837
2843
  if (this.options.allowDelete === true) {
2838
2844
  html += `
2839
2845
  <button id='${this.elementId}_${d.formId}_deleteButton' data-formid='${d.formId}' data-rowid='${d.id}' class='websy-multi-form-delete'>
2840
- ${this.options.deleteButton}
2846
+ ${this.options.deleteIcon}${this.options.deleteLabel}
2841
2847
  </button>
2842
2848
  `
2843
2849
  }
@@ -2846,20 +2852,6 @@ class MultiForm {
2846
2852
  `
2847
2853
  })
2848
2854
  let id = WebsyDesigns.Utils.createIdentity()
2849
- if (this.options.allowAdd === true) {
2850
- html += `
2851
- <div id='${this.elementId}_${id}_formContainer' class='websy-multi-form-form-container'>
2852
- <div id='${this.elementId}_${id}_form' class='websy-multi-form-form'>
2853
- </div>
2854
- <button id='${this.elementId}_${id}_deleteButton' data-formid='${id}' class='hidden websy-multi-form-delete'>
2855
- ${this.options.deleteButton}
2856
- </button>
2857
- <button id='${this.elementId}_${id}_addButton' data-formid='${id}' class='websy-multi-form-add'>
2858
- ${this.options.addButton}
2859
- </button>
2860
- </div>
2861
- `
2862
- }
2863
2855
  el.innerHTML = html
2864
2856
  this.forms = new Array(this.formData.length)
2865
2857
  this.formData.forEach((d, i) => {
@@ -2868,11 +2860,15 @@ class MultiForm {
2868
2860
  formObject.data = d
2869
2861
  this.forms[i] = formObject
2870
2862
  })
2871
- if (this.options.allowAdd === true) {
2872
- let formOptions = Object.assign({}, this.options, { fields: [...this.options.fields.map(f => Object.assign({}, f))] })
2873
- let formObject = new WebsyDesigns.Form(`${this.elementId}_${id}_form`, formOptions)
2874
- this.forms.push(formObject)
2875
- }
2863
+ const addEl = document.getElementById(`${this.elementId}_addButton`)
2864
+ if (addEl) {
2865
+ if (this.options.allowAdd === true) {
2866
+ addEl.style.display = (typeof this.options.maxRows === 'undefined' || this.forms.length < this.options.maxRows) ? 'flex' : 'none'
2867
+ }
2868
+ else {
2869
+ addEl.style.display = 'none'
2870
+ }
2871
+ }
2876
2872
  }
2877
2873
  }
2878
2874
  validateForm () {
@@ -3664,7 +3660,7 @@ class WebsyPDFButton {
3664
3660
  else {
3665
3661
  fileName = this.options.fileName || 'Export'
3666
3662
  }
3667
- msg += `download='${fileName}.pdf'`
3663
+ msg += `download="${fileName.replace(/'/g, '')}.pdf"`
3668
3664
  }
3669
3665
  msg += `
3670
3666
  >
@@ -4375,7 +4371,11 @@ class WebsyResultList {
4375
4371
  }
4376
4372
  }
4377
4373
 
4378
- /* global history */
4374
+ /*
4375
+ global
4376
+ history
4377
+ WebsyDesigns
4378
+ */
4379
4379
  class WebsyRouter {
4380
4380
  constructor (options) {
4381
4381
  const defaults = {
@@ -4392,6 +4392,7 @@ class WebsyRouter {
4392
4392
  persistentParameters: false,
4393
4393
  fieldValueSeparator: ':'
4394
4394
  }
4395
+ this.apiService = new WebsyDesigns.APIService('')
4395
4396
  this.triggerIdList = []
4396
4397
  this.viewIdList = []
4397
4398
  this.previousPath = ''
@@ -4424,7 +4425,7 @@ class WebsyRouter {
4424
4425
  }
4425
4426
  addGroup (group) {
4426
4427
  if (!this.groups[group]) {
4427
- const els = document.querySelectorAll(`.websy-view[data-group="${group}"]`)
4428
+ const els = document.querySelectorAll(`.${this.options.viewClass}[data-group="${group}"]`)
4428
4429
  if (els) {
4429
4430
  this.getClosestParent(els[0], parent => {
4430
4431
  this.groups[group] = {
@@ -4543,9 +4544,9 @@ class WebsyRouter {
4543
4544
  if (!this.groups) {
4544
4545
  this.groups = {}
4545
4546
  }
4546
- const parentEl = document.querySelector(`.websy-view[data-view="${parent}"]`)
4547
+ const parentEl = document.querySelector(`.${this.options.viewClass}[data-view="${parent}"]`)
4547
4548
  if (parentEl) {
4548
- const els = parentEl.querySelectorAll(`.websy-view[data-group]`)
4549
+ const els = parentEl.querySelectorAll(`.${this.options.viewClass}[data-group]`)
4549
4550
  for (let i = 0; i < els.length; i++) {
4550
4551
  const g = els[i].getAttribute('data-group')
4551
4552
  const v = els[i].getAttribute('data-view')
@@ -4803,27 +4804,85 @@ class WebsyRouter {
4803
4804
  })
4804
4805
  }
4805
4806
  }
4807
+ preloadView (view, callbackFn) {
4808
+ if (this.options.views[view].load) {
4809
+ this.options.views[view].load(callbackFn)
4810
+ }
4811
+ }
4812
+ initView (view) {
4813
+ return new Promise((resolve, reject) => {
4814
+ if (!this.options.views[view]) {
4815
+ this.options.views[view] = {
4816
+ components: []
4817
+ }
4818
+ }
4819
+ if (this.options.views[view].ready === true) {
4820
+ resolve()
4821
+ }
4822
+ else if (this.options.views[view].template) {
4823
+ this.preloadView(view, (data = {}) => {
4824
+ const viewEl = document.querySelector(`[data-view='${view}'].${this.options.viewClass}`)
4825
+ if (viewEl) {
4826
+ this.options.views[view].templateInstance = new WebsyDesigns.Template(viewEl, {
4827
+ template: this.options.views[view].template,
4828
+ data,
4829
+ readyCallbackFn: () => {
4830
+ this.options.views[view].ready = true
4831
+ resolve()
4832
+ }
4833
+ })
4834
+ }
4835
+ else {
4836
+ console.log(`No view element found for '${view}' to render template`)
4837
+ this.options.views[view].ready = true
4838
+ resolve()
4839
+ }
4840
+ })
4841
+ }
4842
+ else if (this.options.views[view].ready !== true && this.options.views[view].load) {
4843
+ this.preloadView(view, (data = {}) => {
4844
+ this.options.views[view].ready = true
4845
+ resolve()
4846
+ })
4847
+ }
4848
+ else {
4849
+ this.options.views[view].ready = true
4850
+ resolve()
4851
+ }
4852
+ })
4853
+ }
4806
4854
  showView (view, params, group) {
4807
4855
  if (view === '/' || view === '') {
4808
4856
  view = this.options.defaultView || ''
4809
4857
  }
4810
- this.activateItem(view, this.options.triggerClass)
4811
- this.activateItem(view, this.options.viewClass)
4812
- let children = this.getActiveViewsFromParent(view)
4813
- for (let c = 0; c < children.length; c++) {
4814
- this.activateItem(children[c].view, this.options.triggerClass)
4815
- this.activateItem(children[c].view, this.options.viewClass)
4816
- this.showComponents(children[c].view)
4817
- this.publish('show', [children[c].view, null, group])
4818
- }
4819
- if (this.previousView !== this.currentView || group !== 'main') {
4820
- this.showComponents(view)
4821
- this.publish('show', [view, params, group])
4822
- }
4823
- else if (this.previousView === this.currentView && this.previousParams.path !== this.currentParams.path) {
4824
- this.showComponents(view)
4825
- this.publish('show', [view, params, group])
4826
- }
4858
+ this.initView(view).then(() => {
4859
+ this.activateItem(view, this.options.triggerClass)
4860
+ this.activateItem(view, this.options.viewClass)
4861
+ let children = this.getActiveViewsFromParent(view)
4862
+ for (let c = 0; c < children.length; c++) {
4863
+ this.activateItem(children[c].view, this.options.triggerClass)
4864
+ this.activateItem(children[c].view, this.options.viewClass)
4865
+ this.showComponents(children[c].view)
4866
+ if (children[c].show) {
4867
+ children[c].show.call(children[c])
4868
+ }
4869
+ this.publish('show', [children[c].view, null, group])
4870
+ }
4871
+ if (this.previousView !== this.currentView || group !== 'main') {
4872
+ this.showComponents(view)
4873
+ if (this.options.views[view].show) {
4874
+ this.options.views[view].show.call(this.options.views[view])
4875
+ }
4876
+ this.publish('show', [view, params, group])
4877
+ }
4878
+ else if (this.previousView === this.currentView && this.previousParams.path !== this.currentParams.path) {
4879
+ this.showComponents(view)
4880
+ if (this.options.views[view].show) {
4881
+ this.options.views[view].show.call(this.options.views[view])
4882
+ }
4883
+ this.publish('show', [view, params, group])
4884
+ }
4885
+ })
4827
4886
  }
4828
4887
  reloadCurrentView () {
4829
4888
  this.showView(this.currentView, this.currentParams, 'main')
@@ -5114,7 +5173,18 @@ class WebsyTemplate {
5114
5173
  }
5115
5174
  }
5116
5175
  this.options = Object.assign({}, DEFAULTS, options)
5117
- this.elementId = elementId
5176
+ if (typeof elementId === 'object') {
5177
+ if (elementId.id) {
5178
+ this.elementId = elementId.id
5179
+ }
5180
+ else {
5181
+ elementId.id = WebsyDesigns.Utils.createIdentity()
5182
+ this.elementId = elementId.id
5183
+ }
5184
+ }
5185
+ else {
5186
+ this.elementId = elementId
5187
+ }
5118
5188
  this.templateService = new WebsyDesigns.APIService('')
5119
5189
  if (!elementId) {
5120
5190
  console.log('No element Id provided for Websy Template')
@@ -5232,6 +5302,10 @@ class WebsyTemplate {
5232
5302
  }
5233
5303
  return html
5234
5304
  }
5305
+ set data (d) {
5306
+ this.options.data = d
5307
+ this.render()
5308
+ }
5235
5309
  handleClick (event) {
5236
5310
  if (event.target.classList.contains('clickable')) {
5237
5311
  this.handleEvent(event, 'clickable', 'click')
@@ -9971,8 +10045,10 @@ class WebsyKPI {
9971
10045
  }
9972
10046
  html += `
9973
10047
  <div class="websy-kpi-info">
9974
- <div class="websy-kpi-label ${this.options.label.classes.join(' ') || ''}">
9975
- ${(this.options.label || {}).value || ''}
10048
+ <div class="websy-kpi-label-container">
10049
+ <div class="websy-kpi-label ${this.options.label.classes.join(' ') || ''}">
10050
+ ${(this.options.label || {}).value || ''}
10051
+ </div>
9976
10052
  `
9977
10053
  if (this.options.tooltip && this.options.tooltip.value) {
9978
10054
  html += `