Completed
Push — master ( 45ea87...461362 )
by Jacob
01:48
created

tinymce/js/helpermodule.js   A

Complexity

Total Complexity 35
Complexity/F 2.06

Size

Lines of Code 201
Function Count 17

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 35
dl 0
loc 201
rs 9
c 1
b 0
f 0
cc 0
nc 32
mnd 5
bc 37
fnc 17
bpm 2.1764
cpm 2.0588
noi 0

7 Functions

Rating   Name   Duplication   Size   Complexity  
B M.tinymce_recordrtc.handle_data_available 0 20 5
B M.tinymce_recordrtc.handle_stop 0 44 1
B M.tinymce_recordrtc.start_recording 0 25 1
B M.tinymce_recordrtc.make_xmlhttprequest 0 27 1
A M.tinymce_recordrtc.pad 0 9 2
A M.tinymce_recordrtc.set_time 0 12 2
B M.tinymce_recordrtc.upload_to_server 0 41 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: mediaRecorder */
11
/** global: player */
12
/** global: startStopBtn */
13
/** global: uploadBtn */
14
/** global: recType */
15
16
M.tinymce_recordrtc = M.tinymce_recordrtc || {};
17
18
// Initialize some variables.
19
var blobSize = null;
20
var chunks = null;
21
var countdownSeconds = null;
22
var countdownTicker = null;
23
var maxUploadSize = null;
24
25
// Add chunks of audio/video to array when made available.
26
M.tinymce_recordrtc.handle_data_available = function(event) {
27
    // Size of all recorded data so far.
28
    blobSize += event.data.size;
29
30
    // Push recording slice to array.
31
    // If total size of recording so far exceeds max upload limit, stop recording.
32
    // An extra condition exists to avoid displaying alert twice.
33
    if ((blobSize >= maxUploadSize) && (!window.localStorage.getItem('alerted'))) {
34
        window.localStorage.setItem('alerted', 'true');
35
36
        Y.use('node-event-simulate', function() {
37
            startStopBtn.simulate('click');
38
        });
39
        M.tinymce_recordrtc.show_alert('nearingmaxsize');
40
    } else if ((blobSize >= maxUploadSize) && (window.localStorage.getItem('alerted') === 'true')) {
41
        window.localStorage.removeItem('alerted');
42
    } else {
43
        chunks.push(event.data);
44
    }
45
};
46
47
// Handle recording end.
48
M.tinymce_recordrtc.handle_stop = function() {
49
    // Set source of audio player.
50
    var blob = new window.Blob(chunks, {type: mediaRecorder.mimeType});
51
    player.set('src', window.URL.createObjectURL(blob));
52
53
    // Show audio player with controls enabled, and unmute.
54
    player.set('muted', false);
55
    player.set('controls', true);
56
    player.ancestor().ancestor().removeClass('hide'); // Only audio player is hidden at this point.
57
58
    // Show upload button.
59
    uploadBtn.set('disabled', false);
60
    uploadBtn.set('textContent', M.util.get_string('attachrecording', 'tinymce_recordrtc'));
61
    uploadBtn.ancestor().ancestor().removeClass('hide');
62
63
    // Handle when upload button is clicked.
64
    uploadBtn.on('click', function() {
65
        // Trigger error if no recording has been made.
66
        if (!player.get('src') || chunks === []) {
67
            M.tinymce_recordrtc.show_alert('norecordingfound');
68
        } else {
69
            uploadBtn.set('disabled', true);
70
71
            // Upload recording to server.
72
            M.tinymce_recordrtc.upload_to_server(recType, function(progress, fileURLOrError) {
73
                if (progress === 'ended') { // Insert annotation in text.
74
                    uploadBtn.set('disabled', false);
75
                    M.tinymce_recordrtc.insert_annotation(recType, fileURLOrError);
76
                } else if (progress === 'upload-failed') { // Show error message in upload button.
77
                    uploadBtn.set('disabled', false);
78
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed', 'tinymce_recordrtc') + ' ' + fileURLOrError);
79
                } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle.
80
                    uploadBtn.set('disabled', false);
81
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'tinymce_recordrtc'));
82
                } else if (progress === 'upload-aborted') {
83
                    uploadBtn.set('disabled', false);
84
                    uploadBtn.set('textContent', M.util.get_string('uploadaborted', 'tinymce_recordrtc') + ' ' + fileURLOrError);
85
                } else {
86
                    uploadBtn.set('textContent', progress);
87
                }
88
            });
89
        }
90
    });
91
};
92
93
// Get everything set up to start recording.
94
M.tinymce_recordrtc.start_recording = function(type, stream) {
95
    // If none of the mime-types are supported, fall back on browser defaults.
96
    var options = M.tinymce_recordrtc.best_rec_options(type);
97
    mediaRecorder = new window.MediaRecorder(stream, options);
98
99
    // Initialize MediaRecorder events and start recording.
100
    mediaRecorder.ondataavailable = M.tinymce_recordrtc.handle_data_available;
101
    mediaRecorder.onstop = M.tinymce_recordrtc.handle_stop;
102
    mediaRecorder.start(1000); // Capture in 1s chunks. Must be set to work with Firefox.
103
104
    // Mute audio, distracting while recording.
105
    player.set('muted', true);
106
107
    // Set recording timer to the time specified in the settings.
108
    countdownSeconds = window.params.timelimit;
109
    countdownSeconds++;
110
    var timerText = M.util.get_string('stoprecording', 'tinymce_recordrtc');
111
    timerText += ' (<span id="minutes"></span>:<span id="seconds"></span>)';
112
    startStopBtn.setHTML(timerText);
113
    M.tinymce_recordrtc.set_time();
114
    countdownTicker = window.setInterval(M.tinymce_recordrtc.set_time, 1000);
115
116
    // Make button clickable again, to allow stopping recording.
117
    startStopBtn.set('disabled', false);
118
};
119
120
// Upload recorded audio/video to server.
121
M.tinymce_recordrtc.upload_to_server = function(type, callback) {
122
    var xhr = new window.XMLHttpRequest();
123
124
    // Get src media of audio/video tag.
125
    xhr.open('GET', player.get('src'), true);
126
    xhr.responseType = 'blob';
127
128
    xhr.onload = function() {
129
        if (xhr.status === 200) { // If src media was successfully retrieved.
130
            // blob is now the media that the audio/video tag's src pointed to.
131
            var blob = this.response;
132
133
            // Generate filename with random ID and file extension.
134
            var fileName = (Math.random() * 1000).toString().replace('.', '');
135
            if (type === 'audio') {
136
                fileName += '-audio.ogg';
137
            } else {
138
                fileName += '-video.webm';
139
            }
140
141
            // Create FormData to send to PHP upload/save script.
142
            var formData = new window.FormData();
143
            formData.append('contextid', window.params.contextid);
144
            formData.append('sesskey', window.params.sesskey);
145
            formData.append(type + '-filename', fileName);
146
            formData.append(type + '-blob', blob);
147
148
            // Pass FormData to PHP script using XHR.
149
            M.tinymce_recordrtc.make_xmlhttprequest('save.php', formData, function(progress, responseText) {
150
                if (progress === 'upload-ended') {
151
                    var initialURL = location.href.replace(location.href.split('/').pop(), '') + 'uploads.php/';
152
                    callback('ended', initialURL + responseText);
153
                } else {
154
                    callback(progress);
155
                }
156
            });
157
        }
158
    };
159
160
    xhr.send();
161
};
162
163
// Handle XHR sending/receiving/status.
164
M.tinymce_recordrtc.make_xmlhttprequest = function(url, data, callback) {
165
    var xhr = new window.XMLHttpRequest();
166
167
    xhr.onreadystatechange = function() {
168
        if ((xhr.readyState === 4) && (xhr.status === 200)) { // When request is finished and successful.
169
            callback('upload-ended', xhr.responseText);
170
        } else if (xhr.status === 404) { // When request returns 404 Not Found.
171
            callback('upload-failed-404');
172
        }
173
    };
174
175
    xhr.upload.onprogress = function(event) {
176
        callback(Math.round(event.loaded / event.total * 100) + "% " + M.util.get_string('uploadprogress', 'tinymce_recordrtc'));
177
    };
178
179
    xhr.upload.onerror = function(error) {
180
        callback('upload-failed', error);
181
    };
182
183
    xhr.upload.onabort = function(error) {
184
        callback('upload-aborted', error);
185
    };
186
187
    // POST FormData to PHP script that handles uploading/saving.
188
    xhr.open('POST', url);
189
    xhr.send(data);
190
};
191
192
// Makes 1min and 2s display as 1:02 on timer instead of 1:2, for example.
193
M.tinymce_recordrtc.pad = function(val) {
194
    var valString = val + "";
195
196
    if (valString.length < 2) {
197
        return "0" + valString;
198
    } else {
199
        return valString;
200
    }
201
};
202
203
// Functionality to make recording timer count down.
204
// Also makes recording stop when time limit is hit.
205
M.tinymce_recordrtc.set_time = function() {
206
    countdownSeconds--;
207
208
    startStopBtn.one('span#seconds').set('textContent', M.tinymce_recordrtc.pad(countdownSeconds % 60));
209
    startStopBtn.one('span#minutes').set('textContent', M.tinymce_recordrtc.pad(window.parseInt(countdownSeconds / 60, 10)));
210
211
    if (countdownSeconds === 0) {
212
        Y.use('node-event-simulate', function() {
213
            startStopBtn.simulate('click');
214
        });
215
    }
216
};
217