• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / iznik-nuxt3 / 6bd7579a-30c4-40ea-9a8a-1291e094e81e

01 Oct 2025 01:42PM UTC coverage: 34.694% (-9.9%) from 44.618%
6bd7579a-30c4-40ea-9a8a-1291e094e81e

push

circleci

edwh
MT: In /map, don't show the centre points for groups which are not supposed to show on the map.

1053 of 3928 branches covered (26.81%)

Branch coverage included in aggregate %.

2722 of 6953 relevant lines covered (39.15%)

37.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.43
/components/InfiniteLoading.vue
1
<template>
2
  <client-only>
3
    <div
4
      :key="bump"
5
      v-observe-visibility="{
6
        callback: visibilityChanged,
7
        options: {
8
          rootMargin: '0px 0px ' + distance + 'px 0px',
9
        },
10
      }"
11
      class="infinite-loader pb-4"
12
    >
13
      <slot v-if="state == 'loading'" name="spinner"></slot>
14
      <slot v-if="state == 'complete'" name="complete"></slot>
15
      <slot v-if="state == 'error'" name="error"></slot>
16
    </div>
17
  </client-only>
18
</template>
19
<script setup>
20
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
21

22
// Derived from https://github.com/oumoussa98/vue3-infinite-loading.  Reworked radically to allow an async event
23
// handler, and to make consistent with the rest of this codebase.
24
const props = defineProps({
3✔
25
  top: { type: Boolean, required: false },
26
  target: { type: [String, Boolean], required: false, default: null },
27
  distance: { type: Number, required: false, default: 0 },
28
  identifier: { type: [String, Number], required: false, default: null },
29
  firstload: { type: Boolean, required: false, default: true },
30
  slots: { type: Object, required: false, default: null },
31
})
32

33
const emit = defineEmits(['infinite'])
3✔
34

35
const state = ref('ready')
3✔
36
const bump = ref(0)
3✔
37
const visible = ref(false)
3✔
38
let timer = null
3✔
39

40
// Methods
41
function visibilityChanged(isVisible) {
6✔
42
  visible.value = isVisible
6✔
43
}
44

45
function loading() {
107✔
46
  state.value = 'loading'
107✔
47
}
48

49
function loaded() {
107✔
50
  state.value = 'loaded'
107✔
51
}
52

53
function complete() {
×
54
  state.value = 'complete'
×
55
}
56

57
function error() {
×
58
  state.value = 'error'
×
59
}
60

61
function stopObserver() {
×
62
  complete()
×
63
}
64

65
async function emitInfinite() {
107✔
66
  loading()
107✔
67

68
  // Wait for the next tick otherwise if the event handlers return synchronously we may not end up triggering
69
  // the watch.
70
  await nextTick()
107✔
71
  emit('infinite', {
107✔
72
    loading,
73
    loaded,
74
    complete,
75
    error,
76
    stopObserver,
77
  })
78
}
79

80
function fallback() {
104✔
81
  timer = null
104✔
82

83
  if (visible.value && state.value === 'loaded') {
104!
84
    // We have loaded and not completed, and yet it's still visible.  We need to do some more.
85
    emitInfinite()
104✔
86
  }
87

88
  timer = setTimeout(fallback, 100)
104✔
89
}
90

3✔
91
// Watch state changes
92
watch(state, (newVal) => {
93
  // console.log('state changed', newVal)
94
  if (newVal === 'loading') {
214!
95
    // This is an internal change - nothing to do.
96
  } else if (newVal === 'complete') {
97
    // console.log('Complete, stop observer')
98
    stopObserver()
×
99
  } else {
100
    const parentEl = props.target || document.documentElement
107✔
101
    const prevHeight = parentEl.scrollHeight
107✔
102

103
    if (newVal === 'loaded' && props.top) {
107!
104
      // console.log('Adjust scrollTop')
105
      parentEl.scrollTop = parentEl.scrollHeight - prevHeight
×
106
    }
107
  }
108
})
109

110
// Watch identifier changes
111
watch(
3✔
112
  () => props.identifier,
113
  () => {
114
    // We've been asked to kick the component to reset it.
115
    bump.value++
×
116
    emitInfinite()
×
117
  }
118
)
119

120
// Lifecycle hooks
121
onMounted(async () => {
3✔
122
  if (props.firstload) {
3!
123
    await emitInfinite()
3✔
124
  }
125

126
  // It would be nice if we didn't need a timer and could be purely event-driven.  But there is no guarantee
127
  // that what happens in response to our emit will result in all the components being rendered, and although
128
  // Vue3 has Suspense I can't see an easy way of waiting for all renders to finish.
129
  timer = setTimeout(fallback, 100)
3✔
130
})
131

132
onBeforeUnmount(() => {
3✔
133
  if (timer) {
×
134
    clearTimeout(timer)
×
135
  }
136
})
137

3✔
138
// Expose methods to parent components
139
defineExpose({
140
  loading,
141
  loaded,
142
  complete,
143
  error,
144
  stopObserver,
145
})
146
</script>
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc