@osimatic/helpers-js 1.0.32 → 1.0.35
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/{changelog.txt → CHANGELOG} +9 -1
- package/form_helper.js +37 -15
- package/index.js +2 -4
- package/location.js +3 -3
- package/network.js +41 -35
- package/package.json +1 -1
- package/web_rtc.js +103 -0
- package/.idea/helpers-js.iml +0 -8
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/todos/button_loader.js +0 -50
|
@@ -37,4 +37,12 @@ let httpHeaders = {...} -> HTTPRequest.setHeader(key, value);
|
|
|
37
37
|
remplacer l'utilisation des variables httpHeaders / _httpHeaders par HTTPRequest.getHeaders()
|
|
38
38
|
|
|
39
39
|
FlashMessage.displayRequestFailure(status, exception, modal) -> FlashMessage.displayError(labelErrorOccured, modal)
|
|
40
|
-
FormHelper.logRequestFailure(status, exception) -> HTTPRequest.logJqueryRequestFailure(jqxhr, status, exception) (le log de l'erreur est devenu inutile car fait de base dans la classe HTTPRequest)
|
|
40
|
+
FormHelper.logRequestFailure(status, exception) -> HTTPRequest.logJqueryRequestFailure(jqxhr, status, exception) (le log de l'erreur est devenu inutile car fait de base dans la classe HTTPRequest)
|
|
41
|
+
|
|
42
|
+
Location.checkCoordinates(...) -> GeographicCoordinates.check(...) (car Location est déjà défini en javascript natif)
|
|
43
|
+
|
|
44
|
+
FormHelper.getFormErrorTextBis(...) -> FormHelper.getFormErrorText(...)
|
|
45
|
+
FormHelper.displayFormErrorsFromXhr(form, btnSubmit, xhr) -> FormHelper.displayFormErrors(form, btnSubmit, xhr.responseJSON)
|
|
46
|
+
|
|
47
|
+
1.0.35 :
|
|
48
|
+
ajout méthode HTTPRequest.init() (charge le polyfill de fetch)
|
package/form_helper.js
CHANGED
|
@@ -183,16 +183,6 @@ class FormHelper {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
static getFormErrorText(errors) {
|
|
186
|
-
let errorLabels = '';
|
|
187
|
-
for (let property in errors) {
|
|
188
|
-
if (typeof errors[property] != 'function') {
|
|
189
|
-
errorLabels += '<span>' + errors[property] + '</span><br>';
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return errorLabels;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
static getFormErrorTextBis(errors) {
|
|
196
186
|
let errorLabels = '';
|
|
197
187
|
for (let property in errors) {
|
|
198
188
|
// console.log(property);
|
|
@@ -208,7 +198,7 @@ class FormHelper {
|
|
|
208
198
|
}
|
|
209
199
|
|
|
210
200
|
static displayFormErrors(form, btnSubmit, errors, errorWrapperDiv) {
|
|
211
|
-
this.displayFormErrorsFromText(form, this.
|
|
201
|
+
this.displayFormErrorsFromText(form, this.getFormErrorText(errors), errorWrapperDiv);
|
|
212
202
|
if (btnSubmit != null) {
|
|
213
203
|
if (btnSubmit.buttonLoader != null) {
|
|
214
204
|
btnSubmit.buttonLoader('reset');
|
|
@@ -218,10 +208,6 @@ class FormHelper {
|
|
|
218
208
|
}
|
|
219
209
|
}
|
|
220
210
|
|
|
221
|
-
static displayFormErrorsFromXhr(form, btnSubmit, xhr) {
|
|
222
|
-
this.displayFormErrors(form, btnSubmit, xhr.responseJSON);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
211
|
static displayFormErrorsFromText(form, errorLabels, errorWrapperDiv) {
|
|
226
212
|
let errorDiv = '<div class="alert alert-danger form_errors">'+errorLabels+'</div>';
|
|
227
213
|
|
|
@@ -255,12 +241,48 @@ class FormHelper {
|
|
|
255
241
|
}
|
|
256
242
|
|
|
257
243
|
|
|
244
|
+
static buttonLoader(button, action) {
|
|
245
|
+
button = $(button);
|
|
246
|
+
if (action === 'start' || action === 'loading') {
|
|
247
|
+
if (button.attr('disabled')) {
|
|
248
|
+
return self;
|
|
249
|
+
}
|
|
250
|
+
button.attr('disabled', true);
|
|
251
|
+
button.attr('data-btn-text', button.html());
|
|
252
|
+
//let text = '<span class="spinner"><i class=\'fa fa-circle-notch fa-spin\'></i></span>Traitement en cours…';
|
|
253
|
+
let text = '<i class=\'fa fa-circle-notch fa-spin\'></i> Traitement en cours…';
|
|
254
|
+
if (button.data('load-text') != undefined && button.data('load-text') != null && button.data('load-text') != '') {
|
|
255
|
+
text = button.data('load-text');
|
|
256
|
+
}
|
|
257
|
+
if (button.data('loading-text') != undefined && button.data('loading-text') != null && button.data('loading-text') != '') {
|
|
258
|
+
text = button.data('loading-text');
|
|
259
|
+
}
|
|
260
|
+
button.html(text);
|
|
261
|
+
button.addClass('disabled');
|
|
262
|
+
}
|
|
263
|
+
if (action === 'stop' || action === 'reset') {
|
|
264
|
+
button.html(button.attr('data-btn-text'));
|
|
265
|
+
button.removeClass('disabled');
|
|
266
|
+
button.attr('disabled', false);
|
|
267
|
+
//button.removeAttr("disabled");
|
|
268
|
+
}
|
|
269
|
+
return button;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
258
275
|
|
|
259
276
|
/** @deprecated **/
|
|
260
277
|
static logRequestFailure(status, exception) {
|
|
261
278
|
console.log('request failure. Status: '+status+' ; Exception: '+exception);
|
|
262
279
|
}
|
|
263
280
|
|
|
281
|
+
/** @deprecated **/
|
|
282
|
+
static displayFormErrorsFromXhr(form, btnSubmit, xhr) {
|
|
283
|
+
this.displayFormErrors(form, btnSubmit, xhr.responseJSON);
|
|
284
|
+
}
|
|
285
|
+
|
|
264
286
|
}
|
|
265
287
|
|
|
266
288
|
module.exports = { FormHelper };
|
package/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const { DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime } = require('./da
|
|
|
15
15
|
const { Duration } = require('./duration');
|
|
16
16
|
const { File, CSV, Img } = require('./file');
|
|
17
17
|
const { FormHelper } = require('./form_helper');
|
|
18
|
-
const { Country, PostalAddress,
|
|
18
|
+
const { Country, PostalAddress, GeographicCoordinates } = require('./location');
|
|
19
19
|
const { SocialNetwork } = require('./social_network');
|
|
20
20
|
const { sleep, refresh } = require('./util');
|
|
21
21
|
const { chr, ord, trim, empty } = require('./php.min');
|
|
@@ -40,11 +40,9 @@ const { GoogleRecaptcha } = require('./google_recaptcha');
|
|
|
40
40
|
const { GoogleMap } = require('./google_maps');
|
|
41
41
|
const { OpenStreetMap } = require('./open_street_map');
|
|
42
42
|
|
|
43
|
-
// deprecated
|
|
44
|
-
|
|
45
43
|
module.exports = {
|
|
46
44
|
Array, Object, Number, String,
|
|
47
|
-
HTTPRequest, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress,
|
|
45
|
+
HTTPRequest, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress, GeographicCoordinates, SocialNetwork,
|
|
48
46
|
DataTable, Pagination, Navigation, DetailsSubArray, SelectAll, MultipleActionInTable, FormDate, InputPeriod, ShoppingCart, FlashMessage, CountDown, ImportFromCsv, JwtToken, JwtSession, ListBox,
|
|
49
47
|
sleep, refresh, chr, ord, trim, empty,
|
|
50
48
|
GoogleCharts, GoogleRecaptcha, GoogleMap, OpenStreetMap
|
package/location.js
CHANGED
|
@@ -394,10 +394,10 @@ class PostalAddress {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
class
|
|
398
|
-
static
|
|
397
|
+
class GeographicCoordinates {
|
|
398
|
+
static check(str) {
|
|
399
399
|
return /^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/.test(str);
|
|
400
400
|
}
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
module.exports = { Country, PostalAddress,
|
|
403
|
+
module.exports = { Country, PostalAddress, GeographicCoordinates };
|
package/network.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
class HTTPRequest {
|
|
3
|
+
static init(){
|
|
4
|
+
require('whatwg-fetch'); //fetch polyfill loaded in window.fetch
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
static setRefreshTokenUrl(url) {
|
|
4
8
|
this.refreshTokenUrl = url;
|
|
5
9
|
}
|
|
10
|
+
|
|
6
11
|
static setRefreshTokenCallback(callback) {
|
|
7
12
|
this.refreshTokenCallback = callback;
|
|
8
13
|
}
|
|
@@ -82,49 +87,52 @@ class HTTPRequest {
|
|
|
82
87
|
//console.log(url, jsonData);
|
|
83
88
|
//console.log(response.status, response.statusText, jsonData['error']);
|
|
84
89
|
|
|
85
|
-
if (response.status == 401 && (response.statusText ===
|
|
90
|
+
if (response.status == 401 && (response.statusText === 'Expired JWT Token' || typeof jsonData['error'] != 'undefined' && jsonData['error'] === 'expired_token')) {
|
|
86
91
|
HTTPRequest.refreshToken(() => HTTPRequest.get(url, data, successCallback, errorCallback));
|
|
87
92
|
return;
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
if (response.ok) {
|
|
91
|
-
successCallback(jsonData);
|
|
96
|
+
successCallback(jsonData, response);
|
|
92
97
|
return;
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
catch (e) {
|
|
96
101
|
console.error(e);
|
|
97
102
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
98
|
-
errorCallback(response
|
|
103
|
+
errorCallback(response);
|
|
99
104
|
}
|
|
100
105
|
return;
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
HTTPRequest.logRequestFailure(response, jsonData);
|
|
104
109
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
105
|
-
errorCallback(response,
|
|
110
|
+
errorCallback(response, jsonData);
|
|
106
111
|
}
|
|
107
112
|
return;
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé
|
|
111
|
-
console.error('fetch\'s polyfill used');
|
|
115
|
+
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
112
116
|
$.ajax({
|
|
113
117
|
type: 'GET',
|
|
114
118
|
url: url,
|
|
115
119
|
headers: HTTPRequest.getHeaders(true),
|
|
116
120
|
dataType: 'json',
|
|
117
121
|
cache: false,
|
|
118
|
-
success: (data) =>
|
|
122
|
+
success: (data, status, jqxhr) => {
|
|
123
|
+
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
124
|
+
successCallback(data, jqxhr);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
119
127
|
error: (jqxhr, status, errorThrown) => {
|
|
120
|
-
if (
|
|
128
|
+
if (jqxhr.status == 401 && (jqxhr.statusText === 'Expired JWT Token' || (typeof jqxhr.responseJSON['message'] != 'undefined' && jqxhr.responseJSON['message'] === 'Expired JWT Token') || (typeof jqxhr.responseJSON['error'] != 'undefined' && jqxhr.responseJSON['error'] === 'expired_token' ))) {
|
|
121
129
|
HTTPRequest.refreshToken(() => HTTPRequest.get(url, data, successCallback, errorCallback));
|
|
122
130
|
return;
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
126
134
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
127
|
-
errorCallback(jqxhr,
|
|
135
|
+
errorCallback(jqxhr, jqxhr.responseJSON);
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
});
|
|
@@ -157,7 +165,7 @@ class HTTPRequest {
|
|
|
157
165
|
/*console.log(url);
|
|
158
166
|
console.log(blobData);*/
|
|
159
167
|
|
|
160
|
-
if (response.status == 401 && response.statusText ===
|
|
168
|
+
if (response.status == 401 && response.statusText === 'Expired JWT Token') {
|
|
161
169
|
HTTPRequest.refreshToken(() => HTTPRequest.download(url, data, errorCallback, completeCallback, method));
|
|
162
170
|
return;
|
|
163
171
|
}
|
|
@@ -168,26 +176,23 @@ class HTTPRequest {
|
|
|
168
176
|
else {
|
|
169
177
|
HTTPRequest.logRequestFailure(response, null);
|
|
170
178
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
171
|
-
errorCallback(response
|
|
179
|
+
errorCallback(response);
|
|
172
180
|
}
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
catch (e) {
|
|
176
184
|
console.error(e);
|
|
177
185
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
178
|
-
errorCallback(response
|
|
186
|
+
errorCallback(response);
|
|
179
187
|
}
|
|
180
188
|
}
|
|
181
189
|
if (typeof completeCallback != 'undefined' && completeCallback != null) {
|
|
182
|
-
completeCallback(response
|
|
190
|
+
completeCallback(response);
|
|
183
191
|
}
|
|
184
192
|
return;
|
|
185
193
|
}
|
|
186
194
|
|
|
187
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé
|
|
188
|
-
console.error('fetch\'s polyfill used');
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
191
196
|
let ajaxOptions = {
|
|
192
197
|
type: 'GET',
|
|
193
198
|
url: url,
|
|
@@ -207,19 +212,19 @@ class HTTPRequest {
|
|
|
207
212
|
$.ajax(Object.assign({...ajaxOptions}, {
|
|
208
213
|
success: (data, status, jqxhr) => File.download(data, jqxhr.getResponseHeader('Content-Type'), jqxhr.getResponseHeader('Content-Disposition')),
|
|
209
214
|
error: (jqxhr, status, errorThrown) => {
|
|
210
|
-
if (
|
|
215
|
+
if (jqxhr.status == 401 && (jqxhr.statusText === 'Expired JWT Token' || (typeof jqxhr.responseJSON['message'] != 'undefined' && jqxhr.responseJSON['message'] === 'Expired JWT Token') || (typeof jqxhr.responseJSON['error'] != 'undefined' && jqxhr.responseJSON['error'] === 'expired_token' ))) {
|
|
211
216
|
HTTPRequest.refreshToken(() => HTTPRequest.download(url, data, errorCallback, completeCallback, method));
|
|
212
217
|
return;
|
|
213
218
|
}
|
|
214
219
|
|
|
215
220
|
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
216
221
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
217
|
-
errorCallback(jqxhr
|
|
222
|
+
errorCallback(jqxhr);
|
|
218
223
|
}
|
|
219
224
|
},
|
|
220
|
-
complete: (jqxhr
|
|
225
|
+
complete: (jqxhr) => {
|
|
221
226
|
if (typeof completeCallback != 'undefined' && completeCallback != null) {
|
|
222
|
-
completeCallback(jqxhr
|
|
227
|
+
completeCallback(jqxhr);
|
|
223
228
|
}
|
|
224
229
|
}
|
|
225
230
|
}));
|
|
@@ -228,7 +233,7 @@ class HTTPRequest {
|
|
|
228
233
|
static async post(url, formData, successCallback, errorCallback, formErrorCallback) {
|
|
229
234
|
formData = this.formatFormData(formData);
|
|
230
235
|
|
|
231
|
-
if (window.fetch
|
|
236
|
+
if (window.fetch) {
|
|
232
237
|
const response = await fetch(url, {
|
|
233
238
|
method: 'POST',
|
|
234
239
|
body: formData,
|
|
@@ -239,43 +244,44 @@ class HTTPRequest {
|
|
|
239
244
|
|
|
240
245
|
let jsonData = {};
|
|
241
246
|
try {
|
|
242
|
-
|
|
247
|
+
if (response.statusText !== 'No Content') {
|
|
248
|
+
jsonData = await response.json();
|
|
249
|
+
}
|
|
243
250
|
//console.log(url, jsonData);
|
|
244
251
|
|
|
245
|
-
if (response.status == 401 && url !== HTTPRequest.refreshTokenUrl && (response.statusText ===
|
|
252
|
+
if (response.status == 401 && url !== HTTPRequest.refreshTokenUrl && (response.statusText === 'Expired JWT Token' || (typeof jsonData['error'] != 'undefined' && jsonData['error'] === 'expired_token'))) {
|
|
246
253
|
HTTPRequest.refreshToken(() => HTTPRequest.post(url, formData, successCallback, errorCallback, formErrorCallback));
|
|
247
254
|
return;
|
|
248
255
|
}
|
|
249
256
|
|
|
250
257
|
if (response.ok) {
|
|
251
258
|
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
252
|
-
successCallback(jsonData);
|
|
259
|
+
successCallback(jsonData, response);
|
|
253
260
|
}
|
|
254
261
|
return;
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
if (response.status == 400 && typeof formErrorCallback != 'undefined' && formErrorCallback != null) {
|
|
258
|
-
formErrorCallback(
|
|
265
|
+
formErrorCallback(jsonData, response);
|
|
259
266
|
return;
|
|
260
267
|
}
|
|
261
268
|
}
|
|
262
269
|
catch (e) {
|
|
263
270
|
console.error(e);
|
|
264
271
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
265
|
-
errorCallback(response
|
|
272
|
+
errorCallback(response);
|
|
266
273
|
}
|
|
267
274
|
return;
|
|
268
275
|
}
|
|
269
276
|
|
|
270
277
|
HTTPRequest.logRequestFailure(response, jsonData);
|
|
271
278
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
272
|
-
errorCallback(response,
|
|
279
|
+
errorCallback(response, jsonData);
|
|
273
280
|
}
|
|
274
281
|
return;
|
|
275
282
|
}
|
|
276
283
|
|
|
277
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé
|
|
278
|
-
console.error('fetch\'s polyfill used');
|
|
284
|
+
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
279
285
|
$.ajax({
|
|
280
286
|
type: 'POST',
|
|
281
287
|
url: url,
|
|
@@ -285,24 +291,24 @@ class HTTPRequest {
|
|
|
285
291
|
cache: false,
|
|
286
292
|
contentType: false,
|
|
287
293
|
processData: false,
|
|
288
|
-
success: (data) => {
|
|
294
|
+
success: (data, status, jqxhr) => {
|
|
289
295
|
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
290
|
-
successCallback(data);
|
|
296
|
+
successCallback(data, jqxhr);
|
|
291
297
|
}
|
|
292
298
|
},
|
|
293
299
|
error: (jqxhr, status, errorThrown) => {
|
|
294
|
-
if (
|
|
300
|
+
if (url !== HTTPRequest.refreshTokenUrl && jqxhr.status == 401 && (jqxhr.statusText === 'Expired JWT Token' || (typeof jqxhr.responseJSON['message'] != 'undefined' && jqxhr.responseJSON['message'] === 'Expired JWT Token') || (typeof jqxhr.responseJSON['error'] != 'undefined' && jqxhr.responseJSON['error'] === 'expired_token' ))) {
|
|
295
301
|
HTTPRequest.refreshToken(() => HTTPRequest.post(url, formData, successCallback, errorCallback, formErrorCallback));
|
|
296
302
|
return;
|
|
297
303
|
}
|
|
298
304
|
if (jqxhr.status == 400 && typeof formErrorCallback != 'undefined' && formErrorCallback != null) {
|
|
299
|
-
formErrorCallback(jqxhr,
|
|
305
|
+
formErrorCallback(jqxhr.responseJSON, jqxhr);
|
|
300
306
|
return;
|
|
301
307
|
}
|
|
302
308
|
|
|
303
309
|
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
304
310
|
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
305
|
-
errorCallback(jqxhr,
|
|
311
|
+
errorCallback(jqxhr, jqxhr.responseJSON);
|
|
306
312
|
}
|
|
307
313
|
}
|
|
308
314
|
});
|
package/package.json
CHANGED
package/web_rtc.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
class WebRTC {
|
|
2
|
+
static init (turnSecret, turnUrl, stunUrl) {
|
|
3
|
+
this.turnSecret = turnSecret;
|
|
4
|
+
this.turnUrl = turnUrl;
|
|
5
|
+
this.stunUrl = stunUrl;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
static offer(stream, onICECandidateCallback) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
try {
|
|
11
|
+
let { username, password } = this.getTurnCredentials();
|
|
12
|
+
let peerConn = new RTCPeerConnection(
|
|
13
|
+
{
|
|
14
|
+
iceServers: [
|
|
15
|
+
{ urls: this.turnUrl, username: username, credential: password },
|
|
16
|
+
{ urls: this.stunUrl }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
stream.getTracks().forEach(track => peerConn.addTrack(track, stream));
|
|
22
|
+
|
|
23
|
+
peerConn.onicecandidate = (event) => onICECandidateCallback(event);
|
|
24
|
+
|
|
25
|
+
peerConn.createOffer()
|
|
26
|
+
.then(sdp => peerConn.setLocalDescription(sdp))
|
|
27
|
+
.then(() => resolve(peerConn));
|
|
28
|
+
} catch (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static answer (remoteDescription, onTrackCallback, onICECandidateCallback) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
try {
|
|
37
|
+
let { username, password } = this.getTurnCredentials();
|
|
38
|
+
let peerConn = new RTCPeerConnection(
|
|
39
|
+
{
|
|
40
|
+
iceServers: [
|
|
41
|
+
{ urls: this.turnUrl, username: username, credential: password },
|
|
42
|
+
{ urls: this.stunUrl }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
peerConn.ontrack = event => onTrackCallback(event);
|
|
48
|
+
peerConn.onicecandidate = event => onICECandidateCallback(event);
|
|
49
|
+
|
|
50
|
+
peerConn.setRemoteDescription(remoteDescription)
|
|
51
|
+
.then(() => peerConn.createAnswer())
|
|
52
|
+
.then(sdp => peerConn.setLocalDescription(sdp))
|
|
53
|
+
.then(() => resolve(peerConn));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
reject(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static disconnectPeer(peerConn) {
|
|
61
|
+
if (peerConn) {
|
|
62
|
+
peerConn.onicecandidate = null;
|
|
63
|
+
peerConn.ontrack = null;
|
|
64
|
+
|
|
65
|
+
if (peerConn.signalingState != 'closed') {
|
|
66
|
+
peerConn.getSenders().forEach(sender => peerConn.removeTrack(sender));
|
|
67
|
+
peerConn.close();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
peerConn = null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return peerConn;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
The idea is that WebRTC (or other) clients receive temporary TURN credentials where the user name is comprised of the (Unix)
|
|
78
|
+
expiry timestamp and the password is derived from a secret shared between the service generating those credentials and eturnal.
|
|
79
|
+
The service offering the credentials performs a Base64(HMAC-SHA1($secret, $timestamp)) operation to generate the ephemeral password,
|
|
80
|
+
and eturnal does the same to verify it.
|
|
81
|
+
|
|
82
|
+
https://eturnal.net/documentation/
|
|
83
|
+
https://datatracker.ietf.org/doc/html/draft-uberti-behave-turn-rest-00
|
|
84
|
+
https://stackoverflow.com/questions/35766382/coturn-how-to-use-turn-rest-api
|
|
85
|
+
*/
|
|
86
|
+
static getTurnCredentials() {
|
|
87
|
+
try {
|
|
88
|
+
let crypto = require('crypto');
|
|
89
|
+
let username = String(parseInt(Date.now() / 1000) + 24 * 3600);
|
|
90
|
+
let hmac = crypto.createHmac('sha1', this.turnSecret);
|
|
91
|
+
|
|
92
|
+
hmac.setEncoding('base64');
|
|
93
|
+
hmac.write(username);
|
|
94
|
+
hmac.end();
|
|
95
|
+
|
|
96
|
+
return { username: username, password: hmac.read() };
|
|
97
|
+
} catch(error) {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { WebRTC };
|
package/.idea/helpers-js.iml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager">
|
|
4
|
-
<content url="file://$MODULE_DIR$" />
|
|
5
|
-
<orderEntry type="inheritedJdk" />
|
|
6
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
-
</component>
|
|
8
|
-
</module>
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/helpers-js.iml" filepath="$PROJECT_DIR$/.idea/helpers-js.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/vcs.xml
DELETED
package/todos/button_loader.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
// Loading button plugin (removed from BS4)
|
|
3
|
-
(function($) {
|
|
4
|
-
"use strict";
|
|
5
|
-
|
|
6
|
-
$.fn.extend({
|
|
7
|
-
/*
|
|
8
|
-
button: function (action) {
|
|
9
|
-
console.log(action);
|
|
10
|
-
if (action === 'loading' && this.data('loading-text')) {
|
|
11
|
-
console.log('loading');
|
|
12
|
-
this.data('original-text', this.html()).html(this.data('loading-text')).prop('disabled', true);
|
|
13
|
-
}
|
|
14
|
-
if (action === 'reset' && this.data('original-text')) {
|
|
15
|
-
console.log('reset');
|
|
16
|
-
this.html(this.data('original-text')).prop('disabled', false);
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
buttonLoader: function (action) {
|
|
22
|
-
//console.log(action);
|
|
23
|
-
var self = $(this);
|
|
24
|
-
if (action === 'start' || action === 'loading') {
|
|
25
|
-
if ($(self).attr('disabled')) {
|
|
26
|
-
return self;
|
|
27
|
-
}
|
|
28
|
-
$(self).attr('disabled', true);
|
|
29
|
-
$(self).attr('data-btn-text', $(self).html());
|
|
30
|
-
//let text = '<span class="spinner"><i class=\'fa fa-circle-notch fa-spin\'></i></span>Traitement en cours…';
|
|
31
|
-
let text = '<i class=\'fa fa-circle-notch fa-spin\'></i> Traitement en cours…';
|
|
32
|
-
if ($(self).data('load-text') != undefined && $(self).data('load-text') != null && $(self).data('load-text') != '') {
|
|
33
|
-
text = $(self).data('load-text');
|
|
34
|
-
}
|
|
35
|
-
if ($(self).data('loading-text') != undefined && $(self).data('loading-text') != null && $(self).data('loading-text') != '') {
|
|
36
|
-
text = $(self).data('loading-text');
|
|
37
|
-
}
|
|
38
|
-
$(self).html(text);
|
|
39
|
-
$(self).addClass('disabled');
|
|
40
|
-
}
|
|
41
|
-
if (action === 'stop' || action === 'reset') {
|
|
42
|
-
$(self).html($(self).attr('data-btn-text'));
|
|
43
|
-
$(self).removeClass('disabled');
|
|
44
|
-
$(self).attr('disabled', false);
|
|
45
|
-
//$(self).removeAttr("disabled");
|
|
46
|
-
}
|
|
47
|
-
return self;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}(jQuery));
|