main.js 77 KB

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