fcad-core-dragon 2.1.1 → 2.1.2
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/.editorconfig +7 -7
- package/.gitlab-ci.yml +124 -0
- package/.prettierrc +11 -11
- package/.vscode/extensions.json +8 -8
- package/.vscode/settings.json +46 -16
- package/CHANGELOG +520 -520
- package/README.md +57 -57
- package/documentation/.vitepress/config.js +114 -114
- package/documentation/api-examples.md +49 -49
- package/documentation/composants/app-base-button.md +58 -58
- package/documentation/composants/app-base-error-display.md +59 -59
- package/documentation/composants/app-base-popover.md +68 -68
- package/documentation/composants/app-comp-audio.md +75 -75
- package/documentation/composants/app-comp-branch-buttons.md +111 -111
- package/documentation/composants/app-comp-button-progress.md +53 -53
- package/documentation/composants/app-comp-carousel.md +53 -53
- package/documentation/composants/app-comp-container.md +53 -53
- package/documentation/composants/app-comp-input-checkbox-next.md +42 -42
- package/documentation/composants/app-comp-input-dropdown-next.md +34 -34
- package/documentation/composants/app-comp-input-radio-next.md +39 -39
- package/documentation/composants/app-comp-input-text-next.md +35 -35
- package/documentation/composants/app-comp-input-text-table-next.md +34 -34
- package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -53
- package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -31
- package/documentation/composants/app-comp-jauge.md +31 -31
- package/documentation/composants/app-comp-menu-item.md +55 -55
- package/documentation/composants/app-comp-menu.md +29 -29
- package/documentation/composants/app-comp-navigation.md +41 -41
- package/documentation/composants/app-comp-note-call.md +53 -53
- package/documentation/composants/app-comp-note-credit.md +53 -53
- package/documentation/composants/app-comp-play-bar-next.md +53 -53
- package/documentation/composants/app-comp-pop-up-next.md +93 -93
- package/documentation/composants/app-comp-quiz-next.md +235 -235
- package/documentation/composants/app-comp-quiz-recall.md +53 -53
- package/documentation/composants/app-comp-svg-next.md +53 -53
- package/documentation/composants/app-comp-table-of-content.md +50 -50
- package/documentation/composants/app-comp-video-player.md +82 -82
- package/documentation/composants.md +46 -46
- package/documentation/composants_critiques/ModelPageComposant.md +53 -53
- package/documentation/composants_critiques/app-base-module.md +43 -43
- package/documentation/composants_critiques/app-base-page.md +48 -48
- package/documentation/composants_critiques/app-base.md +311 -311
- package/documentation/composants_critiques/main.md +15 -15
- package/documentation/demarrage.md +50 -50
- package/documentation/deploiement.md +57 -57
- package/documentation/index.md +33 -33
- package/documentation/markdown-examples.md +85 -85
- package/documentation/public/vite.svg +14 -14
- package/documentation/public/vuejs.svg +1 -1
- package/documentation/public/vuetify.svg +5 -5
- package/eslint.config.js +60 -60
- package/junit-report.xml +182 -0
- package/package.json +66 -59
- package/playwright/index.html +12 -0
- package/playwright/index.js +21 -0
- package/playwright-ct.config.js +95 -0
- package/src/$locales/en.json +157 -157
- package/src/$locales/fr.json +120 -120
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBase.vue +1171 -1169
- package/src/components/AppBaseButton.vue +90 -95
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBaseModule.vue +1639 -1634
- package/src/components/AppBasePage.vue +867 -866
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppBaseSkeleton.vue +66 -66
- package/src/components/AppCompAudio.vue +261 -256
- package/src/components/AppCompBranchButtons.vue +508 -508
- package/src/components/AppCompButtonProgress.vue +137 -132
- package/src/components/AppCompCarousel.vue +342 -336
- package/src/components/AppCompContainer.vue +29 -29
- package/src/components/AppCompInputCheckBoxNx.vue +325 -323
- package/src/components/AppCompInputDropdownNx.vue +302 -299
- package/src/components/AppCompInputRadioNx.vue +287 -284
- package/src/components/AppCompInputTextNx.vue +156 -153
- package/src/components/AppCompInputTextTableNx.vue +205 -202
- package/src/components/AppCompInputTextToFillDropdownNx.vue +343 -340
- package/src/components/AppCompInputTextToFillNx.vue +316 -313
- package/src/components/AppCompJauge.vue +81 -81
- package/src/components/AppCompMenu.vue +6 -1
- package/src/components/AppCompMenuItem.vue +246 -240
- package/src/components/AppCompNavigation.vue +977 -972
- package/src/components/AppCompNoteCall.vue +167 -161
- package/src/components/AppCompNoteCredit.vue +496 -491
- package/src/components/AppCompPlayBarNext.vue +2290 -2288
- package/src/components/AppCompPopUpNext.vue +508 -504
- package/src/components/AppCompQuizNext.vue +515 -510
- package/src/components/AppCompQuizRecall.vue +355 -350
- package/src/components/AppCompSVGNext.vue +346 -346
- package/src/components/AppCompSettingsMenu.vue +177 -172
- package/src/components/AppCompTableOfContent.vue +433 -427
- package/src/components/AppCompVideoPlayer.vue +377 -377
- package/src/components/AppCompViewDisplay.vue +6 -6
- package/src/components/BaseModule.vue +55 -55
- package/src/composables/useIdleDetector.js +56 -56
- package/src/composables/useQuiz.js +89 -89
- package/src/composables/useTimer.js +172 -172
- package/src/directives/nvdaFix.js +53 -53
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- package/src/main.js +493 -476
- package/src/module/stores/appStore.js +960 -947
- package/src/module/xapi/ADL.js +520 -520
- package/src/module/xapi/Crypto/Hasher.js +241 -241
- package/src/module/xapi/Crypto/WordArray.js +278 -278
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
- package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
- package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
- package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
- package/src/module/xapi/Crypto/encoders/Base.js +105 -105
- package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
- package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
- package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
- package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
- package/src/module/xapi/Crypto/index.js +53 -53
- package/src/module/xapi/Statement/activity.js +47 -47
- package/src/module/xapi/Statement/agent.js +55 -55
- package/src/module/xapi/Statement/group.js +26 -26
- package/src/module/xapi/Statement/index.js +259 -259
- package/src/module/xapi/Statement/statement.js +253 -253
- package/src/module/xapi/Statement/statementRef.js +23 -23
- package/src/module/xapi/Statement/substatement.js +22 -22
- package/src/module/xapi/Statement/verb.js +36 -36
- package/src/module/xapi/activitytypes.js +17 -17
- package/src/module/xapi/launch.js +157 -157
- package/src/module/xapi/utils.js +167 -167
- package/src/module/xapi/verbs.js +294 -294
- package/src/module/xapi/wrapper.js +1895 -1895
- package/src/module/xapi/xapiStatement.js +444 -444
- package/src/plugins/analytics.js +34 -34
- package/src/plugins/bus.js +12 -8
- package/src/plugins/gsap.js +17 -17
- package/src/plugins/helper.js +355 -358
- package/src/plugins/i18n.js +27 -26
- package/src/plugins/idb.js +227 -227
- package/src/plugins/save.js +37 -37
- package/src/plugins/scorm.js +287 -287
- package/src/plugins/xapi.js +11 -11
- package/src/public/index.html +33 -33
- package/src/router/index.js +57 -57
- package/src/router/routes.js +312 -312
- package/src/shared/generalfuncs.js +344 -344
- package/src/shared/validators.js +1018 -1018
- package/tests/component/AppBaseButton.spec.js +53 -0
- package/tests/component/pinia.spec.js +24 -0
- package/{src/components/tests__ → tests/unit}/AppBaseButton.spec.js +53 -53
- package/tests/unit/AppCompInputCheckBoxNx.spec.js +59 -0
- package/tests/unit/AppCompInputDropdownNx.spec.js +51 -0
- package/tests/unit/AppCompInputRadioNx.spec.js +59 -0
- package/tests/unit/AppCompInputTextNx.spec.js +44 -0
- package/tests/unit/AppCompInputTextTableNx.spec.js +77 -0
- package/tests/unit/AppCompInputTextToFillDropdownNx.spec.js +60 -0
- package/tests/unit/AppCompInputTextToFillNx.spec.js +45 -0
- package/tests/unit/AppCompQuizNext.spec.js +114 -0
- package/tests/unit/AppCompVideoPlayer.spec.js +177 -0
- package/{src/components/tests__ → tests/unit}/useTimer.spec.js +91 -91
- package/vitest.config.js +28 -19
- package/vitest.setup.js +28 -0
- package/src/components/AppBaseButton.test.js +0 -21
package/src/plugins/i18n.js
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import _ from 'lodash'
|
|
2
|
-
/**
|
|
3
|
-
* Merge locales message in project.
|
|
4
|
-
* @summary To merge the locales dictionnary of this library with the locales that user will create
|
|
5
|
-
* @param {Object} i18n - vue-i18n internalization object.
|
|
6
|
-
*/
|
|
7
|
-
export default function mergeLocales(i18n) {
|
|
8
|
-
const thisLocales = import.meta.glob('../$locales/*.json', {
|
|
9
|
-
import: 'default',
|
|
10
|
-
eager: true
|
|
11
|
-
})
|
|
12
|
-
for (const path in thisLocales) {
|
|
13
|
-
const matched = path.match(/([A-Za-z0-9-_]+)\./i)
|
|
14
|
-
if (matched && matched.length > 1) {
|
|
15
|
-
const locale = matched[1]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
/**
|
|
3
|
+
* Merge locales message in project.
|
|
4
|
+
* @summary To merge the locales dictionnary of this library with the locales that user will create
|
|
5
|
+
* @param {Object} i18n - vue-i18n internalization object.
|
|
6
|
+
*/
|
|
7
|
+
export default function mergeLocales(i18n) {
|
|
8
|
+
const thisLocales = import.meta.glob('../$locales/*.json', {
|
|
9
|
+
import: 'default',
|
|
10
|
+
eager: true
|
|
11
|
+
})
|
|
12
|
+
for (const path in thisLocales) {
|
|
13
|
+
const matched = path.match(/([A-Za-z0-9-_]+)\./i)
|
|
14
|
+
if (matched && matched.length > 1) {
|
|
15
|
+
const locale = matched[1]
|
|
16
|
+
// Using lodash to deeply merge objects
|
|
17
|
+
const coreMessages = JSON.parse(JSON.stringify(thisLocales[path]))
|
|
18
|
+
const templateMessages = JSON.parse(
|
|
19
|
+
JSON.stringify(i18n.messages[locale] || i18n.messages.value[locale]) //cover both legacy mode and non legacy mode of vue-i18n
|
|
20
|
+
)
|
|
21
|
+
const mergedMessages = _.merge(coreMessages, templateMessages)
|
|
22
|
+
|
|
23
|
+
// Since merLocalMessage will do a shallow merge of the object. We will use setLocalMessage to replace the message with new message object
|
|
24
|
+
i18n.setLocaleMessage(locale, mergedMessages)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/plugins/idb.js
CHANGED
|
@@ -1,227 +1,227 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* idb library by jakearchibald: https://github.com/jakearchibald/idb
|
|
3
|
-
*/
|
|
4
|
-
import { openDB } from 'idb'
|
|
5
|
-
import $_ from 'lodash'
|
|
6
|
-
//import { createApp } from 'vue'
|
|
7
|
-
//import {*} from "idb";
|
|
8
|
-
let dataBase = null
|
|
9
|
-
let dbName = '$crsDataBase' //test
|
|
10
|
-
let storeName = '$lessonsStore' //test
|
|
11
|
-
//openDB, deleteDB, wrap, unwrap
|
|
12
|
-
//$_id
|
|
13
|
-
//const app = createApp({})
|
|
14
|
-
export const $idb = {
|
|
15
|
-
install(app) {
|
|
16
|
-
app.config.globalProperties.$idb = {
|
|
17
|
-
/*
|
|
18
|
-
* @ Description: create a indexedDB database
|
|
19
|
-
* Open a data base in indexedDB if does not exist and create a store for the lessons package
|
|
20
|
-
*@ return Promise
|
|
21
|
-
*/
|
|
22
|
-
async openDB() {
|
|
23
|
-
try {
|
|
24
|
-
if (!window.indexedDB) {
|
|
25
|
-
console.log(
|
|
26
|
-
"Your browser doesn't support a stable version of IndexedDB. Saving feature of your progress will not be available."
|
|
27
|
-
)
|
|
28
|
-
return
|
|
29
|
-
} else {
|
|
30
|
-
const db = await openDB(dbName, 1, {
|
|
31
|
-
upgrade(db) {
|
|
32
|
-
// Create a store of objects
|
|
33
|
-
const store = db.createObjectStore(storeName, {
|
|
34
|
-
keyPath: '_$id',
|
|
35
|
-
autoIncrement: true
|
|
36
|
-
})
|
|
37
|
-
// Create an index for the data
|
|
38
|
-
store.createIndex('$idb_id', '$idb_id', { unique: true })
|
|
39
|
-
// Create an index for the data
|
|
40
|
-
store.createIndex('$record', '$record', { unique: false })
|
|
41
|
-
|
|
42
|
-
//Create an index that is not unique (two person can have the same age)
|
|
43
|
-
store.createIndex('$last_edit', '$last_edit', { unique: false })
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
dataBase = db
|
|
47
|
-
return dataBase
|
|
48
|
-
}
|
|
49
|
-
} catch (err) {
|
|
50
|
-
console.log('==> Erro ', err)
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
/*
|
|
55
|
-
* @Description: wrapper to insert new data in the store (entry is entered if doesn't already exist in db)
|
|
56
|
-
* @Params storeName {String}: name of the store
|
|
57
|
-
* @Params data {object}: new value to enter
|
|
58
|
-
* @Return promise
|
|
59
|
-
*/
|
|
60
|
-
async insertDataInDB(data) {
|
|
61
|
-
try {
|
|
62
|
-
//Index param
|
|
63
|
-
const searchIndex = '$idb_id'
|
|
64
|
-
//search by package Id index
|
|
65
|
-
const value = await dataBase.getFromIndex(
|
|
66
|
-
storeName,
|
|
67
|
-
searchIndex,
|
|
68
|
-
data[searchIndex]
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
//Add entry to database if does not exist
|
|
72
|
-
if (!value) {
|
|
73
|
-
const addedItem = await dataBase.add(storeName, $_.cloneDeep(data))
|
|
74
|
-
|
|
75
|
-
return addedItem
|
|
76
|
-
}
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.log('Error..', err)
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
/*@Description - Helper to get all data existing in the store
|
|
83
|
-
@Param storeName {String} - Name of the store
|
|
84
|
-
*@Return Promise {array} of all entries
|
|
85
|
-
*/
|
|
86
|
-
async getAllFromDB() {
|
|
87
|
-
try {
|
|
88
|
-
//Get all from the storeName order by last edit
|
|
89
|
-
const entryList = await dataBase.getAllFromIndex(
|
|
90
|
-
storeName,
|
|
91
|
-
'lastEdit'
|
|
92
|
-
)
|
|
93
|
-
return entryList
|
|
94
|
-
} catch (err) {
|
|
95
|
-
console.log('error...', err)
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
/*
|
|
100
|
-
*@Description - Helper to get one entry from the store
|
|
101
|
-
*@Param target {String} - id of the entry
|
|
102
|
-
*@Return Promise {array} of all entries
|
|
103
|
-
*/
|
|
104
|
-
async getFromDB(target) {
|
|
105
|
-
try {
|
|
106
|
-
//Index param
|
|
107
|
-
const searchIndex = '$idb_id'
|
|
108
|
-
//search by package Id index
|
|
109
|
-
const entry = await dataBase.getFromIndex(
|
|
110
|
-
storeName,
|
|
111
|
-
searchIndex,
|
|
112
|
-
target
|
|
113
|
-
)
|
|
114
|
-
return entry
|
|
115
|
-
} catch (err) {
|
|
116
|
-
console.log('error...', err)
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
/*
|
|
121
|
-
*@Description - Helper to update data in a store
|
|
122
|
-
* @Params storeName {String} - name of the store
|
|
123
|
-
* @Params index {String} - name of the index
|
|
124
|
-
* @Params target {String| num} - id of the element to update
|
|
125
|
-
* @Params newValue {Object} - new value to enter
|
|
126
|
-
*@return Promise
|
|
127
|
-
*/
|
|
128
|
-
async updateDataInDB(target, newValue) {
|
|
129
|
-
try {
|
|
130
|
-
//Index param
|
|
131
|
-
const searchIndex = '$idb_id'
|
|
132
|
-
|
|
133
|
-
//search by package Id index
|
|
134
|
-
const existingRecord = await dataBase.getFromIndex(
|
|
135
|
-
storeName,
|
|
136
|
-
searchIndex,
|
|
137
|
-
target
|
|
138
|
-
)
|
|
139
|
-
//If there is an existing record update the record with new data
|
|
140
|
-
if (existingRecord) {
|
|
141
|
-
existingRecord.$record = newValue
|
|
142
|
-
existingRecord.$last_edit = Date.now()
|
|
143
|
-
const updatedItem = await dataBase.put(
|
|
144
|
-
storeName,
|
|
145
|
-
$_.cloneDeep(existingRecord)
|
|
146
|
-
)
|
|
147
|
-
//await this.getAllFromDB(storeName)
|
|
148
|
-
return updatedItem
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
console.log('Error: ', err)
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
/*
|
|
155
|
-
* @Description - Heleper to delete entry from the store
|
|
156
|
-
* @Params storeName {String} - name of the store
|
|
157
|
-
* @Params index {String} - name of the index
|
|
158
|
-
* @Params target {String| num} - id of the element to remove
|
|
159
|
-
* @Return reference of deleted item
|
|
160
|
-
*/
|
|
161
|
-
async deleteDataInDB(target) {
|
|
162
|
-
try {
|
|
163
|
-
//Index param
|
|
164
|
-
const searchIndex = '$idb_id'
|
|
165
|
-
|
|
166
|
-
//search by package Id index
|
|
167
|
-
const existingRecord = await dataBase.getFromIndex(
|
|
168
|
-
storeName,
|
|
169
|
-
searchIndex,
|
|
170
|
-
target
|
|
171
|
-
)
|
|
172
|
-
//If there is an existing delete it from the store
|
|
173
|
-
if (existingRecord) {
|
|
174
|
-
const deletedItem = await dataBase.delete(
|
|
175
|
-
storeName,
|
|
176
|
-
existingRecord._$id
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
return deletedItem
|
|
180
|
-
}
|
|
181
|
-
} catch (err) {
|
|
182
|
-
console.log('Error: ', err)
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
/**
|
|
186
|
-
* @description creating a small save plug-in to save store state in the localStorage
|
|
187
|
-
* the plugin listen for changes made to the Pinia store store to store them in the browser storage.
|
|
188
|
-
* Since the The handler is called after every actions we want to limit the saving of data to storage only
|
|
189
|
-
* when the changes are affecting the user interaction.
|
|
190
|
-
* This prevent resetting the store to initial state when the browser refreshes
|
|
191
|
-
* @param {Object} store Pinia Store
|
|
192
|
-
* @param {String} item package $idb_id
|
|
193
|
-
*/
|
|
194
|
-
async saveState(store, item) {
|
|
195
|
-
store.$onAction(async ({ name, store, args, after }) => {
|
|
196
|
-
//Should only track changes actions on userMetadata
|
|
197
|
-
if (!['updateUserMetaData', 'setUserMetaData'].includes(name)) return
|
|
198
|
-
|
|
199
|
-
// Open DB with a store
|
|
200
|
-
const search = await this.getFromDB(item)
|
|
201
|
-
|
|
202
|
-
if (Object.entries(store.$state.userMetaData).length && search) {
|
|
203
|
-
// Update the db store
|
|
204
|
-
await this.updateDataInDB(item, {
|
|
205
|
-
progress: store.$state.userMetaData,
|
|
206
|
-
userSettings: store.$state.applicationSettings,
|
|
207
|
-
routeHistory: store.getRouteHistory
|
|
208
|
-
})
|
|
209
|
-
//==================================================
|
|
210
|
-
} else {
|
|
211
|
-
//Add Entry to db store
|
|
212
|
-
await this.insertDataInDB({
|
|
213
|
-
$idb_id: item,
|
|
214
|
-
$record: {
|
|
215
|
-
progress: store.$state.userMetaData,
|
|
216
|
-
userSettings: store.$state.applicationSettings,
|
|
217
|
-
routeHistory: store.getRouteHistory
|
|
218
|
-
},
|
|
219
|
-
$last_edit: Date.now()
|
|
220
|
-
})
|
|
221
|
-
}
|
|
222
|
-
//})
|
|
223
|
-
})
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* idb library by jakearchibald: https://github.com/jakearchibald/idb
|
|
3
|
+
*/
|
|
4
|
+
import { openDB } from 'idb'
|
|
5
|
+
import $_ from 'lodash'
|
|
6
|
+
//import { createApp } from 'vue'
|
|
7
|
+
//import {*} from "idb";
|
|
8
|
+
let dataBase = null
|
|
9
|
+
let dbName = '$crsDataBase' //test
|
|
10
|
+
let storeName = '$lessonsStore' //test
|
|
11
|
+
//openDB, deleteDB, wrap, unwrap
|
|
12
|
+
//$_id
|
|
13
|
+
//const app = createApp({})
|
|
14
|
+
export const $idb = {
|
|
15
|
+
install(app) {
|
|
16
|
+
app.config.globalProperties.$idb = {
|
|
17
|
+
/*
|
|
18
|
+
* @ Description: create a indexedDB database
|
|
19
|
+
* Open a data base in indexedDB if does not exist and create a store for the lessons package
|
|
20
|
+
*@ return Promise
|
|
21
|
+
*/
|
|
22
|
+
async openDB() {
|
|
23
|
+
try {
|
|
24
|
+
if (!window.indexedDB) {
|
|
25
|
+
console.log(
|
|
26
|
+
"Your browser doesn't support a stable version of IndexedDB. Saving feature of your progress will not be available."
|
|
27
|
+
)
|
|
28
|
+
return
|
|
29
|
+
} else {
|
|
30
|
+
const db = await openDB(dbName, 1, {
|
|
31
|
+
upgrade(db) {
|
|
32
|
+
// Create a store of objects
|
|
33
|
+
const store = db.createObjectStore(storeName, {
|
|
34
|
+
keyPath: '_$id',
|
|
35
|
+
autoIncrement: true
|
|
36
|
+
})
|
|
37
|
+
// Create an index for the data
|
|
38
|
+
store.createIndex('$idb_id', '$idb_id', { unique: true })
|
|
39
|
+
// Create an index for the data
|
|
40
|
+
store.createIndex('$record', '$record', { unique: false })
|
|
41
|
+
|
|
42
|
+
//Create an index that is not unique (two person can have the same age)
|
|
43
|
+
store.createIndex('$last_edit', '$last_edit', { unique: false })
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
dataBase = db
|
|
47
|
+
return dataBase
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.log('==> Erro ', err)
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* @Description: wrapper to insert new data in the store (entry is entered if doesn't already exist in db)
|
|
56
|
+
* @Params storeName {String}: name of the store
|
|
57
|
+
* @Params data {object}: new value to enter
|
|
58
|
+
* @Return promise
|
|
59
|
+
*/
|
|
60
|
+
async insertDataInDB(data) {
|
|
61
|
+
try {
|
|
62
|
+
//Index param
|
|
63
|
+
const searchIndex = '$idb_id'
|
|
64
|
+
//search by package Id index
|
|
65
|
+
const value = await dataBase.getFromIndex(
|
|
66
|
+
storeName,
|
|
67
|
+
searchIndex,
|
|
68
|
+
data[searchIndex]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
//Add entry to database if does not exist
|
|
72
|
+
if (!value) {
|
|
73
|
+
const addedItem = await dataBase.add(storeName, $_.cloneDeep(data))
|
|
74
|
+
|
|
75
|
+
return addedItem
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.log('Error..', err)
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
/*@Description - Helper to get all data existing in the store
|
|
83
|
+
@Param storeName {String} - Name of the store
|
|
84
|
+
*@Return Promise {array} of all entries
|
|
85
|
+
*/
|
|
86
|
+
async getAllFromDB() {
|
|
87
|
+
try {
|
|
88
|
+
//Get all from the storeName order by last edit
|
|
89
|
+
const entryList = await dataBase.getAllFromIndex(
|
|
90
|
+
storeName,
|
|
91
|
+
'lastEdit'
|
|
92
|
+
)
|
|
93
|
+
return entryList
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.log('error...', err)
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
*@Description - Helper to get one entry from the store
|
|
101
|
+
*@Param target {String} - id of the entry
|
|
102
|
+
*@Return Promise {array} of all entries
|
|
103
|
+
*/
|
|
104
|
+
async getFromDB(target) {
|
|
105
|
+
try {
|
|
106
|
+
//Index param
|
|
107
|
+
const searchIndex = '$idb_id'
|
|
108
|
+
//search by package Id index
|
|
109
|
+
const entry = await dataBase.getFromIndex(
|
|
110
|
+
storeName,
|
|
111
|
+
searchIndex,
|
|
112
|
+
target
|
|
113
|
+
)
|
|
114
|
+
return entry
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.log('error...', err)
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/*
|
|
121
|
+
*@Description - Helper to update data in a store
|
|
122
|
+
* @Params storeName {String} - name of the store
|
|
123
|
+
* @Params index {String} - name of the index
|
|
124
|
+
* @Params target {String| num} - id of the element to update
|
|
125
|
+
* @Params newValue {Object} - new value to enter
|
|
126
|
+
*@return Promise
|
|
127
|
+
*/
|
|
128
|
+
async updateDataInDB(target, newValue) {
|
|
129
|
+
try {
|
|
130
|
+
//Index param
|
|
131
|
+
const searchIndex = '$idb_id'
|
|
132
|
+
|
|
133
|
+
//search by package Id index
|
|
134
|
+
const existingRecord = await dataBase.getFromIndex(
|
|
135
|
+
storeName,
|
|
136
|
+
searchIndex,
|
|
137
|
+
target
|
|
138
|
+
)
|
|
139
|
+
//If there is an existing record update the record with new data
|
|
140
|
+
if (existingRecord) {
|
|
141
|
+
existingRecord.$record = newValue
|
|
142
|
+
existingRecord.$last_edit = Date.now()
|
|
143
|
+
const updatedItem = await dataBase.put(
|
|
144
|
+
storeName,
|
|
145
|
+
$_.cloneDeep(existingRecord)
|
|
146
|
+
)
|
|
147
|
+
//await this.getAllFromDB(storeName)
|
|
148
|
+
return updatedItem
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
console.log('Error: ', err)
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
/*
|
|
155
|
+
* @Description - Heleper to delete entry from the store
|
|
156
|
+
* @Params storeName {String} - name of the store
|
|
157
|
+
* @Params index {String} - name of the index
|
|
158
|
+
* @Params target {String| num} - id of the element to remove
|
|
159
|
+
* @Return reference of deleted item
|
|
160
|
+
*/
|
|
161
|
+
async deleteDataInDB(target) {
|
|
162
|
+
try {
|
|
163
|
+
//Index param
|
|
164
|
+
const searchIndex = '$idb_id'
|
|
165
|
+
|
|
166
|
+
//search by package Id index
|
|
167
|
+
const existingRecord = await dataBase.getFromIndex(
|
|
168
|
+
storeName,
|
|
169
|
+
searchIndex,
|
|
170
|
+
target
|
|
171
|
+
)
|
|
172
|
+
//If there is an existing delete it from the store
|
|
173
|
+
if (existingRecord) {
|
|
174
|
+
const deletedItem = await dataBase.delete(
|
|
175
|
+
storeName,
|
|
176
|
+
existingRecord._$id
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return deletedItem
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.log('Error: ', err)
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* @description creating a small save plug-in to save store state in the localStorage
|
|
187
|
+
* the plugin listen for changes made to the Pinia store store to store them in the browser storage.
|
|
188
|
+
* Since the The handler is called after every actions we want to limit the saving of data to storage only
|
|
189
|
+
* when the changes are affecting the user interaction.
|
|
190
|
+
* This prevent resetting the store to initial state when the browser refreshes
|
|
191
|
+
* @param {Object} store Pinia Store
|
|
192
|
+
* @param {String} item package $idb_id
|
|
193
|
+
*/
|
|
194
|
+
async saveState(store, item) {
|
|
195
|
+
store.$onAction(async ({ name, store, args, after }) => {
|
|
196
|
+
//Should only track changes actions on userMetadata
|
|
197
|
+
if (!['updateUserMetaData', 'setUserMetaData'].includes(name)) return
|
|
198
|
+
|
|
199
|
+
// Open DB with a store
|
|
200
|
+
const search = await this.getFromDB(item)
|
|
201
|
+
|
|
202
|
+
if (Object.entries(store.$state.userMetaData).length && search) {
|
|
203
|
+
// Update the db store
|
|
204
|
+
await this.updateDataInDB(item, {
|
|
205
|
+
progress: store.$state.userMetaData,
|
|
206
|
+
userSettings: store.$state.applicationSettings,
|
|
207
|
+
routeHistory: store.getRouteHistory
|
|
208
|
+
})
|
|
209
|
+
//==================================================
|
|
210
|
+
} else {
|
|
211
|
+
//Add Entry to db store
|
|
212
|
+
await this.insertDataInDB({
|
|
213
|
+
$idb_id: item,
|
|
214
|
+
$record: {
|
|
215
|
+
progress: store.$state.userMetaData,
|
|
216
|
+
userSettings: store.$state.applicationSettings,
|
|
217
|
+
routeHistory: store.getRouteHistory
|
|
218
|
+
},
|
|
219
|
+
$last_edit: Date.now()
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
//})
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
package/src/plugins/save.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/* creating a small save plug-in to save store state in the localStorage
|
|
2
|
-
* the plugin listen for mutations made to the Pinia store and store them in the local browser storage.
|
|
3
|
-
* This prevent reseting the store to initial state when the browser refreshes
|
|
4
|
-
* Note: the plugin is used in the store.js
|
|
5
|
-
*/
|
|
6
|
-
export function saveStatePlugin(store) {
|
|
7
|
-
store.subscribe((mutation, state) => {
|
|
8
|
-
// save the user data
|
|
9
|
-
if (Object.entries(state.$appStore.userMetaData).length) {
|
|
10
|
-
localStorage.setItem(
|
|
11
|
-
'userData',
|
|
12
|
-
JSON.stringify(state.$appStore.userMetaData)
|
|
13
|
-
)
|
|
14
|
-
} else if (
|
|
15
|
-
!localStorage.getItem('userData') &&
|
|
16
|
-
!Object.entries(state.$appStore.userMetaData).length
|
|
17
|
-
) {
|
|
18
|
-
localStorage.setItem('userData', JSON.stringify({}))
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* creating a small save plug-in to get stored state from the localStorage
|
|
25
|
-
*/
|
|
26
|
-
export function getSavedStatePlugin(type, id) {
|
|
27
|
-
if (localStorage.getItem('thisModule')) {
|
|
28
|
-
const savedData = JSON.parse(localStorage.getItem('thisModule'))
|
|
29
|
-
|
|
30
|
-
if (type === 'module' && savedData.id === id) return savedData
|
|
31
|
-
if (type === 'page' && savedData.children.length) {
|
|
32
|
-
return savedData.children.find((p) => id === p.id)
|
|
33
|
-
}
|
|
34
|
-
return JSON.parse(localStorage.getItem('thisModule'))
|
|
35
|
-
}
|
|
36
|
-
return null
|
|
37
|
-
}
|
|
1
|
+
/* creating a small save plug-in to save store state in the localStorage
|
|
2
|
+
* the plugin listen for mutations made to the Pinia store and store them in the local browser storage.
|
|
3
|
+
* This prevent reseting the store to initial state when the browser refreshes
|
|
4
|
+
* Note: the plugin is used in the store.js
|
|
5
|
+
*/
|
|
6
|
+
export function saveStatePlugin(store) {
|
|
7
|
+
store.subscribe((mutation, state) => {
|
|
8
|
+
// save the user data
|
|
9
|
+
if (Object.entries(state.$appStore.userMetaData).length) {
|
|
10
|
+
localStorage.setItem(
|
|
11
|
+
'userData',
|
|
12
|
+
JSON.stringify(state.$appStore.userMetaData)
|
|
13
|
+
)
|
|
14
|
+
} else if (
|
|
15
|
+
!localStorage.getItem('userData') &&
|
|
16
|
+
!Object.entries(state.$appStore.userMetaData).length
|
|
17
|
+
) {
|
|
18
|
+
localStorage.setItem('userData', JSON.stringify({}))
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* creating a small save plug-in to get stored state from the localStorage
|
|
25
|
+
*/
|
|
26
|
+
export function getSavedStatePlugin(type, id) {
|
|
27
|
+
if (localStorage.getItem('thisModule')) {
|
|
28
|
+
const savedData = JSON.parse(localStorage.getItem('thisModule'))
|
|
29
|
+
|
|
30
|
+
if (type === 'module' && savedData.id === id) return savedData
|
|
31
|
+
if (type === 'page' && savedData.children.length) {
|
|
32
|
+
return savedData.children.find((p) => id === p.id)
|
|
33
|
+
}
|
|
34
|
+
return JSON.parse(localStorage.getItem('thisModule'))
|
|
35
|
+
}
|
|
36
|
+
return null
|
|
37
|
+
}
|