@websy/websy-designs 1.3.3 → 1.3.5

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.
@@ -2465,7 +2465,7 @@ class WebsyLogin {
2465
2465
  }
2466
2466
  }
2467
2467
 
2468
- /* global */
2468
+ /* global WebsyDesigns */
2469
2469
  class WebsyNavigationMenu {
2470
2470
  constructor (elementId, options) {
2471
2471
  this.options = Object.assign({}, {
@@ -2473,20 +2473,28 @@ class WebsyNavigationMenu {
2473
2473
  orientation: 'horizontal',
2474
2474
  parentMap: {},
2475
2475
  childIndentation: 10,
2476
- activeSymbol: 'none'
2476
+ activeSymbol: 'none',
2477
+ enableSearch: false,
2478
+ searchProp: 'text',
2479
+ menuIcon: `<svg viewbox="0 0 40 40" width="30" height="40">
2480
+ <rect x="0" y="0" width="30" height="4" rx="2"></rect>
2481
+ <rect x="0" y="12" width="30" height="4" rx="2"></rect>
2482
+ <rect x="0" y="24" width="30" height="4" rx="2"></rect>
2483
+ </svg>`,
2484
+ searchOptions: {}
2477
2485
  }, options)
2478
2486
  if (!elementId) {
2479
2487
  console.log('No element Id provided for Websy Menu')
2480
2488
  return
2481
2489
  }
2490
+ this.maxLevel = 0
2482
2491
  const el = document.getElementById(elementId)
2483
2492
  if (el) {
2484
2493
  this.elementId = elementId
2485
2494
  this.lowestLevel = 0
2486
2495
  this.flatItems = []
2487
2496
  this.itemMap = {}
2488
- this.flattenItems(0, this.options.items)
2489
- console.log(this.flatItems)
2497
+ this.flattenItems(0, this.options.items)
2490
2498
  el.classList.add(`websy-${this.options.orientation}-list-container`)
2491
2499
  el.classList.add('websy-menu')
2492
2500
  if (this.options.align) {
@@ -2498,27 +2506,27 @@ class WebsyNavigationMenu {
2498
2506
  if (this.options.classes) {
2499
2507
  this.options.classes.split(' ').forEach(c => el.classList.add(c))
2500
2508
  }
2501
- el.addEventListener('click', this.handleClick.bind(this))
2509
+ el.addEventListener('click', this.handleClick.bind(this))
2502
2510
  this.render()
2503
2511
  }
2504
2512
  }
2505
- flattenItems (index, items, level = 0) {
2513
+ flattenItems (index, items, level = 0, path = '') {
2506
2514
  if (items[index]) {
2507
2515
  this.lowestLevel = Math.max(level, this.lowestLevel)
2508
2516
  items[index].id = items[index].id || `${this.elementId}_${this.normaliseString(items[index].text)}`
2509
- this.itemMap[items[index].id] = items[index]
2510
2517
  items[index].level = level
2518
+ items[index].hasChildren = items[index].items && items[index].items.length > 0
2519
+ items[index].path = path !== '' ? `${path}::${items[index].id}` : items[index].id
2520
+ this.itemMap[items[index].id] = Object.assign({}, items[index])
2511
2521
  this.flatItems.push(items[index])
2512
2522
  if (items[index].items) {
2513
- this.flattenItems(0, items[index].items, level + 1)
2523
+ this.flattenItems(0, items[index].items, level + 1, items[index].path)
2514
2524
  }
2515
- this.flattenItems(++index, items, level)
2525
+ this.flattenItems(++index, items, level, path)
2516
2526
  }
2517
2527
  }
2518
2528
  handleClick (event) {
2519
- if (event.target.classList.contains('websy-menu-icon') ||
2520
- event.target.nodeName === 'svg' ||
2521
- event.target.nodeName === 'rect') {
2529
+ if (event.target.classList.contains('websy-menu-icon')) {
2522
2530
  this.toggleMobileMenu()
2523
2531
  }
2524
2532
  if (event.target.classList.contains('websy-menu-header')) {
@@ -2526,7 +2534,7 @@ class WebsyNavigationMenu {
2526
2534
  if (event.target.classList.contains('trigger-item') && item.level === this.lowestLevel) {
2527
2535
  this.toggleMobileMenu('remove')
2528
2536
  }
2529
- if (item.items) {
2537
+ if (item.hasChildren === true) {
2530
2538
  event.target.classList.toggle('menu-open')
2531
2539
  this.toggleMenu(item.id)
2532
2540
  }
@@ -2535,6 +2543,42 @@ class WebsyNavigationMenu {
2535
2543
  this.toggleMobileMenu()
2536
2544
  }
2537
2545
  }
2546
+ handleSearch (searchText) {
2547
+ const el = document.getElementById(this.elementId)
2548
+ let lowestItems = this.flatItems.filter(d => d.level === this.maxLevel)
2549
+ let visibleItems = lowestItems
2550
+ let defaultMethod = 'remove'
2551
+ if (searchText.length > 1) {
2552
+ defaultMethod = 'add'
2553
+ visibleItems = lowestItems.filter(d => d[this.options.searchProp].toLowerCase().indexOf(searchText.toLowerCase()) !== -1)
2554
+ }
2555
+ // hide everything
2556
+ const textEls = el.querySelectorAll(`div.websy-menu-header`)
2557
+ for (let t = 0; t < textEls.length; t++) {
2558
+ textEls[t].classList[defaultMethod]('websy-hidden')
2559
+ }
2560
+ const listEls = el.querySelectorAll(`ul.websy-child-list`)
2561
+ for (let l = 0; l < listEls.length; l++) {
2562
+ listEls[l].classList.add('websy-menu-collapsed')
2563
+ }
2564
+ if (searchText.length > 1) {
2565
+ visibleItems.forEach(d => {
2566
+ // show the item and open the list
2567
+ let pathParts = d.path.split('::')
2568
+ pathParts.forEach(p => {
2569
+ const textEl = document.getElementById(p)
2570
+ if (textEl) {
2571
+ textEl.classList.remove('websy-hidden')
2572
+ }
2573
+ const listEl = document.getElementById(`${p}_list`)
2574
+ if (listEl) {
2575
+ listEl.classList.remove('websy-menu-collapsed')
2576
+ }
2577
+ })
2578
+ })
2579
+ }
2580
+ console.log('visibleItems', visibleItems)
2581
+ }
2538
2582
  normaliseString (text) {
2539
2583
  return text.replace(/-/g, '').replace(/\s/g, '_')
2540
2584
  }
@@ -2545,14 +2589,10 @@ class WebsyNavigationMenu {
2545
2589
  if (this.options.collapsible === true) {
2546
2590
  html += `
2547
2591
  <div id='${this.elementId}_menuIcon' class='websy-menu-icon'>
2548
- <svg viewbox="0 0 40 40" width="30" height="40">
2549
- <rect x="0" y="0" width="30" height="4" rx="2"></rect>
2550
- <rect x="0" y="12" width="30" height="4" rx="2"></rect>
2551
- <rect x="0" y="24" width="30" height="4" rx="2"></rect>
2552
- </svg>
2592
+ ${this.options.menuIcon}
2553
2593
  </div>
2554
2594
  `
2555
- }
2595
+ }
2556
2596
  if (this.options.logo) {
2557
2597
  if (Array.isArray(this.options.logo.classes)) {
2558
2598
  this.options.logo.classes = this.options.logo.classes.join(' ')
@@ -2568,14 +2608,25 @@ class WebsyNavigationMenu {
2568
2608
  <div id="${this.elementId}_menuContainer" class="websy-menu-block-container">
2569
2609
  `
2570
2610
  }
2571
- html += this.renderBlock(this.options.items, 'main', 0)
2611
+ if (this.options.enableSearch === true) {
2612
+ html += `
2613
+ <div id='${this.elementId}_search' class='websy-menu-search'></div>
2614
+ `
2615
+ }
2616
+ html += this.renderBlock(this.elementId, this.elementId, this.options.items, 'main', 0)
2572
2617
  html += `</div>`
2573
2618
  el.innerHTML = html
2619
+ if (this.options.enableSearch === true) {
2620
+ this.search = new WebsyDesigns.Search(`${this.elementId}_search`, Object.assign({}, {
2621
+ onSearch: this.handleSearch.bind(this)
2622
+ }, this.options.searchOptions))
2623
+ }
2574
2624
  }
2575
2625
  }
2576
- renderBlock (items, block, level = 0) {
2626
+ renderBlock (id, path, items, block, level = 0) {
2627
+ this.maxLevel = Math.max(this.maxLevel, level)
2577
2628
  let html = `
2578
- <ul class='websy-${this.options.orientation}-list ${level > 0 ? 'websy-child-list' : ''} ${(block !== 'main' ? 'websy-menu-collapsed' : '')}' id='${this.elementId}_${block}_list'
2629
+ <ul class='websy-${this.options.orientation}-list ${level > 0 ? 'websy-child-list' : ''} ${(block !== 'main' ? 'websy-menu-collapsed' : '')}' id='${id}_list' data-path='${path}'
2579
2630
  `
2580
2631
  if (block !== 'main') {
2581
2632
  html += ` data-collapsed='${(block !== 'main' ? 'true' : 'false')}'`
@@ -2593,13 +2644,14 @@ class WebsyNavigationMenu {
2593
2644
  html += `
2594
2645
  <li class='websy-${this.options.orientation}-list-item ${items[i].alwaysOpen === true ? 'always-open' : ''}'>
2595
2646
  <div class='websy-menu-header ${items[i].classes || ''} ${selected} ${active}'
2596
- id='${blockId}'
2597
- data-id='${currentBlock}'
2598
- data-menu-id='${this.elementId}_${currentBlock}_list'
2599
- data-popout-id='${level > 1 ? block : currentBlock}'
2600
- data-text='${items[i].isLink !== true ? items[i].text : ''}'
2601
- style='padding-left: ${level * this.options.childIndentation}px'
2602
- ${(items[i].attributes && items[i].attributes.join(' ')) || ''}
2647
+ id='${blockId}'
2648
+ data-id='${currentBlock}'
2649
+ data-path='${items[i].path}'
2650
+ data-menu-id='${this.elementId}_${currentBlock}_list'
2651
+ data-popout-id='${level > 1 ? block : currentBlock}'
2652
+ data-text='${items[i].isLink !== true ? items[i].text : ''}'
2653
+ style='padding-left: ${level * this.options.childIndentation}px'
2654
+ ${(items[i].attributes && items[i].attributes.join(' ')) || ''}
2603
2655
  >
2604
2656
  `
2605
2657
  if (this.options.orientation === 'horizontal') {
@@ -2619,9 +2671,9 @@ class WebsyNavigationMenu {
2619
2671
  <span class='${items[i].items && items[i].items.length > 0 ? 'menu-carat' : ''}'></span>
2620
2672
  `
2621
2673
  if (this.options.orientation === 'vertical') {
2622
- html += `
2623
- &nbsp;
2624
- `
2674
+ // html += `
2675
+ // &nbsp;
2676
+ // `
2625
2677
  }
2626
2678
  if (items[i].isLink === true && items[i].href) {
2627
2679
  html += `<a href='${items[i].href}'>${items[i].text}</a>`
@@ -2630,7 +2682,7 @@ class WebsyNavigationMenu {
2630
2682
  </div>
2631
2683
  `
2632
2684
  if (items[i].items) {
2633
- html += this.renderBlock(items[i].items, currentBlock, items[i].level + 1)
2685
+ html += this.renderBlock(blockId, items[i].path, items[i].items, currentBlock, items[i].level + 1)
2634
2686
  }
2635
2687
  // map the item to it's parent
2636
2688
  if (block && block !== 'main') {
@@ -2647,6 +2699,8 @@ class WebsyNavigationMenu {
2647
2699
  }
2648
2700
  toggleMenu (id) {
2649
2701
  const el = document.getElementById(`${id}_list`)
2702
+ // const menuId = el.getAttribute('data-menu-id')
2703
+ // const menuEl = document.getElementById(menuId)
2650
2704
  if (el) {
2651
2705
  el.classList.toggle('websy-menu-collapsed')
2652
2706
  }
@@ -3337,7 +3391,7 @@ class WebsyResultList {
3337
3391
  const el = document.getElementById(this.elementId)
3338
3392
  el.innerHTML += html.replace(/\n/g, '')
3339
3393
  }
3340
- buildHTML (d, startIndex = 0, inputTemplate) {
3394
+ buildHTML (d, startIndex = 0, inputTemplate, locator = []) {
3341
3395
  let html = ``
3342
3396
  if (this.options.template) {
3343
3397
  if (d.length > 0) {
@@ -3439,13 +3493,13 @@ class WebsyResultList {
3439
3493
  parts.forEach(p => {
3440
3494
  items = items[p]
3441
3495
  })
3442
- template = template.replace(m[0], this.buildHTML(items, 0, withoutFor))
3496
+ template = template.replace(m[0], this.buildHTML(items, 0, withoutFor, [...locator, `${startIndex + ix}:${c}`]))
3443
3497
  }
3444
3498
  })
3445
3499
  let tagMatches = [...template.matchAll(/(\sdata-event=["|']\w.+)["|']/g)]
3446
3500
  tagMatches.forEach(m => {
3447
3501
  if (m[0] && m.index > -1) {
3448
- template = template.replace(m[0], `${m[0]} data-id=${startIndex + ix}`)
3502
+ template = template.replace(m[0], `${m[0]} data-id=${startIndex + ix} data-locator='${locator.join(';')}'`)
3449
3503
  }
3450
3504
  })
3451
3505
  let flatRow = this.flattenObject(row)
@@ -3506,15 +3560,30 @@ class WebsyResultList {
3506
3560
  l = l.split('(')
3507
3561
  let params = []
3508
3562
  const id = event.target.getAttribute('data-id')
3563
+ const locator = event.target.getAttribute('data-locator')
3509
3564
  if (l[1]) {
3510
3565
  l[1] = l[1].replace(')', '')
3511
3566
  params = l[1].split(',')
3512
3567
  }
3513
3568
  l = l[0]
3569
+ let data = this.rows
3570
+ if (locator !== '') {
3571
+ let locatorItems = locator.split(';')
3572
+ locatorItems.forEach(loc => {
3573
+ let locatorParts = loc.split(':')
3574
+ if (data[locatorParts[0]]) {
3575
+ data = data[locatorParts[0]]
3576
+ let parts = locatorParts[1].split('.')
3577
+ parts.forEach(p => {
3578
+ data = data[p]
3579
+ })
3580
+ }
3581
+ })
3582
+ }
3514
3583
  params = params.map(p => {
3515
3584
  if (typeof p !== 'string' && typeof p !== 'number') {
3516
- if (this.rows[+id]) {
3517
- p = this.rows[+id][p]
3585
+ if (data[+id]) {
3586
+ p = data[+id][p]
3518
3587
  }
3519
3588
  }
3520
3589
  else if (typeof p === 'string') {
@@ -3524,7 +3593,7 @@ class WebsyResultList {
3524
3593
  })
3525
3594
  if (event.target.classList.contains('clickable') && this.options.listeners.click[l]) {
3526
3595
  event.stopPropagation()
3527
- this.options.listeners.click[l].call(this, event, this.rows[+id], ...params)
3596
+ this.options.listeners.click[l].call(this, event, data[+id], ...params)
3528
3597
  }
3529
3598
  }
3530
3599
  }
@@ -3569,7 +3638,14 @@ class WebsyRouter {
3569
3638
  this.previousView = ''
3570
3639
  this.currentView = ''
3571
3640
  this.currentViewMain = ''
3572
- this.currentParams = {}
3641
+ this.currentParams = {
3642
+ path: '',
3643
+ items: {}
3644
+ }
3645
+ this.previousParams = {
3646
+ path: '',
3647
+ items: {}
3648
+ }
3573
3649
  this.controlPressed = false
3574
3650
  this.usesHTMLSuffix = window.location.pathname.indexOf('.htm') !== -1
3575
3651
  window.addEventListener('popstate', this.onPopState.bind(this))
@@ -3610,10 +3686,11 @@ class WebsyRouter {
3610
3686
  }
3611
3687
  }
3612
3688
  }
3613
- addUrlParams (params) {
3689
+ addUrlParams (params, reloadView = false) {
3614
3690
  if (typeof params === 'undefined') {
3615
3691
  return
3616
3692
  }
3693
+ this.previousParams = Object.assign({}, this.currentParams)
3617
3694
  const output = {
3618
3695
  path: '',
3619
3696
  items: {}
@@ -3635,6 +3712,9 @@ class WebsyRouter {
3635
3712
  history.pushState({
3636
3713
  inputPath
3637
3714
  }, inputPath, `${inputPath}?${path}`)
3715
+ if (reloadView === true) {
3716
+ this.showView(this.currentView, this.currentParams, 'main')
3717
+ }
3638
3718
  }
3639
3719
  buildUrlPath (params) {
3640
3720
  let path = []
@@ -3663,6 +3743,7 @@ class WebsyRouter {
3663
3743
  }
3664
3744
  }
3665
3745
  formatParams (params) {
3746
+ this.previousParams = Object.assign({}, this.currentParams)
3666
3747
  const output = {
3667
3748
  path: params,
3668
3749
  items: {}
@@ -3882,6 +3963,10 @@ class WebsyRouter {
3882
3963
  if (this.previousView !== this.currentView || group !== 'main') {
3883
3964
  this.showComponents(view)
3884
3965
  this.publish('show', [view, params, group])
3966
+ }
3967
+ if (this.previousView === this.currentView && this.previousParams.path !== this.currentParams.path) {
3968
+ this.showComponents(view)
3969
+ this.publish('show', [view, params, group])
3885
3970
  }
3886
3971
  }
3887
3972
  reloadCurrentView () {
@@ -3897,17 +3982,14 @@ class WebsyRouter {
3897
3982
  let groupActiveView
3898
3983
  let params = {}
3899
3984
  let newPath = inputPath
3900
- if (inputPath === this.options.defaultView && this.usesHTMLSuffix === false) {
3985
+ if (inputPath.split('?')[0] === this.options.defaultView && this.usesHTMLSuffix === false) {
3901
3986
  inputPath = inputPath.replace(this.options.defaultView, '/')
3902
3987
  }
3903
3988
  if (this.options.persistentParameters === true) {
3904
3989
  if (inputPath.indexOf('?') === -1 && this.queryParams) {
3905
3990
  inputPath += `?${this.queryParams}`
3906
3991
  }
3907
- }
3908
- else {
3909
- this.currentParams = {}
3910
- }
3992
+ }
3911
3993
  if (this.usesHTMLSuffix === true) {
3912
3994
  if (inputPath.indexOf('?') === -1) {
3913
3995
  inputPath = `?view=${inputPath}`
@@ -3928,7 +4010,11 @@ class WebsyRouter {
3928
4010
  inputPath = parts[0]
3929
4011
  }
3930
4012
  else if (group === this.options.defaultGroup) {
3931
- this.currentParams = {}
4013
+ this.previousParams = Object.assign({}, this.currentParams)
4014
+ this.currentParams = {
4015
+ path: '',
4016
+ items: {}
4017
+ }
3932
4018
  }
3933
4019
  if (event) {
3934
4020
  if (event.target && event.target.classList.contains(this.options.triggerToggleClass)) {
@@ -4097,7 +4183,7 @@ class WebsySearch {
4097
4183
  this.elementId = elementId
4098
4184
  const DEFAULTS = {
4099
4185
  searchIcon: `<svg class='search' width="20" height="20" viewBox="0 0 512 512"><path d="M221.09,64A157.09,157.09,0,1,0,378.18,221.09,157.1,157.1,0,0,0,221.09,64Z" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px"/><line x1="338.29" y1="338.29" x2="448" y2="448" style="fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/></svg>`,
4100
- clearIcon: `<svg class='clear' xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512"><title>ionicons-v5-l</title><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>`,
4186
+ clearIcon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 512 512"><title>ionicons-v5-l</title><line x1="368" y1="368" x2="144" y2="144" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="368" y1="144" x2="144" y2="368" style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>`,
4101
4187
  placeholder: 'Search',
4102
4188
  searchTimeout: 500,
4103
4189
  minLength: 2
@@ -4107,12 +4193,15 @@ class WebsySearch {
4107
4193
  const el = document.getElementById(elementId)
4108
4194
  if (el) {
4109
4195
  // el.addEventListener('click', this.handleClick.bind(this))
4196
+ el.addEventListener('click', this.handleClick.bind(this))
4110
4197
  el.addEventListener('keyup', this.handleKeyUp.bind(this))
4111
4198
  el.innerHTML = `
4112
4199
  <div class='websy-search-input-container'>
4113
4200
  ${this.options.searchIcon}
4114
4201
  <input id='${this.elementId}_search' class='websy-search-input' placeholder='${this.options.placeholder || 'Search'}'>
4115
- ${this.options.clearIcon}
4202
+ <div class='clear websy-hidden' id='${this.elementId}_clear'>
4203
+ ${this.options.clearIcon}
4204
+ </div>
4116
4205
  </div>
4117
4206
  `
4118
4207
  }
@@ -4120,11 +4209,25 @@ class WebsySearch {
4120
4209
  console.log('No element found with Id', elementId)
4121
4210
  }
4122
4211
  }
4212
+ handleClick (event) {
4213
+ if (event.target.classList.contains('clear')) {
4214
+ const inputEl = document.getElementById(`${this.elementId}_search`)
4215
+ inputEl.value = ''
4216
+ this.options.onSearch('')
4217
+ }
4218
+ }
4123
4219
  handleKeyUp (event) {
4124
4220
  if (event.target.classList.contains('websy-search-input')) {
4125
4221
  if (this.searchTimeoutFn) {
4126
4222
  clearTimeout(this.searchTimeoutFn)
4127
4223
  }
4224
+ const clearEl = document.getElementById(`${this.elementId}_clear`)
4225
+ if (event.target.value.length > 0) {
4226
+ clearEl.classList.remove('websy-hidden')
4227
+ }
4228
+ else {
4229
+ clearEl.classList.add('websy-hidden')
4230
+ }
4128
4231
  if (event.target.value.length >= this.options.minLength) {
4129
4232
  this.searchTimeoutFn = setTimeout(() => {
4130
4233
  if (this.options.onSearch) {