fcad-core-dragon 2.0.0-beta.1 → 2.0.0-beta.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/{.eslintrc.js → .eslintrc.cjs} +13 -18
- package/bk.scss +117 -0
- package/package.json +23 -39
- package/src/$locales/en.json +30 -16
- package/src/$locales/fr.json +29 -16
- package/src/components/AppBase.vue +740 -305
- package/src/components/AppBaseButton.vue +33 -5
- package/src/components/AppBaseErrorDisplay.vue +43 -35
- package/src/components/AppBaseModule.vue +447 -623
- package/src/components/AppBasePage.vue +37 -25
- package/src/components/AppCompAudio.vue +266 -0
- package/src/components/AppCompBranchButtons.vue +52 -63
- package/src/components/AppCompButtonProgress.vue +1 -16
- package/src/components/AppCompCarousel.vue +43 -39
- package/src/components/AppCompInputCheckBox.vue +9 -3
- package/src/components/AppCompInputDropdown.vue +2 -4
- package/src/components/AppCompInputRadio.vue +8 -15
- package/src/components/AppCompInputTextTable.vue +15 -12
- package/src/components/AppCompInputTextToFillDropdown.vue +16 -14
- package/src/components/AppCompInputTextToFillText.vue +2 -2
- package/src/components/AppCompJauge.vue +13 -1
- package/src/components/AppCompMenu.vue +203 -10
- package/src/components/AppCompMenuItem.vue +20 -3
- package/src/components/AppCompNavigation.vue +351 -355
- package/src/components/AppCompNoteCall.vue +62 -47
- package/src/components/AppCompNoteCredit.vue +182 -79
- package/src/components/AppCompPlayBar.vue +975 -1023
- package/src/components/AppCompPlayBarProgress.vue +73 -0
- package/src/components/AppCompPopUp.vue +175 -114
- package/src/components/AppCompQuiz.vue +67 -81
- package/src/components/AppCompQuizRecall.vue +32 -5
- package/src/components/AppCompSVG.vue +66 -40
- package/src/components/AppCompSettingsMenu.vue +6 -8
- package/src/components/AppCompTableOfContent.vue +166 -45
- package/src/components/AppCompVideoPlayer.vue +154 -110
- package/src/components/BaseModule.vue +21 -17
- package/src/main.js +124 -88
- package/src/mixins/$mediaMixins.js +827 -0
- package/src/mixins/$pageMixins.js +65 -109
- package/src/mixins/$quizMixins.js +12 -26
- package/src/mixins/timerMixin.js +8 -9
- package/src/module/store.js +187 -68
- package/src/module/xapi/ADL.js +90 -53
- package/src/module/xapi/Crypto/Hasher.js +8 -8
- package/src/module/xapi/Crypto/WordArray.js +6 -6
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +4 -4
- package/src/module/xapi/Crypto/algorithms/C_algo.js +14 -18
- package/src/module/xapi/Crypto/algorithms/HMAC.js +1 -1
- package/src/module/xapi/Crypto/algorithms/SHA1.js +1 -1
- package/src/module/xapi/Crypto/encoders/Base.js +7 -7
- package/src/module/xapi/Crypto/encoders/Base64.js +3 -3
- package/src/module/xapi/Crypto/encoders/Hex.js +2 -2
- package/src/module/xapi/Crypto/encoders/Latin1.js +3 -3
- package/src/module/xapi/Crypto/encoders/Utf8.js +3 -3
- package/src/module/xapi/Statement/index.js +1 -1
- package/src/module/xapi/launch.js +10 -10
- package/src/module/xapi/utils.js +17 -17
- package/src/module/xapi/wrapper.js +123 -50
- package/src/module/xapi/xapiStatement.js +29 -29
- package/src/plugins/helper.js +8 -9
- package/src/plugins/i18n.js +23 -10
- package/src/plugins/scorm.js +14 -14
- package/src/router/index.js +3 -4
- package/src/router/routes.js +10 -30
- package/src/shared/generalfuncs.js +31 -24
- package/src/shared/validators.js +730 -20
- package/.prettierrc.js +0 -5
- package/babel.config.js +0 -3
- package/src/components/AppBaseDragChoice.vue +0 -91
- package/src/components/AppBaseDropZone.vue +0 -112
- package/src/components/AppCompBif.vue +0 -120
- package/src/components/AppCompDragAndDrop.vue +0 -339
- package/src/components/AppCompInputAssociation.vue +0 -332
- package/src/components/AppCompMediaPlayer.vue +0 -397
- package/src/plugins/timeManager.js +0 -77
- package/src/routes_bckp.js +0 -313
- package/src/routes_static.js +0 -344
- package/vue.config.js +0 -83
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@ Description: This component is used to display media element (video/audio and Gsap timelined animation )
|
|
3
|
-
@ What it does: The component create the HTMLMediaElement tag( video/audio) from data provided by user.
|
|
4
|
-
Once the HTMLMediaElement tag is created, the component save the HTMLMediaElement to store and
|
|
5
|
-
make it available to all other component that will need id
|
|
6
|
-
-->
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<div
|
|
10
|
-
v-if="mData"
|
|
11
|
-
id="contain-media-player"
|
|
12
|
-
class="app-media-player"
|
|
13
|
-
:class="[{ FS: fullScreen }, animationType, CCBrowser]"
|
|
14
|
-
:style="{ height: [fsHeigh] }"
|
|
15
|
-
>
|
|
16
|
-
<!------------------video section --------------------------->
|
|
17
|
-
<video
|
|
18
|
-
v-if="media && media.mType === 'video'"
|
|
19
|
-
id="video"
|
|
20
|
-
ref="video"
|
|
21
|
-
tabindex="0"
|
|
22
|
-
class="v-media m-video"
|
|
23
|
-
:poster="media.mPoster"
|
|
24
|
-
@loadedmetadata="updateMediaData($event)"
|
|
25
|
-
@load="() => {}"
|
|
26
|
-
@error="() => {}"
|
|
27
|
-
>
|
|
28
|
-
<source
|
|
29
|
-
v-for="(aMedia, index) in media.mSources"
|
|
30
|
-
:key="index"
|
|
31
|
-
:src="`${aMedia.src}`"
|
|
32
|
-
:type="`${media.mType}/${aMedia.type}`"
|
|
33
|
-
/>
|
|
34
|
-
<track
|
|
35
|
-
v-if="media.mSubtitle"
|
|
36
|
-
:src="media.mSubtitle.src"
|
|
37
|
-
:srclang="media.mSubtitle.srclang"
|
|
38
|
-
:label="media.mSubtitle.label"
|
|
39
|
-
/>
|
|
40
|
-
</video>
|
|
41
|
-
<!------------------ audio section --------------------------->
|
|
42
|
-
<video
|
|
43
|
-
v-if="media && media.mType === 'audio'"
|
|
44
|
-
ref="audio"
|
|
45
|
-
tabindex="0"
|
|
46
|
-
class="v-media m-audio"
|
|
47
|
-
:poster="media.mPoster"
|
|
48
|
-
@loadedmetadata="updateMediaData($event)"
|
|
49
|
-
>
|
|
50
|
-
<source
|
|
51
|
-
v-for="(aMedia, index) in media.mSources"
|
|
52
|
-
:key="index"
|
|
53
|
-
:src="`${aMedia.src}`"
|
|
54
|
-
:type="`${media.mType}/${aMedia.type}`"
|
|
55
|
-
/>
|
|
56
|
-
<track
|
|
57
|
-
v-if="media.mSubtitle"
|
|
58
|
-
:src="media.mSubtitle.src"
|
|
59
|
-
:srclang="media.mSubtitle.srcLang"
|
|
60
|
-
:label="media.mSubtitle.label"
|
|
61
|
-
/>
|
|
62
|
-
</video>
|
|
63
|
-
<!------------------animation section --------------------------->
|
|
64
|
-
<div
|
|
65
|
-
v-if="media && hasAnimation"
|
|
66
|
-
id="anim-box"
|
|
67
|
-
ref="anim-box"
|
|
68
|
-
class="anim-canvas"
|
|
69
|
-
:class="[animationType]"
|
|
70
|
-
role="figure"
|
|
71
|
-
aria-roledescription="Animation"
|
|
72
|
-
>
|
|
73
|
-
<p class="sr-only">{{ mediaA11Y.srTxt }}</p>
|
|
74
|
-
<a class="skip-link" href="" @click.prevent="skipTo('playbar-play')">
|
|
75
|
-
{{ mediaA11Y.skipToTxt }}
|
|
76
|
-
</a>
|
|
77
|
-
<slot ref="animScene" name="drawingCanvas">
|
|
78
|
-
You have an animation to create
|
|
79
|
-
</slot>
|
|
80
|
-
</div>
|
|
81
|
-
<!-- <div v-if="mData"> -->
|
|
82
|
-
<app-comp-play-bar :media-to-play="mData" />
|
|
83
|
-
<!-- </div> -->
|
|
84
|
-
<!-- <portal-target :key="$route.fullPath" name="playbar-portal"></portal-target> -->
|
|
85
|
-
</div>
|
|
86
|
-
</template>
|
|
87
|
-
|
|
88
|
-
<script>
|
|
89
|
-
import { mapGetters } from 'vuex'
|
|
90
|
-
|
|
91
|
-
export default {
|
|
92
|
-
props: {
|
|
93
|
-
mData: {
|
|
94
|
-
type: Object,
|
|
95
|
-
required: true
|
|
96
|
-
},
|
|
97
|
-
fullScreen: {
|
|
98
|
-
type: Boolean,
|
|
99
|
-
default: true
|
|
100
|
-
},
|
|
101
|
-
custom: {
|
|
102
|
-
type: Boolean,
|
|
103
|
-
default: false
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
|
|
107
|
-
data() {
|
|
108
|
-
return {
|
|
109
|
-
media: null,
|
|
110
|
-
timeline: null,
|
|
111
|
-
subtitleMenuButtons: [],
|
|
112
|
-
subtitlesMenu: null,
|
|
113
|
-
fsHeigh: null,
|
|
114
|
-
isMedia: false
|
|
115
|
-
//currentMediaElement: null
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
computed: {
|
|
119
|
-
...mapGetters([
|
|
120
|
-
'hasMediaElOrTimeline',
|
|
121
|
-
'getCurrentBrowser',
|
|
122
|
-
'getCurrentPage'
|
|
123
|
-
]),
|
|
124
|
-
|
|
125
|
-
setTimeout() {
|
|
126
|
-
return window.setTimeout
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
hasAnimation() {
|
|
130
|
-
if (
|
|
131
|
-
this.mData &&
|
|
132
|
-
(this.mData.animation || this.mData.type === 'pg_animation')
|
|
133
|
-
) {
|
|
134
|
-
return true
|
|
135
|
-
} else return false
|
|
136
|
-
},
|
|
137
|
-
animationType() {
|
|
138
|
-
let type = null
|
|
139
|
-
if (this.mData) {
|
|
140
|
-
if (this.mData.type === 'pg_animation') {
|
|
141
|
-
type = 'animationOnly'
|
|
142
|
-
}
|
|
143
|
-
if (this.mData.type === 'pg_media') {
|
|
144
|
-
if (this.mData.mediaData.mType === 'audio') {
|
|
145
|
-
type = 'audioAnimation'
|
|
146
|
-
} else if (this.mData.mediaData.mType === 'video') {
|
|
147
|
-
type = 'videoAnimation'
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return type
|
|
152
|
-
},
|
|
153
|
-
CCBrowser() {
|
|
154
|
-
let browser = this.getCurrentBrowser
|
|
155
|
-
|
|
156
|
-
if (browser === 'Safari') {
|
|
157
|
-
return 'safari'
|
|
158
|
-
} else {
|
|
159
|
-
return 'chrome'
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
mediaA11Y() {
|
|
164
|
-
let m = {
|
|
165
|
-
srTxt: '',
|
|
166
|
-
skipToTxt: ''
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
this.$i18n.locale === 'fr'
|
|
170
|
-
? (m = {
|
|
171
|
-
srTxt:
|
|
172
|
-
"Le contenu d'apprentissage sera seulement disponible à la fin de la narration. Appuyez le bouton jouer, pour lancer l'animation.",
|
|
173
|
-
skipToTxt: 'Passer au controleur de media'
|
|
174
|
-
})
|
|
175
|
-
: (m = {
|
|
176
|
-
srTxt:
|
|
177
|
-
'The learning content will be available only at the end of the narration. Press the play button to start the animation',
|
|
178
|
-
skipToTxt: 'Skip to play-bar'
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
return m
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
watch: {
|
|
185
|
-
media() {
|
|
186
|
-
let mElement = this.$refs[this.media.mType]
|
|
187
|
-
/* Handeling media subtitles
|
|
188
|
-
* if there is any subtitle, create the subtitle menu
|
|
189
|
-
*/
|
|
190
|
-
if (mElement && mElement.textTracks) {
|
|
191
|
-
this.subtitlesMenu = []
|
|
192
|
-
for (let i = 0; i < mElement.textTracks.length; i++) {
|
|
193
|
-
this.subtitlesMenu.push({
|
|
194
|
-
id: `subtitle-${mElement.textTracks[i].language}`,
|
|
195
|
-
lang: mElement.textTracks[i].language,
|
|
196
|
-
label: mElement.textTracks[i].label
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
mData: {
|
|
203
|
-
immediate: true,
|
|
204
|
-
handler() {
|
|
205
|
-
if (this.mData && this.mData.type == 'pg_media') {
|
|
206
|
-
this.media = {
|
|
207
|
-
mType: this.mData.mediaData.mType,
|
|
208
|
-
mSources: [...this.mData.mediaData.mSources],
|
|
209
|
-
mPoster: this.mData.mediaData.mPoster || '',
|
|
210
|
-
mSubtitle: this.mData.mediaData.mSubtitle || null,
|
|
211
|
-
mTranscript: this.mData.mediaData.mTranscript || null
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// Its an animation
|
|
215
|
-
else if (this.mData && this.mData.type == 'pg_animation') {
|
|
216
|
-
this.media = this.mData.animation
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
mounted() {
|
|
222
|
-
if (this.fullScreen) {
|
|
223
|
-
this.fsHeigh = ` ${window.innerHeight - 55}px`
|
|
224
|
-
} else {
|
|
225
|
-
this.fsHeigh = `100%`
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
this.$bus.$emit('videoFullScreen', this.fullScreen)
|
|
229
|
-
if (this.media) {
|
|
230
|
-
window.addEventListener('resize', this.caclWindowHeight)
|
|
231
|
-
}
|
|
232
|
-
this.currentMediaElement
|
|
233
|
-
},
|
|
234
|
-
|
|
235
|
-
beforeDestroy() {
|
|
236
|
-
this.$bus.$emit('videoFullScreen', false)
|
|
237
|
-
window.removeEventListener('resize', this.caclWindowHeight)
|
|
238
|
-
},
|
|
239
|
-
methods: {
|
|
240
|
-
hideSutitle() {
|
|
241
|
-
return
|
|
242
|
-
},
|
|
243
|
-
showSubtitle() {
|
|
244
|
-
return
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* @description select available= subtitle for title for a media
|
|
249
|
-
* @param {htmlElement} e
|
|
250
|
-
*/
|
|
251
|
-
selectSubtitle(e) {
|
|
252
|
-
let mElement = document.querySelector(
|
|
253
|
-
`.app-media-player> ${this.media.mType}`
|
|
254
|
-
)
|
|
255
|
-
let subtitlesOption = this.$el.querySelectorAll('.subtitles-menu> a')
|
|
256
|
-
|
|
257
|
-
//set all the subitle options as inactive
|
|
258
|
-
for (let i = 0; i < subtitlesOption.length; i++) {
|
|
259
|
-
subtitlesOption[i].setAttribute('data-state', 'inactive')
|
|
260
|
-
subtitlesOption[i].className = 'sub_inactive'
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
for (let i = 0; i < mElement.textTracks.length; i++) {
|
|
264
|
-
// For the 'subtitles-off' button, the first condition will never match so all will subtitles be turned off
|
|
265
|
-
if (mElement.textTracks[i].language == e.target.lang) {
|
|
266
|
-
mElement.textTracks[i].mode = 'showing'
|
|
267
|
-
e.target.setAttribute('data-state', 'active')
|
|
268
|
-
e.target.className = 'sub_active'
|
|
269
|
-
} else {
|
|
270
|
-
mElement.textTracks[i].mode = 'hidden'
|
|
271
|
-
e.target.setAttribute('data-state', 'active')
|
|
272
|
-
e.target.className = 'sub_active'
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @description update the information for the mediaElement in the store
|
|
279
|
-
* @param {htmlElement} e
|
|
280
|
-
* @fires update-page to AppBaseModule.vue
|
|
281
|
-
*/
|
|
282
|
-
updateMediaData(e) {
|
|
283
|
-
//dispatch loading status of for this component
|
|
284
|
-
this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'loading')
|
|
285
|
-
|
|
286
|
-
this.$store
|
|
287
|
-
.dispatch('updateCurrentMediaElement', e.target)
|
|
288
|
-
.then(() => {
|
|
289
|
-
this.$bus.$emit('update-page')
|
|
290
|
-
if (this.mData.timeline) {
|
|
291
|
-
//Set the length (total duration) of the timeline to the duration of the media
|
|
292
|
-
//Note: using totalDuration() or duration() will not work to define the duration to the length of the media.
|
|
293
|
-
this.mData.timeline.set({}, {}, e.target.duration)
|
|
294
|
-
}
|
|
295
|
-
})
|
|
296
|
-
.then(() =>
|
|
297
|
-
this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'ready')
|
|
298
|
-
)
|
|
299
|
-
},
|
|
300
|
-
caclWindowHeight() {
|
|
301
|
-
document.getElementById(
|
|
302
|
-
'contain-media-player'
|
|
303
|
-
).style.height = `${window.innerHeight - 55}px`
|
|
304
|
-
},
|
|
305
|
-
// TODO: Checking that the media ressource exist/is available
|
|
306
|
-
// true: create set the ressource src
|
|
307
|
-
// false: disable play button, show on screen message media not available to user
|
|
308
|
-
//
|
|
309
|
-
async checkRessource(url) {
|
|
310
|
-
this.axios
|
|
311
|
-
.get(url, { responseType: 'blob' })
|
|
312
|
-
.then((res) => {
|
|
313
|
-
res
|
|
314
|
-
})
|
|
315
|
-
.catch((err) => {
|
|
316
|
-
err
|
|
317
|
-
})
|
|
318
|
-
},
|
|
319
|
-
/**
|
|
320
|
-
* @description- Skip directly to the specify containt/region*
|
|
321
|
-
* main content is Node with defined ID
|
|
322
|
-
* @param {String} targetID- Css selector for the target element
|
|
323
|
-
*/
|
|
324
|
-
|
|
325
|
-
skipTo(targetID) {
|
|
326
|
-
let skipTo = document.querySelector(`#wrapper-content`) //default definition of main element
|
|
327
|
-
|
|
328
|
-
if (targetID) {
|
|
329
|
-
let targetEl = document.querySelector(`#${targetID}`) // search for node element specified as main
|
|
330
|
-
|
|
331
|
-
if (targetEl) skipTo = targetEl
|
|
332
|
-
}
|
|
333
|
-
let targetTop = skipTo.offsetTop
|
|
334
|
-
|
|
335
|
-
let scrollOpt = {
|
|
336
|
-
top: targetTop - 100,
|
|
337
|
-
left: 0,
|
|
338
|
-
behavior: 'auto' //auto
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
//Allowing accessibility control with keyboard
|
|
342
|
-
skipTo.setAttribute('tabIndex', -1)
|
|
343
|
-
window.scrollTo(scrollOpt)
|
|
344
|
-
skipTo.focus()
|
|
345
|
-
},
|
|
346
|
-
|
|
347
|
-
async setMediaElement() {
|
|
348
|
-
const { type } = await this.getCurrentPage
|
|
349
|
-
if (!['pg_media, pg_animation'].includes(type)) return null
|
|
350
|
-
|
|
351
|
-
let mediaObject = {}
|
|
352
|
-
switch (type) {
|
|
353
|
-
case 'pg_media': {
|
|
354
|
-
const {
|
|
355
|
-
animation,
|
|
356
|
-
type,
|
|
357
|
-
mediaData: { mSources, mType, mSubtitle, mPoster, mTranscript },
|
|
358
|
-
timeline,
|
|
359
|
-
mElement
|
|
360
|
-
} = this.getCurrentPage
|
|
361
|
-
|
|
362
|
-
mediaObject = {
|
|
363
|
-
animation,
|
|
364
|
-
type,
|
|
365
|
-
mediaData: { mSources, mType, mSubtitle, mPoster, mTranscript },
|
|
366
|
-
timeline,
|
|
367
|
-
mElement
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
break
|
|
371
|
-
}
|
|
372
|
-
case 'pg_animation': {
|
|
373
|
-
const { animation, type, timeline } = this.getCurrentPage
|
|
374
|
-
mediaObject = { animation, type, timeline }
|
|
375
|
-
break
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return mediaObject
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
</script>
|
|
384
|
-
<style lang="scss">
|
|
385
|
-
$widthVideo: 100%;
|
|
386
|
-
$widthAudioAnimation: 50%;
|
|
387
|
-
|
|
388
|
-
%animation {
|
|
389
|
-
position: absolute;
|
|
390
|
-
top: 0;
|
|
391
|
-
left: 0;
|
|
392
|
-
width: $widthVideo;
|
|
393
|
-
height: 100%;
|
|
394
|
-
z-index: 1;
|
|
395
|
-
overflow: hidden;
|
|
396
|
-
}
|
|
397
|
-
</style>
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
export default function timeManager(Vue) {
|
|
2
|
-
Vue.prototype.$timeManager = new Vue({
|
|
3
|
-
data() {
|
|
4
|
-
return {
|
|
5
|
-
lessonTimeCounter: 0,
|
|
6
|
-
//activityTimeCounter: 0,
|
|
7
|
-
lessonDuration: 0,
|
|
8
|
-
activityDuration: 0,
|
|
9
|
-
activityInterval: null,
|
|
10
|
-
lessonInterval: null,
|
|
11
|
-
fullInterval: null
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
methods: {
|
|
15
|
-
/* Start the timer */
|
|
16
|
-
startTimer(op) {
|
|
17
|
-
if (op && !['activity', 'lesson'].includes(op))
|
|
18
|
-
throw new Error('this is not a valid option for the timer')
|
|
19
|
-
|
|
20
|
-
switch (op) {
|
|
21
|
-
case 'activity':
|
|
22
|
-
this.activityInterval = setInterval(() => {
|
|
23
|
-
this.activityDuration += 1
|
|
24
|
-
}, 1000)
|
|
25
|
-
|
|
26
|
-
break
|
|
27
|
-
|
|
28
|
-
case 'lesson':
|
|
29
|
-
this.lessonInterval = setInterval(() => {
|
|
30
|
-
this.lessonTimeCounter += 1
|
|
31
|
-
}, 1000)
|
|
32
|
-
break
|
|
33
|
-
|
|
34
|
-
default:
|
|
35
|
-
this.fullInterval = setInterval(() => {
|
|
36
|
-
this.activityDuration += 1
|
|
37
|
-
this.lessonDuration += 1
|
|
38
|
-
}, 1000)
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
/* Stop the timer and reset thimer to zero */
|
|
42
|
-
stopTimer(op) {
|
|
43
|
-
if (op && !['activity', 'lesson'].includes(op))
|
|
44
|
-
throw new Error('this is not a valid parameter')
|
|
45
|
-
|
|
46
|
-
if (op === 'activity' && this.activityDuration > 0) {
|
|
47
|
-
clearInterval(this.activityInterval)
|
|
48
|
-
this.activityDuration = 0
|
|
49
|
-
} else if (op === 'lesson' && this.lessonDuration > 0) {
|
|
50
|
-
clearInterval(this.lessonInterval)
|
|
51
|
-
this.lessonDuration = 0
|
|
52
|
-
} else {
|
|
53
|
-
clearInterval(this.fullInterval)
|
|
54
|
-
this.activityDuration = 0
|
|
55
|
-
this.lessonDuration = 0
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
/* Pause the timer but does not reset to zero*/
|
|
59
|
-
pauseTimer(op) {
|
|
60
|
-
if (op && !['activity', 'lesson'].includes(op))
|
|
61
|
-
throw new Error('this is not a valid parameter')
|
|
62
|
-
|
|
63
|
-
if (op === 'activity' && this.activityDuration > 0) {
|
|
64
|
-
window.clearInterval(this.activityDuration)
|
|
65
|
-
} else if (op === 'lesson') {
|
|
66
|
-
window.clearInterval(this.lessonDuration)
|
|
67
|
-
} else {
|
|
68
|
-
clearInterval(this.fullInterval)
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
formatTime(seconds) {
|
|
72
|
-
let t = new Date(null)
|
|
73
|
-
t.setSeconds(seconds)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
}
|