plugins.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320
  1. // Avoid `console` errors in browsers that lack a console.
  2. (function() {
  3. var method;
  4. var noop = function () {};
  5. var methods = [
  6. 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
  7. 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
  8. 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
  9. 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
  10. ];
  11. var length = methods.length;
  12. var console = (window.console = window.console || {});
  13. while (length--) {
  14. method = methods[length];
  15. // Only stub undefined methods.
  16. if (!console[method]) {
  17. console[method] = noop;
  18. }
  19. }
  20. }());
  21. //Affiche un message 'message' de type 'type' pendant 'timeout' secondes
  22. $.message = function (type,message,timeout){
  23. message = message.replace(/<\/?script|iframe|object[^>]*>/gim,'');
  24. var types = {
  25. error : 'ERREUR',
  26. warning : 'ATTENTION',
  27. info : 'INFORMATION',
  28. }
  29. var data = { type: type, content: message, timeout: timeout };
  30. if(types[type]) data.title = types[type];
  31. $.toast(data);
  32. }
  33. //Permet les notifications types toast sans dépendance de librairie/css/html
  34. $.toast = function (options) {
  35. var defaults = {
  36. title: null,
  37. content: '',
  38. type: 'info',
  39. timeout: 3000
  40. };
  41. var o = $.extend(defaults, options);
  42. if ($('.toastContainer').length == 0)
  43. $('body').append('<div class="toastContainer"></div>');
  44. var popupContainer = $('.toastContainer');
  45. var popup = $('<div class="noPrint toast toast-'+o.type+' hidden"><i class="toastRemove fas fa-times hidden" onclick="var toast = $(this).parent(); toast.addClass(\'hidden\');setTimeout(function(){toast.remove();},100);";></i><i class="toastIcon fa"></i><div class="toastContent"><div class="toastTitle"></div><div class="toastMessage"></div></div><div style="clear:both;"></div></div>');
  46. $(popupContainer).append(popup);
  47. if (o.title) $('.toastTitle', popup).html(o.title);
  48. $('.toastMessage', popup).html(o.content);
  49. setTimeout(function () { popup.removeClass('hidden'); }, 50);
  50. if (o.timeout != 0) {
  51. setTimeout(function () {
  52. popup.addClass('hidden');
  53. setTimeout(function () {
  54. popup.remove();
  55. },100);
  56. }, o.timeout);
  57. } else {
  58. popup.find('.toastRemove').removeClass('hidden');
  59. }
  60. }
  61. $.page = function(element){
  62. var path = window.location.pathname.split('/') ;
  63. path = path[path.length-1];
  64. path = path.replace('.php','');
  65. return path;
  66. }
  67. $.getForm= function(element){
  68. return $(element).getForm();
  69. }
  70. $.setForm= function(element,data){
  71. var o = {};
  72. var obj = $(element);
  73. $('input,select,textarea',obj).each(function(i,element){
  74. if(element.id!=null && element.id!=""){
  75. if(data[element.id]!=null){
  76. if($(element).attr("type")=='checkbox' || $(element).attr("type")=='radio'){
  77. $(element).prop("checked",data[element.id]==1 || data[element.id]=='true' ?true:false);
  78. } else {
  79. $(element).val(data[element.id]);
  80. }
  81. }
  82. }
  83. });
  84. return o;
  85. }
  86. //Gestion des tableaux pour le formData
  87. $.form_data = function(formData, key,values){
  88. var hasFile = false;
  89. if(values instanceof File ) hasFile = true;
  90. if( typeof values == 'object' && !(values instanceof File) ){
  91. for(subkey in values)
  92. if($.form_data(formData,key + '[' + subkey + ']',values[subkey])) hasFile = true;
  93. }else{
  94. formData.append(key, values);
  95. }
  96. return hasFile;
  97. }
  98. $.action = function(data,success,error,progress) {
  99. var formData = new FormData();
  100. var defaultSuccess = data.defaultSuccess != undefined ? data.defaultSuccess : true;
  101. // if(data.defaultSuccess !== undefined) delete data.defaultSuccess;
  102. //hasFile determine si un fichier uploadé se trouve dans le tableau des data
  103. // Si c'est le cas, il envois les données en multipart, sinon il les envoie en json classique.
  104. var hasFile = false;
  105. $.each(data, function(key, value){
  106. if($.form_data(formData,key, value) == true) hasFile = true;
  107. });
  108. var request = {
  109. url : 'action.php',
  110. method : 'POST',
  111. success: function(response){
  112. $('.btn.btn-preloader').removeClass('btn-preloader');
  113. if(response && !response.error){
  114. if(success!=null)success(response);
  115. } else {
  116. if(response.errorCode && response.errorCode=='401') window.location = 'action.php?action=logout';
  117. var errorMessage = 'ERREUR : '+"\n"+response.error;
  118. if(response.trace) errorMessage += "\n<div style='font-size:10px;max-height:200px;overflow:auto;text-align:left;'>"+response.trace+"</div>";
  119. if(defaultSuccess) $.message('error',errorMessage,0);
  120. if(error!=null) error(response);
  121. }
  122. },
  123. error : function(response){
  124. $('.btn.btn-preloader').removeClass('btn-preloader');
  125. if(response.status == 200 && $.localhost() ){
  126. $('body').append('<div class="debugFrame" style="box-shadow: 0px 0px 10px rgba(0,0,0,0.5);z-index: 30001;padding: 5px;position: fixed;left: 0;top: 0;width: 40%;min-height: 100%;border-right: 2px solid #ff3b00;background: rgba(210, 222, 255, 0.9);overflow-y: auto;height: 100%; word-break: break-word;"><h3>Action debug</h3> <i style="position:absolute; right:10px; top:10px;font-size:1.5em;" onclick="$(this).parent().remove()" class="fas fa-times pointer"></i>'+response.responseText+'</div>');
  127. } else {
  128. if(response.readyState == 0 && error==null) return;
  129. if(error!=null){
  130. if(response.errorCode && response.errorCode=='401') window.location = 'action.php?action=logout';
  131. error(response);
  132. }else{
  133. $.message('error','Erreur indefinie, merci de contacter un administrateur',0);
  134. }
  135. }
  136. },
  137. xhr: function() {
  138. var xhr = new window.XMLHttpRequest();
  139. if(data.downloadResponse) xhr.responseType = 'blob';
  140. xhr.upload.addEventListener("progress", function(evt){
  141. if (evt.lengthComputable) {
  142. var percentComplete = (evt.loaded / evt.total) * 100;
  143. percentComplete = Math.round(percentComplete * 100) / 100;
  144. if(progress) progress(percentComplete,'upload');
  145. }
  146. }, false);
  147. xhr.addEventListener("progress", function(evt){
  148. if (evt.lengthComputable) {
  149. var percentComplete = evt.loaded / evt.total;
  150. if(progress) progress(percentComplete,'download');
  151. }
  152. }, false);
  153. xhr.addEventListener('readystatechange', function(e) {
  154. if(xhr.readyState == 4 && xhr.status == 200) {
  155. if(data.downloadResponse){
  156. var disposition = xhr.getResponseHeader('content-disposition');
  157. var matches = /"([^"]*)"/.exec(disposition);
  158. var filename = (matches != null && matches[1] ? matches[1] : 'file');
  159. var blob = new Blob([xhr.response], { type: xhr.response.type });
  160. var link = document.createElement('a');
  161. link.href = window.URL.createObjectURL(blob);
  162. link.download = filename;
  163. $('body').append(link);
  164. link.click();
  165. link.remove();
  166. window.URL.revokeObjectURL(link);
  167. }
  168. }
  169. });
  170. return xhr;
  171. }
  172. };
  173. if(!hasFile){
  174. request.data = data;
  175. }else{
  176. request.data = formData;
  177. request.processData = false;
  178. request.contentType = false;
  179. }
  180. $.ajax(request);
  181. }
  182. $.localhost = function(){
  183. return (document.location.hostname=='127.0.0.1' || document.location.hostname=='localhost');
  184. }
  185. $.hashData = function(name){
  186. var page = window.location.hash.substring(1);
  187. page += "&"+window.location.search.substring(1);
  188. data = {};
  189. if(page!='' && page!= null){
  190. options = page.split('&');
  191. var data = {};
  192. for(var key in options){
  193. infos = options[key].split('=');
  194. data[infos[0]] = infos[1];
  195. }
  196. }
  197. if(name == null) return data;
  198. if(typeof name === "object"){
  199. data = name;
  200. hashstring = '';
  201. for(var key in data)
  202. hashstring+= "&"+key+"="+data[key];
  203. hashstring = hashstring.substring(1);
  204. window.location.hash = hashstring;
  205. return;
  206. }
  207. return typeof data[name] == "undefined" ? '':data[name];
  208. }
  209. $.urlParam = function (name,value) {
  210. var parameters = window.location.href.match(/[\\?&]([^&#]*)=([^&#]*)/g);
  211. var data = {};
  212. for (var key in parameters) {
  213. var couple = parameters[key].substring(1, parameters[key].length).split('=');
  214. data[couple[0]] = couple[1];
  215. }
  216. if(name == null) return data;
  217. if (value == null)
  218. return data[name] ? data[name] : null;
  219. if (value != false) data[name] = value;
  220. var url = '?';
  221. for (var key in data) {
  222. if (value == false && key == name) continue;
  223. url += key + '=' + data[key]+'&';
  224. }
  225. window.history.pushState('', document.title, url.substring(0, url.length-1));
  226. }
  227. $.fn.extend({
  228. toJson : function(){
  229. return $.getForm(this);
  230. },
  231. fitText: function(ratio, options) {
  232. var compressor = ratio || 1,
  233. settings = $.extend({
  234. 'minFontSize' : Number.NEGATIVE_INFINITY,
  235. 'maxFontSize' : Number.POSITIVE_INFINITY
  236. }, options);
  237. return this.each(function(){
  238. var element = $(this);
  239. var resizer = function() {
  240. element.css('font-size', Math.max(Math.min(element.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));
  241. };
  242. resizer();
  243. $(window).on('resize.fittext orientationchange.fittext', resizer);
  244. });
  245. },
  246. getForm: function(){
  247. var o = {};
  248. var obj = $(this);
  249. for(var key in obj.data()){
  250. if(key!="action" && key != "id") continue;
  251. o[key] = obj.attr('data-'+key);
  252. }
  253. $('input,select,textarea',obj).each(function(i,element){
  254. var element = $(element);
  255. var id = element.attr('id');
  256. if(id!=null && id!=""){
  257. if(element.attr("type")=='checkbox' || element.attr("type")=='radio'){
  258. o[id] = (element.is(':checked')?1:0);
  259. } else if(element.attr("type")=='file'){
  260. if(!element[0].files.length) return;
  261. if(element[0].files.length == 1){
  262. o[id] = element[0].files[0];
  263. } else {
  264. //Attention, le passage de multiples fichiers
  265. //entraine une modification de la structure du
  266. //tableau $_FILES dans le php (voir fonction normalize_php_files())
  267. o[id] = {};
  268. for(var i=0; i<element[0].files.length; ++i)
  269. o[id][i] = element[0].files[i];
  270. }
  271. } else {
  272. o[id] = element.val();
  273. }
  274. }
  275. });
  276. return o;
  277. },
  278. upload: function (options) {
  279. //var options = $.extend(defaults, options);
  280. return this.each(function () {
  281. var o = options;
  282. var droppedFiles = false;
  283. var div = $(this);
  284. var data = div.data();
  285. data.html =!div.attr('data-label') ? '': div.attr('data-label');
  286. data.label = data.html;
  287. div.html('');
  288. var o = $.extend(o, data);
  289. if(o.readonly == false){
  290. var form = $('<form class="box" method="post" action="' + o.action + '" enctype="multipart/form-data"><input type="file" name="'+(o.fileName?o.fileName:div.attr('id'))+'[]" multiple /></form>');
  291. div.append(form);
  292. var input = form.find('input[type="file"]');
  293. var zone = $('<div class="pointer text-center">' + o.label + '</div>');
  294. div.append(zone);
  295. //test if dnd is enabled n browser
  296. var div = document.createElement('div');
  297. var dragAndDropEnabled = (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window;
  298. //set elements styles
  299. input.attr('style', "width: 0.1px;height: 0.1px;opacity: 0;overflow: hidden; position: absolute;z-index: -1");
  300. //set events
  301. zone.on('click', function (e) {
  302. form.find('input[type="file"]').trigger('click');
  303. e.preventDefault();
  304. e.stopPropagation();
  305. })
  306. .on('drag dragstart dragend dragover dragenter dragleave drop', function (e) {
  307. e.preventDefault();
  308. e.stopPropagation();
  309. })
  310. .on('dragover dragenter', function () {
  311. if (o.hover) form.addClass(o.hover);
  312. })
  313. .on('dragleave dragend drop', function () {
  314. if (o.hover) form.removeClass(o.hover);
  315. })
  316. .on('drop', function (e) {
  317. droppedFiles = e.originalEvent.dataTransfer.files;
  318. form.trigger('submit');
  319. });
  320. input.on('change', function (e) {
  321. form.trigger('submit');
  322. });
  323. form.on('submit', function (e) {
  324. e.preventDefault();
  325. if (o.start){
  326. var result = o.start();
  327. if(result == -1) return;
  328. }
  329. if (dragAndDropEnabled) {
  330. var ajaxData = new FormData();
  331. if (droppedFiles) {
  332. $.each(droppedFiles, function (i, file) {
  333. var ext = file.name.split('.');
  334. ext = ext.pop();
  335. if(o.allowed && $.inArray(ext.toLowerCase(),o.allowed.split(','))===-1){
  336. $.message('error','Extension fichier '+ext+' non permise (autorisé:'+o.allowed+')',0);
  337. return;
  338. }
  339. if(o.size && file.size > o.size){
  340. $.message('error','Taille fichier '+file.size+' octets trop grande (autorisé:'+o.size+' octets)',0);
  341. return;
  342. }
  343. ajaxData.append(input.attr('name'), file);
  344. });
  345. }else{
  346. ajaxData = new FormData(form.get(0));
  347. for(var key in $('input',form).get(0).files){
  348. var file = $('input',form).get(0).files[key];
  349. if(file.name==null || typeof file !='object') continue;
  350. var ext = file.name.split('.');
  351. ext = ext.pop();
  352. if(o.allowed && $.inArray(ext.toLowerCase(),o.allowed.split(','))===-1){
  353. $.message('error','Extension fichier '+ext+' non permise (autorisé:'+o.allowed+')',0);
  354. $('input',form).val();
  355. return;
  356. }
  357. if(o.size && file.size > o.size){
  358. $.message('error','Taille fichier '+file.size+' octets trop grande (autorisé:'+o.size+' octets)',0);
  359. $('input',form).val();
  360. return;
  361. }
  362. }
  363. }
  364. if (o.addData){
  365. var addionnalData = o.addData();
  366. for(var k in addionnalData)
  367. ajaxData.append(k, addionnalData[k]);
  368. }
  369. droppedFiles = null;
  370. $.ajax({
  371. url: form.attr('action'),
  372. type: form.attr('method'),
  373. data: ajaxData,
  374. dataType: 'json',
  375. cache: false,
  376. contentType: false,
  377. processData: false,
  378. complete: function (data) {
  379. if (o.complete) o.complete(data.responseJSON);
  380. },
  381. success: function (data) {
  382. if (o.success) o.success(data);
  383. },
  384. error: function (data) {
  385. if (o.error) o.error(data);
  386. }
  387. });
  388. } else {
  389. var iframeName = 'uploadiframe' + new Date().getTime();
  390. iframe = $('<iframe name="' + iframeName + '" style="display: none;"></iframe>');
  391. $('body').append(iframe);
  392. form.attr('target', iframeName);
  393. iframe.one('load', function () {
  394. var data = JSON.parse(iframe.contents().find('body').text());
  395. if (!data.success) alert(data.error);
  396. form.removeAttr('target');
  397. iframe.remove();
  398. if (o.complete) o.complete();
  399. });
  400. }
  401. });
  402. }
  403. });
  404. },
  405. shiftCheckboxes: function() {
  406. var instance = this;
  407. this.on('click', function(e) {
  408. var checkbox = $(e.target);
  409. if(e.shiftKey && instance.last) {
  410. var from = instance.index(instance.last);
  411. var to = instance.index(checkbox);
  412. instance.slice(Math.min(from, to), Math.max(from, to) + 1)
  413. .filter(':not(:disabled)')
  414. .prop('checked', checkbox.prop('checked'))
  415. .trigger('change');
  416. }
  417. instance.last = checkbox;
  418. });
  419. },
  420. clear: function(){
  421. return this.each(function() {
  422. var obj = $(this);
  423. obj.find('input,select,textarea').val('').prop('checked',false).prop('selected',false);
  424. obj.find('*[contenteditable="true"]').text('');
  425. });
  426. },
  427. addLine: function (rows){
  428. return this.each(function() {
  429. var obj = $(this);
  430. var model = null;
  431. var container = null;
  432. if(obj.prop("tagName") == 'UL'){
  433. container = obj;
  434. model = container.find('li:first-child');
  435. container.find('li:visible').remove();
  436. }else if(obj.prop("tagName") == 'TABLE'){
  437. container = obj.find('tbody');
  438. model = container.find('tr:first-child');
  439. container.find('tr:visible').remove();
  440. }else{
  441. container = obj;
  442. childName = container.children().get(0).nodeName;
  443. model = container.find(childName+':first-child');
  444. container.find(childName+':visible:not(.nofill)').remove();
  445. }
  446. var tpl = model.get(0).outerHTML;
  447. //fix jquery backslahes break
  448. tpl = tpl.replace(/{{##/g,'{{/').replace(/{{\/(.*)}}=""/g,'{{/$1}}');
  449. //fix images url not found on template
  450. tpl = tpl.replace(/(<img\s[^>]*\s)(data-src)/g,'$1src');
  451. for(var key in rows){
  452. var line = $(Mustache.render(tpl,rows[key]));
  453. container.append(line);
  454. line.removeClass('hidden');
  455. }
  456. });
  457. },
  458. //Retourne un node jquery visible à partir d'un
  459. //modèle de template invisible + données mustache
  460. template: function(data){
  461. return $(Mustache.render($(this).get(0).outerHTML,data)).removeClass('hidden');
  462. },
  463. //Permet le resize d'un panel vertical
  464. panelResize : function(options){
  465. var obj = $(this);
  466. var o = $.extend({
  467. handlerClass : 'panel-resize-handler',
  468. hoverClass : 'panel-resize-handler-hover',
  469. handlerWidth : 10,
  470. direction : 'right',
  471. minWidth : 30,
  472. maxWidth : 700,
  473. update : function(data){}
  474. }, options);
  475. var handlerId = 'handler-'+generate_uuid(10);
  476. var handler = $('<div id="'+handlerId+'" class="'+o.handlerClass+'" style="cursor:col-resize;opacity:0.1;position:absolute;z-index:1000;height:'+obj.outerHeight()+'px;width:'+o.handlerWidth+'px;"></div>');
  477. var timeout = null;
  478. var left;
  479. if( o.direction== 'right'){
  480. left = obj.position().left+obj.outerWidth()-(o.handlerWidth/2);
  481. }else if (o.direction== 'left'){
  482. left = obj.position().left-(o.handlerWidth/2);
  483. }
  484. handler.css({
  485. left :left,
  486. top : obj.position().top
  487. });
  488. handler.hover(function(){
  489. clearTimeout(timeout);
  490. handler.addClass(o.hoverClass);
  491. },
  492. function(){
  493. timeout = setTimeout(function(){
  494. handler.removeClass(o.hoverClass);
  495. },300);
  496. });
  497. if(!window.handlerActive) window.handlerActive = {};
  498. if(!window.handlerPosition) window.handlerPosition = {};
  499. handler.mousedown(function(){
  500. window.handlerPosition[handlerId] = handler.position().left;
  501. window.handlerPanelWidth = obj.outerWidth();
  502. window.handlerActive[handlerId] = true;
  503. });
  504. $(document).mouseup(function(){
  505. window.handlerActive[handlerId] = false;
  506. var left;
  507. if( o.direction== 'right'){
  508. left = obj.position().left+obj.outerWidth()-(o.handlerWidth/2);
  509. }else if (o.direction== 'left'){
  510. left = obj.position().left-(o.handlerWidth/2);
  511. }
  512. handler.css({left : left});
  513. o.update({
  514. element : obj,
  515. handler : handler,
  516. width : obj.outerWidth()
  517. });
  518. });
  519. $(document).mousemove(function( event ) {
  520. if(!window.handlerActive[handlerId]) return;
  521. var newPosition = (event.pageX-2);
  522. var negativeWidth = window.handlerPosition[handlerId] - newPosition;
  523. var newWidth = window.handlerPanelWidth- (negativeWidth * (o.direction== 'right'?1:-1) );
  524. if(newWidth < o.minWidth || newWidth <1 || newWidth > o.maxWidth ){
  525. return;
  526. }
  527. handler.css({
  528. left : newPosition+'px'
  529. });
  530. obj.css({
  531. width : newWidth+'px',
  532. maxWidth : newWidth+'px'
  533. });
  534. });
  535. obj.after(handler);
  536. },
  537. fill: function (option,callback,progress){
  538. return this.each(function() {
  539. var obj = $(this);
  540. var model = null;
  541. var container = null;
  542. option = $.extend({
  543. differential : false,
  544. showing : function(item){
  545. //permet la personnalisation de l'apparition des lignes ( removeClass('hidden') par defaut)
  546. item.removeClass('hidden');
  547. }
  548. },option);
  549. var preloader = null;
  550. if(option.preloader){
  551. var preloader = $(option.preloader);
  552. preloader.css('position','absolute');
  553. preloader.css('left',(obj.offset().left+obj.width()/2)+'px');
  554. preloader.css('top',(obj.offset().top+30)+'px');
  555. $('body').append(preloader);
  556. }
  557. if(obj.prop("tagName") == 'UL'){
  558. container = obj;
  559. model = container.find('li:first-child');
  560. if(!option.export && !option.differential) container.children('li:visible').remove();
  561. } else if(obj.prop("tagName") == 'TABLE'){
  562. container = obj.find('tbody');
  563. model = container.find('tr:first-child');
  564. if(!option.export && !option.differential) container.children('tr:visible').remove();
  565. } else if(obj.prop("tagName") == "SELECT"){
  566. container = obj;
  567. model = container.find('option[value*="{{"]');
  568. if(model.length==0) model = $('<option class="hidden" value="{{value}}">{{label}}</option>');
  569. if(!option.export && !option.differential) container.find('option:not([value*="{{"])').remove();
  570. } else{
  571. container = obj;
  572. childName = container.children().get(0).nodeName;
  573. model = container.find(childName+':first-child');
  574. if(!option.export && !option.differential) container.find(childName+':visible:not(.nofill)').remove();
  575. }
  576. var tpl = model.get(0).outerHTML;
  577. //fix jquery backslashes break
  578. tpl = tpl.replace(/{{##/g,'{{/').replace(/{{\/(.*)}}=""/g,'{{/$1}}');
  579. //fix images url not found on template
  580. tpl = tpl.replace(/(<img\s[^>]*\s?)(data-src)/g,'$1src');
  581. var pagination = obj.nextAll('.pagination').length ? obj.nextAll('.pagination') : obj.parent().nextAll('.pagination');
  582. if(pagination.length!=0) option.page = $('li.active',pagination).attr('data-value');
  583. tpl = tpl.replace(/(data-style)/g, 'style');
  584. if(option.export)
  585. option.downloadResponse = true;
  586. //on clone l'objet option pour ne transmettre que des datas utiles
  587. data = $.extend({},option);
  588. delete data.showing;
  589. delete data.templating;
  590. $.action(data,function(r){
  591. //On ne gere la pagination et l'affichage tableau que si on est pas en mode export
  592. if(!option.export){
  593. if(option.differential){
  594. //suppression des élements dom qui ne sont plus en db
  595. $('>[data-id]:visible',container).each(function(i,line){
  596. var line = $(line);
  597. toDelete = true;
  598. for(var key in r.rows){
  599. if(line.attr('data-id') == r.rows[key].id){
  600. toDelete = false;
  601. break;
  602. }
  603. }
  604. if(toDelete) line.remove();
  605. });
  606. }
  607. //var activeIds = [];
  608. for(var key in r.rows){
  609. var line;
  610. var data = r.rows[key];
  611. var lineTpl = tpl;
  612. if(option.templating) lineTpl = option.templating(data,line,tpl);
  613. if(!option.differential){
  614. line = $(Mustache.render(lineTpl,data));
  615. container.append(line);
  616. option.showing(line,key);
  617. }else{
  618. //activeIds.push(data.id);
  619. var existing = $('> [data-id="'+data.id+'"]',container);
  620. //existe en data et pas dans le dom : ajout
  621. if(existing.length == 0){
  622. line = $(Mustache.render(lineTpl,data));
  623. line.attr('data-update-tag',data.updated);
  624. if(key==0){
  625. container.append(line);
  626. }else{
  627. var previousIndex = key-1;
  628. var previous = $('>[data-id]:visible',container).eq(previousIndex);
  629. previous.after(line);
  630. }
  631. option.showing(line,key);
  632. }else{
  633. //existe en data et dans le dom et pas de modification : on passe au suivant
  634. if(existing.attr('data-update-tag') == data.updated){
  635. continue;
  636. //existe en data et dans le dom mais a été modifié : on remplace
  637. }else{
  638. line = $(Mustache.render(lineTpl,data));
  639. line.attr('data-update-tag',data.updated);
  640. existing.after(line);
  641. existing.remove();
  642. option.showing(line,key);
  643. }
  644. }
  645. }
  646. }
  647. if(option.differential){
  648. var existingDom = [];
  649. for(var key in r.rows){
  650. var data = r.rows[key];
  651. var line = $('>[data-id="'+r.rows[key].id+'"]',container);
  652. var index = line.index() -1;
  653. if(key != index){
  654. var prevIndex = (key-1);
  655. if(prevIndex<0){
  656. container.prepend(line.detach());
  657. }else{
  658. var prevElement = $('>[data-id]:visible()',container).eq(prevIndex);
  659. prevElement.after(line.detach());
  660. }
  661. }
  662. }
  663. }
  664. if(r.pagination){
  665. $('.page-item-previous,.page-item-next').remove();
  666. r.pagination.pages = Math.ceil(r.pagination.pages);
  667. var previewNumber = pagination.attr('data-range') != '' && pagination.attr('data-range') != null ? parseInt(pagination.attr('data-range')) : 5;
  668. previewNumber = previewNumber < 2 ? 2 : previewNumber;
  669. var template = pagination.find('li:not(:visible)');
  670. if(template.length>0 ){
  671. template = template.get(0).outerHTML;
  672. $('li:not(:eq(0))',pagination).remove();
  673. var current = parseInt(r.pagination.current);
  674. var previousPages = current-previewNumber;
  675. var nextPages = current+previewNumber;
  676. var dropDownTpl = '<div data-toggle="dropdown"><i class="fas fa-ellipsis-h pointer"></i></div><div class="dropdown-menu pagination-select">{{#choices}}<span class="dropdown-item">{{.}}</span>{{/choices}}</div>';
  677. for(i=0;i<r.pagination.pages;i++){
  678. var li = $(Mustache.render(template,{value:i,label:i+1}));
  679. if(
  680. (previousPages < i && i < nextPages)
  681. || i==0 || i==r.pagination.pages-1
  682. ){
  683. li.removeClass('hidden');
  684. if(i==current) li.addClass('active');
  685. }else{
  686. if(i==1 || i==r.pagination.pages-2){
  687. var dotli = li.clone()
  688. var start = i==1 ? 2: current+previewNumber+1;
  689. var end = i==1 ? (current+1)-previewNumber : r.pagination.pages-1;
  690. var choices = [];
  691. for(u=start; u<end+1;u++)
  692. choices.push(u);
  693. rightDropDown = $(Mustache.render(dropDownTpl,{choices:choices}));
  694. dotli.removeClass('hidden')
  695. .attr('title','Voir les pages '+(start)+' à '+(end))
  696. .removeAttr('onclick')
  697. .css('position','relative')
  698. .addClass('page-link').html(rightDropDown);
  699. pagination.append(dotli);
  700. }
  701. }
  702. pagination.append(li);
  703. }
  704. if(current!=0){
  705. var prev = $('<li class="page-item page-item-previous"><span class="page-link" ><span><i class="fas fa-angle-left"></i></span></span></li>');
  706. pagination.prepend(prev);
  707. prev.click(function(){
  708. pagination.find('li[data-value="'+(current-1)+'"]').trigger('click');
  709. });
  710. }
  711. if(current<r.pagination.pages-1){
  712. var next = $('<li class="page-item page-item-next"><span class="page-link" ><span><i class="fas fa-angle-right"></i></span></span></li>');
  713. pagination.append(next);
  714. next.click(function(){
  715. pagination.find('li[data-value="'+(current+1)+'"]').trigger('click');
  716. });
  717. }
  718. if(r.pagination.pages>1){
  719. pagination.find('.page-item:not(.hidden):first .page-link').css('border-radius','0.25rem 0 0 0.25rem');
  720. }else{
  721. pagination.find('.page-item:not(.hidden):first .page-link').css('border-radius','0.25rem 0.25rem 0.25rem 0.25rem');
  722. }
  723. $('.pagination-select span',pagination).click(function(){
  724. var selectedPage = (parseInt($(this).text())-1);
  725. pagination.find('li[data-value="'+selectedPage+'"]').trigger('click');
  726. });
  727. }
  728. }
  729. }
  730. if(preloader) preloader.remove();
  731. if(callback!=null)callback(r);
  732. },null,function(percent,type){
  733. if(progress) progress(percent,type);
  734. });
  735. });
  736. },
  737. filters: function (values){
  738. var obj = $(this);
  739. var box = obj.next('.filter-box');
  740. if(values){
  741. if(values.keyword && values.keyword!='')
  742. $('.filter-keyword',box).val(values.keyword);
  743. for(var key in values.advanced){
  744. var filter = values.advanced[key];
  745. filter_add($('.filter-add-button',box),filter);
  746. }
  747. return;
  748. }
  749. var formData = {
  750. keyword : $('.filter-keyword',box).val()
  751. };
  752. formData.advanced = [], formData.multiple = [], formData.custom = {};
  753. $('.filterRow:visible',box).each(function(i,row){
  754. var row = $(row);
  755. if(row.find('.filter-column').val()=='') return;
  756. var filter = {
  757. join : row.find('.filter-join').val(),
  758. column : row.find('.filter-column').val(),
  759. type : row.find('.filter-column option:selected').attr('data-filter-type'),
  760. operator : {},
  761. value : {}
  762. }
  763. if ($('.filter-value-block',row).length > 1) {
  764. $('.filter-value-block',row).each(function(j,block){
  765. var block = $(block);
  766. filter.operator[j] = block.find('.filter-operator').val();
  767. filter.value[j] = block.find('.filter-value').last().val();
  768. });
  769. formData.multiple.push(filter);
  770. } else {
  771. filter.operator = row.find('.filter-operator').val();
  772. values = row.find('.filter-value');
  773. if(values.length > 1){
  774. filter.value = [];
  775. for(var j=0; j<values.length; ++j){
  776. filter.value.push(values.eq(j).val());
  777. }
  778. values.eq(j).attr('data-custom') == 'true' ? formData.custom[filter.column] = filter : formData.advanced.push(filter);
  779. } else {
  780. filter.value = values.val();
  781. values.last().attr('data-custom') == 'true' ? formData.custom[filter.column] = filter : formData.advanced.push(filter);
  782. }
  783. }
  784. });
  785. return formData;
  786. },
  787. enter: function (option){
  788. return this.each(function() {
  789. var obj = $(this);
  790. obj.keydown(function(event){
  791. if(event.keyCode == 13){
  792. option();
  793. return false;
  794. }
  795. });
  796. });
  797. },
  798. sortable_table: function (option){
  799. if(option=='get'){
  800. var obj = $(this);
  801. var response = {};
  802. obj.find('thead th[data-sortable]').each(function(i,th){
  803. var th = $(th);
  804. if(th.attr('data-sort') && th.attr('data-sort')!=""){
  805. response = {
  806. sort : th.attr('data-sort'),
  807. sortable : th.attr('data-sortable')
  808. };
  809. }
  810. });
  811. return response;
  812. }
  813. return this.each(function() {
  814. var obj = $(this);
  815. obj.find('thead th[data-sortable]').click(function(){
  816. var th = $(this);
  817. var data = th.data();
  818. if(!data.sort || data.sort==''){
  819. data.sort = 'asc'
  820. }else if(data.sort == 'asc'){
  821. data.sort ='desc'
  822. }else{
  823. data.sort = '';
  824. }
  825. obj.find('thead th').removeClass('sort-asc').removeClass('sort-desc').removeAttr('data-sort');
  826. if(data.sort!='') th.addClass('sort-'+data.sort);
  827. th.attr('data-sort',data.sort);
  828. if(option.onSort) option.onSort();
  829. });
  830. });
  831. },
  832. autocomplete: function(o){
  833. return this.each(function() {
  834. var obj = $(this);
  835. if(o == 'off') return obj.typeahead('destroy');
  836. obj.attr('autocomplete','off');
  837. var option = obj.data();
  838. option = $.extend(option,o);
  839. obj.typeahead({
  840. items: (o.items) ? o.items : 5,
  841. minLength: o.suggest ? 0 : (o.minLength ? o.minLength : 2) ,
  842. fitToElement: false,
  843. autoSelect : false,
  844. selectOnBlur : false,
  845. displayText : function(item){
  846. return (o.skin) ? o.skin(item,obj) : item.name || item;
  847. },
  848. source: function(keyword, response){
  849. if(o.onKeypress) o.onKeypress(obj);
  850. if(o.dynamicData) o.data = $.extend(o.data,o.dynamicData());
  851. if(o.data) o.data.limit = (o.items) ? o.items : 5;
  852. $.action({
  853. action: option.action,
  854. keyword: obj.val(),
  855. data: o.data
  856. },function(r){
  857. if(r.rows != null) response(r.rows);
  858. });
  859. },
  860. highlighter: function(item){
  861. if(o.highlight) {
  862. return o.highlight(item)
  863. }
  864. else {
  865. var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
  866. return item.replace(new RegExp('('+query+')', 'ig'), function($1, match){
  867. return '<strong>'+match+'</strong>';
  868. });
  869. }
  870. },
  871. matcher: function(r){
  872. if(obj.val() == r.name)
  873. if(o.onClick)
  874. o.onClick(r,obj);
  875. return '<div>'+r.name+'</div>';
  876. },
  877. afterSelect: function(item) {
  878. obj.data('selected',true);
  879. if(o.onClick) o.onClick(item,obj);
  880. obj.trigger("change");
  881. }
  882. }).blur(function(){
  883. if(o.onBlur) o.onBlur(obj);
  884. });
  885. if(o.suggest){
  886. obj.on("click", function () {
  887. ev = $.Event("keydown");
  888. ev.keyCode = ev.which = 40;
  889. $(this).trigger(ev);
  890. return true
  891. });
  892. }
  893. obj.data('typeahead').next = function (event) {
  894. var active = this.$menu.find('.active').removeClass('active');
  895. var next = active.next();
  896. if (!next.length) {
  897. next = $(this.$menu.find($(this.options.item || this.theme.item).prop('tagName'))[0]);
  898. }
  899. while (next.hasClass('divider') || next.hasClass('dropdown-header')) {
  900. next = next.next();
  901. }
  902. next.addClass('active');
  903. var newVal = this.updater(next.data('value'));
  904. this.$element.val(newVal.name || newVal.label || newVal);
  905. };
  906. obj.data('typeahead').prev = function (event) {
  907. var active = this.$menu.find('.active').removeClass('active');
  908. var prev = active.prev();
  909. if (!prev.length){
  910. prev = this.$menu.find($(this.options.item || this.theme.item).prop('tagName')).last();
  911. }
  912. while (prev.hasClass('divider') || prev.hasClass('dropdown-header')) {
  913. prev = prev.prev();
  914. }
  915. prev.addClass('active');
  916. var newVal = this.updater(prev.data('value'));
  917. if (this.changeInputOnMove) this.$element.val(newVal.name || newVal.label || newVal);
  918. };
  919. });
  920. },
  921. location: function (options){
  922. return this.each(function() {
  923. var obj = $(this);
  924. var o = $.extend({},options);
  925. obj.off('keyup').on('keyup', function(event) {
  926. if(!$(this).val().length) return;
  927. });
  928. obj.autocomplete({
  929. action: 'location_search',
  930. force: (o.force ? o.force : false),
  931. items: (o.items ? o.items : 8),
  932. data: {
  933. maxresults: (o.items ? o.items : 8),
  934. language: (o.language ? o.language : "fr"),
  935. country: (o.country ? o.country : "FRA"),
  936. },
  937. skin : function(item){
  938. var html = '<small class="text-muted"><i class="fas fa-map-marker-alt d-inline-block mr-2 text-muted"></i>';
  939. var re = new RegExp(obj.val(),"gi");
  940. name = item.label.replace(re, function (x) {
  941. return '<strong class="text-primary">'+x+'</strong>';
  942. });
  943. html += name+'</small>';
  944. return html;
  945. },
  946. highlight : function(item){
  947. return item;
  948. },
  949. onClick : function(selected,element){
  950. obj.val(selected.label);
  951. if(!is_empty_obj(selected.address)) {
  952. var infos = {
  953. number: selected.address.houseNumber ? selected.address.houseNumber : '',
  954. street: selected.address.street ? selected.address.street : '',
  955. district: selected.address.district ? selected.address.district : '',
  956. city: selected.address.city ? selected.address.city : '',
  957. county: selected.address.county ? selected.address.county : '',
  958. state: selected.address.state ? selected.address.state : '',
  959. country: selected.address.country ? selected.address.country : '',
  960. zip: selected.address.postalCode ? selected.address.postalCode : '',
  961. };
  962. infos.address = (infos.street && infos.street.length && infos.number && infos.number.length) ? infos.number+' '+infos.street : (infos.street ? infos.street : '');
  963. obj.removeData();
  964. obj.data(infos);
  965. if(o.select) o.select(infos);
  966. if(o.geocode) o.geocode(selected);
  967. }
  968. },
  969. onBlur : function(selected,element){
  970. },
  971. onCancel : function(element){
  972. obj.val('');
  973. }
  974. });
  975. });
  976. },
  977. colorInput: function (options) {
  978. return this.each(function () {
  979. var o = $.extend({
  980. choices : [
  981. '#34495e',
  982. '#9b59b6',
  983. '#3498db',
  984. '#2ecc71',
  985. '#1abc9c',
  986. '#95a5a6',
  987. '#ecf0f1',
  988. '#e74c3c',
  989. '#e67e22',
  990. '#f1c40f',
  991. '#d35400',
  992. '#55E6C1',
  993. '#EAB543',
  994. '#F8EFBA',
  995. '#FD7272',
  996. '#3B3B98',
  997. '#B33771',
  998. '#6c5ce7',
  999. '#0984e3',
  1000. '#00cec9',
  1001. '#fd79a8',
  1002. '#d63031',
  1003. '#a29bfe',
  1004. '#55efc4'
  1005. ]
  1006. },options);
  1007. var input = $(this);
  1008. input.hide();
  1009. var component = input.data('component-color');
  1010. if(component){
  1011. //reload
  1012. }else{
  1013. var component = $('<div class="component-color form-control"><div class="component-color-thumb"></div><div class="component-color-picker hidden"></div><input type="color" class="component-color-palette"></div>');
  1014. //load
  1015. input.data('component-color',component);
  1016. input.after(component);
  1017. component.append(input.detach());
  1018. }
  1019. var picker = $('.component-color-picker',component);
  1020. var palette = $('.component-color-palette',component);
  1021. var thumb = $('.component-color-thumb',component);
  1022. thumb.css('backgroundColor',input.val());
  1023. var html = '<ul>';
  1024. for(var k in o.choices){
  1025. html += '<li><div class="color-choice" data-color="'+o.choices[k]+'" style="background-color:'+o.choices[k]+'"></div></li>';
  1026. }
  1027. html += '<li><div class="other-color" title="Autre couleur"><i class="fas fa-palette"></i></div></li>';
  1028. html += '</ul>';
  1029. picker.html(html);
  1030. $('.other-color',component).click( function(){
  1031. palette.click();
  1032. });
  1033. palette.change(function(){
  1034. input.val(palette.val()).change();
  1035. picker.addClass('hidden');
  1036. });
  1037. input.change(function(){
  1038. thumb.css('backgroundColor',input.val());
  1039. });
  1040. component.click(function(e){
  1041. e.stopPropagation();
  1042. picker.removeClass('hidden');
  1043. setTimeout(function(){picker.addClass('active')},50);
  1044. });
  1045. $('.color-choice',picker).click(function(e){
  1046. e.stopPropagation();
  1047. picker.removeClass('active');
  1048. setTimeout(function(){picker.addClass('hidden')},200);
  1049. input.val($(this).attr('data-color')).change();
  1050. });
  1051. $(window).click(function() {
  1052. picker.removeClass('active');
  1053. setTimeout(function(){picker.addClass('hidden')},200);
  1054. });
  1055. });
  1056. },
  1057. date: function (options){
  1058. return this.each(function(){
  1059. var obj = $(this);
  1060. obj.on('paste', function(e){
  1061. is_valid_date(e.originalEvent.clipboardData.getData('Text')) ? obj.val("") : e.preventDefault();
  1062. });
  1063. //Jours ouvrés
  1064. var minDate = options.beginDate;
  1065. var beforeShowDay = '';
  1066. if(options.workdays){
  1067. var minDate = new Date();
  1068. var daysToAdd = [0, 0, 2, 2, 2, 2, 1];
  1069. minDate.setDate(minDate.getDate()+parseInt(options.beginDate)+daysToAdd[minDate.getDay()]);
  1070. beforeShowDay = $.datepicker.noWeekends;
  1071. }
  1072. obj.datepicker({
  1073. dateFormat: options.dateFormat,
  1074. dayNames: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
  1075. dayNamesMin: ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"],
  1076. dayNamesShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"],
  1077. monthNames: ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Décembre"],
  1078. monthNamesShort: ["Jan","Fév","Mars","Avr","Mai","Juin","Juil","Aout","Sept","Oct","Nov","Déc"],
  1079. firstDay: 1,
  1080. minDate: minDate,
  1081. beforeShowDay: beforeShowDay,
  1082. maxDate: options.endDate,
  1083. changeMonth: true,
  1084. yearRange: "-30:+30",
  1085. changeYear: true,
  1086. onSelect: function(dateText, inst){
  1087. obj.trigger("blur");
  1088. },
  1089. beforeShow: function(){
  1090. if(obj.is('[readonly]')) return false;
  1091. }
  1092. }).keypress(function(event){
  1093. if(event.keyCode==47) event.preventDefault();
  1094. var length = obj.val().length;
  1095. if(length == 2 || length == 5) obj.val(obj.val()+'/');
  1096. }).blur(function(event){
  1097. obj.removeClass('border border-danger');
  1098. if(obj.val()=='') return;
  1099. var segments = obj.val().split('/');
  1100. if(segments.length!=3) return;
  1101. if(segments[0] > 31 || segments[1] > 12) obj.addClass('border border-danger');
  1102. }).attr('maxlength','10');
  1103. obj.attr('placeholder',options.placeholder);
  1104. obj.attr('title','Format '+options.dateFormat);
  1105. });
  1106. },
  1107. hour: function (options){
  1108. return this.each(function() {
  1109. var obj = $(this);
  1110. obj.on('paste', function(e){
  1111. is_valid_hour(e.originalEvent.clipboardData.getData('Text')) ? obj.val("") : e.preventDefault();
  1112. });
  1113. obj.timepicker({
  1114. scrollDefault: 'now',
  1115. timeFormat: options.timeFormat,
  1116. step: options.step,
  1117. onSelect: function(timeText, inst) {
  1118. obj.trigger("blur");
  1119. }
  1120. }).keypress(function(e) {
  1121. if(!e.key.match(/[0-9:]/)) e.preventDefault();
  1122. if(obj.val().length == 2) obj.val(obj.val()+':');
  1123. }).blur(function(event){
  1124. obj.removeClass('border border-danger')
  1125. if(obj.val()=='') return;
  1126. var segments = obj.val().split(':');
  1127. if(segments.length!=2) return;
  1128. if(segments[0] > 23 || segments[1] > 59) obj.addClass('border border-danger');
  1129. }).attr('maxlength','5');
  1130. obj.attr("placeholder",options.placeholder);
  1131. obj.attr('title',"Format hh:mm");
  1132. });
  1133. },
  1134. raiseNumber: function(from,to) {
  1135. return this.each(function(){
  1136. var obj = $(this);
  1137. obj.text(from);
  1138. var interval = from<=to ? (800 / (to - from)) : (800 / (from - to));
  1139. var interval = setInterval(function(){
  1140. var number = parseFloat(obj.text());
  1141. if(from<=to){
  1142. if(number>=to) {
  1143. clearInterval(interval);
  1144. return;
  1145. }
  1146. obj.text(number+1);
  1147. } else {
  1148. if(number<=to) {
  1149. clearInterval(interval);
  1150. return;
  1151. }
  1152. obj.text(number-1);
  1153. }
  1154. },interval);
  1155. });
  1156. }
  1157. });