mobiparc.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. 
  2. //### Helpers handlebars personnalisés
  3. Handlebars.registerHelper('lower', function (options) {
  4. return options.fn(this).toLowerCase();
  5. });
  6. Handlebars.registerHelper('repuri', function (find, replace, options) {
  7. return encodeURI(options.fn(this).replace(find, replace).toString());
  8. });
  9. Handlebars.registerHelper('todate', function (options) {
  10. var d = options.fn(this);
  11. var dt = new Date(Number.parseInt(d) * 1);
  12. return dt.toLocaleString();
  13. });
  14. Handlebars.registerHelper('timestamp', function (options) {
  15. return Number.parseInt(options.fn(this));
  16. });
  17. Handlebars.registerHelper('if_eq', function (a, opts) {
  18. var b = localStorage.hasOwnProperty("contact") ? localStorage.getItem("contact") : "";
  19. if (a === b) // Or === depending on your needs
  20. return opts.fn(this);
  21. else
  22. return opts.inverse(this);
  23. });
  24. // ### References
  25. // ref a la section main
  26. var main = document.getElementsByClassName('main')[0];
  27. //### Initialisation
  28. // JS s'execute: Retire l'avertissement 'Javascript est requis' (de fait, on sait que JS est actif...)
  29. document.body.classList.remove("nojs");
  30. // Installe le service worker
  31. if ('serviceWorker' in navigator) {
  32. console.log("[ServiceWorker] Installe");
  33. navigator.serviceWorker.register('../sw.js');
  34. }
  35. // Nettoie la section main
  36. $(".main").empty();
  37. // Open (or create) the database
  38. var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
  39. var open = indexedDB.open("MobiParc", 3);
  40. // Create the schema
  41. open.onupgradeneeded = function () {
  42. var db = open.result;
  43. var store = db.createObjectStore("activites", { keyPath: "tstamp" });
  44. console.log("[Activites DB] Cree");
  45. };
  46. // Obtient l'id de la section a afficher en fonction de l'url
  47. function getSectionId() {
  48. return (window.location.hash.slice(1).length > 0 ? window.location.hash.slice(1) : "index");
  49. };
  50. // Memorise la section en cours
  51. var sectionId = getSectionId();
  52. // compile la page entiere avec handlebars
  53. var template = Handlebars.compile(document.getElementById(sectionId).innerHTML);
  54. // Essaie de peupler la page en cours avec les données de la base (s'il y en a a afficher)
  55. try {
  56. var db = open.result;
  57. var txs = db.transaction(sectionId, "readonly");
  58. var stores = txs.objectStore(sectionId);
  59. console.log("Got all " + sectionId + ": ");
  60. stores.getAll().onsuccess = function (event) {
  61. var data = { data: event.target.result };
  62. main.innerHTML = template(data);
  63. };
  64. }
  65. catch (e) {
  66. main.innerHTML = template({});
  67. }
  68. //######### MAIN ###############
  69. // ### Interactions
  70. // Affiche ou masque la sidebar
  71. $('.bt-menu').on('click', 'svg', function () {
  72. $(this).closest('nav').find('div:not(:first)').toggleClass('sidebar');
  73. });
  74. $(document).on('click', '.sidebar', function () {
  75. $(this).closest('nav').find('div:not(:first)').toggleClass('sidebar');
  76. });
  77. // Affiche ou masque le bouton de sync
  78. if (navigator.onLine) {
  79. $(".data-sync").removeAttr("disabled");
  80. }
  81. else {
  82. if (!$(".data-sync").is(":disabled"))
  83. {
  84. $(".data-sync").attr("disabled")
  85. }
  86. }
  87. /* retour haut de page*/
  88. window.onscroll = function (ev) {
  89. document.getElementById("cRetour").className = (window.pageYOffset > 100) ? "cVisible" : "cInvisible";
  90. };
  91. $('#cRetour').on('click', function () {
  92. $('html, body').animate({ scrollTop: 0 }, 200);
  93. });
  94. // Gere l'affichage des classes modales
  95. $(".modal-open, .modal-background, .modal-close").click(function () {
  96. $(".modal-content,.modal-background").toggleClass("active");
  97. if ($(this).hasClass("modal-close")) location.reload();
  98. });
  99. // Recharge dynamiquement le contenu HTML à chaque changement d'url
  100. $(window).on('hashchange', function () {
  101. var href = $(this).attr('href');
  102. $('html, body').animate({ scrollTop: 0 }, 200);
  103. template = Handlebars.compile(document.getElementById(sectionId).innerHTML);
  104. if (sectionId != 'activites') {
  105. $(".main").empty();
  106. try {
  107. var db = open.result;
  108. var txs = db.transaction(sectionId, "readonly");
  109. var stores = txs.objectStore(sectionId);
  110. console.log("Got all " + sectionId + ": ");
  111. stores.getAll().onsuccess = function (event) {
  112. var data = { data: event.target.result };
  113. main.innerHTML = template(data);
  114. };
  115. }
  116. catch (e) {
  117. main.innerHTML = template({});
  118. }
  119. }
  120. });
  121. var addSubmitHandler = function() {
  122. if ($(".main").find(".data-form").length) {
  123. form = $(".main").find(".data-form")[0];
  124. form.addEventListener('submit', handleFormSubmit);
  125. console.log("handler added");
  126. }
  127. };
  128. addSubmitHandler();
  129. // Observeur: suit les modifications apportees a la section main
  130. // >> Infos: https://davidwalsh.name/mutationobserver-api
  131. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  132. var mainsection = document.querySelector("section.main");
  133. var observer = new MutationObserver(function (mutations) {
  134. //gestion des mise element selectable
  135. $(".selectable > tbody").selectable({
  136. filter: "tr",
  137. stop: function () {
  138. $(".del").removeAttr("disabled");
  139. }
  140. });
  141. document.getElementsByClassName('results-display')[0].innerHTML = null;
  142. });
  143. // Notify me of everything!
  144. var observerConfig = {
  145. attributes: true,
  146. childList: true,
  147. characterData: true
  148. };
  149. target = document.querySelector("section.main");
  150. observer.observe(target, observerConfig);
  151. // Intercepte la soumision de formulaires
  152. if ($(".main").find(".data-form").length) {
  153. var form = $(".main").find(".data-form")[0];
  154. $(form).on("submit", function (event) { // on requires jquery 1.7+
  155. handleFormSubmit(event);
  156. });
  157. }
  158. var form;
  159. var handleFormSubmit = function handleFormSubmit(event) {
  160. console.log("handle submit");
  161. // Stop the form from submitting since we’re handling that with AJAX.
  162. event.preventDefault();
  163. // Call our function to get the form data.
  164. var data = formToJSON(form.elements);
  165. // Demo only: print the form data onscreen as a formatted JSON object.
  166. var dataContainer = document.getElementsByClassName('results-display')[0];
  167. // Use `JSON.stringify()` to make the output valid, human-readable JSON.
  168. dataContainer.textContent = JSON.stringify(data, null, " ");
  169. if ($(form).hasClass("activite")) {
  170. data.tstamp = Date.now();
  171. data.user = localStorage.hasOwnProperty("params") ? JSON.parse(localStorage.getItem("params")).user : "(unknown)";
  172. var db = open.result;
  173. var txs = db.transaction("activites", "readwrite");
  174. var stores = txs.objectStore("activites");
  175. stores.put(data);
  176. $(".main").empty();
  177. stores.getAll().onsuccess = function (event) {
  178. var data = { data: event.target.result };
  179. var template = Handlebars.compile(document.getElementById("activites").innerHTML);
  180. $(".main").html(template(data));
  181. };
  182. }
  183. console.log(data);
  184. };
  185. // Gere le clic sur un bouton supprimer
  186. $("body").on("click", ".del", function (event) {
  187. var del = $(this);
  188. if (confirm("Supprimer la selection!") == true) {
  189. $(del).prop("disabled", true);
  190. $(".ui-selected").each(function () {
  191. var elt = $(this);
  192. var id = $(elt).data("id");
  193. var datatype = $(elt).data("type");
  194. var db = open.result;
  195. var tx = db.transaction(datatype, "readwrite");
  196. var store = tx.objectStore(datatype);
  197. store.delete(id).onsuccess = function (evt) {
  198. $(elt).remove();
  199. };
  200. });
  201. }
  202. });
  203. // ### Synchronisation des données
  204. $(".data-sync").on("click", function () {
  205. var db = open.result;
  206. var txs = db.transaction("activite", "readonly");
  207. var stores = txs.objectStore("activite");
  208. console.log("post all : ");
  209. stores.openCursor().onsuccess = function (event) {
  210. //var data = { data: event.target.result };
  211. var cursor = event.target.result;
  212. if (cursor) {
  213. //cursor.model = "anomaly";
  214. cursor.value.model = "activite";
  215. var id = cursor.value.tstamp;
  216. var posting = $.post("/api/mobiparc", { data: JSON.stringify(cursor.value) });
  217. // Put the results in a div
  218. posting.done(function (data) {
  219. if (data == 'ole') {
  220. var tx = db.transaction("activite", "readwrite");
  221. var store = tx.objectStore("activite");
  222. store.delete(id).onsuccess = function (evt) {
  223. $('.sync-result').append("Sync ok activite : " + id + "<br>");
  224. };
  225. }
  226. });
  227. cursor.continue();
  228. }
  229. else {
  230. console.log("end activite");
  231. }
  232. };
  233. })
  234. //###### TOOLBOX ######
  235. function createGuid() {
  236. return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
  237. (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  238. )
  239. }
  240. function getLocation() {
  241. try {
  242. if (navigator.geolocation) {
  243. navigator.geolocation.getCurrentPosition(showPosition);
  244. } else {
  245. console.log("Geolocation is not supported by this browser.");
  246. return 0;
  247. }
  248. }
  249. catch (e) {
  250. console.log("Geolocation: error");
  251. }
  252. }
  253. function showPosition(position) {
  254. $("input[name='coordinates']").val(position.coords.latitude + "," + position.coords.longitude);
  255. console.log(position.coords);
  256. }
  257. // ### Serialization
  258. /**
  259. * Checks that an element has a non-empty `name` and `value` property.
  260. * @param {Element} element the element to check
  261. * @return {Bool} true if the element is an input, false if not
  262. */
  263. var isValidElement = function isValidElement(element) {
  264. return element.name && element.value;
  265. };
  266. /**
  267. * Checks if an element’s value can be saved (e.g. not an unselected checkbox).
  268. * @param {Element} element the element to check
  269. * @return {Boolean} true if the value should be added, false if not
  270. */
  271. var isValidValue = function isValidValue(element) {
  272. return !['checkbox', 'radio'].includes(element.type) || element.checked;
  273. };
  274. /**
  275. * Checks if an input is a checkbox, because checkboxes allow multiple values.
  276. * @param {Element} element the element to check
  277. * @return {Boolean} true if the element is a checkbox, false if not
  278. */
  279. var isCheckbox = function isCheckbox(element) {
  280. return element.type === 'checkbox';
  281. };
  282. //var isHidden = function isHidden(element) {
  283. // return element.type === 'hidden';
  284. //};
  285. /**
  286. * Checks if an input is a `select` with the `multiple` attribute.
  287. * @param {Element} element the element to check
  288. * @return {Boolean} true if the element is a multiselect, false if not
  289. */
  290. var isMultiSelect = function isMultiSelect(element) {
  291. return element.options && element.multiple;
  292. };
  293. /**
  294. * Retrieves the selected options from a multi-select as an array.
  295. * @param {HTMLOptionsCollection} options the options for the select
  296. * @return {Array} an array of selected option values
  297. */
  298. var getSelectValues = function getSelectValues(options) {
  299. return [].reduce.call(options, function (values, option) {
  300. return option.selected ? values.concat(option.value) : values;
  301. }, []);
  302. };
  303. /**
  304. * A more verbose implementation of `formToJSON()` to explain how it works.
  305. *
  306. * NOTE: This function is unused, and is only here for the purpose of explaining how
  307. * reducing form elements works.
  308. *
  309. * @param {HTMLFormControlsCollection} elements the form elements
  310. * @return {Object} form data as an object literal
  311. */
  312. var formToJSON_deconstructed = function formToJSON_deconstructed(elements) {
  313. // This is the function that is called on each element of the array.
  314. var reducerFunction = function reducerFunction(data, element) {
  315. // Add the current field to the object.
  316. data[element.name] = element.value;
  317. // For the demo only: show each step in the reducer’s progress.
  318. console.log(JSON.stringify(data));
  319. return data;
  320. };
  321. // This is used as the initial value of `data` in `reducerFunction()`.
  322. var reducerInitialValue = {};
  323. // To help visualize what happens, log the inital value, which we know is `{}`.
  324. console.log('Initial `data` value:', JSON.stringify(reducerInitialValue));
  325. // Now we reduce by `call`-ing `Array.prototype.reduce()` on `elements`.
  326. var formData = [].reduce.call(elements, reducerFunction, reducerInitialValue);
  327. // The result is then returned for use elsewhere.
  328. return formData;
  329. };
  330. /**
  331. * Retrieves input data from a form and returns it as a JSON object.
  332. * @param {HTMLFormControlsCollection} elements the form elements
  333. * @return {Object} form data as an object literal
  334. */
  335. var formToJSON = function formToJSON(elements) {
  336. return [].reduce.call(elements, function (data, element) {
  337. // Make sure the element has the required properties and should be added.
  338. if (isValidElement(element) && isValidValue(element)) {
  339. /*
  340. * Some fields allow for more than one value, so we need to check if this
  341. * is one of those fields and, if so, store the values as an array.
  342. */
  343. if (isCheckbox(element)) {
  344. data[element.name] = (data[element.name] || []).concat(element.value);
  345. } else if (isMultiSelect(element)) {
  346. data[element.name] = getSelectValues(element);
  347. } else {
  348. data[element.name] = element.value;
  349. }
  350. }
  351. return data;
  352. }, {});
  353. };