@enso-ui/how-to 4.0.12 → 4.0.16
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enso-ui/how-to",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.16",
|
|
4
4
|
"description": "Basic how-to package",
|
|
5
5
|
"main": "src/bulma/pages/howTo/Index.vue",
|
|
6
6
|
"scripts": {
|
|
@@ -28,12 +28,11 @@
|
|
|
28
28
|
"@enso-ui/transitions": "^2.0",
|
|
29
29
|
"@fortawesome/fontawesome-svg-core": "^1.2.2",
|
|
30
30
|
"@fortawesome/free-regular-svg-icons": "^5.2.0",
|
|
31
|
-
"@fortawesome/free-solid-svg-icons": "^5.2
|
|
31
|
+
"@fortawesome/free-solid-svg-icons": "^5.11.2",
|
|
32
32
|
"@fortawesome/vue-fontawesome": "3.0.0-5",
|
|
33
|
-
"v-tooltip": "4.0.0-beta.2",
|
|
33
|
+
"v-tooltip": "^4.0.0-beta.2",
|
|
34
34
|
"video.js": "^7.0",
|
|
35
|
-
"vue": "^3.0"
|
|
36
|
-
"vue-video-player": "^5.0"
|
|
35
|
+
"vue": "^3.0"
|
|
37
36
|
},
|
|
38
37
|
"devDependencies": {
|
|
39
38
|
"@vue/cli-plugin-babel": "5.0.0-beta.6",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
<div class="columns is-multiline">
|
|
73
73
|
<div class="column is-half"
|
|
74
74
|
v-for="(vid, index) in filteredVideos"
|
|
75
|
-
:key="
|
|
75
|
+
:key="vid.id">
|
|
76
76
|
<how-to-video class="is-rounded raises-on-hover"
|
|
77
77
|
:video="vid"
|
|
78
78
|
:tags="tags"
|
|
@@ -199,9 +199,11 @@ export default {
|
|
|
199
199
|
|
|
200
200
|
directives: { focus },
|
|
201
201
|
|
|
202
|
-
components: {
|
|
202
|
+
components: {
|
|
203
|
+
Fa, Fade, HowToVideo, Uploader,
|
|
204
|
+
},
|
|
203
205
|
|
|
204
|
-
inject: ['canAccess', 'errorHandler', 'i18n', 'route', 'toastr'],
|
|
206
|
+
inject: ['canAccess', 'errorHandler', 'http', 'i18n', 'route', 'toastr'],
|
|
205
207
|
|
|
206
208
|
data: () => ({
|
|
207
209
|
videos: [],
|
|
@@ -236,7 +238,7 @@ export default {
|
|
|
236
238
|
? this.videos
|
|
237
239
|
: this.videos.filter(({ tagList }) => tagList
|
|
238
240
|
.filter(
|
|
239
|
-
|
|
241
|
+
tagId => this.selectedTags.findIndex(({ id }) => tagId === id) !== -1,
|
|
240
242
|
).length === this.selectedTags.length);
|
|
241
243
|
},
|
|
242
244
|
filteredTags() {
|
|
@@ -265,12 +267,12 @@ export default {
|
|
|
265
267
|
|
|
266
268
|
methods: {
|
|
267
269
|
getVideos() {
|
|
268
|
-
|
|
270
|
+
this.http.get(this.route('howTo.videos.index'))
|
|
269
271
|
.then(({ data }) => (this.videos = data))
|
|
270
272
|
.catch(this.errorHandler);
|
|
271
273
|
},
|
|
272
274
|
getTags() {
|
|
273
|
-
|
|
275
|
+
this.http.get(this.route('howTo.tags.index'))
|
|
274
276
|
.then(({ data }) => (this.tags = data))
|
|
275
277
|
.catch(this.errorHandler);
|
|
276
278
|
},
|
|
@@ -295,7 +297,7 @@ export default {
|
|
|
295
297
|
this.deselectTags();
|
|
296
298
|
},
|
|
297
299
|
deselectTags() {
|
|
298
|
-
this.tags.map(
|
|
300
|
+
this.tags.map(tag => {
|
|
299
301
|
tag.selected = false;
|
|
300
302
|
return tag;
|
|
301
303
|
});
|
|
@@ -305,26 +307,26 @@ export default {
|
|
|
305
307
|
return;
|
|
306
308
|
}
|
|
307
309
|
|
|
308
|
-
|
|
310
|
+
this.http.post(this.route('howTo.tags.store'), { name: this.query })
|
|
309
311
|
.then(({ data }) => {
|
|
310
312
|
this.tags.push(data);
|
|
311
313
|
this.query = '';
|
|
312
314
|
}).catch(this.errorHandler);
|
|
313
315
|
},
|
|
314
316
|
updateTag() {
|
|
315
|
-
|
|
317
|
+
this.http.patch(this.route('howTo.tags.update', this.selectedTag.id), {
|
|
316
318
|
name: this.selectedTag.name,
|
|
317
319
|
}).catch(this.errorHandler);
|
|
318
320
|
},
|
|
319
321
|
deleteTag(tagId) {
|
|
320
|
-
|
|
322
|
+
this.http.delete(this.route('howTo.tags.destroy', tagId))
|
|
321
323
|
.then(() => {
|
|
322
324
|
const index = this.tags.findIndex(({ id }) => id === tagId);
|
|
323
325
|
this.tags.splice(index, 1);
|
|
324
326
|
}).catch(this.errorHandler);
|
|
325
327
|
},
|
|
326
328
|
update() {
|
|
327
|
-
|
|
329
|
+
this.http.patch(this.route('howTo.videos.update', this.video.id), this.video)
|
|
328
330
|
.then(({ data }) => {
|
|
329
331
|
this.toastr.success(data.message);
|
|
330
332
|
this.reset();
|
|
@@ -35,21 +35,20 @@
|
|
|
35
35
|
</card-control>
|
|
36
36
|
<card-control v-if="canAccess('howTo.videos.update')">
|
|
37
37
|
<span class="icon"
|
|
38
|
-
@click="tagging = !tagging;
|
|
38
|
+
@click="tagging = !tagging;
|
|
39
|
+
$emit(tagging ? 'start-tagging' : 'stop-tagging')">
|
|
39
40
|
<fa :icon="tagging ? 'check' : 'tags'"/>
|
|
40
41
|
</span>
|
|
41
42
|
</card-control>
|
|
42
43
|
<card-control v-if="canAccess('howTo.posters.destroy') && video.poster">
|
|
43
|
-
<confirmation @confirm="destroyPoster"
|
|
44
|
-
v-tooltip="i18n('Remove poster')">
|
|
44
|
+
<confirmation @confirm="destroyPoster">
|
|
45
45
|
<span class="icon is-small">
|
|
46
46
|
<fa :icon="['far', 'trash-alt']"/>
|
|
47
47
|
</span>
|
|
48
48
|
</confirmation>
|
|
49
49
|
</card-control>
|
|
50
50
|
<card-control v-else-if="canAccess('howTo.videos.destroy')">
|
|
51
|
-
<confirmation @confirm="destroyVideo"
|
|
52
|
-
v-tooltip="i18n('Delete video')">
|
|
51
|
+
<confirmation @confirm="destroyVideo">
|
|
53
52
|
<span class="icon is-small">
|
|
54
53
|
<fa :icon="['far', 'trash-alt']"/>
|
|
55
54
|
</span>
|
|
@@ -96,14 +95,13 @@ import { FontAwesomeIcon as Fa } from '@fortawesome/vue-fontawesome';
|
|
|
96
95
|
import { library } from '@fortawesome/fontawesome-svg-core';
|
|
97
96
|
import { faInfo, faTags, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
|
|
98
97
|
import { faTrashAlt, faEdit, faImage } from '@fortawesome/free-regular-svg-icons';
|
|
99
|
-
import { videoPlayer } from 'vue-video-player';
|
|
100
|
-
import 'vue-video-player/src/custom-theme.css';
|
|
101
98
|
import {
|
|
102
99
|
Card, CardHeader, CardCollapse, CardControl, CardContent,
|
|
103
100
|
CardFooter, CardFooterItem,
|
|
104
101
|
} from '@enso-ui/card/bulma';
|
|
105
102
|
import Confirmation from '@enso-ui/confirmation/bulma';
|
|
106
103
|
import { Uploader } from '@enso-ui/uploader';
|
|
104
|
+
import VideoPlayer from './VideoPlayer.vue';
|
|
107
105
|
import 'video.js/dist/video-js.css';
|
|
108
106
|
|
|
109
107
|
library.add([faTrashAlt, faInfo, faTags, faEdit, faImage, faInfoCircle]);
|
|
@@ -124,10 +122,10 @@ export default {
|
|
|
124
122
|
CardContent,
|
|
125
123
|
Fa,
|
|
126
124
|
Uploader,
|
|
127
|
-
|
|
125
|
+
VideoPlayer,
|
|
128
126
|
},
|
|
129
127
|
|
|
130
|
-
inject: ['canAccess', 'errorHandler', 'i18n', 'route', 'toastr'],
|
|
128
|
+
inject: ['canAccess', 'errorHandler', 'http', 'i18n', 'route', 'toastr'],
|
|
131
129
|
|
|
132
130
|
props: {
|
|
133
131
|
video: {
|
|
@@ -140,7 +138,7 @@ export default {
|
|
|
140
138
|
},
|
|
141
139
|
},
|
|
142
140
|
|
|
143
|
-
emits: ['delete',
|
|
141
|
+
emits: ['delete', 'edit', 'start-tagging', 'stop-tagging'],
|
|
144
142
|
|
|
145
143
|
data: () => ({
|
|
146
144
|
tagging: false,
|
|
@@ -169,21 +167,21 @@ export default {
|
|
|
169
167
|
};
|
|
170
168
|
},
|
|
171
169
|
destroyPoster() {
|
|
172
|
-
|
|
170
|
+
this.http.delete(this.route('howTo.posters.destroy', this.video.poster.id))
|
|
173
171
|
.then(({ data }) => {
|
|
174
172
|
this.toastr.success(data.message);
|
|
175
173
|
this.video.poster = null;
|
|
176
174
|
}).catch(this.errorHandler);
|
|
177
175
|
},
|
|
178
176
|
destroyVideo() {
|
|
179
|
-
|
|
177
|
+
this.http.delete(this.route('howTo.videos.destroy', this.video.id))
|
|
180
178
|
.then(({ data }) => {
|
|
181
179
|
this.toastr.success(data.message);
|
|
182
180
|
this.$emit('delete');
|
|
183
181
|
}).catch(this.errorHandler);
|
|
184
182
|
},
|
|
185
183
|
removeTag(tag) {
|
|
186
|
-
const index = this.video.tagList.findIndex(
|
|
184
|
+
const index = this.video.tagList.findIndex(id => id === tag.id);
|
|
187
185
|
this.video.tagList.splice(index, 1);
|
|
188
186
|
},
|
|
189
187
|
},
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="video-player" v-if="reseted">
|
|
3
|
+
<video class="video-js" ref="video">
|
|
4
|
+
<track v-for="crtTrack in trackList"
|
|
5
|
+
:key="crtTrack.src"
|
|
6
|
+
:kind="crtTrack.kind"
|
|
7
|
+
:label="crtTrack.label"
|
|
8
|
+
:src="crtTrack.src"
|
|
9
|
+
:srcLang="crtTrack.srcLang"
|
|
10
|
+
:default="crtTrack.default">
|
|
11
|
+
</video>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
// lib
|
|
17
|
+
import _videojs from 'video.js';
|
|
18
|
+
|
|
19
|
+
const videojs = window.videojs || _videojs;
|
|
20
|
+
|
|
21
|
+
// as of videojs 6.6.0
|
|
22
|
+
const DEFAULT_EVENTS = [
|
|
23
|
+
'loadeddata',
|
|
24
|
+
'canplay',
|
|
25
|
+
'canplaythrough',
|
|
26
|
+
'play',
|
|
27
|
+
'pause',
|
|
28
|
+
'waiting',
|
|
29
|
+
'playing',
|
|
30
|
+
'ended',
|
|
31
|
+
'error',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// export
|
|
35
|
+
export default {
|
|
36
|
+
name: 'VideoPlayer',
|
|
37
|
+
|
|
38
|
+
props: {
|
|
39
|
+
start: {
|
|
40
|
+
type: Number,
|
|
41
|
+
default: 0,
|
|
42
|
+
},
|
|
43
|
+
crossOrigin: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: '',
|
|
46
|
+
},
|
|
47
|
+
playsinline: {
|
|
48
|
+
type: Boolean,
|
|
49
|
+
default: false,
|
|
50
|
+
},
|
|
51
|
+
customEventName: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: 'statechanged',
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
type: Object,
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
events: {
|
|
60
|
+
type: Array,
|
|
61
|
+
default: () => [],
|
|
62
|
+
},
|
|
63
|
+
globalOptions: {
|
|
64
|
+
type: Object,
|
|
65
|
+
default: () => ({
|
|
66
|
+
// autoplay: false,
|
|
67
|
+
controls: true,
|
|
68
|
+
// preload: 'auto',
|
|
69
|
+
// fluid: false,
|
|
70
|
+
// muted: false,
|
|
71
|
+
controlBar: {
|
|
72
|
+
remainingTimeDisplay: false,
|
|
73
|
+
playToggle: {},
|
|
74
|
+
progressControl: {},
|
|
75
|
+
fullscreenToggle: {},
|
|
76
|
+
volumeMenuButton: {
|
|
77
|
+
inline: false,
|
|
78
|
+
vertical: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
techOrder: ['html5'],
|
|
82
|
+
plugins: {},
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
globalEvents: {
|
|
86
|
+
type: Array,
|
|
87
|
+
default: () => [],
|
|
88
|
+
},
|
|
89
|
+
trackList: {
|
|
90
|
+
type: Array,
|
|
91
|
+
default: () => [],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
emits: ['ready'],
|
|
96
|
+
|
|
97
|
+
data() {
|
|
98
|
+
return {
|
|
99
|
+
player: null,
|
|
100
|
+
reseted: true,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
watch: {
|
|
105
|
+
options: {
|
|
106
|
+
deep: true,
|
|
107
|
+
handler(options) {
|
|
108
|
+
this.dispose(() => {
|
|
109
|
+
if (options && options.sources && options.sources.length) {
|
|
110
|
+
this.initialize();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
mounted() {
|
|
118
|
+
if (!this.player) {
|
|
119
|
+
this.initialize();
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
beforeUnmount() {
|
|
124
|
+
if (this.player) {
|
|
125
|
+
this.dispose();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
methods: {
|
|
130
|
+
initialize() {
|
|
131
|
+
// videojs options
|
|
132
|
+
const videoOptions = { ...this.globalOptions, ...this.options };
|
|
133
|
+
|
|
134
|
+
// ios fullscreen
|
|
135
|
+
if (this.playsinline) {
|
|
136
|
+
this.$refs.video.setAttribute('playsinline', this.playsinline);
|
|
137
|
+
this.$refs.video.setAttribute('webkit-playsinline', this.playsinline);
|
|
138
|
+
this.$refs.video.setAttribute('x5-playsinline', this.playsinline);
|
|
139
|
+
this.$refs.video.setAttribute('x5-video-player-type', 'h5');
|
|
140
|
+
this.$refs.video.setAttribute('x5-video-player-fullscreen', false);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// cross origin
|
|
144
|
+
if (this.crossOrigin !== '') {
|
|
145
|
+
this.$refs.video.crossOrigin = this.crossOrigin;
|
|
146
|
+
this.$refs.video.setAttribute('crossOrigin', this.crossOrigin);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// emit event
|
|
150
|
+
const emitPlayerState = (event, value) => {
|
|
151
|
+
if (event) {
|
|
152
|
+
this.$emit(event, this.player);
|
|
153
|
+
}
|
|
154
|
+
if (value) {
|
|
155
|
+
this.$emit(this.customEventName, { [event]: value });
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// avoid error "VIDEOJS: ERROR: Unable to find plugin: __ob__"
|
|
160
|
+
if (videoOptions.plugins) {
|
|
161
|
+
delete videoOptions.plugins.__ob__;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// videoOptions
|
|
165
|
+
// console.log('videoOptions', videoOptions)
|
|
166
|
+
|
|
167
|
+
// player
|
|
168
|
+
const self = this;
|
|
169
|
+
this.player = videojs(this.$refs.video, videoOptions, function () {
|
|
170
|
+
// events
|
|
171
|
+
const events = DEFAULT_EVENTS.concat(self.events).concat(self.globalEvents);
|
|
172
|
+
|
|
173
|
+
// watch events
|
|
174
|
+
const onEdEvents = {};
|
|
175
|
+
for (let i = 0; i < events.length; i++) {
|
|
176
|
+
if (typeof events[i] === 'string' && onEdEvents[events[i]] === undefined) {
|
|
177
|
+
(event => {
|
|
178
|
+
onEdEvents[event] = null;
|
|
179
|
+
this.on(event, () => {
|
|
180
|
+
emitPlayerState(event, true);
|
|
181
|
+
});
|
|
182
|
+
})(events[i]);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// watch timeupdate
|
|
187
|
+
this.on('timeupdate', function () {
|
|
188
|
+
emitPlayerState('timeupdate', this.currentTime());
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// player readied
|
|
192
|
+
self.$emit('ready', this);
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
dispose(callback) {
|
|
196
|
+
if (this.player && this.player.dispose) {
|
|
197
|
+
if (this.player.techName_ !== 'Flash') {
|
|
198
|
+
this.player.pause && this.player.pause();
|
|
199
|
+
}
|
|
200
|
+
this.player.dispose();
|
|
201
|
+
this.player = null;
|
|
202
|
+
this.$nextTick(() => {
|
|
203
|
+
this.reseted = false;
|
|
204
|
+
this.$nextTick(() => {
|
|
205
|
+
this.reseted = true;
|
|
206
|
+
this.$nextTick(() => {
|
|
207
|
+
callback && callback();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
</script>
|
|
216
|
+
|
|
217
|
+
<style>
|
|
218
|
+
.vjs-custom-skin > .video-js .vjs-big-play-button {
|
|
219
|
+
top: 50%;
|
|
220
|
+
left: 50%;
|
|
221
|
+
margin-left: -1.5em;
|
|
222
|
+
margin-top: -1em
|
|
223
|
+
}
|
|
224
|
+
</style>
|