GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( ba2ae1...790382 )
by Jesus
14s
created

tinymce/js/commonmodule.js   B

Complexity

Total Complexity 45
Complexity/F 2.05

Size

Lines of Code 279
Function Count 22

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 19
Bugs 1 Features 0
Metric Value
wmc 45
dl 0
loc 279
rs 8.3673
c 19
b 1
f 0
cc 0
nc 32
mnd 5
bc 48
fnc 22
bpm 2.1818
cpm 2.0454
noi 0

12 Functions

Rating   Name   Duplication   Size   Complexity  
B M.tinymce_recordrtc.make_xmlhttprequest 0 27 1
A M.tinymce_recordrtc.pad 0 9 2
B M.tinymce_recordrtc.handle_stop 0 44 1
A M.tinymce_recordrtc.insert_annotation 0 12 2
A M.tinymce_recordrtc.handle_data_available 0 23 3
B 0 21 5
B M.tinymce_recordrtc.start_recording 0 25 1
A M.tinymce_recordrtc.set_time 0 12 2
A M.tinymce_recordrtc.capture_user_media 0 3 1
A M.tinymce_recordrtc.create_annotation 0 12 2
A M.tinymce_recordrtc.upload_to_server 0 53 1
A commonmodule.js ➔ d 0 3 1

How to fix   Complexity   

Complexity

Complex classes like tinymce/js/commonmodule.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
// TinyMCE recordrtc library functions.
2
// @package    tinymce_recordrtc.
3
// @author     Jesus Federico  (jesus [at] blindsidenetworks [dt] com).
4
// @author     Jacob Prud'homme (jacob [dt] prudhomme [at] blindsidenetworks [dt] com)
5
// @copyright  2016 onwards, Blindside Networks Inc.
6
// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
7
8
// ESLint directives.
9
/* global tinyMCE, tinyMCEPopup */
10
/* exported alertWarning, alertDanger, countdownTicker, playerDOM */
11
/* eslint-disable camelcase, no-alert */
12
13
// Scrutinizer CI directives.
14
/** global: navigator */
15
/** global: parent */
16
/** global: M */
17
/** global: Y */
18
/** global: tinyMCEPopup */
19
20
M.tinymce_recordrtc = M.tinymce_recordrtc || {};
21
22
// Extract plugin settings to params hash.
23
(function() {
24
    var params = {};
25
    var r = /([^&=]+)=?([^&]*)/g;
26
27
    var d = function(s) {
28
        return window.decodeURIComponent(s.replace(/\+/g, ' '));
29
    };
30
31
    var search = window.location.search;
32
    var match = r.exec(search.substring(1));
33
    while (match) {
34
        params[d(match[1])] = d(match[2]);
35
36
        if (d(match[2]) === 'true' || d(match[2]) === 'false') {
37
            params[d(match[1])] = d(match[2]) === 'true' ? true : false;
38
        }
39
        match = r.exec(search.substring(1));
40
    }
41
42
    window.params = params;
43
})();
44
45
// Initialize some variables.
46
var alertWarning = null;
47
var alertDanger = null;
48
var blobSize = null;
49
var chunks = null;
50
var countdownSeconds = null;
51
var countdownTicker = null;
52
var maxUploadSize = null;
53
var mediaRecorder = null;
54
var player = null;
55
var playerDOM = null;
56
var recType = null;
57
var startStopBtn = null;
58
var uploadBtn = null;
59
60
// Capture webcam/microphone stream.
61
M.tinymce_recordrtc.capture_user_media = function(mediaConstraints, successCallback, errorCallback) {
62
    window.navigator.mediaDevices.getUserMedia(mediaConstraints).then(successCallback).catch(errorCallback);
63
};
64
65
// Add chunks of audio/video to array when made available.
66
M.tinymce_recordrtc.handle_data_available = function(event) {
67
    // Push recording slice to array.
68
    chunks.push(event.data);
69
    // Size of all recorded data so far.
70
    blobSize += event.data.size;
71
72
    // If total size of recording so far exceeds max upload limit, stop recording.
73
    // An extra condition exists to avoid displaying alert twice.
74
    if (blobSize >= maxUploadSize) {
75
        if (!window.localStorage.getItem('alerted')) {
76
            window.localStorage.setItem('alerted', 'true');
77
78
            Y.use('node-event-simulate', function() {
79
                startStopBtn.simulate('click');
80
            });
81
            M.tinymce_recordrtc.show_alert('nearingmaxsize');
82
        } else {
83
            window.localStorage.removeItem('alerted');
84
        }
85
86
        chunks.pop();
87
    }
88
};
89
90
M.tinymce_recordrtc.handle_stop = function() {
91
    // Set source of audio player.
92
    var blob = new window.Blob(chunks, {type: mediaRecorder.mimeType});
93
    player.set('src', window.URL.createObjectURL(blob));
94
95
    // Show audio player with controls enabled, and unmute.
96
    player.set('muted', false);
97
    player.set('controls', true);
98
    player.ancestor().ancestor().removeClass('hide');
99
100
    // Show upload button.
101
    uploadBtn.ancestor().ancestor().removeClass('hide');
102
    uploadBtn.set('textContent', M.util.get_string('attachrecording', 'tinymce_recordrtc'));
103
    uploadBtn.set('disabled', false);
104
105
    // Handle when upload button is clicked.
106
    uploadBtn.on('click', function() {
107
        // Trigger error if no recording has been made.
108
        if (chunks.length === 0) {
109
            M.tinymce_recordrtc.show_alert('norecordingfound');
110
        } else {
111
            uploadBtn.set('disabled', true);
112
113
            // Upload recording to server.
114
            M.tinymce_recordrtc.upload_to_server(recType, function(progress, fileURLOrError) {
115
                if (progress === 'ended') { // Insert annotation in text.
116
                    uploadBtn.set('disabled', false);
117
                    M.tinymce_recordrtc.insert_annotation(recType, fileURLOrError);
118
                } else if (progress === 'upload-failed') { // Show error message in upload button.
119
                    uploadBtn.set('disabled', false);
120
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed', 'tinymce_recordrtc') + ' ' + fileURLOrError);
121
                } else if (progress === 'upload-failed-404') { // 404 error = File too large in Moodle.
122
                    uploadBtn.set('disabled', false);
123
                    uploadBtn.set('textContent', M.util.get_string('uploadfailed404', 'tinymce_recordrtc'));
124
                } else if (progress === 'upload-aborted') {
125
                    uploadBtn.set('disabled', false);
126
                    uploadBtn.set('textContent', M.util.get_string('uploadaborted', 'tinymce_recordrtc') + ' ' + fileURLOrError);
127
                } else {
128
                    uploadBtn.set('textContent', progress);
129
                }
130
            });
131
        }
132
    });
133
};
134
135
// Get everything set up to start recording.
136
M.tinymce_recordrtc.start_recording = function(type, stream) {
137
    // The options for the recording codecs and bitrates.
138
    var options = M.tinymce_recordrtc.select_rec_options(type);
139
    mediaRecorder = new window.MediaRecorder(stream, options);
140
141
    // Initialize MediaRecorder events and start recording.
142
    mediaRecorder.ondataavailable = M.tinymce_recordrtc.handle_data_available;
143
    mediaRecorder.onstop = M.tinymce_recordrtc.handle_stop;
144
    mediaRecorder.start(1000); // Capture in 1s chunks. Must be set to work with Firefox.
145
146
    // Mute audio, distracting while recording.
147
    player.set('muted', true);
148
149
    // Set recording timer to the time specified in the settings.
150
    countdownSeconds = window.params.timelimit;
151
    countdownSeconds++;
152
    var timerText = M.util.get_string('stoprecording', 'tinymce_recordrtc');
153
    timerText += ' (<span id="minutes"></span>:<span id="seconds"></span>)';
154
    startStopBtn.setHTML(timerText);
155
    M.tinymce_recordrtc.set_time();
156
    countdownTicker = window.setInterval(M.tinymce_recordrtc.set_time, 1000);
157
158
    // Make button clickable again, to allow stopping recording.
159
    startStopBtn.set('disabled', false);
160
};
161
162
// Upload recorded audio/video to server.
163
M.tinymce_recordrtc.upload_to_server = function(type, callback) {
164
    var xhr = new window.XMLHttpRequest();
165
166
    // Get src media of audio/video tag.
167
    xhr.open('GET', player.get('src'), true);
168
    xhr.responseType = 'blob';
169
170
    xhr.onload = function() {
171
        if (xhr.status === 200) { // If src media was successfully retrieved.
172
            // blob is now the media that the audio/video tag's src pointed to.
173
            var blob = this.response;
174
175
            // Generate filename with random ID and file extension.
176
            var fileName = (Math.random() * 1000).toString().replace('.', '');
177
            fileName += (type === 'audio') ? '-audio.ogg'
178
                                           : '-video.webm';
179
180
            // Create FormData to send to PHP filepicker-upload script.
181
            var formData = new window.FormData(),
182
                editorId = tinyMCE.activeEditor.id,
183
                filepickerOptions = parent.M.editor_tinymce.filepicker_options[editorId].link,
184
                repositoryKeys = window.Object.keys(filepickerOptions.repositories);
185
186
            formData.append('repo_upload_file', blob, fileName);
187
            formData.append('itemid', filepickerOptions.itemid);
188
189
            for (var i = 0; i < repositoryKeys.length; i++) {
190
                if (filepickerOptions.repositories[repositoryKeys[i]].type === 'upload') {
191
                    formData.append('repo_id', filepickerOptions.repositories[repositoryKeys[i]].id);
192
                    break;
193
                }
194
            }
195
196
            formData.append('env', filepickerOptions.env);
197
            formData.append('sesskey', M.cfg.sesskey);
198
            formData.append('client_id', filepickerOptions.client_id);
199
            formData.append('savepath', '/');
200
            formData.append('ctx_id', filepickerOptions.context.id);
201
202
            // Pass FormData to PHP script using XHR.
203
            var uploadEndpoint = M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload';
204
            M.tinymce_recordrtc.make_xmlhttprequest(uploadEndpoint, formData, function(progress, responseText) {
205
                if (progress === 'upload-ended') {
206
                    callback('ended', window.JSON.parse(responseText).url);
207
                } else {
208
                    callback(progress);
209
                }
210
            });
211
        }
212
    };
213
214
    xhr.send();
215
};
216
217
// Handle XHR sending/receiving/status.
218
M.tinymce_recordrtc.make_xmlhttprequest = function(url, data, callback) {
219
    var xhr = new window.XMLHttpRequest();
220
221
    xhr.onreadystatechange = function() {
222
        if ((xhr.readyState === 4) && (xhr.status === 200)) { // When request is finished and successful.
223
            callback('upload-ended', xhr.responseText);
224
        } else if (xhr.status === 404) { // When request returns 404 Not Found.
225
            callback('upload-failed-404');
226
        }
227
    };
228
229
    xhr.upload.onprogress = function(event) {
230
        callback(Math.round(event.loaded / event.total * 100) + "% " + M.util.get_string('uploadprogress', 'tinymce_recordrtc'));
231
    };
232
233
    xhr.upload.onerror = function(error) {
234
        callback('upload-failed', error);
235
    };
236
237
    xhr.upload.onabort = function(error) {
238
        callback('upload-aborted', error);
239
    };
240
241
    // POST FormData to PHP script that handles uploading/saving.
242
    xhr.open('POST', url);
243
    xhr.send(data);
244
};
245
246
// Makes 1min and 2s display as 1:02 on timer instead of 1:2, for example.
247
M.tinymce_recordrtc.pad = function(val) {
248
    var valString = val + "";
249
250
    if (valString.length < 2) {
251
        return "0" + valString;
252
    } else {
253
        return valString;
254
    }
255
};
256
257
// Functionality to make recording timer count down.
258
// Also makes recording stop when time limit is hit.
259
M.tinymce_recordrtc.set_time = function() {
260
    countdownSeconds--;
261
262
    startStopBtn.one('span#seconds').set('textContent', M.tinymce_recordrtc.pad(countdownSeconds % 60));
263
    startStopBtn.one('span#minutes').set('textContent', M.tinymce_recordrtc.pad(window.parseInt(countdownSeconds / 60, 10)));
264
265
    if (countdownSeconds === 0) {
266
        Y.use('node-event-simulate', function() {
267
            startStopBtn.simulate('click');
268
        });
269
    }
270
};
271
272
// Generates link to recorded annotation to be inserted.
273
M.tinymce_recordrtc.create_annotation = function(type, recording_url) {
274
    var linkText = window.prompt(M.util.get_string('annotationprompt', 'tinymce_recordrtc'),
275
                                 M.util.get_string('annotation:' + type, 'tinymce_recordrtc'));
276
277
    // Return HTML for annotation link, if user did not press "Cancel".
278
    if (!linkText) {
279
        return undefined;
280
    } else {
281
        var annotation = '<div><a target="_blank" href="' + recording_url + '">' + linkText + '</a></div>';
282
        return annotation;
283
    }
284
};
285
286
// Inserts link to annotation in editor text area.
287
M.tinymce_recordrtc.insert_annotation = function(type, recording_url) {
288
    var annotation = M.tinymce_recordrtc.create_annotation(type, recording_url);
289
290
    // Insert annotation link.
291
    // If user pressed "Cancel", just go back to main recording screen.
292
    if (!annotation) {
293
        uploadBtn.set('textContent', M.util.get_string('attachrecording', 'tinymce_recordrtc'));
294
    } else {
295
        tinyMCEPopup.editor.execCommand('mceInsertContent', false, annotation);
296
        tinyMCEPopup.close();
297
    }
298
};
299