@live-change/dao-vue3 0.8.21 → 0.8.23

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.
package/LICENSE.md ADDED
@@ -0,0 +1,11 @@
1
+ Copyright 2019-2024 Michał Łaszczewski
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import reactiveMixin from './lib/reactiveMixin.js'
2
2
  import reactivePrefetchMixin from './lib/reactivePrefetchMixin.js'
3
- import { live, fetch } from './lib/live.js'
3
+ export { live, fetch } from './lib/live.js'
4
4
  import ReactiveObservableList from './lib/ReactiveObservableList.js'
5
5
  import RangeBuckets from './lib/RangeBuckets.js'
6
+ import freezable from './lib/freezable.js'
6
7
 
7
8
  const ReactiveDaoVue = {
8
9
  install(Vue, options) {
@@ -14,6 +15,6 @@ const ReactiveDaoVue = {
14
15
  }
15
16
 
16
17
  //// TODO: rename reactive to live
17
- export { ReactiveDaoVue, reactiveMixin, reactivePrefetchMixin, ReactiveObservableList, RangeBuckets, live, fetch }
18
+ export { ReactiveDaoVue, reactiveMixin, reactivePrefetchMixin, ReactiveObservableList, RangeBuckets, freezable }
18
19
 
19
20
  export default ReactiveDaoVue
@@ -1,5 +1,6 @@
1
1
  import live from "./live.js"
2
- import { computed, reactive, ref, unref, watch } from "vue"
2
+ import freezable from './freezable.js'
3
+ import { computed, reactive, ref, unref, watch, shallowRef, isRef } from "vue"
3
4
 
4
5
  class Bucket {
5
6
 
@@ -16,10 +17,14 @@ class Bucket {
16
17
  this.onDispose = []
17
18
  this.domElements = []
18
19
 
20
+ this.freeze = () => {}
21
+ this.unfreeze = () => {}
22
+ this.changed = ref(false)
23
+
19
24
  this.data = computed(() => {
20
25
  const ldv = this.liveData.value
21
26
  if(!ldv) return []
22
- let source = unref(ldv)
27
+ let source = unref(unref(ldv))
23
28
  if(this.range.reverse) {
24
29
  source = source.slice()
25
30
  source.reverse()
@@ -35,6 +40,7 @@ class Bucket {
35
40
  ))
36
41
  })
37
42
  this.liveData = ref(null)
43
+ this.rawLiveData = ref(null)
38
44
 
39
45
  this.load()
40
46
 
@@ -48,8 +54,16 @@ class Bucket {
48
54
  async load() {
49
55
  this.path = this.pathFunction(this.range)
50
56
  this.dataPromise = live(this.api(), this.path, fun => this.onDispose.push(fun))
51
- this.dataPromise.then(data => {
52
- this.liveData.value = data
57
+ this.dataPromise.then(dataRef => {
58
+ this.rawLiveData.value = dataRef
59
+ const { freeze, unfreeze, output, changed } = freezable(dataRef)
60
+ this.freeze = freeze
61
+ this.unfreeze = unfreeze
62
+ watch(() => changed.value, v => {
63
+ if(isRef(this.changed)) this.changed.value = v
64
+ else this.changed = v
65
+ }, { immediate: true })
66
+ this.liveData.value = output
53
67
  })
54
68
  return this.dataPromise
55
69
  }
@@ -64,7 +78,7 @@ class Bucket {
64
78
 
65
79
  canClose() {
66
80
  const data = unref(this.data)
67
- return data && data.length == this.bucketSize
81
+ return data && data.length === this.bucketSize
68
82
  }
69
83
 
70
84
  async closeTop() {
@@ -105,17 +119,19 @@ class RangeBuckets {
105
119
  this.canLoadTop = computed(() => this.isTopLoadPossible())
106
120
  this.canLoadBottom = computed(() => this.isBottomLoadPossible())
107
121
 
122
+ this.changed = computed(() => this.buckets.some(bucket => bucket.changed))
123
+
108
124
  this.loadFirstBucket()
109
125
  }
110
126
 
111
127
  isTopLoadPossible() {
112
- if(this.buckets.length == 0) return false
128
+ if(this.buckets.length === 0) return false
113
129
  const firstBucket = this.buckets[0]
114
130
  return firstBucket.isTopClosed() || firstBucket.canClose()
115
131
  }
116
132
 
117
133
  isBottomLoadPossible() {
118
- if(this.buckets.length == 0) return false
134
+ if(this.buckets.length === 0) return false
119
135
  const lastBucket = this.buckets[this.buckets.length - 1]
120
136
  return lastBucket.isBottomClosed() || lastBucket.canClose()
121
137
  }
@@ -141,11 +157,11 @@ class RangeBuckets {
141
157
 
142
158
  async loadTop() {
143
159
  //console.log("LOAD TOP!", this.isTopLoadPossible())
144
- if(this.buckets.length == 0) return this.loadFirstBucket()
160
+ if(this.buckets.length === 0) return this.loadFirstBucket()
145
161
  const firstBucket = this.buckets[0]
146
162
  await firstBucket.promise
147
163
  if(!this.isTopLoadPossible()) return
148
- if(firstBucket != this.buckets[0]) {
164
+ if(firstBucket !== this.buckets[0]) {
149
165
  return this.buckets[0].promise
150
166
  }
151
167
  let range = { limit: this.bucketSize, reverse: true }
@@ -174,11 +190,11 @@ class RangeBuckets {
174
190
 
175
191
  async loadBottom() {
176
192
  //console.log("LOAD BOTTOM!", this.isBottomLoadPossible())
177
- if(this.buckets.length == 0) return this.loadFirstBucket()
193
+ if(this.buckets.length === 0) return this.loadFirstBucket()
178
194
  const lastBucket = this.buckets[this.buckets.length - 1]
179
195
  await lastBucket.promise
180
196
  if(!this.isBottomLoadPossible()) return
181
- if(lastBucket != this.buckets[this.buckets.length - 1]) {
197
+ if(lastBucket !== this.buckets[this.buckets.length - 1]) {
182
198
  return this.buckets[this.buckets.length - 1].promise
183
199
  }
184
200
  let range = { limit: this.bucketSize }
@@ -205,7 +221,7 @@ class RangeBuckets {
205
221
  }
206
222
 
207
223
  dropTop() {
208
- if(this.buckets.length == 0) throw new Error('impossible to drop from empty')
224
+ if(this.buckets.length === 0) throw new Error('impossible to drop from empty')
209
225
  //console.log("DROP TOP!")
210
226
  const droppedBucket = this.buckets[0]
211
227
  const height = droppedBucket.domElements.reduce((acc, el) => acc + (el?.offsetHeight || 0), 0)
@@ -217,7 +233,7 @@ class RangeBuckets {
217
233
 
218
234
  dropBottom() {
219
235
  //console.log("DROP BOTTOM!")
220
- if(this.buckets.length == 0) throw new Error('impossible to drop from empty')
236
+ if(this.buckets.length === 0) throw new Error('impossible to drop from empty')
221
237
  const droppedBucket = this.buckets[this.buckets.length - 1]
222
238
  const height = droppedBucket.domElements.reduce((acc, el) => acc + el?.offsetHeight, 0)
223
239
  this.buckets.pop()
@@ -225,6 +241,18 @@ class RangeBuckets {
225
241
  return height
226
242
  }
227
243
 
244
+ freeze() {
245
+ for(const bucket of this.buckets) {
246
+ bucket.freeze()
247
+ }
248
+ }
249
+
250
+ unfreeze() {
251
+ for(const bucket of this.buckets) {
252
+ bucket.unfreeze()
253
+ }
254
+ }
255
+
228
256
  dispose() {
229
257
  for(const bucket of this.buckets) {
230
258
  bucket.dispose()
@@ -0,0 +1,24 @@
1
+ import { ref, onUnmounted, getCurrentInstance, unref, reactive, isRef, shallowRef, watch, computed } from 'vue'
2
+
3
+ export default function freezable(source) {
4
+ if(typeof window === 'undefined') return {
5
+ output: source,
6
+ changed: ref(false),
7
+ freeze() {},
8
+ unfreeze() {}
9
+ }
10
+ const frozen = ref(false)
11
+ function freeze() {
12
+ if(frozen.value) return
13
+ frozen.value = JSON.parse(JSON.stringify(source.value))
14
+ }
15
+ function unfreeze() {
16
+ frozen.value = false
17
+ }
18
+ const output = computed(() => {
19
+ if(frozen.value) return frozen.value
20
+ return source.value
21
+ })
22
+ const changed = computed(() => JSON.stringify(output.value) !== JSON.stringify(source.value))
23
+ return { output, freeze, unfreeze, changed }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/dao-vue3",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "author": {
5
5
  "email": "m8@em8.pl",
6
6
  "name": "Michał Łaszczewski",
@@ -10,7 +10,7 @@
10
10
  "url": "https://github.com/live-change/live-change-stack/issues"
11
11
  },
12
12
  "dependencies": {
13
- "@live-change/dao": "0.8.21"
13
+ "@live-change/dao": "^0.8.23"
14
14
  },
15
15
  "type": "module",
16
16
  "description": "Vue.js integration for live-change dao",
@@ -32,5 +32,5 @@
32
32
  "scripts": {
33
33
  "compileTests": "webpack test/*.js tests-bundle.js"
34
34
  },
35
- "gitHead": "4453aa639a9fe1a857d93d73ebd28a82c97fdd87"
35
+ "gitHead": "581260523149a1e596f08e878b5f4fabeaba26ea"
36
36
  }