main.js 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383
  1. $(document).ready(function(){
  2. if($.urlParam('title')!=null){
  3. window.parent.document.title = decodeURI($.urlParam('title'));
  4. }
  5. var page = $.page();
  6. page = page == '' ? 'index' : page;
  7. var init = 'init_'+page;
  8. init = init.replace(/[^a-z_0-9]/g,'_');
  9. init_components();
  10. if($.urlParam('module')==null){
  11. if(window[init]!=null) window[init]($.urlParam());
  12. } else {
  13. var mod = $.urlParam('module').replace(/[^a-z_0-9]/g,'_');
  14. var init = 'init_plugin_'+mod;
  15. if(window[init]!=null) window[init]($.urlParam());
  16. }
  17. //SHOW HTTP ERROR/NOTICE
  18. if ($.urlParam('error') != null) {
  19. $.message('error', decodeURIComponent($.urlParam('error')), 0);
  20. $.urlParam('error', false);
  21. }
  22. if ($.urlParam('info') != null) {
  23. $.message('info', decodeURIComponent($.urlParam('info')));
  24. $.urlParam('info', false);
  25. }
  26. if ($.urlParam('success') != null) {
  27. $.message('success', decodeURIComponent($.urlParam('success')));
  28. $.urlParam('success', false);
  29. }
  30. //Icône menu mobile
  31. $('#mainMenu > button').on('click', function(e){
  32. $('.menu').toggleClass('open');
  33. });
  34. $('.navbar-toggler').on('click', function(e){
  35. if($(e.target).closest('#mainMenu').length) return;
  36. $('#navbarCollapse').collapse('hide');
  37. $('.menu').removeClass('open');
  38. });
  39. //Positionnement nom de l'utilisateur
  40. if($(document).width() <= 767){
  41. var userFullname = $('#loginHeader > .user-dropdown-menu .user-fullname').detach();
  42. $('#loginHeader > .user-dropdown-menu > button.dropdown-toggle').append(userFullname);
  43. }
  44. });
  45. //Changement positionnement nom de l'utilisateur
  46. //connecté au redimensionnement de la fenêtre
  47. $(window).resize(function(event) {
  48. if($(document).width() > 767){
  49. var userFullname = $('#loginHeader > .user-dropdown-menu > button.dropdown-toggle > .user-fullname').detach();
  50. $('#loginHeader > .user-dropdown-menu > .dropdown-menu').prepend(userFullname);
  51. }
  52. if($(document).width() <= 767){
  53. var userFullname = $('#loginHeader > .user-dropdown-menu .user-fullname').detach();
  54. $('#loginHeader > .user-dropdown-menu > button.dropdown-toggle').append(userFullname);
  55. }
  56. });
  57. /* COMPOSANT */
  58. function init_components(selector){
  59. var selected = selector ? $('[data-type]',selector) : '[data-type]';
  60. $(selected).each(function(i,input){
  61. var input = $(input);
  62. switch($(input).attr('data-type')){
  63. case 'date':
  64. input.date();
  65. break;
  66. /**
  67. * data-step : L'intervalle entre 2 valeurs en minutes
  68. */
  69. case 'hour':
  70. input.hour();
  71. break;
  72. case 'image':
  73. if(input.closest('.type-image-bloc').length!=0) break;
  74. input.wrap( "<div class='type-image-bloc'></div>");
  75. var src = ($(input).attr('value')!='') ? $(input).attr('value') : 'img/default-image.png';
  76. src += src.indexOf('?')!=-1 ? '&' : '?';
  77. src += 't='+(Math.random()*1000);
  78. var thumbnail = $('<img src="'+src+'" >');
  79. var deleteBtn = !input.attr('data-delete') ? '' : '<div class="btn btn-delete-img noPrint" onclick="'+input.attr('data-delete')+'"><i class="fas fa-times"></i></div>';
  80. input.before(thumbnail);
  81. if(thumbnail.attr('src').indexOf('default-') === -1) thumbnail.before(deleteBtn);
  82. input.addClass('noPrint');
  83. input.change(function(){
  84. var reader = new FileReader();
  85. reader.onload = function (e) {
  86. thumbnail.attr('src', e.target.result);
  87. thumbnail.before(deleteBtn);
  88. }
  89. reader.readAsDataURL(input.get(0).files[0]);
  90. });
  91. break;
  92. //Selection de tag liés a un dictionnary
  93. case 'tag-list':
  94. var container;
  95. var picker;
  96. var pickerLi;
  97. if(!input.data("data-component")){
  98. container = $('<div class="'+input.attr('class')+' data-type-tag-list"><ul><li class="tag-picker-li"><input type="text"></li></ul></div>');
  99. input.before(container);
  100. input.data("data-component", container);
  101. if(input.attr("required")) container.attr("required","");
  102. } else {
  103. container = input.data("data-component");
  104. }
  105. picker = container.find('input:eq(0)');
  106. pickerLi = container.find('ul li.tag-picker-li');
  107. container.find('.tag-picker-tag').remove();
  108. pickerLi.show();
  109. var pickerFunctions = {
  110. //Récuperation des valeurs sélectionnées (objet et id) en fonction des tags visuels présents
  111. getValues : function( container){
  112. var tags = container.find('ul .tag-picker-tag');
  113. var values = {object:[],id:[]};
  114. tags.each(function(i,element){
  115. if($(element).attr('data-id') == '') return;
  116. var object = $(element).data();
  117. values['object'].push(object);
  118. values['id'].push(object.id);
  119. });
  120. return values;
  121. },
  122. //Ajout d'un tag visuel et mise à jour de l'input brut en fonction de l'objet fournis
  123. addTag : function( container,tag){
  124. pickerLi = container.find('ul li.tag-picker-li');
  125. if( container.find('li[data-id="'+tag.id+'"]').length>0) return;
  126. var tag = $('<li class="tag-picker-tag" data-slug="'+tag.slug+'" data-id="'+tag.id+'"><div>'+tag.name+'<i class="fa fa-times"></i></div></li>');
  127. pickerLi.before(tag);
  128. var values = pickerFunctions.getValues( container);
  129. input.val(values['id'].join(','));
  130. input.data('values',values['object']);
  131. if((values['id'].length) == 1 && input.attr('data-multiple') == null){
  132. pickerLi.hide();
  133. }else{
  134. pickerLi.show();
  135. }
  136. tag.find('i').click(function(){
  137. $(this).closest('.tag-picker-tag').remove();
  138. var values = pickerFunctions.getValues( container);
  139. input.val(values['id'].join(','));
  140. input.data('values',values['object']);
  141. if((values['id'].length-1) ==1 && input.attr('data-multiple') == null){
  142. pickerLi.hide();
  143. }else{
  144. pickerLi.show();
  145. }
  146. });
  147. }
  148. }
  149. //Gestion des champs déja remplis au chargement de la page
  150. if(input.val() !=''){
  151. var id = input.val();
  152. container.find('ul').append('<li class="tag-picker-loader"><i class="fas fa-hourglass-half fa-spin"></i> Chargement...</li>');
  153. picker.hide();
  154. $.action({
  155. action : 'tag_list_by_id',
  156. id : id
  157. },function(r){
  158. container.find('.tag-picker-loader').remove();
  159. picker.show();
  160. for(var key in r.tags)
  161. pickerFunctions.addTag( container,r.tags[key]);
  162. });
  163. }
  164. //Sélectionne l'input d'auto-completion ou que l'on clique dans le composant
  165. container.find('ul').click(function(e){
  166. picker.focus();
  167. e.stopPropagation();
  168. });
  169. //Selectionne l'item dropdown actif lors de l'appuis sur entré
  170. picker.keyup(function(e){
  171. if(e.keyCode!=13 || input.is('[readonly]')) return;
  172. var active = $('.tag-picker-li .dropdown-menu .active');
  173. if(active.length==0) return;
  174. active.trigger('click');
  175. input.val('');
  176. });
  177. //aucompletion sur le nom des tags
  178. picker.autocomplete({
  179. action : 'tag_list_autocomplete',
  180. data : {
  181. parent : input.attr('data-slug')
  182. },
  183. skin : function(item){
  184. var html = '';
  185. var re = new RegExp(picker.val(),"gi");
  186. name = item.name.replace(re, function (x) {
  187. return '<strong>'+x+'</strong>';
  188. });
  189. html += '<div class="tag-infos"><span>'+name+'</span>';
  190. html += '<div class="clear"></div>';
  191. return html;
  192. },
  193. highlight : function(item){
  194. return item;
  195. },
  196. onClick : function(selected,element){
  197. picker.val('');
  198. selected.label = selected.name;
  199. pickerFunctions.addTag(container,selected);
  200. input.trigger('click').trigger('change');
  201. },
  202. onBlur : function(selected){
  203. if(input.attr('data-force')!='false' && input.val() == '') picker.val('');
  204. }
  205. });
  206. break;
  207. case 'user':
  208. var userContainer;
  209. var userPicker;
  210. var pickerLi;
  211. if(!input.data("data-component")){
  212. userContainer = $('<div class="'+input.attr('class')+' data-type-user"><ul><li class="user-picker-li"><input type="text"></li></ul></div>');
  213. input.before(userContainer);
  214. input.data("data-component", userContainer);
  215. if(input.attr("required")) userContainer.attr("required","");
  216. } else {
  217. userContainer = input.data("data-component");
  218. }
  219. userPicker = userContainer.find('input:eq(0)');
  220. pickerLi = userContainer.find('ul li.user-picker-li');
  221. userContainer.find('.user-picker-tag').remove();
  222. pickerLi.show();
  223. var pickerFunctions = {
  224. //Récuperation des valeurs sélectionnées (objet et uid) en fonction des tags visuels présents
  225. getValues : function(userContainer){
  226. var tags = userContainer.find('ul .user-picker-tag');
  227. var values = {object:[],uid:[]};
  228. tags.each(function(i,element){
  229. if($(element).attr('data-uid') == '') return;
  230. var object = $(element).data();
  231. values['object'].push(object);
  232. values['uid'].push(object.uid);
  233. });
  234. return values;
  235. },
  236. //Ajout d'un tag visuel et mise à jour de l'input brut en fonction de l'objet user fournis
  237. addTag : function(userContainer,user){
  238. pickerLi = userContainer.find('ul li.user-picker-li');
  239. if(userContainer.find('li[data-uid="'+user.uid+'"]').length>0) return;
  240. var tag = $('<li class="user-picker-tag" data-entity="'+user.type+'" data-fullname="'+user.fullname+'" data-uid="'+user.uid+'"><div title="'+(user.type=='rank'?'Rang':'Utilisateur')+'">'+user.fullname+'<i class="fa fa-times"></i></div></li>');
  241. pickerLi.before(tag);
  242. var values = pickerFunctions.getValues(userContainer);
  243. input.val(values['uid'].join(','));
  244. input.data('values',values['object']);
  245. if((values['uid'].length) == 1 && input.attr('data-multiple') == null){
  246. pickerLi.hide();
  247. }else{
  248. pickerLi.show();
  249. }
  250. tag.find('i').click(function(){
  251. $(this).closest('.user-picker-tag').remove();
  252. var values = pickerFunctions.getValues(userContainer);
  253. input.val(values['uid'].join(','));
  254. input.data('values',values['object']);
  255. if((values['uid'].length-1) ==1 && input.attr('data-multiple') == null){
  256. pickerLi.hide();
  257. }else{
  258. pickerLi.show();
  259. }
  260. });
  261. }
  262. }
  263. //Gestion des champs déja remplis au chargement de la page
  264. if(input.val() !=''){
  265. var login = input.val();
  266. userContainer.find('ul').append('<li class="user-picker-loader"><i class="fas fa-hourglass-half fa-spin"></i> Chargement...</li>');
  267. userPicker.hide();
  268. $.action({
  269. action : 'user_by_uid',
  270. login : login
  271. },function(r){
  272. userContainer.find('.user-picker-loader').remove();
  273. userPicker.show();
  274. for(var key in r.users)
  275. pickerFunctions.addTag(userContainer,r.users[key]);
  276. });
  277. }
  278. //Sélectionne l'input d'auto-completion ou que l'on clique dans le composant
  279. userContainer.find('ul').click(function(e){
  280. userPicker.focus();
  281. e.stopPropagation();
  282. });
  283. //Selectionne l'item dropdown actif lors de l'appuis sur entré
  284. userPicker.keyup(function(e){
  285. if(e.keyCode!=13 || input.is('[readonly]')) return;
  286. var active = $('.user-picker-li .dropdown-menu .active');
  287. if(active.length==0) return;
  288. active.trigger('click');
  289. input.val('');
  290. });
  291. var types = ['user'];
  292. if(input.data('types') && input.data('types')!='')
  293. types = input.data('types').split(',');
  294. //aucompletion sur le nom des users / rangs
  295. userPicker.autocomplete({
  296. action : 'user_autocomplete',
  297. data : {
  298. types : types
  299. },
  300. skin : function(item){
  301. var html = '';
  302. var re = new RegExp(userPicker.val(),"gi");
  303. name = item.name.replace(re, function (x) {
  304. return '<strong>'+x+'</strong>';
  305. });
  306. if(item.type=='user'){
  307. if(item.avatar) html += '<div class="user-logo"><img src="'+item.avatar+'" class="avatar-mini avatar-rounded"></div>';
  308. html += '<div class="user-infos"><span>'+name+'</span> <small class="text-muted">- Utilisateur</small>';
  309. html += item.function ? '<br/><small>'+item.function+'</small></div>' : '</div>';
  310. html += '<div class="clear"></div>';
  311. }else{
  312. html += '<div class="rank-logo"><i class="far fa-address-card"></i></div>';
  313. html += '<div class="rank-infos"><span>'+name+'</span> <small class="text-muted">- Rang</small>';
  314. html += item.description ? '<br/><small>'+item.description+'</small></div>' : '</div>';
  315. html += '<div class="clear"></div>';
  316. }
  317. return html;
  318. },
  319. highlight : function(item){
  320. return item;
  321. },
  322. onClick : function(selected,element){
  323. userPicker.val('');
  324. selected.fullname = selected.name;
  325. selected.uid = selected.id;
  326. pickerFunctions.addTag(userContainer,selected);
  327. input.trigger('click').trigger('change');
  328. },
  329. onBlur : function(selected){
  330. if(input.attr('data-force')!='false' && input.val() == '') userPicker.val('');
  331. }
  332. });
  333. break;
  334. /**
  335. * data-labels : tableau des libellés entre double quotes eg : ["Libellé 1","Libellé 2"]
  336. * data-values : taleau des valeurs eg : [12,13]
  337. * data-colors : taleau des couleurs entre double quotes eg : ["#cecece","#222222"]
  338. */
  339. case 'doughnut':
  340. var data = input.data();
  341. var myChart = new Chart(input.get(0).getContext('2d'), {
  342. type: 'doughnut',
  343. data: {
  344. labels: data.labels,
  345. datasets: [{
  346. data: data.values,
  347. backgroundColor: data.colors
  348. }]
  349. },
  350. options: {
  351. cutoutPercentage:80
  352. }
  353. });
  354. break;
  355. /**
  356. * data-labels : tableau des libellés entre double quotes eg : ["Libellé1","Libellé 2"]
  357. * data-values : taleau des valeurs eg : [12,13]
  358. * data-colors : taleau des couleurs entre double quotes eg : ["#cecece","#222222"]
  359. */
  360. case 'bar':
  361. var data = input.data();
  362. var myChart = new Chart(input.get(0).getContext('2d'), {
  363. type: 'bar',
  364. data: {
  365. labels: data.labels,
  366. datasets: [{
  367. label : input.html(),
  368. data: data.values,
  369. backgroundColor: data.colors
  370. }]
  371. },
  372. options: {
  373. scales: {
  374. yAxes: [{
  375. ticks: {
  376. beginAtZero:true
  377. }
  378. }]
  379. },
  380. legend: {
  381. display: false
  382. }
  383. }
  384. });
  385. break;
  386. /**
  387. * data-labels : tableau des libellés entre double quotes eg : ["Libellé1","Libellé 2"]
  388. * data-values : taleau des valeurs eg : [12,13]
  389. * data-color : couleurs eg : #cecece
  390. */
  391. case 'line':
  392. var data = input.data();
  393. var myChart = new Chart(input.get(0).getContext('2d'), {
  394. type: 'line',
  395. data: {
  396. labels: data.labels,
  397. datasets: [{
  398. label : input.html(),
  399. data: data.values,
  400. borderColor: [data.color]
  401. }]
  402. },
  403. options: {
  404. scales: {
  405. yAxes: [{
  406. ticks: {
  407. beginAtZero:true
  408. }
  409. }]
  410. }
  411. }
  412. });
  413. break;
  414. /**
  415. * data-input-city : le champ d'id "#votre-id" à remplir avec la ville
  416. * data-input-latitude : le champ d'id "#votre-id" à remplir avec la latitude
  417. * data-input-longitude : le champ d'id "#votre-id" à remplir avec la longitude
  418. * data-input-country : le champ d'id "#votre-id" à remplir avec le pays
  419. * data-input-code : le champ d'id "#votre-id" à remplir avec le code postal
  420. * data-input-street : le champ d'id "#votre-id" à remplir avec la rue
  421. * data-input-number : le champ d'id "#votre-id" à remplir avec le n°
  422. */
  423. case 'location':
  424. input.location({
  425. select :function(location){
  426. var attributes = {};
  427. for(var key in location){
  428. attributes['data-'+key] = location[key];
  429. if(input.attr('data-input-'+key)!='') $(input.attr('data-input-'+key)).val(location[key]).text(location[key]);
  430. }
  431. input.attr(attributes);
  432. }
  433. });
  434. break;
  435. /**
  436. * data-depth : nb de profondeur de liste (ex: 2, affichera 2 select au maximum), 1 par défaut
  437. * data-slug : le slug de la liste mère à afficher, listes primaires par défaut
  438. * data-value : la valeur de l'entité à récup en base
  439. * data-disable-label : cache le label de sous-liste si mentionné
  440. * data-hierarchy : si mentionné à false, ne récupère pas
  441. * data-parent-id : l'id de la liste parente associée
  442. */
  443. case 'dictionnary':
  444. var slug = input.attr('data-slug') ? input.attr('data-slug') : "";
  445. var parentId = input.attr('data-parent-id') && input.attr('data-parent-id').length ? input.attr('data-parent-id') : "";
  446. if (!slug.match(/^[a-z\d\-_]+$/i) && parentId == '') return;
  447. $.action({
  448. action : 'load_dictionnary_component',
  449. slug: slug,
  450. parentId : parentId,
  451. hierarchy : input.attr('data-hierarchy') == 'false' ? 0 : 1,
  452. value: input.attr('data-value')
  453. },function(r){
  454. var children = r.content.childs ? r.content.childs : r.content;
  455. input.attr('onchange', 'get_sub_dictionnary(this, "'+input.attr('name')+'",'+1+');');
  456. input.append('<option value=""> - </option>');
  457. $.each(children, function (index, value){
  458. if (value.selected) {
  459. input.append('<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" selected>'+value.label+'</option>');
  460. get_selected_values(input, value);
  461. }
  462. else
  463. input.append('<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'">'+value.label+'</option>');
  464. });
  465. });
  466. break;
  467. /**
  468. * data-label : le label affiché dans la zone
  469. * data-delete : méthode de suppression de doc de l'entité
  470. * data-save : méthode de sauvegarde de doc de l'entité (si mentionné, save automatique)
  471. * data-readonly: Empeche l'ajout/suppression de documents
  472. * data-allowed : les extensions de fichier acceptées
  473. */
  474. case 'dropzone':
  475. if(input.find('form').length != 0) break;
  476. if(!input.attr('data-action')) input.attr('data-action','action.php?action=upload_temporary_file');
  477. var readonly = input.attr('data-readonly') == "true" ? true : false;
  478. var customTpl = input.find('> *:not(:visible)');
  479. var customActions = '';
  480. if(customTpl && customTpl.length){
  481. $.each(customTpl, function(i, action){
  482. if(i>2) return;
  483. var valCalc = readonly ? i*28+3 : i*28+25;
  484. customActions += $(action).removeClass('hidden').css('right', valCalc).get(0).outerHTML;
  485. });
  486. }
  487. var preview = '<li data-path="{{path}}">';
  488. preview += input.get(0).hasAttribute('data-preview') ? '<img style="margin: 0 5px;float: left;max-height:100px;max-width:80px;" src="{{url}}"/>' : '<i class="fa {{icon}}"></i>';
  489. preview += ' <a {{#url}}href="{{url}}"{{/url}} target="_blank" title="{{name}}">{{name}}{{lastModification}}</a> '+customActions+' <i class="fas fa-times pointer '+(input.attr('data-delete')?'':'hidden')+'" onclick="{{#temporary}}dropzone_delete_file(this);{{/temporary}}{{^temporary}}'+input.attr('data-delete')+'(this){{/temporary}}"></i><div class="clear"></div></li>';
  490. var valueFiles = input.html()!='' && is_json_string(input.text()) ? JSON.parse(input.text()) : [];
  491. input.html('');
  492. var allowed = input.attr('data-allowed');
  493. if(allowed) allowed = allowed.split(',');
  494. var save = input.attr('data-save');
  495. var size = input.attr('data-max-size');
  496. input.upload({
  497. allowed : allowed,
  498. size : size == '' ? 0 : size,
  499. readonly: readonly,
  500. start: function(){
  501. preload.show();
  502. },
  503. success: function(response){
  504. if(response.previews.length && response.previews[0].name) {
  505. var inputTemp = $('#'+input.attr('id')+'_temporary');
  506. var currVal = inputTemp.val().length ? JSON.parse(inputTemp.val()) : [];
  507. for(var i in response.previews){
  508. files.append(Mustache.render(preview,response.previews[i]));
  509. currVal.push(response.previews[i]);
  510. }
  511. inputTemp.val(JSON.stringify(currVal));
  512. if(save)
  513. window[save](response.previews);
  514. }
  515. preload.fadeOut();
  516. },
  517. complete: function(){
  518. preload.fadeOut();
  519. }
  520. });
  521. var preload = $('<div class="preload progress-bar progress-bar-striped progress-bar-animated"></div>');
  522. input.append(preload);
  523. var files = $('<ul></ul>');
  524. input.append(files);
  525. var filesValues = $('<input type="hidden" name="'+input.attr('id')+'_temporary" id="'+input.attr('id')+'_temporary">');
  526. input.append(filesValues);
  527. for(var i in valueFiles) {
  528. files.append(Mustache.render(preview,valueFiles[i]));
  529. if(readonly) files.find('li > i.fa-times').remove();
  530. }
  531. if(!valueFiles.length && readonly)
  532. input.append('<div>Aucun document</div>');
  533. break;
  534. /**
  535. * data-simple : Si "true" alors interface avec moins de boutons
  536. */
  537. case 'wysiwyg':
  538. var buttons = [
  539. ['strong', 'em', 'underline','del'],
  540. ['foreColor', 'backColor'],
  541. ['undo', 'redo'], // Only supported in Blink browsers
  542. ['formatting'],
  543. ['superscript', 'subscript'],
  544. ['link'],
  545. ['insertImage'],
  546. ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
  547. ['unorderedList', 'orderedList'],
  548. ['horizontalRule'],
  549. ['removeformat'],
  550. ['fullscreen'],
  551. ['viewHTML']
  552. ]
  553. if(input.attr('data-simple') == 'true'){
  554. buttons = [
  555. ['strong', 'em', 'underline','del'],
  556. ['foreColor', 'backColor'],
  557. ['undo', 'redo'], // Only supported in Blink browsers
  558. ['formatting'],
  559. ['link'],
  560. ['unorderedList', 'orderedList'],
  561. ['insertImage']
  562. ]
  563. }
  564. var defaultOptions = {
  565. btns: buttons,
  566. lang: 'fr',
  567. autogrow: true,
  568. semantic: false
  569. };
  570. var data = input.data();
  571. var options = $.extend(defaultOptions,data);
  572. input.trumbowyg(options);
  573. break;
  574. /**
  575. * data-join : Spécifie la liaison par défaut des filtres (and | or) si rien n'est spéficié ou que l'attrbute n'existe pas,
  576. * un select apparait pour que l'utilisateur puisse choisir,
  577. * data-slug : Si spécifié, la recherche devient enregistrable pour une réutilisation ultérieure,
  578. * data-only-advanced : Si l'attribut est présent, cache la recherche simple et ouvre par defaut la recherche avancée
  579. */
  580. case 'filter':
  581. if(input.next('.filter-box:visible').length!=0) break;
  582. input.hide();
  583. var data = input.data();
  584. var box = $('.filter-box:not(:visible)').clone();
  585. input.after(box);
  586. box.show();
  587. if($('option',input).length == 0)
  588. box.find('.advanced-button-search').hide();
  589. box.attr('data-join',data.join);
  590. if(data.join!='' && data.join!=null)
  591. box.find('.filter-join').addClass('hidden');
  592. var options = '<option value=""> - Choix filtre - </option>';
  593. $('option',input).each(function(i,element){
  594. options += element.outerHTML;
  595. });
  596. $('.filter-column').append(options);
  597. box.on('keyup', '.filter-value, .filter-keyword', function(event){
  598. if(event.keyCode == 13) filter_search();
  599. });
  600. if(data.onlyAdvanced!=null){
  601. $('.simple-search').hide();
  602. box.find('.advanced-search').show();
  603. }
  604. if(data.onlyAdvanced==null && $('option',input).length != 0)
  605. $('.simple-search div.btn.filter-button-search:visible').html('<i class="fas fa-search"></i>');
  606. if(data.slug && data.slug!=''){
  607. box.find('.advanced-search-save').removeClass('hidden');
  608. box.find('.advanced-search-action-separator').removeClass('hidden');
  609. $.action({
  610. action : 'filter_load',
  611. slug : data.slug,
  612. },function(response){
  613. if(response.filters.advanced && response.filters.advanced.length > 0) {
  614. box.find('.advanced-search').show();
  615. for(var i=response.filters.advanced.length-1 ; i != -1 ; i--){
  616. var filter = response.filters.advanced[i];
  617. filter_add(box.find('.filterRow:visible:eq(0)'),filter);
  618. }
  619. }
  620. box.find('.filterRow:visible:eq(0)').remove();
  621. if(data.function && (!data.hasOwnProperty('autosearch') || data.autosearch==true )) window[data.function]();
  622. });
  623. }
  624. break;
  625. /**
  626. * data-toggle-event : Pour le moment, que "hover", de base au click
  627. * data-show-strength: Si indiqué, affiche la barre de force du mot de passe renseigné dans l'input
  628. */
  629. case 'password':
  630. if(input.closest('.password-field').length) return;
  631. input.attr('type', 'password');
  632. input.wrap(function() {return '<div class="password-field"></div>';});
  633. var container = input.parent('.password-field');
  634. container.append('<i class="fas fa-eye-slash noPrint password-toggler"></i>');
  635. container.find('i.password-toggler').attr((input.attr('data-toggle-event') == 'hover')?{
  636. 'onmouseover': 'toggle_password(this);',
  637. 'onmouseleave': 'toggle_password(this);'
  638. }:{'onclick': 'toggle_password(this);'});
  639. if(input.attr('data-generator') !== undefined) {
  640. container.append('<i class="fas fa-shield-alt noPrint password-generator"></i>')
  641. container.find('i.password-generator').on('click', function(){
  642. if(input.val()!='' && !confirm('Attention, un mot de passe est déjà défini.\nVoulez-vous quand même en générer un nouveau ?')) return;
  643. var strong = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[=/\()%ยง!@#$%^&*])(?=.{10,})');
  644. do {
  645. password = generate_password();
  646. } while(!strong.test(password))
  647. input.val(password);
  648. if(input.attr('data-show-strength') !== undefined)
  649. check_password_strength(input);
  650. });
  651. function generate_password(){
  652. var password = "";
  653. var charset = get_characters_set();
  654. var length = Math.ceil(parseFloat(64) * Math.log(2) / Math.log(charset.length));
  655. for (var i=0; i<length; ++i)
  656. password += charset[get_random_int(charset.length)];
  657. return password;
  658. }
  659. }
  660. if(input.attr('data-show-strength') !== undefined) {
  661. input.parent('.password-field').append('<div class="strength-lines"><div class="line"></div><div class="line"></div><div class="line"></div></div>');
  662. // check_password_strength($('input[data-type="password"][data-show-strength]'));
  663. // Strength validation on keyup-event
  664. input.on("keyup mouseup", function(e) {
  665. check_password_strength($(this));
  666. });
  667. //Check password strength
  668. function check_password_strength(input) {
  669. var value = $(input).val();
  670. var container = $(input).closest('.password-field');
  671. $(".line", container).removeClass("strength-low strength-medium strength-hard").addClass("strength-transparent");
  672. if(!value.length) return;
  673. var strongRegex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[=/\()%ยง!@#$%^&*])(?=.{10,})'),
  674. mediumRegex = new RegExp('^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})');
  675. if(strongRegex.test(value)) {
  676. $(".line", container).removeClass("strength-transparent").addClass("strength-hard");
  677. } else if (mediumRegex.test(value)) {
  678. $(".line:not(:last-of-type)", container).removeClass("strength-transparent").addClass("strength-medium");
  679. } else {
  680. $(".line:nth-child(1)", container).removeClass("strength-transparent").addClass("strength-low");
  681. }
  682. }
  683. }
  684. break;
  685. case 'icon':
  686. input.hide();
  687. input.next('.component-icon').remove();
  688. var data = {
  689. value : input.val(),
  690. choices : []
  691. };
  692. var icons = $.fontAwesome();
  693. var line = [];
  694. for(var key in icons){
  695. if(line.length==15){
  696. data.choices.push(line);
  697. line = [];
  698. }
  699. line.push(icons[key].icon);
  700. }
  701. var selector = $(Mustache.render($('.component-icon.hide').get(0).outerHTML,data));
  702. selector.removeClass('hide');
  703. input.after(selector);
  704. selector.on('show.bs.dropdown', function () {
  705. setTimeout(function(){selector.find('input.form-control').focus();},0);
  706. })
  707. selector.find('.dropdown-icon-item').click(function(){
  708. selector.find('.dropdown-icon-item').show();
  709. selector.find('input.form-control').val('');
  710. var icon = $(this).attr('data-icon');
  711. input.val(icon);
  712. selector.find('.dropdown-toggle i').attr('class',icon);
  713. });
  714. selector.find('input.form-control').keyup(function(){
  715. var value = $(this).val();
  716. $('.dropdown-icon-item i',selector).each(function(i,iconElement){
  717. iconElement = $(iconElement);
  718. parent = iconElement.parent();
  719. iconElement.attr('class').indexOf(value)!=-1 ? parent.show() : parent.hide();
  720. });
  721. /*var icon = $(this).attr('data-icon');
  722. input.val(icon);
  723. selector.find('.dropdown-toggle i').attr('class',icon);*/
  724. });
  725. break;
  726. /**
  727. * data-title (*) : Le titre du modal
  728. * data-warning : Message affiché dans le tooltip au survol
  729. * data-loaded (*): fonction callback appelée auprès le chargement du modal (bien pour setter des actions custom sur les boutons dans le modal par exemple)
  730. * data-params : Les paramètres utilisés pour l'appel du callback
  731. * data-url (*) : L'URL vers le contenu du modal qui sera ajouté au modal préexistant dans le footer
  732. * data-precall : fonction appelée avant le chargement du modal (méthode de check sur l'UI par exemple)
  733. * Pour customiser l'icône du quickform, il suffit de placer le contenu que l'on veut dans la div de data-type="quickform"
  734. */
  735. case 'quickform':
  736. if(input.find('span').length) return;
  737. if(input.attr('disabled')) return;
  738. var qfUrl = input.attr('data-url');
  739. var cbLoaded = input.attr('data-loaded');
  740. var preCb = input.attr('data-precall') ? input.attr('data-precall') : '';
  741. var warningMsg = input.attr('data-warning') ? input.attr('data-warning') : '';
  742. if(!input.find('* > i').length){
  743. var icon = input.children('i').detach();
  744. icon = icon.length ? icon : $('<i class="fas fa-plus-square"></i>');
  745. var checker = '<span title="'+warningMsg+'">'+icon.get(0).outerHTML+'</span>';
  746. input.append(checker);
  747. }
  748. var title = input.attr('data-title');
  749. var params = input.attr('data-params') ? input.attr('data-params').split(',') : [];
  750. $(document).ready(function(e){
  751. if(warningMsg.length)
  752. $('.quickform > span').tooltip({
  753. track: true,
  754. tooltipClass: 'quickform-tooltip',
  755. });
  756. input.on('click', function(e){
  757. if(preCb.length && !window[preCb]()) return;
  758. $.ajax({
  759. type: 'GET',
  760. url: qfUrl,
  761. async: true,
  762. success : function(modal){
  763. $('#quickform-modal-label').text(title);
  764. $('.quickform-modal .modal-footer > div:first-of-type').nextAll().remove();
  765. if(cbLoaded) window[cbLoaded].apply(null,params);
  766. }
  767. }).done(function(modalBody){
  768. var modal = $('.quickform-modal');
  769. var qfBody = $('.modal-body', modal)
  770. qfBody.html('').append(modalBody);
  771. reset_quickform_modal();
  772. modal.modal('show');
  773. init_components($('#quickform-modal'));
  774. });
  775. });
  776. });
  777. break;
  778. /**
  779. * data-class : Classe custom à ajouter au conteneur du l'input
  780. */
  781. case 'checkbox':
  782. //3 cas possibles :
  783. // - input sans rien, data-type="checkbox" --> on fait tout
  784. // - input avec coquille sans data-uuid, --> on génère simplement un data-uuid et maj valeur
  785. // - input avec coquille et data-uuid --> on maj simplement sa valeur
  786. if(input.get(0).hasAttribute('data-uuid')) return;
  787. if(input.attr('type') != 'checkbox') input.attr('type', 'checkbox');
  788. if(!input.closest('label.check-component').length) {
  789. var labelBox = $('<label class="check-component"></label>');
  790. var checkbox = $('<div class="box"></div>');
  791. var id = input.attr('id');
  792. var title = input.attr('title');
  793. var customClass = input.attr('data-class');
  794. if(id) labelBox.attr('for', id);
  795. if(title) labelBox.attr('title', title);
  796. if(customClass) labelBox.addClass(customClass);
  797. input.removeAttr('title data-class').wrap(labelBox);
  798. input.after(checkbox);
  799. }
  800. var uuid = generate_uuid(15);
  801. input.attr('data-uuid', uuid);
  802. if(input.get(0).hasAttribute('id')) return;
  803. input.closest('label.check-component').find('div.box').click(function(e){
  804. $('input[data-uuid="'+uuid+'"]').prop('checked', $('input[data-uuid="'+uuid+'"]').prop('checked'));
  805. });
  806. break;
  807. /**
  808. * data-label : Libellé affiché à côté de l'input radio
  809. * name (*) : Le nom du groupe dont fait partie l'input radio
  810. */
  811. case 'radio':
  812. if(input.get(0).hasAttribute('data-uuid')) return;
  813. if(input.attr('type') != 'radio') input.attr('type', 'radio');
  814. var uuid = generate_uuid(15);
  815. var id = input.get(0).hasAttribute('id')? input.attr('id') : '';
  816. var title = input.get(0).hasAttribute('title') ? input.attr('title') : '';
  817. var label = input.attr('data-label');
  818. var labelBox = $('<label data-uid="'+uuid+'"></label>');
  819. labelBox.attr({
  820. 'for': id,
  821. 'title': title
  822. });
  823. input.addClass('radio-component').removeAttr('title data-label').attr('data-uuid', uuid);
  824. input.after(labelBox);
  825. if(label) labelBox.after('<label for="'+id+'">'+label+'</label>');
  826. if(input.attr('id') && input.attr('id').length) return;
  827. labelBox.click(function(e){ $('input[data-uuid="'+uuid+'"]').prop('checked', true); });
  828. break;
  829. /**
  830. * data-action : l'action php pour récupérer l'UI de la card
  831. * data-parameters : paramètres à passer avec l'action json encodés
  832. */
  833. case 'card':
  834. if(!input.is(':visible')) return;
  835. var action = input.attr('data-action');
  836. if(!action) {
  837. console.log('CARD COMPONENT: Need "data-action" to get card content');
  838. return;
  839. }
  840. var showDelay = input.attr('data-show-delay') ? input.attr('data-show-delay') : 0;
  841. var hideDelay = input.attr('data-hide-delay') ? input.attr('data-hide-delay') : 600;
  842. var parameters = input.attr('data-parameters');
  843. var data = parameters ? JSON.parse(parameters) : {};
  844. data.action = action;
  845. input.addClass('card-component-container');
  846. $(document).ready(function(){
  847. input.mouseenter(function(event){
  848. var e = event.toElement || event.relatedTarget;
  849. if (e.parentNode != this && e != this) return;
  850. event.stopImmediatePropagation();
  851. event.stopPropagation();
  852. $('*[data-type="card"]').find('.wrapper').addClass('card-component-hide').removeClass('card-component-hover').remove();
  853. timeout = setTimeout(function(){
  854. var curInput = input;
  855. if(!curInput.find('.card-component').length) {
  856. $.action(data, function(r){
  857. if(!r.content) return;
  858. //On utilise un wrapper pour gérer les overflows "out of the box"
  859. var wrapper = $('<div class="wrapper"></div>');
  860. wrapper.css({top: curInput.offset().top+'px'});
  861. var card = $(r.content);
  862. curInput.append(card);
  863. card.wrap(wrapper);
  864. card.addClass('card-component card-component-hover');
  865. });
  866. } else {
  867. var card = $(curInput.find('.card-component'));
  868. card.addClass('card-component-hover').removeClass('card-component-hide');
  869. }
  870. clearTimeout(curInput.data('tOutbox'));
  871. }, showDelay);
  872. });
  873. input.add(input.find('.card-component')).mouseleave(function(e){
  874. e.stopImmediatePropagation();
  875. e.stopPropagation();
  876. var input = $(this),
  877. card = input.find('.card-component'),
  878. tOutbox = setTimeout(function(){
  879. if(!$('.card-component:hover').length) {
  880. card.addClass('card-component-hide').removeClass('card-component-hover');
  881. setTimeout(function(){
  882. card.remove();
  883. }, 250);
  884. }
  885. }, hideDelay);
  886. //Clear du timeout d'apparition
  887. clearTimeout(timeout);
  888. //Set du l'id de timeout, permet de clear ce trigger si la souris revient sur l'input
  889. input.data('tOutbox', tOutbox);
  890. });
  891. });
  892. break;
  893. /**
  894. * data-dictionnary : Le slug du dictionnary à utiliser
  895. */
  896. case 'dictionnary-table':
  897. if(input.hasClass('component-dictionnary-table')) return;
  898. if(!input.attr('data-dictionnary') || !input.attr('data-dictionnary').length) return;
  899. var tpl = $('.component-dictionnary-table').get(0).outerHTML;
  900. $.action({
  901. action: 'load_dictionnary_component',
  902. slug : input.attr('data-dictionnary')
  903. },function(r){
  904. var list = $(Mustache.render(tpl,{label:'{{label}}', slug:'{{slug}}', id:'{{id}}',parent:r.content}));
  905. input.append(list);
  906. list.show();
  907. dictionnary_table_refresh(list);
  908. //Save
  909. $(input).on('click','thead .btn-success',function(){
  910. var line = $(this).closest('tr');
  911. var data = {
  912. action: 'dictionnary_table_save',
  913. label: line.find('input.list-label').val(),
  914. id: list.attr('data-id'),
  915. list: list.attr('data-dictionnary')
  916. };
  917. if(list.find('input.list-slug')) data.slug = $('input.list-slug', list).val();
  918. $.action(data, function(r){
  919. list.attr('data-id', '');
  920. line.find('input').val('');
  921. $.message('success','Enregistré');
  922. dictionnary_table_refresh(list);
  923. });
  924. });
  925. //Suppression
  926. $(input).on('click','tbody tr .btn-danger',function(){
  927. if(!confirm('Êtes-vous sûr de vouloir supprimer cet élément de liste ?')) return;
  928. var line = $(this).closest('tr');
  929. $.action({
  930. action: 'delete_dictionnary',
  931. id: line.attr('data-id')
  932. },function(r){
  933. line.remove();
  934. line.closest('.edit-field').val('');
  935. $.message('info', 'Élément de liste supprimé');
  936. });
  937. });
  938. //Édition
  939. $(input).on('click','tbody tr .btn-edit',function(){
  940. var line = $(this).closest('tr');
  941. $.action({
  942. action: 'edit_dictionnary',
  943. id: line.attr('data-id')
  944. },function(r){
  945. list.find('input.list-label').val(r.label);
  946. if(list.find('input.list-slug')) $('input.list-slug', list).val(r.slug);
  947. list.attr('data-id',r.id);
  948. });
  949. });
  950. });
  951. break;
  952. //Permet aux plugins d'ajouter leurs composants
  953. //via la fonction init_components_nomcomposant(input);
  954. default:
  955. var type = input.attr('data-type');
  956. if(window['init_components_'+type] !=null) window['init_components_'+type](input);
  957. break;
  958. }
  959. });
  960. }
  961. /* PRELOADER */
  962. function toggle_preloader_to(elemToHide, parent){
  963. if(!$('#preloader-upload-container').length) {
  964. $(elemToHide).hide();
  965. $(parent).prepend('<div id="preloader"><div id="preloader-shadow"></div><div id="preloader-box"></div></div><div id="preloader-text">Connexion en cours...</div>').fadeIn(150);
  966. $('body').css('overflow', 'hidden');
  967. } else {
  968. $('body').css('overflow', '');
  969. $('#preloader').fadeOut(300).remove();
  970. }
  971. }
  972. /** BACK TO TOP **/
  973. $('#toTheTop').click(function() {
  974. scroll_top(150);
  975. });
  976. // Affichage du bouton dès lors où l'on a scrollé
  977. $(window).on('ready scroll', function(){
  978. scrollPos = $(document).scrollTop();
  979. if (scrollPos >= 100) {
  980. $('#toTheTop').css('display','flex').animate({opacity:1}, 100);
  981. } else {
  982. $('#toTheTop').stop().animate({opacity:0}, 100);
  983. $('#toTheTop').removeAttr('style');
  984. }
  985. });
  986. //Permet de scroller en haut de page
  987. function scroll_top(time){
  988. $('html,body').animate({scrollTop:0},time);
  989. }
  990. /** CONTRÔLES DATE ET HEURE **/
  991. function is_valid_date(string){
  992. var format = /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/;
  993. return format.test(string);
  994. }
  995. function is_valid_hour(string){
  996. var format = /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/;
  997. return format.test(string);
  998. }
  999. //SHOW/HIDE PASSWORD
  1000. function toggle_password(element){
  1001. if ($(element).hasClass('fa-eye-slash')) {
  1002. $(element).removeClass('fa-eye-slash').addClass('fa-eye');
  1003. $(element).prev('input').attr('type', 'text');
  1004. } else {
  1005. $(element).removeClass('fa-eye').addClass('fa-eye-slash');
  1006. $(element).prev('input').attr('type', 'password');
  1007. }
  1008. }
  1009. /** QUICKFORM **/
  1010. function reset_quickform_modal(){
  1011. $('.modal form').attr('data-id','');
  1012. $('input, textarea', '.modal').each(function(i, v){
  1013. if($(v).attr('type') == 'checkbox')
  1014. $(v).prop('checked', false);
  1015. else
  1016. $(v).val('');
  1017. });
  1018. }
  1019. /** FILTER **/
  1020. $(document).ready(function(){
  1021. // RESET KEYWORD
  1022. $("input.filter-keyword").on('keyup',function(){
  1023. var posx = (this.offsetWidth + this.offsetLeft - 20);
  1024. var props = $(this).val()!='' ? {'left':posx,'opacity':'1'} : {'left':posx+30,'opacity':'0'}
  1025. $('#search-clear').css(props);
  1026. });
  1027. $("#search-clear").click(function(){
  1028. $(".filter-keyword").val('');
  1029. $(this).attr('style', '');
  1030. $(".filter-keyword").focus();
  1031. var searchCallback = $('#filters').attr('data-function');
  1032. if(searchCallback) window[searchCallback]();
  1033. });
  1034. });
  1035. //TOGGLE FILTERS SEARCH
  1036. function switch_advanced_filter(element){
  1037. $(element).closest('.filter-box').find('.advanced-search').slideToggle(100);
  1038. }
  1039. // SEARCH
  1040. function filter_search(box){
  1041. box = !box ? $('.filter-box:eq(0)'): box;
  1042. var component = box.prev('[data-type="filter"]');
  1043. var data = component.data();
  1044. window[data.function]();
  1045. if(data.callback) window[data.callback]();
  1046. }
  1047. function filter_clean(element){
  1048. var box = $(element).closest('.filter-box');
  1049. $('.filterRow:visible:not(:eq(0))',box).remove();
  1050. $('.filterRow:visible .filter-column',box).prop('selectedIndex',0).trigger('change');
  1051. }
  1052. function filter_save(element){
  1053. var input = $(element).closest('.filter-box').prev();
  1054. var data = input.filters();
  1055. $.action({
  1056. action : 'filter_save',
  1057. slug : input.attr('data-slug'),
  1058. filters : data
  1059. },function(response){
  1060. $.message('info',response.message);
  1061. });
  1062. }
  1063. // ADD
  1064. function filter_add(element,data){
  1065. var box = $(element).closest('.filter-box');
  1066. var line = $(element).closest('.filterRow');
  1067. var newline = line.clone();
  1068. newline.find('input').val('');
  1069. newline.find('input:eq(3)').replaceWith('<div readonly="readonly" class="form-control">Sélectionnez la colonne de tri</div>');
  1070. newline.find('.filter-values').show();
  1071. newline.find('.filter-value-block').remove();
  1072. line.after(newline);
  1073. if(box.attr('data-join') == null || box.attr('data-join') == ''){
  1074. box.find('.filter-join:not(:eq(0))').removeClass('invisible');
  1075. } else {
  1076. box.find('.filter-join:not(:eq(0))').val(box.attr('data-join'));
  1077. }
  1078. init_components(newline);
  1079. if(!data) return;
  1080. $('.filter-column',newline).val(data.column).trigger('change');
  1081. $('.filter-operator',newline).val(data.operator).trigger('change');
  1082. if(!Array.isArray(data.value)) data.value = [data.value];
  1083. //Exception pour les composant dictionnary multi niveau
  1084. $('.filter-value[data-type="dictionnary"]',newline).attr('data-value',data.value.slice(-1)[0] );
  1085. for(var i in data.value){
  1086. $('.filter-value:eq('+i+')',newline)
  1087. .val(data.value[i])
  1088. .trigger('change');
  1089. }
  1090. init_components(newline);
  1091. }
  1092. // DELETE
  1093. function filter_delete(element){
  1094. var line = $(element).closest('.filterRow');
  1095. if($('.filterRow:visible').length>1){
  1096. line.remove();
  1097. }else{
  1098. line.find('input').val('');
  1099. line.find('select').prop('selectedIndex',0);
  1100. line.find('.filter-value-block').remove();
  1101. line.find('.filter-join').addClass('invisible');
  1102. line.find('div.filter-values').show();
  1103. }
  1104. }
  1105. //SET COMPARATOR
  1106. function filter_set_comparator(element){
  1107. var selected = $('option:selected',element);
  1108. var line = $(element).closest('.filterRow');
  1109. filter_refresh_values(line);
  1110. if(selected.attr('data-values')){
  1111. if(selected.attr('data-values')==0){
  1112. $('.filter-value:eq(0)',line).remove();
  1113. }else if(selected.attr('data-values')>1){
  1114. for(var i=0;i<selected.attr('data-values')-1;i++){
  1115. var cloneValue = $('.filter-value:eq(0)',line).clone();
  1116. cloneValue.addClass('ml-1').removeClass('hasDatepicker').removeAttr('id');
  1117. $('.filter-value-block',line).append(cloneValue);
  1118. init_components(line);
  1119. }
  1120. }
  1121. }
  1122. init_components(line);
  1123. }
  1124. // SET
  1125. function filter_set_column(element){
  1126. var line = $(element).closest('.filterRow');
  1127. $('.filter-operator,.filter-value',line).remove();
  1128. filter_refresh_operator(line);
  1129. filter_refresh_values(line);
  1130. init_components(line);
  1131. }
  1132. function filter_refresh_operator(line){
  1133. var valueZone = line.find('.filter-values');
  1134. var filterColumn = line.find('.filter-column');
  1135. var operatorColumn = line.find('.filter-operator');
  1136. var option = $('option:selected',filterColumn);
  1137. var data = option.data();
  1138. // Si aucun filtre n'est selctionné, on remove les champs suivants
  1139. if(!option.val().length) {
  1140. line.find('input').val('');
  1141. line.find('select').prop('selectedIndex',0);
  1142. line.find('.filter-value-block').remove();
  1143. line.find('.filter-join').addClass('invisible');
  1144. valueZone.show();
  1145. return;
  1146. }
  1147. data.value = filterColumn.val();
  1148. //supression de lancien block operateur + valeur
  1149. line.find('.filter-value-block').remove();
  1150. //ajout du bloc operateur / valeur
  1151. var templateOperator = '<div class="filter-value-block">'+$('.filter-value-block[data-value-type="'+data.filterType+'"]:hidden .filter-operator').get(0).outerHTML.replace('data-template','data-type')+"</div>";
  1152. filterOperator = $(templateOperator);
  1153. valueZone.hide().after(filterOperator);
  1154. line.find('.filter-value-block').css('display','inline-block');
  1155. }
  1156. function filter_refresh_values(line){
  1157. var filterColumn = line.find('.filter-column');
  1158. var currOption = $('option:selected',filterColumn);
  1159. var data = currOption.data();
  1160. //data.value = filterColumn.val();
  1161. //supression de lancien block operateur + valeur
  1162. line.find('.filter-value-block .filter-value').remove();
  1163. //ajout du bloc operateur / valeur
  1164. var templateValue = $('.filter-value-block[data-value-type="'+data.filterType+'"]:hidden .filter-value').get(0).outerHTML.replace('data-template','data-type');
  1165. filterValue = $(Mustache.render(templateValue,data));
  1166. //Si le type de champ est une liste on la remplit avec le datasource
  1167. if(data.filterSource){
  1168. var source = JSON.parse(currOption.attr('data-filter-source'));
  1169. var options = '<option value=""> - </option>';
  1170. for (var k in source)
  1171. options += '<option value="'+k+'">'+source[k]+'</option>';
  1172. filterValue.append(options);
  1173. }
  1174. filterValue.removeClass('hasDatepicker').removeAttr('id');
  1175. $('.filter-operator',line).after(filterValue);
  1176. }
  1177. // INIT - INDEX
  1178. function init_index(){
  1179. }
  1180. function init_setting(parameter){
  1181. switch(parameter.section){
  1182. case 'plugin':
  1183. search_plugin(function(){
  1184. $('input.toggle').change(function(){
  1185. var input = $(this);
  1186. var button = input.closest('.activator');
  1187. var label = $('> label', button).detach();
  1188. var value = input.prop('checked');
  1189. if(!value) {
  1190. if(!confirm("Êtes-vous sûr de vouloir désactiver ce plugin ?\nCela entraînera la suppression de toutes les données associées.")) {
  1191. input.prop('checked',!value);
  1192. button.prepend(label);
  1193. return;
  1194. }
  1195. button.removeClass('btn-danger').addClass('btn-info').text('Activer').prepend(label);
  1196. } else {
  1197. button.addClass('btn-danger').removeClass('btn-info').text('Désactiver').prepend(label);
  1198. }
  1199. $.action({
  1200. action : 'change_plugin_state',
  1201. plugin : input.closest('li').attr('data-id'),
  1202. state: value ? 1 : 0
  1203. }, function(r){
  1204. }, function(r){
  1205. input.prop('checked',!value);
  1206. });
  1207. });
  1208. });
  1209. break;
  1210. case 'user':
  1211. search_user();
  1212. break;
  1213. case 'firm':
  1214. search_firm();
  1215. break;
  1216. case 'firmPlugin':
  1217. search_firm_plugin('update_checkboxes');
  1218. break;
  1219. case 'userfirmrank':
  1220. search_userfirmrank();
  1221. break;
  1222. case 'log':
  1223. search_log();
  1224. $('#logs').sortable_table({
  1225. onSort : search_log
  1226. });
  1227. break;
  1228. case 'rank':
  1229. search_rank();
  1230. break;
  1231. case 'dictionnary':
  1232. search_dictionnary();
  1233. break;
  1234. case 'right':
  1235. search_right('update_checkboxes');
  1236. break;
  1237. default:
  1238. if(parameter.section!= null){
  1239. var section = parameter.section.replace(/[^a-z_0-9]/g,'_');
  1240. var init = 'init_setting_'+section;
  1241. if(window[init]!=null) window[init]($.urlParam());
  1242. }
  1243. break;
  1244. }
  1245. }
  1246. /** RIGHT **/
  1247. function right_switch(element){
  1248. $(element).closest('tr').find('input').trigger('click');
  1249. }
  1250. /** FORM **/
  1251. function send_form(element){
  1252. var form = $(element).closest('[data-form]');
  1253. var data = $.getForm(form);
  1254. var data = {};
  1255. for(var key in form.data()){
  1256. if(key!="action" && key != "id") continue;
  1257. data[key] = form.attr('data-'+key);
  1258. }
  1259. $('input,select,textarea',form).each(function(i,element){
  1260. element = $(element);
  1261. if(element.attr('data-id')!=null && element.attr('data-id')!=""){
  1262. if(element.attr("type")=='checkbox' || element.attr("type")=='radio'){
  1263. data[element.attr('data-id')] = (element.is(':checked')?1:0);
  1264. }else{
  1265. data[element.attr('data-id')] = element.val();
  1266. }
  1267. }
  1268. });
  1269. data.action = 'send_form';
  1270. $.action(data,function(r){
  1271. });
  1272. }
  1273. /** LOG **/
  1274. // SEARCH
  1275. function search_log(callback){
  1276. $('#logs').fill({
  1277. action:'search_log',
  1278. filters : $('#filters').filters(),
  1279. sort : $('#logs').sortable_table('get')
  1280. },function(){
  1281. if(callback!=null) callback();
  1282. });
  1283. }
  1284. /** USER FIRM RANK**/
  1285. // SEARCH
  1286. function search_userfirmrank(callback){
  1287. $('#userfirmranks').fill({firm : $('#firm').val(),action:'search_userfirmrank'},function(){
  1288. if(callback!=null) callback();
  1289. });
  1290. }
  1291. // SAVE
  1292. function save_userfirmrank(){
  1293. var data = $.getForm('#userfirmrankForm');
  1294. data.id = $('#userfirmrankForm').attr('data-id');
  1295. $.action(data,function(r){
  1296. if(typeof r.success !== 'undefined'){
  1297. var messageSuccess = 'Utilisateur ajouté pour '+(r.success.length > 1 ? 'les ' : 'l\'')+'établissement'+(r.success.length > 1 ? 's : ' : ' : ')+r.success
  1298. $.message('success',messageSuccess,0);
  1299. }
  1300. $('#userfirmrankForm').attr('data-id','');
  1301. $('#userfirmrankForm input').val('');
  1302. $('#firm').val($("#firm option:first").val());
  1303. $('#rank').val($("#rank option:first").val());
  1304. search_userfirmrank();
  1305. });
  1306. }
  1307. // EDIT
  1308. function edit_userfirmrank(element){
  1309. var line = $(element).closest('tr');
  1310. $.action({
  1311. action:'edit_userfirmrank',
  1312. id:line.attr('data-id')
  1313. },function(r){
  1314. $.setForm('#userfirmrankForm',r);
  1315. $('#firm').change();
  1316. init_components($('#userfirmrankForm'));
  1317. $('#userfirmrankForm').attr('data-id',r.id);
  1318. });
  1319. }
  1320. // DELETE
  1321. function delete_userfirmrank(element){
  1322. if(!confirm('Êtes vous sûr de vouloir supprimer ce lien Établissement / Utilisateur / Rang ?')) return;
  1323. var line = $(element).closest('tr');
  1324. $.action({
  1325. action : 'delete_userfirmrank',
  1326. id : line.attr('data-id')
  1327. },function(r){
  1328. $.message('info', 'Lien Établissement / Utilisateur / Rang supprimé.')
  1329. line.remove();
  1330. });
  1331. }
  1332. /** FIRM **/
  1333. // SEARCH
  1334. function search_firm(callback){
  1335. $('#firms').fill({action:'search_firm'},function(){
  1336. if(callback!=null) callback();
  1337. });
  1338. }
  1339. // EDIT
  1340. function edit_firm(element){
  1341. var line = $(element).closest('tr');
  1342. window.location = 'firm.php?id='+line.attr('data-id');
  1343. }
  1344. // DELETE
  1345. function delete_firm(element){
  1346. if(!confirm('Êtes vous sûr de vouloir supprimer cet établissement ?')) return;
  1347. var line = $(element).closest('tr');
  1348. $.action({
  1349. action : 'delete_firm',
  1350. id : line.attr('data-id')
  1351. },function(r){
  1352. $.message('info','Établissement supprimé');
  1353. line.remove();
  1354. });
  1355. }
  1356. /** FIRM PLUGINS **/
  1357. // SEARCH
  1358. function search_right(callback){
  1359. $('#ranks').fill({
  1360. action: 'search_right',
  1361. rank: $('#rank').attr('data-rank'),
  1362. firm: $('#firm').val()
  1363. },function(r){
  1364. if(callback!=null) update_checkboxes(r);
  1365. });
  1366. }
  1367. // TOGGLE RIGHT
  1368. function toggle_right(element){
  1369. var line = $(element).closest('tr');
  1370. $.action({
  1371. action:'toggle_right',
  1372. rank:$('#rank').attr('data-rank'),
  1373. firm:$('#firm').val(),
  1374. section:line.attr('data-section'),
  1375. right:$(element).attr('data-right'),
  1376. state:$(element).prop('checked')?1:0
  1377. });
  1378. }
  1379. // SEARCH
  1380. function search_firm_plugin(callback){
  1381. $('#firmplugins').fill({
  1382. action:'search_firm_plugin',
  1383. firm:$('#firm').val()
  1384. },function(r){
  1385. if(callback!=null) update_checkboxes(r);
  1386. });
  1387. }
  1388. // ENABLE/DISABLE
  1389. function toggle_firm_plugin(element){
  1390. var line = $(element).closest('tr');
  1391. $.action({
  1392. action:'toggle_firm_plugin',
  1393. firm :$('#firm').val(),
  1394. state : $(element).prop('checked')?1:0,
  1395. plugin: line.attr('data-id')
  1396. });
  1397. }
  1398. function update_checkboxes(response){
  1399. $('input[data-result="0"]').prop('checked',false);
  1400. $('input[data-result="1"]').prop('checked',true);
  1401. $('input[data-result="2"]').prop('indeterminate',true);
  1402. }
  1403. // SUPPRESSION LOGO ÉTABLISSEMENT
  1404. function firm_logo_delete(element){
  1405. if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
  1406. var imageComposer = $(element).parent().find("input[data-type='image']");
  1407. $.action({
  1408. action: 'firm_logo_delete',
  1409. id: $('#firm').val()
  1410. }, function(r){
  1411. imageComposer.wrap('<form>').closest('form').get(0).reset();
  1412. imageComposer.unwrap();
  1413. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  1414. $(element).remove();
  1415. });
  1416. }
  1417. /** USER **/
  1418. // SEARCH
  1419. function search_user(callback){
  1420. $('#users').fill({action:'search_user'},function(){
  1421. if(callback!=null) callback();
  1422. });
  1423. }
  1424. // SAVE
  1425. function save_user(){
  1426. var data = $.getForm('#userFormAdmin');
  1427. data.id = $('#userFormAdmin').attr('data-id');
  1428. $.action(data,function(r){
  1429. $.message('success','Utilisateur enregistré');
  1430. $('#login').removeAttr('readonly');
  1431. $('#userFormAdmin input').val('');
  1432. $('#userFormAdmin').attr('data-id','');
  1433. search_user();
  1434. });
  1435. }
  1436. // EDIT
  1437. function edit_user(element){
  1438. var line = $(element).closest('tr');
  1439. $.action({
  1440. action:'edit_user',
  1441. login:line.attr('data-user')
  1442. },function(r){
  1443. $.setForm('#userFormAdmin',r);
  1444. $('#userFormAdmin').attr('data-id',r.id);
  1445. $('#login').attr('readonly', true);
  1446. init_components('#userFormAdmin');
  1447. });
  1448. }
  1449. // DELETE
  1450. function delete_user(element){
  1451. if(!confirm('Êtes vous sûr de vouloir supprimer cet utilisateur ?')) return;
  1452. var line = $(element).closest('tr');
  1453. $.action({
  1454. action : 'delete_user',
  1455. login : line.attr('data-user')
  1456. },function(r){
  1457. $.message('info','Utilisateur supprimé');
  1458. $('#userFormAdmin').attr('data-id','');
  1459. reset_inputs($('#userFormAdmin'));
  1460. $('#login').removeAttr('readonly');
  1461. line.remove();
  1462. });
  1463. }
  1464. /* ACCOUNT **/
  1465. function account_lost_password (){
  1466. $.action({
  1467. action: 'account_lost_password',
  1468. mail : $('#mail').val()
  1469. }, function(r){
  1470. $.message('success','Confirmation envoyée par e-mail');
  1471. });
  1472. }
  1473. function account_save(element){
  1474. var data = $('#user-form').toJson();
  1475. data.login= $('#login').val();
  1476. data.avatar = $('#avatar')[0].files[0];
  1477. data.action = 'account_save';
  1478. $.action(data, function(r){
  1479. $.message('success','Enregistré');
  1480. if(r.warning) $.message('warning',r.warning);
  1481. });
  1482. }
  1483. // SUPPRIME AVATAR USER
  1484. function account_avatar_delete(element){
  1485. if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
  1486. var imageComposer = $(element).parent().find("input[data-type='image']");
  1487. $.action({
  1488. action: 'account_avatar_delete',
  1489. login: $('#login').val()
  1490. }, function(r){
  1491. imageComposer.wrap('<form>').closest('form').get(0).reset();
  1492. imageComposer.unwrap();
  1493. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  1494. $(element).remove();
  1495. });
  1496. }
  1497. /** RANKS **/
  1498. // SEARCH
  1499. function search_rank(callback){
  1500. $('#ranks').fill({action:'search_rank'},function(){
  1501. if(callback!=null) callback();
  1502. });
  1503. }
  1504. // SAVE
  1505. function save_rank(){
  1506. var data = $.getForm('#rankForm');
  1507. data.id = $('#rankForm').attr('data-id');
  1508. $.action(data,function(r){
  1509. $.message('success','Rang enregistré');
  1510. $('#rankForm input').val('');
  1511. $('#rankForm').attr('data-id','');
  1512. search_rank();
  1513. });
  1514. }
  1515. // EDIT
  1516. function edit_rank(element){
  1517. var line = $(element).closest('tr');
  1518. $.action({action:'edit_rank',id:line.attr('data-id')},function(r){
  1519. $.setForm('#rankForm',r);
  1520. $('#rankForm').attr('data-id',r.id);
  1521. });
  1522. }
  1523. // DELETE
  1524. function delete_rank(element){
  1525. if(!confirm('Êtes vous sûr de vouloir supprimer ce rang ?')) return;
  1526. var line = $(element).closest('tr');
  1527. $.action({
  1528. action : 'delete_rank',
  1529. id : line.attr('data-id')
  1530. },function(r){
  1531. $.message('info','Rang supprimé');
  1532. line.remove();
  1533. });
  1534. }
  1535. /** DICTIONNARY **/
  1536. // SEARCH
  1537. function search_dictionnary(callback){
  1538. var parentValue = $('#parent').val();
  1539. parentValue != "" ? $('#prev-button').removeClass('hide') : $('#prev-button').addClass('hide');
  1540. $('#dictionnaries').fill({
  1541. action:'search_dictionnary',
  1542. parent : parentValue
  1543. },function(r){
  1544. reset_inputs($('#dictionnaryForm'), false, true);
  1545. if(callback!=null) callback();
  1546. var tpl = $('#parent').find('option[value="{{id}}"]');
  1547. if(!tpl.parent('span').length) tpl.wrap('<span>').hide();
  1548. });
  1549. }
  1550. // SAVE
  1551. function save_dictionnary(){
  1552. var data = $.getForm('#dictionnaryForm');
  1553. data.id = $('#dictionnaryForm').attr('data-id');
  1554. data.parent = $('#parent').val();
  1555. $.action(data,function(r){
  1556. $.message('success','Liste enregistrée');
  1557. $('#dictionnaryForm input').val('');
  1558. $('#dictionnaryForm').attr('data-id','');
  1559. search_dictionnary();
  1560. });
  1561. }
  1562. // EDIT
  1563. function edit_dictionnary(element){
  1564. var line = $(element).closest('tr');
  1565. $.action({
  1566. action: 'edit_dictionnary',
  1567. id: line.attr('data-id')
  1568. },function(r){
  1569. $.setForm('#dictionnaryForm',r);
  1570. $('#dictionnaryForm').attr('data-id',r.id);
  1571. });
  1572. }
  1573. // DELETE
  1574. function delete_dictionnary(element){
  1575. if(!confirm('Êtes-vous sûr de vouloir supprimer cette liste ?')) return;
  1576. var line = $(element).closest('tr');
  1577. $.action({
  1578. action: 'delete_dictionnary',
  1579. id: line.attr('data-id')
  1580. },function(r){
  1581. line.remove();
  1582. $.message('info','Liste supprimée');
  1583. });
  1584. }
  1585. // Remplissage de la liste (select) --> Dans les settings
  1586. function get_dictionnary_items(elem, elemToFill){
  1587. var parent = $(elem).closest('tr');
  1588. var id = $(parent).attr('data-id');
  1589. var parentId = $(parent).attr('data-parent');
  1590. $(elemToFill).fill({
  1591. action:'search_dictionnary',
  1592. parent : parentId.toString()
  1593. },function(){
  1594. $(elemToFill).val(id).change();
  1595. });
  1596. }
  1597. // Ajout de sous-liste --> Dans les settings
  1598. function add_sub_dictionnary(elem){
  1599. reset_inputs($('#dictionnaryForm'), false, true);
  1600. var parent = $(elem).closest('tr');
  1601. var id = $(parent).attr('data-id');
  1602. var value = parent.find(".itemLabel").text();
  1603. if ($("#parent option[value='"+id+"']").length > 0)
  1604. $('#parent').val(id).change();
  1605. else {
  1606. get_dictionnary_items(elem, "#parent");
  1607. $('code').addClass('hide');
  1608. }
  1609. $('#prev-button').removeClass('hide');
  1610. }
  1611. // Récupération éléments de la liste précédente --> Dans les settings
  1612. function previous_list_dictionnary(elem){
  1613. var selected = $('#parent > option:selected').val();
  1614. reset_inputs($('#dictionnaryForm'), false, true);
  1615. $.action({
  1616. action: 'get_parent_dictionnary',
  1617. selected: selected
  1618. }, function(r){
  1619. var data = r.rows[0];
  1620. $('#parent option[value!="{{id}}"]').remove();
  1621. if (data.parentId == "") $('#prev-button').addClass('hide');
  1622. if (data.parents[0].parent == "0") {
  1623. $('#parent').append("<option value='' selected>-</option>");
  1624. $('code').removeClass('hide');
  1625. }
  1626. $.each(data.parents, function (index, value){
  1627. if (value.id == data.parentId)
  1628. $('#parent').append("<option selected value='"+value.id+"'>"+value.label+"</option>");
  1629. else
  1630. $('#parent').append("<option value='"+value.id+"'>"+value.label+"</option>");
  1631. });
  1632. search_dictionnary();
  1633. });
  1634. }
  1635. // Récupération des sous-listes pour les champ de type "dictionnary" --> Où le module est appelé
  1636. function get_sub_dictionnary(elem, name, currentDepth){
  1637. var input = $(elem);
  1638. var selectValue = input.val();
  1639. var optSubLabel = $('option:selected', elem).attr('data-sublabel');
  1640. var depth = (input.attr('data-depth') && input.attr('data-depth') != "") ? input.attr('data-depth') : "1";
  1641. var fieldName = name == '' ? input.attr('name') : name;
  1642. currentDepth -= currentDepth != 1 ? input.nextAll('select').length : 0;
  1643. if(input.closest('span.dictionnary-container').length != 0){
  1644. var id = input.nextAll().last().attr('id');
  1645. input.attr('id', id).nextAll().remove();
  1646. }
  1647. if (selectValue.length && currentDepth < depth) {
  1648. input.removeAttr('name');
  1649. currentDepth += 1;
  1650. $.action({
  1651. action: 'search_dictionnary',
  1652. parent: selectValue
  1653. }, function(r){
  1654. var option = '';
  1655. if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
  1656. var newSelect = clone_input_dictionnary(input, selectValue, fieldName);
  1657. var currentDepth = input.closest('span.dictionnary-container').children('select').length;
  1658. if (input.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null") input.after('<label class="label-select">'+optSubLabel+'</label>');
  1659. newSelect.attr('onchange', 'get_sub_dictionnary(this, "'+fieldName+'", '+currentDepth+');');
  1660. newSelect.append('<option value=""> - </option>');
  1661. $.each(r.rows, function(index, value){
  1662. option += '<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'">'+value.label+'</option>';
  1663. });
  1664. newSelect.append(option);
  1665. });
  1666. } else if (!selectValue.length) {
  1667. input.attr('name', fieldName);
  1668. } else if (currentDepth == depth && input.attr('data-filter-type-value') && input.attr('data-filter-type-value').length) {
  1669. data = input.data();
  1670. input.closest('.filter-value-block').next('.filter-value-block[data-value-type="'+data.filterTypeValue+'"]').remove();
  1671. var template = $('.filter-value-block[data-value-type="'+data.filterTypeValue+'"]:hidden').get(0).outerHTML;
  1672. filterValue = $(Mustache.render(template,data));
  1673. filterValue.css('display','inline-block');
  1674. filterValue.find('input').removeClass('hasDatepicker').removeAttr('id');
  1675. input.closest('.filter-value-block').after(filterValue);
  1676. }
  1677. }
  1678. // Récupération des sous-listes depuis l'id du plus petit enfant --> Où le module est appelé
  1679. function get_selected_values(elem, select){
  1680. var input = $(elem);
  1681. if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
  1682. var fieldName = input.attr('name');
  1683. var currentDepth = 1+input.closest('span.dictionnary-container').children('select').length;
  1684. var optSubLabel = select.sublistlabel;
  1685. var option = '';
  1686. if (typeof select.childs !== 'undefined' && select.childs.length > 0) {
  1687. var newSelect = clone_input_dictionnary(input, select.id, fieldName);
  1688. if (newSelect.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null" && optSubLabel != undefined) input.after('<label class="label-select">'+optSubLabel+'</label>');
  1689. newSelect.append('<option value=""> - </option>');
  1690. }
  1691. $.each(select.childs, function(index, value){
  1692. var selected = '';
  1693. if (value.hasOwnProperty("selected")) {
  1694. input.removeAttr('name');
  1695. get_selected_values(newSelect, value);
  1696. selected = "selected";
  1697. }
  1698. newSelect.attr('onchange', 'get_sub_dictionnary(this,"'+fieldName+'", '+currentDepth+');');
  1699. option += '<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" '+selected+'>'+value.label+'</option>';
  1700. });
  1701. if(newSelect) newSelect.append(option);
  1702. }
  1703. // Clone du select de type "dictionnary"
  1704. function clone_input_dictionnary(input, id, name){
  1705. var newSelect = input.clone();
  1706. input.removeAttr('id').after(newSelect).after(' ');
  1707. newSelect.removeAttr("data-type").removeAttr('name').removeAttr('data-value');
  1708. // newSelect.attr('id', 'children-select-'+id).attr('name', name);
  1709. newSelect.find('option').remove();
  1710. return newSelect;
  1711. }
  1712. //Rafraîchit la table de la liste donnée
  1713. //En lien avec le composant dictionnary_table
  1714. function dictionnary_table_refresh(elem){
  1715. var id = $(elem).attr('data-dictionnary');
  1716. var table = $(elem).find('table:eq(0)');
  1717. $.action({
  1718. action: 'dictionnary_table_search',
  1719. id: id
  1720. },function(r){
  1721. table.find('tbody tr:visible').remove();
  1722. var tpl = table.find('tbody tr:hidden').get(0).outerHTML;
  1723. for(var key in r.rows){
  1724. var row = r.rows[key];
  1725. var line = $(Mustache.render(tpl,row));
  1726. line.removeClass('hidden');
  1727. table.find('tbody').append(line);
  1728. }
  1729. });
  1730. }
  1731. /** PLUGINS **/
  1732. // SEARCH
  1733. function search_plugin(callback){
  1734. $('#plugins').fill({action:'search_plugin'},function(){
  1735. if(callback!=null) callback();
  1736. });
  1737. }
  1738. // RÉCUPÉRATION PARAMÈTRE URL
  1739. var get_url_parameter = function get_url_parameter(sParam, string) {
  1740. var sPageURL = !string ? decodeURIComponent(window.location.search.substring(1)) : string;
  1741. var sURLVariables = sPageURL.split('&'),
  1742. sParameterName,
  1743. i;
  1744. for (i = 0; i < sURLVariables.length; i++) {
  1745. sParameterName = sURLVariables[i].split('=');
  1746. if (sParameterName[0] === sParam) {
  1747. return sParameterName[1] === undefined ? true : sParameterName[1];
  1748. }
  1749. }
  1750. };
  1751. // DROPZONE
  1752. function dropzone_delete_file(element){
  1753. if(!confirm('Êtes-vous sûr de vouloir supprimer cet item ?')) return;
  1754. var elem = $(element);
  1755. var line = elem.closest('li');
  1756. var container = elem.closest('div[data-type="dropzone"]');
  1757. var inputTemp = container.find('#'+container.attr('id')+'_temporary');
  1758. var values = inputTemp.val().length ? JSON.parse(inputTemp.val()) : [];
  1759. for (var i in values) {
  1760. if(values[i]['path'] == line.attr('data-path'))
  1761. values.splice(i, 1);
  1762. }
  1763. line.remove();
  1764. inputTemp.val(JSON.stringify(values));
  1765. }
  1766. /* GENERAL SETTINGS */
  1767. //Sauvegarde de la configuration générale
  1768. function general_settings_save(){
  1769. var data = $('#general-settings').getForm();
  1770. data.logo = $('#logo')[0].files[0];
  1771. data.logo_dark = $('#logo_dark')[0].files[0];
  1772. data.favicon = $('#favicon')[0].files[0];
  1773. data.password_format = $('#password-format-form').attr('data-format');
  1774. $.action(data, function(r){
  1775. $.message('success', 'Configuration enregistrée');
  1776. });
  1777. }
  1778. function general_reset_password_delay(){
  1779. if(!confirm('Êtes-vous sûr de vouloir forcer tous les utilisateurs à réinitialiser leurs mot de passe ?')) return;
  1780. $.action({
  1781. action: 'general_reset_password_delay'
  1782. }, function(r){
  1783. $.message('info', 'Action confirmée');
  1784. });
  1785. }
  1786. function password_settings_format(){
  1787. var patterns = [];
  1788. $('#password-format-form input[data-pattern]:checked').each(function(){
  1789. patterns.push($(this).attr('data-pattern'));
  1790. });
  1791. $('#password-format-form').attr('data-format',JSON.stringify(patterns));
  1792. }
  1793. //Suppression image générale application
  1794. function general_logo_delete(element){
  1795. if(!confirm('Êtes-vous sûr de vouloir supprimer l\'image ?')) return;
  1796. var imageComposer = $(element).parent().find("input[data-type='image']");
  1797. $.action({
  1798. action: 'general_logo_delete'
  1799. }, function(r){
  1800. imageComposer.wrap('<form>').closest('form').get(0).reset();
  1801. imageComposer.unwrap();
  1802. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  1803. $(element).remove();
  1804. $.message('info', 'Image supprimée');
  1805. });
  1806. }
  1807. //Suppression favicon générale application
  1808. function general_favicon_delete(element){
  1809. if(!confirm('Êtes-vous sûr de vouloir supprimer l\'image ?')) return;
  1810. var imageComposer = $(element).parent().find("input[data-type='image']");
  1811. $.action({
  1812. action: 'general_favicon_delete'
  1813. }, function(r){
  1814. imageComposer.wrap('<form>').closest('form').get(0).reset();
  1815. imageComposer.unwrap();
  1816. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  1817. $(element).remove();
  1818. $.message('info', 'Favicon supprimée');
  1819. });
  1820. }
  1821. //Active/Désactive la page de maintenance du site
  1822. function toggle_maintenance(){
  1823. var checkbox = $('#maintenance');
  1824. var state = checkbox.is(':checked') ? 'd\'activer' : 'de désactiver';
  1825. if(!confirm("Vous êtes sur le point "+state+" la page de maintenance du site.\nVoulez-vous continuer ?")){
  1826. checkbox.is(':checked') ? checkbox.removeAttr('checked').prop('checked', false) : checkbox.attr('checked', true).prop('checked', true);
  1827. return;
  1828. }
  1829. general_settings_save();
  1830. }
  1831. /* FUNCTIONS */
  1832. //Récupère la plus petite valeur d'un tableau
  1833. function getMinValue(arr) {
  1834. return arr.reduce(function (p, v) {
  1835. return ( p < v ? p : v );
  1836. });
  1837. };
  1838. //Récupère la plus grande valeur d'un tableau
  1839. function getMaxValue(arr) {
  1840. return arr.reduce(function (p, v) {
  1841. return ( p > v ? p : v );
  1842. });
  1843. };
  1844. //Check si la valeur saisie dans l'input
  1845. //est une adresse e-mail bien formatée
  1846. function is_email(email) {
  1847. var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  1848. return re.test(String(email).toLowerCase());
  1849. }
  1850. //Check si la valeur saisie dans
  1851. //l'input est une url bien formatée
  1852. function is_url(str) {
  1853. regexp = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
  1854. if (regexp.test(str))
  1855. return true;
  1856. return false;
  1857. }
  1858. //Check format n° de téléphone
  1859. function is_phone_number(number, required, label){
  1860. if (required && number == ''){
  1861. $.message('error',label+' obligatoire');
  1862. return false;
  1863. }
  1864. if (number != ''){
  1865. number = number.replace(/\s/g, '');
  1866. number = number.replace(/\./g, '');
  1867. number = number.replace(/-/g, '');
  1868. if(is_numeric(number)) {
  1869. if(/^(?:(?:\+|00)\d{2}|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(number) == false){
  1870. $.message('error',' Le format du n° de '+label.toLowerCase()+' est invalide');
  1871. return false;
  1872. }
  1873. } else {
  1874. $.message('error',' Le n° de '+label.toLowerCase()+' contient des caractères interdits');
  1875. return false;
  1876. }
  1877. }
  1878. return true;
  1879. }
  1880. //Check si la valeur de
  1881. //l'input est numérique
  1882. function is_numeric(n) {
  1883. return !isNaN(parseFloat(n)) && isFinite(n);
  1884. }
  1885. function str_price_to_decimal(str){
  1886. return str.replace(/,/g,'.').replace(/ /g,'');
  1887. }
  1888. //Comme la fonction ucfirst de PHP
  1889. function ucfirst(string) {
  1890. return string.charAt(0).toUpperCase() + string.slice(1);
  1891. }
  1892. //Permet de revenir/rester sur l'onglet courant
  1893. //au reload de page, ou au clic sur un lien particulier
  1894. if (location.hash) {
  1895. $('a[href="' + location.hash + '"]').tab('show');
  1896. }
  1897. var activeTab = localStorage.getItem('activeTab');
  1898. if (activeTab) {
  1899. $('a[href="' + activeTab + '"]').tab('show');
  1900. }
  1901. $('body').on('click', 'a[data-toggle="tab"]', function(e){
  1902. e.preventDefault();
  1903. var tab_name = this.getAttribute('href');
  1904. history.pushState ? history.pushState(null, null, tab_name) : location.hash = tab_name;
  1905. localStorage.setItem('activeTab', tab_name);
  1906. $(this).tab('show');
  1907. return false;
  1908. });
  1909. $(window).on('popstate', function () {
  1910. var anchor = location.hash || $('a[data-toggle="tab"]').first().attr('href');
  1911. $('a[data-toggle="tab"][href="' + anchor + '"]').tab('show');
  1912. });
  1913. //Check si la chaîne de caractères
  1914. //fournies est une chaîne JSON
  1915. function is_json_string(str) {
  1916. try {
  1917. JSON.parse(str);
  1918. } catch (e) {
  1919. return false;
  1920. }
  1921. return true;
  1922. }
  1923. //Sélectionne le texte de l'élément passé en paramètre
  1924. function select_text(element, event){
  1925. event.stopImmediatePropagation();
  1926. var sel, range;
  1927. var el = $(element).get(0); //get element id
  1928. if (window.getSelection && document.createRange) { //Browser compatibility
  1929. sel = window.getSelection();
  1930. if(sel.toString() == ''){ //no text selection
  1931. window.setTimeout(function(){
  1932. range = document.createRange(); //range object
  1933. range.selectNodeContents(el); //sets Range
  1934. sel.removeAllRanges(); //remove all ranges from selection
  1935. sel.addRange(range);//add Range to a Selection.
  1936. },1);
  1937. }
  1938. }else if (document.selection) { //older ie
  1939. sel = document.selection.createRange();
  1940. if(sel.text == ''){ //no text selection
  1941. range = document.body.createTextRange();//Creates TextRange object
  1942. range.moveToElementText(el);//sets Range
  1943. range.select(); //make selection.
  1944. }
  1945. }
  1946. }
  1947. //Permet de copier le contenu de l'element dans le presse-papier
  1948. function copy_to_clipboard(element) {
  1949. var element = $(element);
  1950. var temp = $('<input>');
  1951. $('body').append(temp);
  1952. temp.val(element.text()).select();
  1953. setTimeout(function(){document.execCommand('copy');},0);
  1954. temp.remove();
  1955. element.tooltip({
  1956. items: 'code',
  1957. tooltipClass: 'quickform-tooltip',
  1958. content: 'Copié dans le presse papier',
  1959. open: {effect:'fade',duration:750},
  1960. close: {effect:'fade',duration:750}
  1961. });
  1962. element.tooltip('open');
  1963. setTimeout(function(){element.tooltip('close');element.tooltip('destroy');}, 2000);
  1964. }
  1965. //Reset des inputs d'un conteneur
  1966. function reset_inputs(container, onlyVisible, domData){
  1967. var container = container ? container : $('body');
  1968. var visibility = onlyVisible ? onlyVisible : false;
  1969. var dom = domData ? domData : false;
  1970. if(dom) container.removeAttr('data-id');
  1971. var classicInputs = visibility==true ? $('input:visible, textarea:visible', container) : $('input, textarea', container);
  1972. classicInputs.each(function(i, v){
  1973. if($(v).attr('type') == 'checkbox')
  1974. $(v).prop('checked', false);
  1975. else
  1976. $(v).val('');
  1977. });
  1978. var customInputs = visibility==true ? $('*[contenteditable="true"]:visible', container) : $('*[contenteditable="true"]', container);
  1979. customInputs.each(function(j,val){
  1980. $(val).text('');
  1981. });
  1982. }
  1983. //Check si le contenu d'un input est
  1984. //selectionné (en surbrillance avec le curseur)
  1985. function is_text_selected(input) {
  1986. if (typeof input.selectionStart == "number") {
  1987. return input.selectionStart == 0 && input.selectionEnd == input.value.length;
  1988. } else if (typeof document.selection != "undefined") {
  1989. input.focus();
  1990. return document.selection.createRange().text == input.value;
  1991. }
  1992. }
  1993. //Renvoie un tableau en ayant supprimé
  1994. //toutes les valuers dupliquées
  1995. function only_uniq_values(a) {
  1996. var seen = {};
  1997. var out = [];
  1998. var len = a.length;
  1999. var j = 0;
  2000. for(var i = 0; i < len; i++) {
  2001. var item = a[i];
  2002. if(seen[item] !== 1) {
  2003. seen[item] = 1;
  2004. out[j++] = item;
  2005. }
  2006. }
  2007. return out;
  2008. }
  2009. //Contrôle éléments saisis dans input de type number.
  2010. //Autorise ou non les décimales et les nb négatifs
  2011. function input_number_control(e, decimal, relative){
  2012. var authorizedKeys = [8,9,37,39,46,54,109,110,188,190];
  2013. switch (e.keyCode) {
  2014. case 110:
  2015. case 188:
  2016. case 190:
  2017. return decimal?decimal:false;
  2018. break;
  2019. case 54:
  2020. case 109:
  2021. return relative?relative:false;
  2022. break;
  2023. default:
  2024. return (
  2025. (e.keyCode >= 48 && e.keyCode <= 57) ||
  2026. (e.keyCode >= 96 && e.keyCode <= 105) ||
  2027. ((e.keyCode == 65 || e.keyCode == 86 || e.keyCode == 67) && (e.ctrlKey === true || e.metaKey === true)) ||
  2028. (authorizedKeys.indexOf(e.keyCode) !== -1)
  2029. );
  2030. break;
  2031. }
  2032. }
  2033. //Check si l'objet est vide ou non
  2034. //Retourne true si vide, false sinon
  2035. function is_empty_obj(obj) {
  2036. for(var key in obj) {
  2037. if(obj.hasOwnProperty(key))
  2038. return false;
  2039. }
  2040. return true;
  2041. }
  2042. //Permet de retourner une propriété d'un
  2043. //objet de manière totalement aléatoire
  2044. function random_property(obj) {
  2045. var keys = Object.keys(obj)
  2046. return obj[keys[ keys.length * Math.random() << 0]];
  2047. }
  2048. function get_characters_set() {
  2049. var CHARACTER_SETS = [
  2050. ["0123456789"],
  2051. ["abcdefghijklmnopqrstuvwxyz"],
  2052. ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"],
  2053. ["!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"],
  2054. ];
  2055. // Concatène les jeux de caractères
  2056. var rawCharset = "";
  2057. CHARACTER_SETS.forEach(function(entry, i) {
  2058. rawCharset += entry[0];
  2059. });
  2060. // Parse en UTF-16, supprime les doublons, convertit en tableau de string
  2061. var charset = [];
  2062. for (var i = 0; i < rawCharset.length; ++i) {
  2063. var c = rawCharset.charCodeAt(i);
  2064. if (c<0xD800 || c>=0xE000) {//Check si character UTF-16 valide
  2065. var s = rawCharset.charAt(i);
  2066. if (charset.indexOf(s) == -1) charset.push(s);
  2067. continue;
  2068. }
  2069. if (0xD800<=c && c<0xDC00 && i+1<rawCharset.length) {
  2070. var d = rawCharset.charCodeAt(i + 1);
  2071. if (0xDC00<=d && d<0xE000) {
  2072. var s = rawCharset.substring(i, i+2);
  2073. i++;
  2074. if (charset.indexOf(s) == -1) charset.push(s);
  2075. continue;
  2076. }
  2077. }
  2078. throw "Invalid UTF-16";
  2079. }
  2080. return charset;
  2081. }
  2082. //Retourne un entier aléatoire dans la plage [0, n)
  2083. //(2 méthodes utilisées)
  2084. function get_random_int(maxRange) {
  2085. //Récup d'un entier aléatoire via le module Math
  2086. //(fallback si pas de module crypto)
  2087. var x = random_int_math(maxRange);
  2088. //Récupération d'un entier aléatoire via le moule crypto
  2089. x = (x + random_int_crypto(maxRange)) % maxRange;
  2090. return x;
  2091. }
  2092. //Retourne un entier aléatoire
  2093. //Peu sécurisé (car calculable) mais
  2094. //présent sur tous les navigateurs
  2095. function random_int_math(maxRange) {
  2096. var x = Math.floor(Math.random() * maxRange);
  2097. if (x < 0 || x >= maxRange) throw "Arithmetic exception";
  2098. return x;
  2099. }
  2100. //Retourne un entier aléatoire
  2101. //Extrêmement sécurisé, mais pas
  2102. //disponible sur tous les navigateurs
  2103. //+ d'infos ici: https://developer.mozilla.org/fr/docs/Web/API/RandomSource/getRandomValues
  2104. function random_int_crypto(maxRange) {
  2105. var cryptoObject = null
  2106. if ("crypto" in window) {
  2107. //Check si le module crypto est disponible (Chrome, Firefox, Safari)
  2108. cryptoObject = crypto;
  2109. } else if ("msCrypto" in window) {
  2110. //Check si le module crypto est disponible (Edge, IE)
  2111. cryptoObject = msCrypto;
  2112. }
  2113. //Check + récupération propriétés/fonctions nécessaires du module crypto
  2114. if ("getRandomValues" in cryptoObject && "Uint32Array" in window && typeof Uint32Array == "function") {
  2115. //Generate an unbiased sample
  2116. var x = new Uint32Array(1);
  2117. //Modification des élements du
  2118. //tableau par des nb aléatoires
  2119. do cryptoObject.getRandomValues(x);
  2120. while (x[0] - x[0] % maxRange > 4294967296 - maxRange);
  2121. return x[0] % maxRange;
  2122. } else {
  2123. return 0;
  2124. }
  2125. }
  2126. //Permet de générer un UUID de
  2127. //longueur souhaitée (ou 10 si pas de paramètre)
  2128. function generate_uuid(length){
  2129. var length = length !== undefined ? length : 10;
  2130. var mem = "0x1"+("0".repeat(length));
  2131. return Math.floor((1 + Math.random()) * mem).toString(16).substring(1);
  2132. }