Completed
Push — master ( d2e836...c77b13 )
by Jacob
01:39
created

tinymce/js/premiumvideomodule.js   A

Complexity

Total Complexity 35
Complexity/F 1.75

Size

Lines of Code 225
Function Count 20

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 35
dl 0
loc 225
rs 9
c 1
b 0
f 0
cc 0
nc 3
mnd 2
bc 27
fnc 20
bpm 1.35
cpm 1.75
noi 8

2 Functions

Rating   Name   Duplication   Size   Complexity  
B M.tinymce_recordrtc.stop_recording_video 0 31 1
B M.tinymce_recordrtc.capture_audio_video 0 26 1
1
// TinyMCE recordrtc library functions.
2
// @package    tinymce_recordrtc.
3
// @author     Jesus Federico  (jesus [at] blindsidenetworks [dt] com).
4
// @copyright  2016 to present, Blindside Networks Inc.
5
// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
6
7
// Scrutinizer CI directives.
8
/** global: M */
9
/** global: Y */
10
/** global: tinyMCEPopup */
11
/** global: recordrtc */
12
/** global: alertWarning */
13
/** global: alertDanger */
14
/** global: maxUploadSize */
15
/** global: mediaRecorder */
16
/** global: player */
17
/** global: playerDOM */
18
/** global: recType */
19
/** global: startStopBtn */
20
/** global: uploadBtn */
21
/** global: socket */
22
23
// This function is initialized from PHP.
24
M.tinymce_recordrtc.view_init = function() {
25
    // Assignment of global variables.
26
    alertWarning = Y.one('div#alert-warning');
27
    alertDanger = Y.one('div#alert-danger');
28
    player = Y.one('video#player');
29
    playerDOM = document.querySelector('video#player');
30
    startStopBtn = Y.one('button#start-stop');
31
    uploadBtn = Y.one('button#upload');
32
    recType = 'video';
33
    socket = window.io(window.params.serverurl);
34
35
    // Show alert and redirect user if connection is not secure.
36
    M.tinymce_recordrtc.check_secure();
37
    // Show alert if using non-ideal browser.
38
    M.tinymce_recordrtc.check_browser();
39
40
    // Connect to premium recording server.
41
    M.tinymce_recordrtc.init_connection();
42
43
    // Run when user clicks on "record" button.
44
    startStopBtn.on('click', function() {
45
        startStopBtn.set('disabled', true);
46
47
        // If button is displaying "Start Recording" or "Record Again".
48
        if ((startStopBtn.get('textContent') === M.util.get_string('startrecording', 'tinymce_recordrtc')) ||
49
            (startStopBtn.get('textContent') === M.util.get_string('recordagain', 'tinymce_recordrtc')) ||
50
            (startStopBtn.get('textContent') === M.util.get_string('recordingfailed', 'tinymce_recordrtc'))) {
51
            // Make sure the upload button is not shown.
52
            uploadBtn.ancestor().ancestor().addClass('hide');
53
54
            // Change look of recording button.
55
            if (!recordrtc.oldermoodle) {
56
                startStopBtn.replaceClass('btn-outline-danger', 'btn-danger');
57
            }
58
59
            // Initialize common configurations.
60
            var commonConfig = {
61
                // When the stream is captured from the microphone/webcam.
62
                onMediaCaptured: function(stream) {
63
                    // Make video stream available at a higher level by making it a property of startStopBtn.
64
                    startStopBtn.stream = stream;
65
66
                    M.tinymce_recordrtc.start_recording(recType, startStopBtn.stream);
67
                },
68
69
                // Revert button to "Record Again" when recording is stopped.
70
                onMediaStopped: function(btnLabel) {
71
                    startStopBtn.set('textContent', btnLabel);
72
                    startStopBtn.set('disabled', false);
73
                    if (!recordrtc.oldermoodle) {
74
                        startStopBtn.replaceClass('btn-danger', 'btn-outline-danger');
75
                    }
76
                },
77
78
                // Handle recording errors.
79
                onMediaCapturingFailed: function(error) {
80
                    var btnLabel = M.util.get_string('recordingfailed', 'tinymce_recordrtc');
81
82
                    // Handle getUserMedia-thrown errors.
83
                    switch (error.name) {
84
                        case 'AbortError':
85
                            Y.use('moodle-core-notification-alert', function() {
86
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
87
                                    title: M.util.get_string('gumabort_title', 'tinymce_recordrtc'),
88
                                    message: M.util.get_string('gumabort', 'tinymce_recordrtc')
89
                                });
90
                            });
91
92
                            // Proceed to treat as a stopped recording.
93
                            commonConfig.onMediaStopped(btnLabel);
94
                            break;
95
                        case 'NotAllowedError':
96
                            Y.use('moodle-core-notification-alert', function() {
97
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
98
                                    title: M.util.get_string('gumnotallowed_title', 'tinymce_recordrtc'),
99
                                    message: M.util.get_string('gumnotallowed', 'tinymce_recordrtc')
100
                                });
101
                            });
102
103
                            // Proceed to treat as a stopped recording.
104
                            commonConfig.onMediaStopped(btnLabel);
105
                            break;
106
                        case 'NotFoundError':
107
                            Y.use('moodle-core-notification-alert', function() {
108
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
109
                                    title: M.util.get_string('gumnotfound_title', 'tinymce_recordrtc'),
110
                                    message: M.util.get_string('gumnotfound', 'tinymce_recordrtc')
111
                                });
112
                            });
113
114
                            // Proceed to treat as a stopped recording.
115
                            commonConfig.onMediaStopped(btnLabel);
116
                            break;
117
                        case 'NotReadableError':
118
                            Y.use('moodle-core-notification-alert', function() {
119
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
120
                                    title: M.util.get_string('gumnotreadable_title', 'tinymce_recordrtc'),
121
                                    message: M.util.get_string('gumnotreadable', 'tinymce_recordrtc')
122
                                });
123
                            });
124
125
                            // Proceed to treat as a stopped recording.
126
                            commonConfig.onMediaStopped(btnLabel);
127
                            break;
128
                        case 'OverConstrainedError':
129
                            Y.use('moodle-core-notification-alert', function() {
130
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
131
                                    title: M.util.get_string('gumoverconstrained_title', 'tinymce_recordrtc'),
132
                                    message: M.util.get_string('gumoverconstrained', 'tinymce_recordrtc')
133
                                });
134
                            });
135
136
                            // Proceed to treat as a stopped recording.
137
                            commonConfig.onMediaStopped(btnLabel);
138
                            break;
139
                        case 'SecurityError':
140
                            Y.use('moodle-core-notification-alert', function() {
141
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
142
                                    title: M.util.get_string('gumsecurity_title', 'tinymce_recordrtc'),
143
                                    message: M.util.get_string('gumsecurity', 'tinymce_recordrtc')
144
                                });
145
                            });
146
147
                            tinyMCEPopup.close();
148
                            break;
149
                        case 'TypeError':
150
                            Y.use('moodle-core-notification-alert', function() {
151
                                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
152
                                    title: M.util.get_string('gumtype_title', 'tinymce_recordrtc'),
153
                                    message: M.util.get_string('gumtype', 'tinymce_recordrtc')
154
                                });
155
                            });
156
157
                            // Proceed to treat as a stopped recording.
158
                            commonConfig.onMediaStopped(btnLabel);
159
                            break;
160
                        default:
161
                            break;
162
                    }
163
                }
164
            };
165
166
            // Show video tag without controls to view webcam stream.
167
            player.ancestor().ancestor().removeClass('hide');
168
            player.set('controls', false);
169
170
            // Capture audio+video stream from webcam/microphone.
171
            M.tinymce_recordrtc.capture_audio_video(commonConfig);
172
        } else { // If button is displaying "Stop Recording".
173
            // Disable "Record Again" button for 1s to allow background processing (closing streams).
174
            window.setTimeout(function() {
175
                startStopBtn.set('disabled', false);
176
            }, 1000);
177
178
            // Stop recording.
179
            M.tinymce_recordrtc.stop_recording_video(startStopBtn.stream);
180
181
            // Change button to offer to record again.
182
            startStopBtn.set('textContent', M.util.get_string('recordagain', 'tinymce_recordrtc'));
183
            if (!recordrtc.oldermoodle) {
184
                startStopBtn.replaceClass('btn-danger', 'btn-outline-danger');
185
            }
186
        }
187
    });
188
};
189
190
// Setup to get audio+video stream from microphone/webcam.
191
M.tinymce_recordrtc.capture_audio_video = function(config) {
192
    M.tinymce_recordrtc.capture_user_media(
193
        // Media constraints.
194
        {
195
            audio: true,
196
            video: {
197
                width: {ideal: 640},
198
                height: {ideal: 480}
199
            }
200
        },
201
202
        // Success callback.
203
        function(audioVideoStream) {
204
            // Set video player source to microphone+webcam stream, and play it back as it's recording.
205
            playerDOM.srcObject = audioVideoStream;
206
            playerDOM.play();
207
208
            config.onMediaCaptured(audioVideoStream);
209
        },
210
211
        // Error callback.
212
        function(error) {
213
            config.onMediaCapturingFailed(error);
214
        }
215
    );
216
};
217
218
M.tinymce_recordrtc.stop_recording_video = function(stream) {
219
    // Stop recording microphone stream.
220
    mediaRecorder.stop();
221
222
    // Stop each individual MediaTrack.
223
    stream.getTracks().forEach(function(track) {
224
        track.stop();
225
    });
226
227
    // Show upload button.
228
    uploadBtn.ancestor().ancestor().removeClass('hide');
229
    uploadBtn.set('textContent', M.util.get_string('attachrecording', 'tinymce_recordrtc'));
230
    uploadBtn.set('disabled', false);
231
232
    // Handle when upload button is clicked.
233
    uploadBtn.on('click', function() {
234
        // Trigger error if no recording has been made.
235
        if (!player.get('src')) {
236
            Y.use('moodle-core-notification-alert', function() {
237
                new M.core.alert({
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new M.core.alert({Identi...(tinymce_recordrtc)))}) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
238
                    title: M.util.get_string('norecordingfound_title', 'tinymce_recordrtc'),
239
                    message: M.util.get_string('norecordingfound', 'tinymce_recordrtc')
240
                });
241
            });
242
        } else {
243
            uploadBtn.set('disabled', true);
244
245
            M.tinymce_recordrtc.insert_annotation(recType, player.get('src'));
246
        }
247
    });
248
};
249