main.js 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869
  1. var isProcessing;
  2. //Permet aux composant de mutualiser leurs appels
  3. var componentQueue = {};
  4. $(document).ready(function(){
  5. if(localStorage.getItem('configuration') !== null){
  6. //Le local storage a été mis à jour lors de la connexion
  7. var inactivityDelay = JSON.parse(localStorage.getItem('configuration')).inactivityDelay;
  8. //On est bien dans le cadre d'une conf de gestion de l'inactivité utilisateur
  9. if(inactivityDelay !== null){
  10. var timeout;
  11. //Durée d'affichage (en sec) du message pendant laquelle on peut éviter la déco
  12. var messageTime = 58;
  13. //Conversion en milli secondes pour $.message et settimeout
  14. var messageTimeMilliseconds = messageTime * 1000;
  15. //On s'assure de travailler avec des entiers
  16. inactivityDelay = parseInt(inactivityDelay);
  17. //Controle de valeur délai min à 60 sec
  18. inactivityDelay = inactivityDelay < 60 ? 60 : inactivityDelay;
  19. //Déclaration du compteur;
  20. var inactivityCounter;
  21. //Gestion de l'activité de l'utilisateur durant l'affichage du message toast
  22. var userActive = false;
  23. $(document).on('mousemove',function(){
  24. //L'utilisateur est actif, permet de savoir s'il a bougé durant l'affichage du message et donc de savoir si on le déco ou pas
  25. userActive = true;
  26. //Si l'utilisateur bouge pendant que le message est affiché
  27. //Alors on réinitialise l'activité du user et on efface les toasts
  28. if($('.toast.inactivity_message').is(':visible')){
  29. core_initialize_activity();
  30. clearTimeout(timeout);
  31. }
  32. //Si l'utilisateur bouge on arrete l'exécution du compteur
  33. clearInterval(inactivityCounter);
  34. //On réinitialise le compteur avec le délai d'inactivité
  35. var countdown = inactivityDelay - messageTime;
  36. //Le compteur s'exécute tant que l'utilisateur ne bouge pas
  37. inactivityCounter = setInterval(function(){
  38. //Décompte du nombre de sec restantes pour éviter la déco
  39. countdown--;
  40. //Déclenchement de l'affichage du toast informant de la déco imminente
  41. if(countdown === 0){
  42. $.message('warning','Votre session va expirer, vous allez être déconnecté.',messageTimeMilliseconds,'inactivity_message');
  43. userActive = false;
  44. //A la fin du message
  45. timeout = setTimeout(function(){
  46. //Si l'utilisateur a été actif on réinitialise son activité
  47. //Sinon on le déco
  48. if(userActive){
  49. core_initialize_activity();
  50. }else{
  51. core_logout();
  52. }
  53. },messageTimeMilliseconds);
  54. }
  55. }, 1000);
  56. }).mousemove();
  57. }
  58. }
  59. if($.urlParam('title')!=null) window.parent.document.title = decodeURI($.urlParam('title'));
  60. if($('.login-request').length) $('#login-dropdown').remove();
  61. var page = $.page();
  62. page = page == '' ? 'index' : page;
  63. var init = 'init_'+page;
  64. init = init.replace(/[^a-z_0-9]/g,'_');
  65. init_components();
  66. if($.urlParam('module')==null){
  67. if(window[init]!=null) window[init]($.urlParam());
  68. } else {
  69. var mod = $.urlParam('module').replace(/[^a-z_0-9]/g,'_');
  70. var init = 'init_plugin_'+mod;
  71. if(window[init]!=null) window[init]($.urlParam());
  72. }
  73. //SHOW HTTP ERROR/NOTICE
  74. if($.urlParam('error') != null) {
  75. $.message('error', decodeURIComponent($.urlParam('error')), 0);
  76. $.urlParam('error', false);
  77. }
  78. if($.urlParam('warning') != null) {
  79. $.message('warning', decodeURIComponent($.urlParam('warning')), 0);
  80. $.urlParam('warning', false);
  81. }
  82. if($.urlParam('info') != null) {
  83. $.message('info', decodeURIComponent($.urlParam('info')));
  84. $.urlParam('info', false);
  85. }
  86. if($.urlParam('success') != null) {
  87. $.message('success', decodeURIComponent($.urlParam('success')));
  88. $.urlParam('success', false);
  89. }
  90. //Icône menu mobile
  91. $('#mainMenu > button').on('click', function(e){
  92. $('.menu').toggleClass('open');
  93. });
  94. $('.navbar-toggler').on('click', function(e){
  95. if($(e.target).closest('#mainMenu').length) return;
  96. $('#navbarCollapse').collapse('hide');
  97. $('.menu').removeClass('open');
  98. });
  99. //Positionnement du loginHeader
  100. if($(document).width() <= 767) $('#mainMenu .navbar-brand').after($('#loginHeader').detach());
  101. });
  102. //Changement positionnement loginHeader
  103. //au redimensionnement de la fenêtre
  104. $(window).resize(function(event) {
  105. if(is_phone()) return;
  106. var width = $(document).width();
  107. var loginForm = $('#loginHeader').detach();
  108. if(width>767) $('#navbarCollapse').append(loginForm);
  109. if(width<=767) $('#mainMenu .navbar-brand').after(loginForm);
  110. });
  111. /** BACK TO TOP **/
  112. $('#scroll-top').click(function() {
  113. scroll_top(150);
  114. });
  115. // Affichage du bouton dès lors où l'on a scrollé
  116. $(window).on('scroll', function(){
  117. scrollPos = $(document).scrollTop();
  118. if (scrollPos >= 100) {
  119. $('#scroll-top').addClass('active');
  120. } else {
  121. $('#scroll-top').removeClass('active');
  122. }
  123. });
  124. //Permet de scroller en haut de page
  125. function scroll_top(time){
  126. $('html,body').animate({scrollTop:0},time);
  127. }
  128. /** CONTRÔLES DATE ET HEURE **/
  129. function is_valid_date(string){
  130. 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})$/;
  131. return format.test(string);
  132. }
  133. function is_valid_hour(string){
  134. var format = /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/;
  135. return format.test(string);
  136. }
  137. //SHOW/HIDE PASSWORD
  138. function toggle_password(element){
  139. event.stopPropagation();
  140. var element = $(element);
  141. element.prev('input').attr('type', (element.hasClass('fa-eye-slash') ? 'text' : 'password'));
  142. element.toggleClass('fa-eye fa-eye-slash');
  143. }
  144. /** QUICKFORM **/
  145. function reset_quickform_modal(){
  146. $('.modal form').attr('data-id','');
  147. $('input, textarea', '.modal').each(function(i, v){
  148. if($(v).attr('type') == 'checkbox')
  149. $(v).prop('checked', false);
  150. else
  151. $(v).val('');
  152. });
  153. }
  154. /** CORE **/
  155. //LOGIN
  156. $(document).ready(function(){
  157. $('body').on('keyup', '.login-form input', function(e){
  158. if(e.keyCode == 13){
  159. var button = $(this).closest('.login-form').find('.btn-login');
  160. core_login(button);
  161. }
  162. });
  163. });
  164. function core_login(element){
  165. if(isProcessing) return;
  166. var btn = $(element);
  167. btn.addClass('btn-preloader');
  168. var form = btn.closest('.login-form');
  169. var data = form.toJson(true);
  170. data.redirect = form.attr('data-redirect');
  171. data.url = form.attr('data-url');
  172. data.action = 'core_login';
  173. isProcessing = true;
  174. $.action(data
  175. ,function(r){
  176. isProcessing = false;
  177. if(r.inactivityDelay)
  178. localStorage.setItem('configuration',JSON.stringify({'inactivityDelay' : parseInt(r.inactivityDelay)}));
  179. if(r.redirect) window.location = r.redirect;
  180. },function(r){
  181. isProcessing = false;
  182. $('[data-password]',form).val('');
  183. }, function(r){
  184. isProcessing = false;
  185. });
  186. }
  187. function core_logout(url){
  188. $.action({
  189. action:'core_logout',
  190. url: url
  191. },function(r){
  192. localStorage.setItem('configuration',JSON.stringify({'inactivityDelay' : null}));
  193. if(r.redirect) window.location = r.redirect;
  194. });
  195. }
  196. function core_initialize_activity(){
  197. $.action({
  198. action:'initialize_activity'
  199. },function(){
  200. $('.toast.inactivity_message').remove();
  201. });
  202. }
  203. // INIT - INDEX
  204. function init_index(){
  205. $('#loginHeader #login-button').keypress(function(e){
  206. var key = e.which;
  207. if(key == 13){
  208. $('#login-button').click();
  209. return false;
  210. }
  211. });
  212. }
  213. function init_setting(parameter){
  214. switch(parameter.section){
  215. case 'plugin':
  216. core_plugin_search();
  217. $('.section-plugin').on('change', 'input.toggle', function(){
  218. var input = $(this);
  219. var button = input.closest('.activator');
  220. var label = $('> label', button).detach();
  221. var value = input.prop('checked');
  222. if(!value && !confirm("Êtes-vous sûr de vouloir désactiver ce plugin ?\nCela entraînera la suppression de toutes les données associées.")) {
  223. input.prop('checked',!value);
  224. button.prepend(label);
  225. return;
  226. }
  227. button.text((!value?'Activer':'Désactiver'))
  228. .toggleClass('text-success text-muted')
  229. .prepend(label);
  230. $.action({
  231. action : 'core_plugin_state_save',
  232. plugin : input.closest('li').attr('data-id'),
  233. state: value ? 1 : 0
  234. }, function(r){
  235. core_plugin_firm_show();
  236. }, function(r){
  237. button.text(value?'Activer':'Désactiver')
  238. .toggleClass('text-success text-muted')
  239. .prepend(label);
  240. input.prop('checked',!value);
  241. core_plugin_firm_show();
  242. });
  243. });
  244. break;
  245. case 'user':
  246. core_user_search();
  247. break;
  248. case 'firmPlugin':
  249. core_firm_plugin_search();
  250. break;
  251. case 'userfirmrank':
  252. core_userfirmrank_search();
  253. break;
  254. case 'log':
  255. $('#logs').sortable_table({
  256. onSort : search_log
  257. });
  258. break;
  259. case 'rank':
  260. core_rank_search();
  261. break;
  262. case 'dictionary':
  263. core_dictionary_search();
  264. $('#label').blur(function(){
  265. if($('#label').val() != '' && $('#slug').val() == ''){
  266. $('#slug').off('click');
  267. core_dictionary_slug_proposal($('#label'), $('#parent'));
  268. }
  269. });
  270. $('#slug').off('click');
  271. $('#slug').on('click', function(){
  272. if($('#label').val() != '' && $('#slug').val() == '')
  273. core_dictionary_slug_proposal($('#label'), $('#parent'));
  274. });
  275. break;
  276. case 'right':
  277. core_right_search();
  278. break;
  279. default:
  280. if(parameter.section!= null){
  281. var section = parameter.section.replace(/[^a-z_0-9]/g,'_');
  282. var init = 'init_setting_'+section;
  283. if(window[init]!=null) window[init]($.urlParam());
  284. }
  285. break;
  286. }
  287. }
  288. /** RIGHT **/
  289. function right_switch(element){
  290. $(element).closest('tr').find('input').trigger('click');
  291. }
  292. /** FORM **/
  293. function send_form(element){
  294. var form = $(element).closest('[data-form]');
  295. var data = $.getForm(form);
  296. var data = {};
  297. for(var key in form.data()){
  298. if(key!="action" && key != "id") continue;
  299. data[key] = form.attr('data-'+key);
  300. }
  301. $('input,select,textarea',form).each(function(i,element){
  302. element = $(element);
  303. if(element.attr('data-id')!=null && element.attr('data-id')!=""){
  304. if(element.attr("type")=='checkbox' || element.attr("type")=='radio'){
  305. data[element.attr('data-id')] = (element.is(':checked')?1:0);
  306. }else{
  307. data[element.attr('data-id')] = element.val();
  308. }
  309. }
  310. });
  311. data.action = 'send_form';
  312. $.action(data,function(r){
  313. });
  314. }
  315. /** LOG **/
  316. // SEARCH
  317. function search_log(exportMode, callback){
  318. if(isProcessing) return;
  319. var box = new FilterBox('#filters');
  320. if(exportMode) $('#export-logs-btn').addClass('btn-preloader');
  321. isProcessing = true;
  322. $('#logs').fill({
  323. action:'core_search_log',
  324. filters: box.filters(),
  325. sort: $('#logs').sortable_table('get'),
  326. export: !exportMode ? false : exportMode,
  327. },function(){
  328. isProcessing = false;
  329. if(callback!=null) callback();
  330. },function(){
  331. isProcessing = false;
  332. });
  333. }
  334. /** USER FIRM RANK**/
  335. // SEARCH
  336. function core_userfirmrank_search(callback){
  337. $('#userfirmranks').fill({
  338. firm : $('#firm').val(),
  339. action:'core_userfirmrank_search'
  340. },function(){
  341. if(callback!=null) callback();
  342. });
  343. }
  344. // SAVE
  345. function core_user_savefirmrank(element){
  346. if(isProcessing) return;
  347. var button = $(element);
  348. var data = $.getForm('#userfirmrankForm');
  349. data.id = $('#userfirmrankForm').attr('data-id');
  350. button.html('<i class="fas fa-spin fa-spinner"></i> Enregistrement en cours').addClass('disabled');
  351. isProcessing = true;
  352. $.action(data,function(r){
  353. button.html('<i class="fas fa-check"></i> Enregistrer').removeClass('disabled');
  354. if(typeof r.success !== 'undefined'){
  355. for(var i = 0; i<r.success.length; i++)
  356. $.message('success',r.success[i]);
  357. }
  358. if(typeof r.warning !== 'undefined'){
  359. for(var i = 0; i<r.warning.length; i++)
  360. $.message('warning',r.warning[i]);
  361. }
  362. $('#userfirmrankForm').attr('data-id','');
  363. $('#userfirmrankForm input').val('');
  364. init_components('#userfirmrankForm');
  365. $('#firm').val($("#firm option:first").val());
  366. $('#rank').val($("#rank option:first").val());
  367. isProcessing = false;
  368. core_userfirmrank_search();
  369. });
  370. }
  371. // EDIT
  372. function core_userfirmrank_edit(element){
  373. var form = $('#userfirmrankForm');
  374. var line = $(element).closest('tr');
  375. $.action({
  376. action:'core_userfirmrank_edit',
  377. id:line.attr('data-id')
  378. },function(r){
  379. $.setForm(form,r);
  380. $('#firm').change();
  381. init_components(form);
  382. form.attr('data-id',r.id);
  383. });
  384. }
  385. // DELETE
  386. function core_userfirmrank_delete(element){
  387. if(isProcessing) return;
  388. if(!confirm('Êtes vous sûr de vouloir supprimer ce lien Établissement / Utilisateur / Rang ?')) return;
  389. var line = $(element).closest('tr');
  390. isProcessing = true;
  391. $.action({
  392. action : 'core_userfirmrank_delete',
  393. id : line.attr('data-id')
  394. },function(r){
  395. isProcessing = false;
  396. $.message('info', 'Lien Établissement / Utilisateur / Rang supprimé.')
  397. line.remove();
  398. },function(r){
  399. isProcessing = false;
  400. });
  401. }
  402. /** FIRM **/
  403. //Récuperation d'une liste etablissement dans le tableau #firms
  404. function core_firm_search(callback,exportMode){
  405. if(isProcessing) return;
  406. var table = $('#firms');
  407. var box = new FilterBox('#core_firm-filters');
  408. if(exportMode) $('.btn-export').addClass('btn-preloader');
  409. isProcessing = true;
  410. table.fill({
  411. action:'core_firm_search',
  412. filters: box.filters(),
  413. sort: table.sortable_table('get'),
  414. export: !exportMode ? false : exportMode
  415. },function(response){
  416. isProcessing = false;
  417. if(!exportMode) $('.results-count > span').text(response.pagination.total);
  418. if(callback!=null) callback();
  419. },function(r){
  420. isProcessing = false;
  421. });
  422. }
  423. //Ajout ou modification etablissement
  424. function core_firm_save(){
  425. if(isProcessing) return;
  426. var form = $('#firm-form');
  427. var data = form.toJson();
  428. isProcessing = true;
  429. $.action(data,function(r){
  430. isProcessing = false;
  431. form.attr('data-id',r.id);
  432. $.urlParam('id',r.id);
  433. $.message('success','Enregistré');
  434. },function(r){
  435. isProcessing = false;
  436. });
  437. }
  438. //Suppression établissement
  439. function core_firm_delete(element){
  440. if(!confirm('Êtes-vous sûr de vouloir supprimer cet établissement ?') || isProcessing) return;
  441. var line = $(element).closest('.item-line');
  442. isProcessing = true;
  443. $.action({
  444. action: 'core_firm_delete',
  445. id: line.attr('data-id')
  446. },function(r){
  447. isProcessing = false;
  448. line.remove();
  449. $.message('info','Établissement supprimé');
  450. },function(r){
  451. isProcessing = false;
  452. });
  453. }
  454. /** FIRM PLUGINS **/
  455. // SEARCH
  456. function core_right_search(callback){
  457. $('#rights').fill({
  458. action: 'core_right_search',
  459. targetUid: $('#targetUid').attr('data-rank'),
  460. firm: $('#firm').val()
  461. },function(r){
  462. update_checkboxes(r);
  463. if(callback!=null) callback(r);
  464. });
  465. }
  466. // TOGGLE RIGHT
  467. function core_right_toggle(element){
  468. var line = $(element).closest('tr');
  469. $.action({
  470. action:'core_right_toggle',
  471. targetUid:$('#targetUid').attr('data-rank'),
  472. targetScope: 'rank',
  473. firm:$('#firm').val(),
  474. scope:line.attr('data-scope'),
  475. right:$(element).attr('data-right'),
  476. state:$(element).prop('checked')?1:0
  477. });
  478. }
  479. // SEARCH
  480. function core_firm_plugin_search(callback){
  481. $('#firmplugins').fill({
  482. action: 'core_firm_plugin_search',
  483. firm: $('#firm').val()
  484. },function(r){
  485. update_checkboxes(r);
  486. if(callback!=null) callback(r)
  487. });
  488. }
  489. // ENABLE/DISABLE
  490. function core_firm_plugin_save(element){
  491. var line = $(element).closest('.item');
  492. $.action({
  493. action:'core_firm_plugin_save',
  494. firm :$(element).closest('.firm-item').attr('data-id'),
  495. state : $(element).prop('checked')?1:0,
  496. plugin: line.attr('data-id')
  497. });
  498. }
  499. function update_checkboxes(response){
  500. $('input[data-result="0"]').prop('checked',false);
  501. $('input[data-result="1"]').prop('checked',true);
  502. $('input[data-result="2"]').prop('indeterminate',true);
  503. }
  504. /*
  505. // SUPPRESSION LOGO ÉTABLISSEMENT
  506. function firm_logo_delete(element){
  507. if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
  508. var imageComposer = $(element).parent().find("input[data-type='image']");
  509. $.action({
  510. action: 'firm_logo_delete',
  511. id: $('#firm').val()
  512. }, function(r){
  513. imageComposer.wrap('<form>').closest('form').get(0).reset();
  514. imageComposer.unwrap();
  515. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  516. $(element).remove();
  517. });
  518. }*/
  519. /** USER **/
  520. // SEARCH
  521. function core_user_search(callback){
  522. $('#users').fill({
  523. action: 'core_user_search'
  524. },function(){
  525. if(callback!=null) callback();
  526. });
  527. }
  528. // SAVE
  529. function core_user_save(){
  530. var form = $('#userFormAdmin');
  531. var data = $.getForm(form);
  532. data.id = form.attr('data-id');
  533. $.action(data,function(r){
  534. $.message('success','Utilisateur enregistré');
  535. $('#login').removeAttr('readonly');
  536. $('input',form).val('');
  537. form.attr('data-id','');
  538. init_components(form);
  539. core_user_search();
  540. });
  541. }
  542. // EDIT
  543. function core_user_edit(element){
  544. var line = $(element).closest('tr');
  545. $.action({
  546. action: 'core_user_edit',
  547. login: line.attr('data-user')
  548. },function(r){
  549. $.setForm('#userFormAdmin',r);
  550. $('#userFormAdmin').attr('data-id',r.id);
  551. $('#login').attr('readonly', true);
  552. $('#password2').val('');
  553. init_components('#userFormAdmin');
  554. $('html,body').animate({ scrollTop: 0}, 300);
  555. });
  556. }
  557. // DELETE
  558. function core_user_delete(element){
  559. if(!confirm('Êtes vous sûr de vouloir supprimer cet utilisateur ?')) return;
  560. var line = $(element).closest('tr');
  561. $.action({
  562. action : 'core_user_delete',
  563. login : line.attr('data-user')
  564. },function(r){
  565. $.message('info','Utilisateur supprimé');
  566. $('#userFormAdmin').attr('data-id','');
  567. reset_inputs($('#userFormAdmin'));
  568. $('#login').removeAttr('readonly');
  569. line.remove();
  570. });
  571. }
  572. /* ACCOUNT **/
  573. function core_account_lost_password(element){
  574. if(isProcessing) return;
  575. var btn = $(element);
  576. btn.addClass('btn-preloader').attr('disabled', true);
  577. isProcessing = true;
  578. $.action({
  579. action: 'core_account_lost_password',
  580. mail : $('#mail').val()
  581. }, function(r){
  582. isProcessing = false;
  583. $.message('success','Confirmation envoyée par e-mail');
  584. btn.removeAttr('disabled');
  585. }, function(r){
  586. isProcessing = false;
  587. btn.removeAttr('disabled');
  588. });
  589. }
  590. function core_account_save(element){
  591. var data = $('#user-form').toJson();
  592. data.login = $('#login').val();
  593. data.avatar = $('#avatar')[0].files[0];
  594. data.action = 'core_account_save';
  595. $.action(data, function(r){
  596. $('.password-field input').val('');
  597. $.message('success','Enregistré');
  598. if(r.warning) $.message('warning',r.warning);
  599. });
  600. }
  601. function core_account_api_save(element){
  602. var data = $('#account-api-form').toJson();
  603. data.action = 'core_account_api_save';
  604. $.action(data, function(r){
  605. $.message('success','Enregistré');
  606. });
  607. }
  608. // SUPPRIME AVATAR USER
  609. function core_account_avatar_delete(element){
  610. if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
  611. var imageComposer = $(element).parent().find("input[data-type='image']");
  612. $.action({
  613. action: 'core_account_avatar_delete',
  614. login: $('#login').val()
  615. }, function(r){
  616. imageComposer.wrap('<form>').closest('form').get(0).reset();
  617. imageComposer.unwrap();
  618. $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
  619. $(element).remove();
  620. });
  621. }
  622. /** RANKS **/
  623. // SEARCH
  624. function core_rank_search(callback){
  625. $('#ranks').fill({
  626. action: 'core_rank_search'
  627. },function(){
  628. if(callback!=null) callback();
  629. });
  630. }
  631. // SAVE
  632. function core_rank_save(){
  633. var data = $.getForm('#rankForm');
  634. data.id = $('#rankForm').attr('data-id');
  635. $.action(data,function(r){
  636. $.message('success','Rang enregistré');
  637. $('#rankForm input').val('');
  638. $('#rankForm').attr('data-id','');
  639. core_rank_search();
  640. });
  641. }
  642. // EDIT
  643. function core_rank_edit(element){
  644. var line = $(element).closest('tr');
  645. $.action({action:'core_rank_edit',id:line.attr('data-id')},function(r){
  646. $.setForm('#rankForm',r);
  647. $('#rankForm').attr('data-id',r.id);
  648. });
  649. }
  650. // DELETE
  651. function core_rank_delete(element){
  652. if(!confirm('Êtes vous sûr de vouloir supprimer ce rang ?')) return;
  653. var line = $(element).closest('tr');
  654. $.action({
  655. action : 'core_rank_delete',
  656. id : line.attr('data-id')
  657. },function(r){
  658. $.message('info','Rang supprimé');
  659. line.remove();
  660. });
  661. }
  662. /** DICTIONNARY **/
  663. // SEARCH
  664. function core_dictionary_search(callback){
  665. var parentValue = $('#parent').val();
  666. parentValue != "" ? $('#prev-button').removeClass('hidden') : $('#prev-button').addClass('hidden');
  667. $('#dictionnaries').fill({
  668. action:'core_dictionary_search',
  669. parent : parentValue
  670. },function(r){
  671. reset_inputs($('#dictionaryForm'), false, true);
  672. if(callback!=null) callback();
  673. var tpl = $('#parent').find('option[value="{{id}}"]');
  674. if(!tpl.parent('span').length) tpl.wrap('<span>').addClass('hidden');
  675. });
  676. }
  677. // SAVE
  678. function core_dictionary_save(){
  679. var data = $.getForm('#dictionaryForm');
  680. data.id = $('#dictionaryForm').attr('data-id');
  681. data.parent = $('#parent').val();
  682. $.action(data,function(r){
  683. $.message('success','Liste enregistrée');
  684. $('#dictionaryForm input').val('');
  685. $('#dictionaryForm').attr('data-id','');
  686. core_dictionary_search();
  687. });
  688. }
  689. // EDIT
  690. function core_dictionary_edit(element){
  691. var line = $(element).closest('tr');
  692. $.action({
  693. action: 'core_dictionary_edit',
  694. id: line.attr('data-id')
  695. },function(r){
  696. $.setForm('#dictionaryForm',r);
  697. $('#dictionaryForm').attr('data-id',r.id);
  698. });
  699. }
  700. // DELETE
  701. function core_dictionary_delete(element){
  702. if(!confirm('Êtes-vous sûr de vouloir supprimer cette liste ?')) return;
  703. var line = $(element).closest('tr');
  704. $.action({
  705. action: 'core_dictionary_delete',
  706. id: line.attr('data-id')
  707. },function(r){
  708. line.remove();
  709. $.message('info','Liste supprimée');
  710. });
  711. }
  712. // Remplissage de la liste (select) --> Dans les settings
  713. function get_dictionary_items(elem, elemToFill){
  714. var parent = $(elem).closest('tr');
  715. var id = $(parent).attr('data-id');
  716. var parentId = $(parent).attr('data-parent');
  717. $(elemToFill).fill({
  718. action:'core_dictionary_search',
  719. parent : parentId.toString()
  720. },function(){
  721. $(elemToFill).val(id).change();
  722. });
  723. }
  724. // Ajout de sous-liste --> Dans les settings
  725. function add_sub_dictionary(elem){
  726. reset_inputs($('#dictionaryForm'), false, true);
  727. var parent = $(elem).closest('tr');
  728. var id = $(parent).attr('data-id');
  729. var value = parent.find(".itemLabel").text();
  730. if ($("#parent option[value='"+id+"']").length > 0)
  731. $('#parent').val(id).change();
  732. else {
  733. get_dictionary_items(elem, "#parent");
  734. $('code').addClass('hidden');
  735. }
  736. $('#prev-button').removeClass('hidden');
  737. }
  738. // Récupération éléments de la liste précédente --> Dans les settings
  739. function previous_list_dictionary(elem){
  740. var selected = $('#parent > option:selected').val();
  741. reset_inputs($('#dictionaryForm'), false, true);
  742. $.action({
  743. action: 'core_dictionary_get_parent',
  744. selected: selected
  745. }, function(r){
  746. var data = r.rows[0];
  747. $('#parent option[value!="{{id}}"]').remove();
  748. if (data.parentId == "") $('#prev-button').addClass('hidden');
  749. if (data.parents[0].parent == "0") {
  750. $('#parent').append("<option value='' selected>-</option>");
  751. $('code').removeClass('hidden');
  752. }
  753. $.each(data.parents, function (index, value){
  754. if (value.id == data.parentId)
  755. $('#parent').append("<option selected value='"+value.id+"'>"+value.label+"</option>");
  756. else
  757. $('#parent').append("<option value='"+value.id+"'>"+value.label+"</option>");
  758. });
  759. core_dictionary_search();
  760. });
  761. }
  762. // Récupération des sous-listes pour les champ de type "dictionary" --> Où le module est appelé
  763. function get_sub_dictionary(elem, name, currentDepth){
  764. var input = $(elem);
  765. var data = input.data();
  766. data.output = data.output ? data.output : 'id';
  767. var selectValue = input.val();
  768. var optSubLabel = $('option:selected', elem).attr('data-sublabel');
  769. var depth = (input.attr('data-depth') && input.attr('data-depth') != "") ? input.attr('data-depth') : "1";
  770. var fieldName = name == '' ? input.attr('name') : name;
  771. currentDepth -= currentDepth != 1 ? input.nextAll('select').length : 0;
  772. if(input.closest('span.dictionary-container').length != 0){
  773. var id = input.nextAll().last().attr('id');
  774. input.attr('id', id).nextAll().remove();
  775. }
  776. if (selectValue.length && currentDepth < depth) {
  777. input.removeAttr('name');
  778. currentDepth += 1;
  779. $.action({
  780. action: 'core_dictionary_search',
  781. parent: selectValue
  782. }, function(r){
  783. var option = '';
  784. if(input.closest('span.dictionary-container').length == 0) input.wrap('<span class="dictionary-container"></span>');
  785. var newSelect = clone_input_dictionary(input, selectValue, fieldName);
  786. var currentDepth = input.closest('span.dictionary-container').children('select').length;
  787. if (input.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null") input.after('<label class="label-select">'+optSubLabel+'</label>');
  788. newSelect.attr('onchange', 'get_sub_dictionary(this, "'+fieldName+'", '+currentDepth+');');
  789. newSelect.append('<option value=""> - </option>');
  790. $.each(r.rows, function(index, value){
  791. option += '<option value="'+value[data.output]+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'">'+value.label+'</option>';
  792. });
  793. newSelect.append(option);
  794. });
  795. } else if (!selectValue.length) {
  796. input.attr('name', fieldName);
  797. }
  798. }
  799. // Récupération des sous-listes depuis l'id du plus petit enfant --> Où le module est appelé
  800. function get_selected_values(elem, select){
  801. var input = $(elem);
  802. var data = input.data();
  803. data.output = data.output ? data.output : 'id';
  804. if(input.closest('span.dictionary-container').length == 0) input.wrap('<span class="dictionary-container"></span>');
  805. var fieldName = input.attr('name');
  806. var currentDepth = 1+input.closest('span.dictionary-container').children('select').length;
  807. var optSubLabel = select.sublistlabel;
  808. var option = '';
  809. if ( select.childs && select.childs.length > 0) {
  810. var newSelect = clone_input_dictionary(input, select.id, fieldName);
  811. if (newSelect.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null" && optSubLabel != undefined) input.after('<label class="label-select">'+optSubLabel+'</label>');
  812. newSelect.append('<option value=""> - </option>');
  813. }
  814. $.each(select.childs, function(index, value){
  815. var selected = '';
  816. if (value.hasOwnProperty("selected")) {
  817. input.removeAttr('name');
  818. get_selected_values(newSelect, value);
  819. selected = "selected";
  820. }
  821. newSelect.attr('onchange', 'get_sub_dictionary(this,"'+fieldName+'", '+currentDepth+');');
  822. option += '<option value="'+value[data.output]+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" '+selected+'>'+value.label+'</option>';
  823. });
  824. if(newSelect) newSelect.append(option);
  825. }
  826. // Clone du select de type "dictionary"
  827. function clone_input_dictionary(input, id, name){
  828. var newSelect = input.clone();
  829. input.removeAttr('id').after(newSelect).after(' ');
  830. newSelect.removeAttr("data-type").removeAttr('name').removeAttr('data-value');
  831. // newSelect.attr('id', 'children-select-'+id).attr('name', name);
  832. newSelect.find('option').remove();
  833. return newSelect;
  834. }
  835. //Rafraîchit la table de la liste donnée
  836. //En lien avec le composant dictionary_table
  837. function dictionary_table_refresh(elem){
  838. var id = $(elem).attr('data-dictionary');
  839. var table = $(elem).find('table:eq(0)');
  840. $.action({
  841. action: 'core_dictionary_table_search',
  842. id: id
  843. },function(r){
  844. table.find('tbody tr:visible').remove();
  845. var tpl = table.find('tbody tr:hidden').get(0).outerHTML;
  846. for(var key in r.rows){
  847. var row = r.rows[key];
  848. var line = $(Mustache.render(tpl,row));
  849. line.removeClass('hidden');
  850. table.find('tbody').append(line);
  851. }
  852. });
  853. }
  854. function core_dictionary_slug_proposal(element, parent){
  855. var line = $(element).closest('tr');
  856. $.action({
  857. action : 'core_dictionary_slug_proposal',
  858. id : line.attr('data-id'),
  859. label : $(element).val(),
  860. parent : $(parent).val()
  861. },function(response){
  862. $('#slug').val(response.slug);
  863. });
  864. }
  865. /** PLUGINS **/
  866. // SEARCH
  867. function core_plugin_search(callback){
  868. var list = $('#plugins');
  869. list.fill({
  870. action:'core_plugin_search'
  871. },function(){
  872. init_tooltips(list);
  873. core_plugin_firm_show();
  874. $('.firm-toggle').each(function(i,element){
  875. $(element).prop('checked',$(element).attr('data-value')=='1');
  876. });
  877. if(callback!=null) callback();
  878. });
  879. }
  880. function core_plugin_firm_show(){
  881. $('#plugins .item').each(function(i,element){
  882. $('.plugin-firm-block',element).toggleClass('hidden',!$('input.toggle',element).prop('checked'));
  883. });
  884. }
  885. // RÉCUPÉRATION PARAMÈTRE URL
  886. var get_url_parameter = function get_url_parameter(sParam, string) {
  887. var sPageURL = !string ? decodeURIComponent(window.location.search.substring(1)) : string;
  888. var sURLVariables = sPageURL.split('&'),
  889. sParameterName,
  890. i;
  891. for (i = 0; i < sURLVariables.length; i++) {
  892. sParameterName = sURLVariables[i].split('=');
  893. if (sParameterName[0] === sParam) {
  894. return sParameterName[1] === undefined ? true : sParameterName[1];
  895. }
  896. }
  897. };
  898. // DROPZONE
  899. function dropzone_delete_file(element){
  900. if(!confirm('Êtes-vous sûr de vouloir supprimer ce fichier ?')) return;
  901. var elem = $(element);
  902. var line = elem.closest('li');
  903. var container = elem.closest('div[data-type="dropzone"]');
  904. var inputTemp = container.find('#'+container.attr('id')+'_temporary');
  905. var values = inputTemp.val().length ? JSON.parse(inputTemp.val()) : [];
  906. for (var i in values) {
  907. if(values[i]['path'] == line.attr('data-path'))
  908. values.splice(i, 1);
  909. }
  910. line.remove();
  911. inputTemp.val(JSON.stringify(values));
  912. }
  913. /* GENERAL SETTINGS */
  914. //Sauvegarde de la configuration générale
  915. function core_general_settings_save(){
  916. var data = $('#general-settings').toJson();
  917. data.password_format = $('#password-format-form').attr('data-format');
  918. $.action(data, function(r){
  919. $.message('success', 'Configuration enregistrée');
  920. });
  921. }
  922. function core_general_password_reset_delay(){
  923. if(!confirm('Êtes-vous sûr de vouloir forcer tous les utilisateurs à réinitialiser leurs mot de passe ?')) return;
  924. $.action({
  925. action: 'core_general_password_reset_delay'
  926. }, function(r){
  927. $.message('success', 'Validé');
  928. });
  929. }
  930. function password_settings_format(){
  931. var patterns = [];
  932. $('#password-format-form input[data-pattern]:checked').each(function(){
  933. patterns.push($(this).attr('data-pattern'));
  934. });
  935. $('#password-format-form').attr('data-format',JSON.stringify(patterns));
  936. }
  937. //Active/Désactive la page de maintenance du site
  938. function toggle_maintenance(){
  939. var checkbox = $('#maintenance');
  940. var state = checkbox.is(':checked') ? 'd\'activer' : 'de désactiver';
  941. if(!confirm("Vous êtes sur le point "+state+" la page de maintenance du site.\nVoulez-vous continuer ?")){
  942. checkbox.is(':checked') ? checkbox.removeAttr('checked').prop('checked', false) : checkbox.attr('checked', true).prop('checked', true);
  943. return;
  944. }
  945. core_general_settings_save();
  946. }
  947. /* FUNCTIONS */
  948. //Récupère la plus petite valeur d'un tableau
  949. function getMinValue(arr) {
  950. return arr.reduce(function (p, v) {
  951. return ( p < v ? p : v );
  952. });
  953. };
  954. //Récupère la plus grande valeur d'un tableau
  955. function getMaxValue(arr) {
  956. return arr.reduce(function (p, v) {
  957. return ( p > v ? p : v );
  958. });
  959. };
  960. //Check si la valeur saisie dans l'input
  961. //est une adresse e-mail bien formatée
  962. function is_email(email) {
  963. 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,}))$/;
  964. return re.test(String(email).toLowerCase());
  965. }
  966. //Check si la valeur saisie dans
  967. //l'input est une url bien formatée
  968. function is_url(str) {
  969. 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*)?$/;
  970. if (regexp.test(str))
  971. return true;
  972. return false;
  973. }
  974. //Check format n° de téléphone
  975. function is_phone_number(number, required, label){
  976. if (required && number == ''){
  977. $.message('error',label+' obligatoire');
  978. return false;
  979. }
  980. if (number != ''){
  981. number = number.replace(/\s/g, '');
  982. number = number.replace(/\./g, '');
  983. number = number.replace(/-/g, '');
  984. if(is_numeric(number)) {
  985. if(/^(?:(?:\+|00)\d{2}|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(number) == false){
  986. $.message('error',' Le format du n° de '+label.toLowerCase()+' est invalide');
  987. return false;
  988. }
  989. } else {
  990. $.message('error',' Le n° de '+label.toLowerCase()+' contient des caractères interdits');
  991. return false;
  992. }
  993. }
  994. return true;
  995. }
  996. //Check si la valeur de l'input est numérique
  997. function is_numeric(n) {
  998. return !isNaN(parseFloat(n)) && isFinite(n);
  999. }
  1000. //Detecte le pourcentage de luminosité d'une couleur au format rgb(r,g,b) ou hexa (#ffffff)
  1001. function color_light(color) {
  1002. //format rgb : rgb(255,255,255)
  1003. if(color.indexOf('rgb') !== -1){
  1004. regex = /([0-9]*)[\s|\t]*,[\s|\t]*([0-9]*)[\s|\t]*,[\s|\t]*([0-9]*)[\s|\t]*/gm;
  1005. var m = regex.exec(color);
  1006. if(!m || m.length<4) return 100;
  1007. var r = m[1];
  1008. var g = m[2];
  1009. var b = m[3];
  1010. //format hexa : #ffffff
  1011. }else{
  1012. var c = color.substring(1);
  1013. var rgb = parseInt(c, 16);
  1014. var r = (rgb >> 16) & 0xff;
  1015. var g = (rgb >> 8) & 0xff;
  1016. var b = (rgb >> 0) & 0xff;
  1017. }
  1018. var light = 0.2126 * r + 0.7152 * g + 0.0722 * b;
  1019. return Math.round(light * 100 / 255);
  1020. }
  1021. function number_with_space(number) {
  1022. return number.toLocaleString('fr-FR');
  1023. }
  1024. function str_price_to_decimal(str){
  1025. return str.replace(/,/g,'.').replace(/ /g,'');
  1026. }
  1027. //Comme la fonction ucfirst de PHP
  1028. function ucfirst(string) {
  1029. return string.charAt(0).toUpperCase() + string.slice(1);
  1030. }
  1031. //Permet de revenir/rester sur l'onglet courant
  1032. //au reload de page, ou au clic sur un lien particulier
  1033. if (location.hash) $('a[href="' + location.hash + '"]').tab('show');
  1034. var activeTab = localStorage.getItem('activeTab');
  1035. if (activeTab && $('a[href="' + activeTab + '"]').lenght) $('a[href="' + activeTab + '"]').tab('show');
  1036. $('body').on('click', 'a[data-toggle="tab"]', function(e){
  1037. e.preventDefault();
  1038. var tab_name = this.getAttribute('href');
  1039. history.pushState ? history.pushState(null, null, tab_name) : location.hash = tab_name;
  1040. localStorage.setItem('activeTab', tab_name);
  1041. $(this).tab('show');
  1042. return false;
  1043. });
  1044. $(window).on('popstate', function () {
  1045. var anchor = location.hash || $('a[data-toggle="tab"]').first().attr('href');
  1046. $('a[data-toggle="tab"][href="' + anchor + '"]').tab('show');
  1047. });
  1048. //Check si la chaîne de caractères
  1049. //fournies est une chaîne JSON
  1050. function is_json_string(str) {
  1051. try {
  1052. JSON.parse(str);
  1053. } catch (e) {
  1054. return false;
  1055. }
  1056. return true;
  1057. }
  1058. //Sélectionne le texte de l'élément passé en paramètre
  1059. function select_text(element, event){
  1060. event.stopImmediatePropagation();
  1061. var sel, range;
  1062. var el = $(element).get(0); //get element id
  1063. if(window.getSelection && document.createRange) { //Browser compatibility
  1064. sel = window.getSelection();
  1065. if(sel.toString() == ''){ //no text selection
  1066. window.setTimeout(function(){
  1067. range = document.createRange(); //range object
  1068. range.selectNodeContents(el); //sets Range
  1069. sel.removeAllRanges(); //remove all ranges from selection
  1070. sel.addRange(range); //add Range to a Selection.
  1071. },1);
  1072. }
  1073. } else if (document.selection) { //older ie
  1074. sel = document.selection.createRange();
  1075. if(sel.text == ''){ //no text selection
  1076. range = document.body.createTextRange(); //Creates TextRange object
  1077. range.moveToElementText(el); //sets Range
  1078. range.select(); //make selection.
  1079. }
  1080. }
  1081. }
  1082. //Récupère le contenu du texte sélectionné / highlighté
  1083. function get_selected_text(element) {
  1084. var elem = element.get(0);
  1085. if(elem.tagName === "TEXTAREA" || (elem.tagName === "INPUT" && elem.type === "text"))
  1086. return elem.value.substring(elem.selectionStart, elem.selectionEnd);
  1087. return null;
  1088. }
  1089. //Permet de copier le contenu de l'element dans le presse-papier
  1090. function copy_string(string,element) {
  1091. var temparea = document.createElement('textarea');
  1092. temparea.value = string;
  1093. temparea.setAttribute('readonly', '');
  1094. temparea.style = {position: 'absolute', left: '-9999px'};
  1095. document.body.appendChild(temparea);
  1096. temparea.select();
  1097. document.execCommand('copy');
  1098. document.body.removeChild(temparea);
  1099. if(element){
  1100. element = $(element);
  1101. if(element.data('ui-tooltip')) return;
  1102. element.tooltip({
  1103. items: '*',
  1104. tooltipClass: 'quickform-tooltip',
  1105. content: 'Copié dans le presse papier',
  1106. open: {effect:'fade',duration:750},
  1107. close: {effect:'fade',duration:750}
  1108. });
  1109. element.tooltip('open');
  1110. setTimeout(function(){element.tooltip('close');element.tooltip('destroy');}, 2000);
  1111. }
  1112. }
  1113. //Reset des inputs d'un conteneur
  1114. function reset_inputs(container, onlyVisible, domData){
  1115. var container = container ? container : $('body');
  1116. var visibility = onlyVisible ? onlyVisible : false;
  1117. var dom = domData ? domData : false;
  1118. if(dom) container.removeAttr('data-id');
  1119. var classicInputs = visibility==true ? $('input:visible, textarea:visible, select:visible', container) : $('input, textarea, select', container);
  1120. classicInputs.each(function(i, v){
  1121. if($(v).attr('type') == 'checkbox')
  1122. $(v).prop('checked', false);
  1123. else
  1124. $(v).val('');
  1125. });
  1126. var customInputs = visibility==true ? $('*[contenteditable="true"]:visible', container) : $('*[contenteditable="true"]', container);
  1127. customInputs.each(function(j,val){
  1128. $(val).text('');
  1129. });
  1130. }
  1131. //Check si le contenu d'un input est
  1132. //selectionné (en surbrillance avec le curseur)
  1133. function is_text_selected(input) {
  1134. if (typeof input.selectionStart == "number") {
  1135. return input.selectionStart == 0 && input.selectionEnd == input.value.length;
  1136. } else if (typeof document.selection != "undefined") {
  1137. input.focus();
  1138. return document.selection.createRange().text == input.value;
  1139. }
  1140. }
  1141. //Renvoie un tableau en ayant supprimé
  1142. //toutes les valeurs dupliquées
  1143. function only_uniq_values(a) {
  1144. var seen = {};
  1145. var out = [];
  1146. var len = a.length;
  1147. var j = 0;
  1148. for(var i = 0; i < len; i++) {
  1149. var item = a[i];
  1150. if(seen[item] !== 1) {
  1151. seen[item] = 1;
  1152. out[j++] = item;
  1153. }
  1154. }
  1155. return out;
  1156. }
  1157. //Contrôle éléments saisis dans input de type number.
  1158. //Autorise ou non les décimales et les nb négatifs
  1159. function input_number_control(e, decimal, relative){
  1160. var authorizedKeys = [
  1161. "Backspace", "Delete", "Tab",
  1162. "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown",
  1163. "-", ".", ",",
  1164. "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
  1165. ];
  1166. switch (e.key) {
  1167. case ".":
  1168. case ',':
  1169. return decimal?decimal:false;
  1170. break;
  1171. case '-':
  1172. return relative?relative:false;
  1173. break;
  1174. default:
  1175. return (
  1176. ((e.key=="a" || e.key=="c" || e.key=="v" || e.key=="z" || e.key=="x") && (e.ctrlKey===true || e.metaKey===true)) ||
  1177. (authorizedKeys.indexOf(e.key) !== -1)
  1178. );
  1179. break;
  1180. }
  1181. }
  1182. //Permet de checker si la saisie est en majuscule ou non
  1183. //Fonction utilisable uniquement dans function callback de listener d'event
  1184. function is_caps(){
  1185. e = window.event;
  1186. return is_phone() ? true : (e.shiftKey !== true && e.metaKey !== true) ? (e.getModifierState("CapsLock") ? true : false) : (e.getModifierState("CapsLock") ? false : true);
  1187. }
  1188. //Check si l'objet est vide ou non
  1189. //Retourne true si vide, false sinon
  1190. function is_empty_obj(obj) {
  1191. for(var key in obj)
  1192. if(obj.hasOwnProperty(key)) return false;
  1193. return true;
  1194. }
  1195. //Permet de retourner une propriété d'un
  1196. //objet de manière totalement aléatoire
  1197. function random_property(obj) {
  1198. var keys = Object.keys(obj)
  1199. return obj[keys[ keys.length * Math.random() << 0]];
  1200. }
  1201. function get_characters_set() {
  1202. var CHARACTER_SETS = [
  1203. ["0123456789"],
  1204. ["abcdefghijklmnopqrstuvwxyz"],
  1205. ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"],
  1206. ["!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"],
  1207. ];
  1208. // Concatène les jeux de caractères
  1209. var rawCharset = "";
  1210. CHARACTER_SETS.forEach(function(entry, i) {
  1211. rawCharset += entry[0];
  1212. });
  1213. // Parse en UTF-16, supprime les doublons, convertit en tableau de string
  1214. var charset = [];
  1215. for (var i = 0; i < rawCharset.length; ++i) {
  1216. var c = rawCharset.charCodeAt(i);
  1217. //Check si character UTF-16 valide
  1218. if (c<0xD800 || c>=0xE000) {
  1219. var s = rawCharset.charAt(i);
  1220. if (charset.indexOf(s) == -1) charset.push(s);
  1221. continue;
  1222. }
  1223. if (0xD800<=c && c<0xDC00 && i+1<rawCharset.length) {
  1224. var d = rawCharset.charCodeAt(i + 1);
  1225. if (0xDC00<=d && d<0xE000) {
  1226. var s = rawCharset.substring(i, i+2);
  1227. i++;
  1228. if (charset.indexOf(s) == -1) charset.push(s);
  1229. continue;
  1230. }
  1231. }
  1232. throw "Invalid UTF-16";
  1233. }
  1234. return charset;
  1235. }
  1236. //Retourne un entier aléatoire dans la plage [0, n)
  1237. //(2 méthodes utilisées)
  1238. function get_random_int(maxRange) {
  1239. //Récup d'un entier aléatoire via le module Math
  1240. //(fallback si pas de module crypto)
  1241. var x = random_int_math(maxRange);
  1242. //Récupération d'un entier aléatoire via le module crypto
  1243. x = (x + random_int_crypto(maxRange)) % maxRange;
  1244. return x;
  1245. }
  1246. //Retourne un entier aléatoire
  1247. //Peu sécurisé (car calculable) mais
  1248. //présent sur tous les navigateurs
  1249. function random_int_math(maxRange) {
  1250. var x = Math.floor(Math.random() * maxRange);
  1251. if (x < 0 || x >= maxRange) throw "Arithmetic exception";
  1252. return x;
  1253. }
  1254. //Retourne un entier aléatoire
  1255. //Extrêmement sécurisé, mais pas
  1256. //disponible sur tous les navigateurs
  1257. //+ d'infos ici: https://developer.mozilla.org/fr/docs/Web/API/RandomSource/getRandomValues
  1258. function random_int_crypto(maxRange) {
  1259. var cryptoObject = null
  1260. if ("crypto" in window) {
  1261. //Check si le module crypto est disponible (Chrome, Firefox, Safari)
  1262. cryptoObject = crypto;
  1263. } else if ("msCrypto" in window) {
  1264. //Check si le module crypto est disponible (Edge, IE)
  1265. cryptoObject = msCrypto;
  1266. }
  1267. //Check + récupération propriétés/fonctions nécessaires du module crypto
  1268. if ("getRandomValues" in cryptoObject && "Uint32Array" in window && typeof Uint32Array == "function") {
  1269. //Génère un échantillon impartial/aléatoire
  1270. var x = new Uint32Array(1);
  1271. //Modification des élements du
  1272. //tableau par des nb aléatoires
  1273. do cryptoObject.getRandomValues(x);
  1274. while (x[0] - x[0] % maxRange > 4294967296 - maxRange);
  1275. return x[0] % maxRange;
  1276. } else {
  1277. return 0;
  1278. }
  1279. }
  1280. //Permet de générer un UUID de
  1281. //longueur souhaitée (ou 10 si pas de paramètre)
  1282. function generate_uuid(length){
  1283. var length = length !== undefined ? length : 10;
  1284. //Fallback repeat sur string
  1285. //pour les anciens navigateurs
  1286. if(!String.prototype.repeat){
  1287. String.prototype.repeat = function(length){
  1288. var length = parseInt(length);
  1289. if (length < 1) return '';
  1290. var result = '',
  1291. pattern = this.valueOf();
  1292. while (length > 1) {
  1293. if(length & 1) result += pattern;
  1294. length >>= 1, pattern += pattern;
  1295. }
  1296. return result + pattern;
  1297. };
  1298. }
  1299. var mem = "0x1"+("0".repeat(length));
  1300. return Math.floor((1 + Math.random()) * mem).toString(16).substring(1);
  1301. }
  1302. function readable_size(bytes) {
  1303. var thresh = 1000;
  1304. if(Math.abs(bytes) < thresh) {
  1305. return bytes + ' B';
  1306. }
  1307. var units = ['ko','Mo','Go','To','Po','Eo','Zo','Yo'];
  1308. var u = -1;
  1309. do {
  1310. bytes /= thresh;
  1311. ++u;
  1312. } while(Math.abs(bytes) >= thresh && u < units.length - 1);
  1313. return bytes.toFixed(1)+' '+units[u];
  1314. }
  1315. /**
  1316. * Permet de faire cligner l'onglet
  1317. * navigateur avec un message custom
  1318. * @param {string} message => le message à afficher
  1319. * @param {int} interval => l'intervalle entre 2 clignotement en ms
  1320. * @param {int} repetitions => le nombre de clignotements
  1321. */
  1322. function blink_tab(message, interval, repetitions) {
  1323. interval = interval != undefined && !isNaN(interval) ? interval : 750;
  1324. repetitions = parseInt(repetitions)*2;
  1325. if(isNaN(repetitions)) repetitions = 10;
  1326. if(repetitions%2!==0) repetitions += 1
  1327. var original = document.title,
  1328. timeoutId,
  1329. blink = function() {
  1330. document.title = document.title == message ? original : message;
  1331. if(--repetitions > 0) timeoutId = setTimeout(blink, interval);
  1332. },
  1333. clear = function() {
  1334. clearTimeout(timeoutId);
  1335. document.title = original;
  1336. window.onmousemove = null;
  1337. timeoutId = null;
  1338. };
  1339. if(!timeoutId) {
  1340. timeoutId = setTimeout(blink, interval);
  1341. window.onmousemove = clear;
  1342. }
  1343. }
  1344. //Échappe les caractères spéciaux utilisés dans les regexps
  1345. function escape_regex_chars(text){
  1346. //return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
  1347. return text.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
  1348. }
  1349. //Détecte si le navigateur est un mobile ou non
  1350. function is_phone(){
  1351. var navigatorName = navigator.userAgent||navigator.vendor||window.opera;
  1352. if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(navigatorName)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigatorName.substr(0,4)))
  1353. return true;
  1354. return false;
  1355. }
  1356. //Retourne le nom complet d'un jour en fonction de son numéro (1: Lundi,..., 7: Dimanche)
  1357. function day_name($day){
  1358. $days = ['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche'];
  1359. //Pour gérer le cas du dimanche car Date().getDay() pour un dimanche retourne 0.
  1360. $day = $day==0 ? 7 : $day;
  1361. return $days[$day-1]!=null ? $days[$day-1] : $day;
  1362. }
  1363. //Retourne le nom complet d'un mois en fonction de son numéro
  1364. function month_name($month){
  1365. $months = ['Janvier','Fevrier','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Décembre'];
  1366. return $months[$month]!=null ? $months[$month] : $month;
  1367. }
  1368. //Supprime la valeur ciblée d'un tableau
  1369. function remove_array_value(array, item){
  1370. var index = array.indexOf(item);
  1371. if(index !== -1) array.splice(index, 1);
  1372. }
  1373. //Gestion des lignes de table en striped avec rowspan
  1374. function manage_striped_rowspan(table){
  1375. var i = 0;
  1376. var cols = table.find("tbody tr:not(.hidden):first").children().length;
  1377. if($("tbody tr:not(.hidden):first", table).find("[colspan]").attr("colspan")!=null)
  1378. cols += (parseInt($("tbody tr:not(.hidden):first").find("[colspan]").attr("colspan"))-1);
  1379. $("tbody tr:not(.hidden)",table).each(function(){
  1380. var tr = $(this);
  1381. var child = tr.children().length;
  1382. if(tr.find("[colspan]").attr("colspan")!=null)
  1383. child += (parseInt(tr.find("[colspan]").attr("colspan"))-1);
  1384. if(child>(cols-1)){
  1385. if(i%2==0) tr.addClass("striped-row");
  1386. i++;
  1387. } else {
  1388. tr.addClass(tr.prev().attr("class"));
  1389. }
  1390. });
  1391. }
  1392. /** PERMISSION **/
  1393. //Récuperation d'une liste de permission dans le tableau #permissions
  1394. function core_right_search(callback){
  1395. var data = {
  1396. action:'core_right_search',
  1397. firm:$('#permission-firm').val(),
  1398. };
  1399. var modal = $('#permission-modal');
  1400. modal.attr('data-firm',data.firm)
  1401. data.uid = modal.attr('data-uid');
  1402. data.scope = modal.attr('data-scope');
  1403. $('#permissions tbody tr:visible').remove();
  1404. $('#permissions').fill(data,function(response){
  1405. if(callback!=null) callback();
  1406. });
  1407. }
  1408. //Ajout ou modification d'élément permission
  1409. function core_right_edit(data){
  1410. var options = $.extend({
  1411. read : true,
  1412. edit : true,
  1413. delete : true,
  1414. configure : true,
  1415. recursive : true
  1416. },data);
  1417. var modal = $('#permission-modal');
  1418. modal.find('.col-recursive,.col-configure,.col-read,.col-edit,.col-delete').addClass('hidden');
  1419. if(options.firm === null){
  1420. $('.permission-firm-block').removeClass('hidden');
  1421. }else{
  1422. $('#permission-firm').val(options.firm);
  1423. $('.permission-firm-block').addClass('hidden');
  1424. }
  1425. if(options.recursive) modal.find('.col-recursive').removeClass('hidden');
  1426. if(options.configure) modal.find('.col-configure').removeClass('hidden');
  1427. if(options.read) modal.find('.col-read').removeClass('hidden');
  1428. if(options.edit) modal.find('.col-edit').removeClass('hidden');
  1429. if(options.delete) modal.find('.col-delete').removeClass('hidden');
  1430. modal.attr('data-save',options.saveAction);
  1431. modal.attr('data-delete',options.deleteAction);
  1432. modal.attr('data-scope',data.scope).attr('data-uid',data.uid);
  1433. var myFirm = $('#loginHeader').attr('data-firm');
  1434. if(options.firm!==null) myFirm = options.firm;
  1435. $.action({
  1436. action: 'core_firm_search',
  1437. export : false
  1438. },function(response){
  1439. var html = '<option value="">Tous</option>';
  1440. for(var k in response.rows){
  1441. var firm = response.rows[k];
  1442. html+='<option '+(myFirm == firm.id ? "selected='selected'":"")+' value="'+firm.id+'">'+firm.label+'</option>';
  1443. }
  1444. $('#permission-firm').html(html);
  1445. modal.modal('show');
  1446. $('#permission-firm',modal).val();
  1447. modal.unbind('shown.bs.modal').on('shown.bs.modal', function () {
  1448. core_right_search();
  1449. });
  1450. });
  1451. }
  1452. //Ajout ou modification d'élément permission
  1453. function core_right_save(){
  1454. var modal = $('#permission-modal');
  1455. var data = $('#permission-form').toJson();
  1456. data.action = modal.attr('data-save');
  1457. data.uid = modal.attr('data-uid');
  1458. data.scope = modal.attr('data-scope');
  1459. data.firm = $('#permission-firm').val();
  1460. var target = $('#target').data('values');
  1461. if(target && target.length>0){
  1462. target = target[0];
  1463. data.targetScope = target.entity;
  1464. data.targetUid = target.uid;
  1465. }
  1466. $.action(data,function(r){
  1467. core_right_search();
  1468. $('#permission-form').clear();
  1469. init_components(modal);
  1470. });
  1471. }
  1472. //Suppression d'élement permission
  1473. function core_right_delete(element){
  1474. if(!confirm('Êtes-vous sûr de vouloir supprimer cet item ?')) return;
  1475. var line = $(element).closest('tr');
  1476. var modal = $('#permission-modal');
  1477. $.action({
  1478. action: modal.attr('data-delete'),
  1479. id: line.attr('data-id')
  1480. },function(r){
  1481. line.remove();
  1482. $.message('info','Item supprimé');
  1483. });
  1484. }
  1485. // History
  1486. function core_history_search(callback){
  1487. var panel = $('.history-panel');
  1488. $('.comments-loader', panel).removeClass('hidden');
  1489. $('.comments', panel).fill({
  1490. action: 'core_history_search',
  1491. keyword: $('.comment-keyword').val(),
  1492. uid: panel.attr('data-uid'),
  1493. scope: panel.attr('data-scope'),
  1494. },function(){
  1495. $('.comments-loader', panel).addClass('hidden');
  1496. $('.comment[data-importance="important"] .history-importance input', panel).prop('checked',true);
  1497. init_tooltips();
  1498. if(callback!=null) callback();
  1499. });
  1500. }
  1501. function history_add(element,data){
  1502. var tpl = $('.comments >li:eq(0)').get(0).outerHTML;
  1503. if(!data){
  1504. var now = new Date();
  1505. data = {
  1506. type : {icon: 'far fa-comments', color:'#6ab04c', slug: 'comment'},
  1507. created : {fullname: day_name(now.getDay())+' '+now.getDate()+' '+month_name(now.getMonth())+' '+now.getFullYear(), time: now.getHours()+':'+now.getMinutes()},
  1508. creator : {fullname: 'Vous'},
  1509. sort : ''
  1510. };
  1511. }
  1512. var comment = $(Mustache.render(tpl,data)).removeClass('hidden');
  1513. if(element){
  1514. var commentAfter = $(element).closest('.comment');
  1515. var sort = commentAfter.attr('data-sort') && !isNaN(commentAfter.attr('data-sort')) ? parseFloat(commentAfter.attr('data-sort')) : 0 ;
  1516. comment.attr('data-replace-sort',sort);
  1517. }else{
  1518. var commentAfter = $('.history-panel .comments >li:eq(0)');
  1519. }
  1520. commentAfter.after(comment);
  1521. history_edit(comment);
  1522. }
  1523. function history_edit(element){
  1524. var comment = $(element);
  1525. if(comment.attr('data-edition-mode') == "true" || comment.attr('data-type')!='comment' ) return;
  1526. comment.attr('data-edition-mode','true');
  1527. var commentElement = $('.history-content', comment);
  1528. var content = commentElement.html();
  1529. var textarea = $('<textarea data-simple="true" class="w-100" data-buttons="strong,em,underline,del,unorderedList,orderedList" data-type="wysiwyg" data-mention-user="user">'+content+'</textarea>');
  1530. commentElement.html(textarea);
  1531. init_components(commentElement);
  1532. $('.trumbowyg-editor',commentElement).focus();
  1533. }
  1534. function core_history_save(element){
  1535. var comment = $(element);
  1536. var commentElement = $('.history-content', comment);
  1537. comment.removeAttr('data-edition-mode');
  1538. var message = comment.find('textarea').val();
  1539. message = message == '' ? 'Aucun commentaire' : message;
  1540. commentElement.html(message);
  1541. var panel = $('.history-panel');
  1542. var parameters = window.location.href.match(/[\\?&]([^&#]*)=([^&#]*)/g);
  1543. var urlParameters = {};
  1544. for (var key in parameters) {
  1545. var couple = parameters[key].substring(1, parameters[key].length).split('=');
  1546. urlParameters[couple[0]] = couple[1];
  1547. }
  1548. var replaceSort = isNaN(comment.attr('data-replace-sort')) ? null : parseInt(comment.attr('data-replace-sort'));
  1549. var importanceElement = comment.find('.history-importance input')
  1550. var importance = importanceElement.prop('checked') ? 'important' : 'normal';
  1551. $.action({
  1552. action: 'core_history_save',
  1553. id: comment.attr('data-id'),
  1554. sort: comment.attr('data-sort'),
  1555. replaceSort:replaceSort,
  1556. scope : panel.attr('data-scope'),
  1557. uid: panel.attr('data-uid'),
  1558. comment : message,
  1559. importance : importance,
  1560. meta:urlParameters
  1561. },function(r){
  1562. if(replaceSort){
  1563. $('.history-panel .comment:visible').each(function(){
  1564. var element = $(this);
  1565. if(isNaN(element.attr('data-sort'))) return ;
  1566. var sort = parseInt(element.attr('data-sort'));
  1567. if(sort<replaceSort) return;
  1568. element.attr('data-sort',sort+1);
  1569. });
  1570. }
  1571. comment.attr('data-sort',r.sort);
  1572. comment.attr('data-id',r.id);
  1573. importanceElement.attr('data-importance', importance);
  1574. });
  1575. }
  1576. function core_history_importance_save(element){
  1577. var importance = $(element).prop('checked') ? 'important' : 'normal';
  1578. var comment = $(element).closest('.comment');
  1579. var id = $(element).closest('.history-panel').attr('data-uid');
  1580. $.action({
  1581. action: 'core_history_importance_save',
  1582. id: comment.attr('data-id'),
  1583. importance : importance
  1584. },function(r){
  1585. comment.attr('data-importance', importance);
  1586. core_history_importance_save_count(id);
  1587. });
  1588. }
  1589. function core_history_delete(element){
  1590. if(!confirm('Êtes-vous sûr de vouloir supprimer ce commentaire ?')) return;
  1591. var comment = $(element).closest('.comment');
  1592. var id = $(element).closest('.history-panel').attr('data-uid');
  1593. $.action({
  1594. action: 'core_history_delete',
  1595. id: comment.attr('data-id')
  1596. },function(r){
  1597. comment.remove();
  1598. core_history_importance_save_count(id);
  1599. });
  1600. }
  1601. function core_history_importance_save_count(uid){
  1602. var count = $('.history-importance input:checked').length;
  1603. var historyNotification = $('a[data-uid="'+uid+'"] .history-notification');
  1604. if(count == 0){
  1605. historyNotification.addClass('hidden');
  1606. return;
  1607. }
  1608. historyNotification.removeClass('hidden').html(count).attr('data-original-title',count+' messages importants');
  1609. }
  1610. /*
  1611. Convertit la chaine de caractères passées en paramètres en entités html
  1612. # htmlentities
  1613. */
  1614. function html_entities(str){
  1615. return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  1616. }
  1617. //Override base64 encode avec gestion chars unicode (encodés sur 2 bytes ou +)
  1618. //Compatible anciens navigateurs
  1619. function btoa_unicode(str) {
  1620. //1. encodeURIComponent pour avoir la chaîne UTF-8 encodée avec les %,
  1621. //2. On encode le résultat en bytes bruts
  1622. //3. On envoie dans btoa
  1623. return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
  1624. function toSolidBytes(match, p1) {
  1625. return String.fromCharCode('0x' + p1);
  1626. }));
  1627. }
  1628. //Override base64 decode avec gestion chars unicode (encodés sur 2 bytes ou +)
  1629. //Compatible anciens navigateurs
  1630. function atob_unicode(str) {
  1631. //cf btoa_unicode() mais cheminement inverse
  1632. return decodeURIComponent(atob(str).split('').map(function(c) {
  1633. return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  1634. }).join(''));
  1635. }