From ea29d032bb60d72bcd7c612a078fd7672d589158 Mon Sep 17 00:00:00 2001
From: Raphael Beekmann
".concat(e.nls.map("satLayerEsri"),"
")]=n,i.getPreference("map-plan-layer"))switch(i.getPreference("map-plan-layer")){case e.nls.map("planLayerOSM"):r.addTo(e._map);break;case e.nls.map("satLayerEsri"):n.addTo(e._map);break;default:r.addTo(e._map)}else r.addTo(e._map);window.L.control.layers(a,{},{position:"bottomright"}).addTo(e._map),e._zoomSlider=new d(e._map),t()}))}},{key:"_initEvents",value:function(){var e=this;return new Promise((function(t){document.getElementById("user-profile").addEventListener("click",e.userProfileModal.bind(e)),document.getElementById("hide-show").addEventListener("click",e.hidShowModal.bind(e)),document.getElementById("center-on").addEventListener("click",e.toggleFocusLock.bind(e)),document.getElementById("overlay").addEventListener("click",e.closeModal.bind(e)),e._map.on("click",e.mapClicked.bind(e)),e._map.on("drag",(function(){e._map.panInsideBounds(i.MAP_BOUNDS,{animate:!0}),"true"===i.getPreference("map-center-on-user")&&e.toggleFocusLock()})),e._map.on("zoomstart",(function(){e._isZooming=!0,"true"===i.getPreference("poi-show-circle")&&(e.setMarkerCircles(e._marks.spot,!1),e.setMarkerCircles(e._marks.store,!1),e.setMarkerCircles(e._marks.bar,!1),e.setMarkerCircles([e._user],!1),e.setMarkerCircles([{circle:e._user.range}],!1))})),e._map.on("zoomend",(function(){e._isZooming=!1,"true"===i.getPreference("poi-show-circle")&&e._map.getZoom()>=15&&(e.setMarkerCircles(e._marks.spot,!0),e.setMarkerCircles(e._marks.store,!0),e.setMarkerCircles(e._marks.bar,!0),e.setMarkerCircles([e._user],!0),e.setMarkerCircles([{circle:e._user.range}],!0)),"true"===i.getPreference("poi-marker-label")&&(e._map.getZoom()<15?(e.setMarkerLabels(e._marks.spot,!1),e.setMarkerLabels(e._marks.store,!1),e.setMarkerLabels(e._marks.bar,!1)):(e.setMarkerLabels(e._marks.spot,!0),e.setMarkerLabels(e._marks.store,!0),e.setMarkerLabels(e._marks.bar,!0))),e.updateDebugUI()})),e._map.on("baselayerchange",(function(e){i.setPreference("map-plan-layer",i.stripDom(e.name))})),t()}))}},{key:"_initMarkers",value:function(){var e=this;return new Promise((function(t){var r={animateAddingMarkers:!0,disableClusteringAtZoom:18,spiderfyOnMaxZoom:!1};e._clusters.spot=new window.L.MarkerClusterGroup(Object.assign(r,{iconCreateFunction:function(e){return window.L.divIcon({className:"cluster-icon-wrapper",html:'\n \n '.concat(e.getChildCount(),"\n ")})}})),e._clusters.store=new window.L.MarkerClusterGroup(Object.assign(r,{iconCreateFunction:function(e){return window.L.divIcon({className:"cluster-icon-wrapper",html:'\n \n '.concat(e.getChildCount(),"\n ")})}})),e._clusters.bar=new window.L.MarkerClusterGroup(Object.assign(r,{iconCreateFunction:function(e){return window.L.divIcon({className:"cluster-icon-wrapper",html:'\n \n '.concat(e.getChildCount(),"\n ")})}})),"true"===i.getPreference("poi-show-spot")&&e._map.addLayer(e._clusters.spot),"true"===i.getPreference("poi-show-store")&&e._map.addLayer(e._clusters.store),"true"===i.getPreference("poi-show-bar")&&e._map.addLayer(e._clusters.bar);for(var n=function(t){e.markPopupFactory(t).then((function(r){t.dom=r,t.marker=e.placeMarker(t),e._marks[t.type].push(t),e._clusters[t.type].addLayer(t.marker)}))},a=JSON.parse(i.getPreference("saved-spot"))||[],o=0;o\n * This component handles the whole BeerCrackerz app. It includes the map manipulation,\n * the geolocation API to update the user position and process any map events that are\n * relevant to an UX stand point. For more information, please consult the application\n * description page at https://about.beercrackerz.org/\n *\n **/\n function BeerCrackerz() {\n var _this;\n\n _classCallCheck(this, BeerCrackerz);\n\n _this = _super.call(this);\n /**\n * The core Leaflet.js map\n * @type {Object}\n * @private\n **/\n\n _this._map = null;\n /**\n * The zoom slider handler\n * @type {Object}\n * @private\n **/\n\n _this._zoomSlider = null;\n /**\n * The notification handler\n * @type {Object}\n * @private\n **/\n\n _this._notification = null;\n /**\n * The user object holds everything useful to ensure a proper session\n * @type {Object}\n * @private\n **/\n\n _this._user = {\n lat: 48.853121540141096,\n // Default lat to Paris Notre-Dame latitude\n lng: 2.3498955769881156,\n // Default lng to Paris Notre-Dame longitude\n accuracy: 0,\n // Accuracy in meter given by geolocation API\n marker: null,\n // The user marker on map\n circle: null,\n // The accuracy circle around the user marker\n range: null,\n // The range in which user can add a new marker\n color: _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].USER_COLOR,\n // The color to use for circle (match the user marker color)\n id: -1,\n username: ''\n };\n /**\n * The stored marks for spots, stores and bars\n * @type {Object}\n * @private\n **/\n\n _this._marks = {\n spot: [],\n store: [],\n bar: []\n };\n /**\n * The stored clusters for markers, see Leaflet.markercluster plugin\n * @type {Object}\n * @private\n **/\n\n _this._clusters = {\n spot: {},\n store: {},\n bar: {}\n };\n /**\n * The temporary marker for new marks only\n * @type {Object}\n * @private\n **/\n\n _this._newMarker = null;\n /**\n * The debug DOM object\n * @type {Object}\n * @private\n **/\n\n _this._debugElement = null;\n /**\n * ID for geolocation watch callback\n * @type {Number}\n * @private\n **/\n\n _this._watchId = null;\n /**\n * Flag to know if a zoom action is occuring on map\n * @type {Boolean}\n * @private\n **/\n\n _this._isZooming = false;\n /**\n * The LangManager must be instantiated to handle nls accross the app\n * @type {Boolean}\n * @private\n **/\n // The BeerCrackerz app is only initialized once nls are set up\n\n _this._lang = new _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"](window.navigator.language.substring(0, 2), _this._init.bind(_assertThisInitialized(_this)));\n return _this;\n } // ======================================================================== //\n // ----------------- Application initialization sequence ------------------ //\n // ======================================================================== //\n\n /**\n * @method\n * @name _init\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _init() method is designed to properly configure the user session, according\n * to its saved preferences and its position. It first build the debug interface,\n * then loads the user preferences, then create the map and finally, events are listened.\n *\n **/\n\n\n _createClass(BeerCrackerz, [{\n key: \"_init\",\n value: function _init() {\n this._debugElement = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].initDebugInterface();\n this._notification = new _js_ui_Notification_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"]();\n\n this._initUser().then(this._initPreferences.bind(this)).then(this._initGeolocation.bind(this)).then(this._initMap.bind(this)).then(this._initEvents.bind(this)).then(this._initMarkers.bind(this));\n }\n /**\n * @method\n * @name _initUser\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _init() method initialize the user object according to its information\n * and statistic so the UI can be properly built.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initUser\",\n value: function _initUser() {\n var _this2 = this;\n\n return new Promise(function (resolve) {\n // TODO fill user information from server\n _this2._user.id = 42;\n _this2._user.username = 'messmaker';\n resolve();\n });\n }\n /**\n * @method\n * @name _initPreferences\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initPreferences() will initialize user preference if they are not set yet,\n * it will also update the UI according to user preferences ; debug DOM visible,\n * update the command classList for selected ones.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initPreferences\",\n value: function _initPreferences() {\n var _this3 = this;\n\n return new Promise(function (resolve) {\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-spot') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-spot', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-store') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-store', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-bar') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-bar', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-plan-layer', true);\n }\n\n if (window.DEBUG === true || _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('app-debug') === 'true') {\n window.DEBUG = true; // Ensure to set global flag if preference comes from local storage\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('app-debug', true); // Ensure to set local storage preference if debug flag was added to the url\n\n _this3.addDebugUI();\n } // Update icon class if center on preference is set to true\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n document.getElementById('center-on').classList.add('lock-center-on');\n }\n\n resolve();\n });\n }\n /**\n * @method\n * @name _initGeolocation\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initGeolocation() method will request from browser the location authorization.\n * Once granted, an event listener is set on any position update, so it can update the\n * map state and the markers position. This method can be called again, only if the\n * geolocation watch has been cleared ; for example when updating the accuracy options.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initGeolocation\",\n value: function _initGeolocation() {\n var _this4 = this;\n\n return new Promise(function (resolve) {\n if ('geolocation' in navigator) {\n var options = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true' ? _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].HIGH_ACCURACY : _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].OPTIMIZED_ACCURACY;\n _this4._watchId = navigator.geolocation.watchPosition(function (position) {\n // Update saved user position\n _this4._user.lat = position.coords.latitude;\n _this4._user.lng = position.coords.longitude;\n _this4._user.accuracy = position.coords.accuracy; // Only draw marker if map is already created\n\n if (_this4._map) {\n _this4.drawUserMarker();\n\n _this4.updateMarkerCirclesVisibility(); // Update map position if focus lock is active\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true' && !_this4._isZooming) {\n _this4._map.setView(_this4._user);\n } // Updating debug info\n\n\n _this4.updateDebugUI();\n }\n\n resolve();\n }, resolve, options);\n } else {\n _this4._notification.raise(_this4.nls.notif('geolocationError'));\n\n resolve();\n }\n });\n }\n /**\n * @method\n * @name _initMap\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initMap() method will create the Leaflet.js map with two base layers (plan/satellite),\n * add scale control, remove zoom control and set map bounds.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initMap\",\n value: function _initMap() {\n var _this5 = this;\n\n return new Promise(function (resolve) {\n // Use main div to inject OSM into\n _this5._map = window.L.map('beer-crakerz-map', {\n zoomControl: false\n }).setView([_this5._user.lat, _this5._user.lng], 18); // Add meter and feet scale on map\n\n window.L.control.scale().addTo(_this5._map); // Place user marker on the map\n\n _this5.drawUserMarker(); // Add OSM credits to the map next to leaflet credits\n\n\n var osm = _js_utils_ProviderEnum_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].planOsm; //const plan = Providers.planGeo;\n\n var esri = _js_utils_ProviderEnum_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].satEsri; //const geo = Providers.satGeo;\n // Prevent panning outside of the world's edge\n\n _this5._map.setMaxBounds(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].MAP_BOUNDS); // Add layer group to interface\n\n\n var baseMaps = {};\n baseMaps[\"
\".concat(_this5.nls.map('planLayerOSM'), \"
\")] = osm; //baseMaps[`${this.nls.map('planLayerGeo')}
`] = plan; \n\n baseMaps[\"\".concat(_this5.nls.map('satLayerEsri'), \"
\")] = esri; //baseMaps[`${this.nls.map('satLayerGeo')}
`] = geo;\n // Append layer depending on user preference\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer')) {\n switch (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer')) {\n case _this5.nls.map('planLayerOSM'):\n osm.addTo(_this5._map);\n break;\n\n /*case this.nls.map('planLayerGeo'):\n plan.addTo(this._map);\n break;*/\n\n case _this5.nls.map('satLayerEsri'):\n esri.addTo(_this5._map);\n break;\n\n /*case this.nls.map('satLayerGeo'):\n geo.addTo(this._map);\n break;*/\n\n default:\n osm.addTo(_this5._map);\n break;\n }\n } else {\n // No saved pref, fallback on OSM base map\n osm.addTo(_this5._map);\n } // Add layer switch radio on bottom right of the map\n\n\n window.L.control.layers(baseMaps, {}, {\n position: 'bottomright'\n }).addTo(_this5._map); // Init zoom slider when map has been created\n\n _this5._zoomSlider = new _js_ui_ZoomSlider_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"](_this5._map);\n resolve();\n });\n }\n /**\n * @method\n * @name _initEvents\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *\n * The _initEvents() method will listen to all required events to manipulate the map. Those events\n * are both for commands and for map events (click, drag, zoom and layer change).\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initEvents\",\n value: function _initEvents() {\n var _this6 = this;\n\n return new Promise(function (resolve) {\n // Command events\n document.getElementById('user-profile').addEventListener('click', _this6.userProfileModal.bind(_this6));\n document.getElementById('hide-show').addEventListener('click', _this6.hidShowModal.bind(_this6));\n document.getElementById('center-on').addEventListener('click', _this6.toggleFocusLock.bind(_this6));\n document.getElementById('overlay').addEventListener('click', _this6.closeModal.bind(_this6)); // Subscribe to click event on map to react\n\n _this6._map.on('click', _this6.mapClicked.bind(_this6)); // Map is dragged by user mouse/finger\n\n\n _this6._map.on('drag', function () {\n // Constrain pan to the map bounds\n _this6._map.panInsideBounds(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].MAP_BOUNDS, {\n animate: true\n }); // Disable lock focus if user drags the map\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n _this6.toggleFocusLock();\n }\n }); // Map events\n\n\n _this6._map.on('zoomstart', function () {\n _this6._isZooming = true;\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n _this6.setMarkerCircles(_this6._marks.spot, false);\n\n _this6.setMarkerCircles(_this6._marks.store, false);\n\n _this6.setMarkerCircles(_this6._marks.bar, false);\n\n _this6.setMarkerCircles([_this6._user], false);\n\n _this6.setMarkerCircles([{\n circle: _this6._user.range\n }], false);\n }\n });\n\n _this6._map.on('zoomend', function () {\n _this6._isZooming = false;\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n if (_this6._map.getZoom() >= 15) {\n _this6.setMarkerCircles(_this6._marks.spot, true);\n\n _this6.setMarkerCircles(_this6._marks.store, true);\n\n _this6.setMarkerCircles(_this6._marks.bar, true);\n\n _this6.setMarkerCircles([_this6._user], true);\n\n _this6.setMarkerCircles([{\n circle: _this6._user.range\n }], true);\n }\n } // Auto hide labels if zoom level is too high (and restore it when needed)\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true') {\n if (_this6._map.getZoom() < 15) {\n _this6.setMarkerLabels(_this6._marks.spot, false);\n\n _this6.setMarkerLabels(_this6._marks.store, false);\n\n _this6.setMarkerLabels(_this6._marks.bar, false);\n } else {\n _this6.setMarkerLabels(_this6._marks.spot, true);\n\n _this6.setMarkerLabels(_this6._marks.store, true);\n\n _this6.setMarkerLabels(_this6._marks.bar, true);\n }\n } // Updating debug info\n\n\n _this6.updateDebugUI();\n });\n\n _this6._map.on('baselayerchange', function (event) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-plan-layer', _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].stripDom(event.name));\n });\n\n resolve();\n });\n }\n /**\n * @method\n * @name _initMarkers\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initEvents() method will initialize all saved marker into the map.\n * Markers must be retrieved from server with a specific format to ensure it works\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initMarkers\",\n value: function _initMarkers() {\n var _this7 = this;\n\n return new Promise(function (resolve) {\n // Init map clusters for marks to be displayed (disable clustering at opened popup zoom level)\n var clusterOptions = {\n animateAddingMarkers: true,\n disableClusteringAtZoom: 18,\n spiderfyOnMaxZoom: false\n };\n _this7._clusters.spot = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n }));\n _this7._clusters.store = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n }));\n _this7._clusters.bar = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n })); // Append clusters to the map depending on user preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-spot\") === 'true') {\n _this7._map.addLayer(_this7._clusters.spot);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-store\") === 'true') {\n _this7._map.addLayer(_this7._clusters.store);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-bar\") === 'true') {\n _this7._map.addLayer(_this7._clusters.bar);\n } // Load data from local storage, later to be fetched from server\n\n\n var iterateMarkers = function iterateMarkers(mark) {\n _this7.markPopupFactory(mark).then(function (dom) {\n mark.dom = dom;\n mark.marker = _this7.placeMarker(mark);\n\n _this7._marks[mark.type].push(mark);\n\n _this7._clusters[mark.type].addLayer(mark.marker);\n });\n };\n\n var marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-spot')) || [];\n\n for (var i = 0; i < marks.length; ++i) {\n iterateMarkers(marks[i]);\n }\n\n marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-store')) || [];\n\n for (var _i = 0; _i < marks.length; ++_i) {\n iterateMarkers(marks[_i]);\n }\n\n marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-bar')) || [];\n\n for (var _i2 = 0; _i2 < marks.length; ++_i2) {\n iterateMarkers(marks[_i2]);\n }\n\n resolve();\n });\n } // ======================================================================== //\n // ------------------------- Toggle for map items ------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name toggleFocusLock\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleFocusLock() method will, depending on user preference, lock or unlock\n * the map centering around the user marker at each position refresh. This way the user\n * can roam while the map is following its position.\n *\n **/\n\n }, {\n key: \"toggleFocusLock\",\n value: function toggleFocusLock() {\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n this._notification.raise(this.nls.notif(\"unlockFocusOn\"));\n\n document.getElementById('center-on').classList.remove('lock-center-on');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-center-on-user', 'false');\n } else {\n this._notification.raise(this.nls.notif(\"lockFocusOn\"));\n\n document.getElementById('center-on').classList.add('lock-center-on');\n\n this._map.flyTo([this._user.lat, this._user.lng], 18);\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-center-on-user', 'true');\n }\n }\n /**\n * @method\n * @name toggleLabel\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleLabel() method will, depending on user preference, display or not\n * the labels attached to spots/stores/bars marks. This label is basically the\n * mark name given by its creator.\n *\n **/\n\n }, {\n key: \"toggleLabel\",\n value: function toggleLabel() {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true');\n this.setMarkerLabels(this._marks.spot, visible);\n this.setMarkerLabels(this._marks.store, visible);\n this.setMarkerLabels(this._marks.bar, visible);\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-marker-label', visible);\n }\n /**\n * @method\n * @name toggleCircle\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleCircle() method will, depending on user preference, display or not\n * the circles around the spots/stores/bars marks. This circle indicates the minimal\n * distance which allow the user to make updates on the mark information\n *\n **/\n\n }, {\n key: \"toggleCircle\",\n value: function toggleCircle() {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true');\n this.setMarkerCircles(this._marks.spot, visible);\n this.setMarkerCircles(this._marks.store, visible);\n this.setMarkerCircles(this._marks.bar, visible);\n this.setMarkerCircles([this._user], visible);\n this.setMarkerCircles([{\n circle: this._user.range\n }], visible);\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-circle', visible);\n }\n /**\n * @method\n * @name toggleMarkers\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleMarkers() method will, depending on user preference, display or not\n * a given mark type. This way, the user can fine tune what is displayed on the map.\n * A mark type in spots/stores/bars must be given as an argument\n *\n * @param {String} type The mark type in spots/tores/bars\n **/\n\n }, {\n key: \"toggleMarkers\",\n value: function toggleMarkers(type) {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-\".concat(type)) === 'true');\n\n if (visible === true) {\n this._map.addLayer(this._clusters[type]);\n } else {\n this._map.removeLayer(this._clusters[type]);\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"poi-show-\".concat(type), visible);\n }\n /**\n * @method\n * @name toggleHighAccuracy\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleHighAccuracy() method will, depending on user preference, update the\n * geolocation accuracy between optimized and high. The high settings might cause\n * more memory and processing consumption, but gives better results. It will clear\n * any previous position watch on the geolocation API so it can subscribe a new one\n * with the new accuracy parameters (see Utils for values)\n *\n **/\n\n }, {\n key: \"toggleHighAccuracy\",\n value: function toggleHighAccuracy() {\n var high = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-high-accuracy', high);\n navigator.geolocation.clearWatch(this._watchId);\n\n this._initGeolocation().then(this.updateDebugUI.bind(this));\n }\n /**\n * @method\n * @name toggleDebug\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleDebug() method will, depending on user preference, add or remove\n * the debug DOM element to the user interface. The debug DOM display several\n * useful information to identify an issue with the geolocation API\n *\n **/\n\n }, {\n key: \"toggleDebug\",\n value: function toggleDebug() {\n var visible = !window.DEBUG;\n window.DEBUG = visible;\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('app-debug', visible);\n\n if (visible) {\n this.addDebugUI();\n } else {\n this.removeDebugUI();\n }\n } // ======================================================================== //\n // ----------------- App modals display and interaction ------------------- //\n // ======================================================================== //\n\n }, {\n key: \"newMarkModal\",\n value: function newMarkModal(dom) {\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex';\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n }\n }, {\n key: \"editMarkModal\",\n value: function editMarkModal(options) {\n var _this8 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate(\"assets/html/modal/edit\".concat(options.type, \".html\")).then(function (dom) {\n var name = dom.querySelector(\"#\".concat(options.type, \"-name\"));\n var description = dom.querySelector(\"#\".concat(options.type, \"-desc\"));\n var submit = dom.querySelector(\"#\".concat(options.type, \"-submit\"));\n var cancel = dom.querySelector(\"#\".concat(options.type, \"-cancel\"));\n var rate = dom.querySelector(\"#\".concat(options.type, \"-rating\"));\n var rating = new _js_ui_Rating_js__WEBPACK_IMPORTED_MODULE_6__[\"default\"](rate, options.rate); // Update nls for template\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this8.nls.modal(\"\".concat(options.type, \"EditTitle\")));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-name\")), \"{{\".concat(options.type.toUpperCase(), \"_NAME}}\"), _this8.nls[options.type]('nameLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-desc\")), \"{{\".concat(options.type.toUpperCase(), \"_DESC}}\"), _this8.nls[options.type]('descLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-rate\")), \"{{\".concat(options.type.toUpperCase(), \"_RATE}}\"), _this8.nls[options.type]('rateLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(submit, \"{{\".concat(options.type.toUpperCase(), \"_SUBMIT}}\"), _this8.nls.nav('add'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(cancel, \"{{\".concat(options.type.toUpperCase(), \"_CANCEL}}\"), _this8.nls.nav('cancel'));\n name.value = options.name;\n description.value = options.description;\n submit.addEventListener('click', function () {\n // Iterate through marks to find matching one (by coord as marks coordinates are unique)\n for (var i = 0; i < _this8._marks[options.type].length; ++i) {\n // We found, remove circle, label and marker from map/clusters\n if (options.lat === _this8._marks[options.type][i].lat && options.lng === _this8._marks[options.type][i].lng) {\n _this8._marks[options.type][i].name = name.value;\n _this8._marks[options.type][i].description = description.value;\n _this8._marks[options.type][i].rate = rating.currentRate;\n options.tooltip.removeFrom(_this8.map);\n\n _this8.markPopupFactory(options).then(function (dom) {\n options.dom = dom;\n options.marker.setPopupContent(options.dom);\n });\n\n break;\n }\n } // Format marks to be saved and then update user preference with\n\n\n var formattedMarks = [];\n\n for (var _i3 = 0; _i3 < _this8._marks[options.type].length; ++_i3) {\n formattedMarks.push(_this8.formatSavedMarker(_this8._marks[options.type][_i3]));\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(formattedMarks)); // Notify user through UI that marker has been successfully deleted\n\n _this8._notification.raise(_this8.nls.notif(\"\".concat(options.type, \"Deleted\")));\n\n _this8.closeModal(null, true);\n });\n cancel.addEventListener('click', _this8.closeModal.bind(_this8, null, true));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex';\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name deleteMarkModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * The deleteMarkModal() method will request the mark delete modal, which prompts\n * the user a confirmation to actually delete the mark\n *\n * @param {Function} cb The function to callback with true or false depending on user's choice\n **/\n\n }, {\n key: \"deleteMarkModal\",\n value: function deleteMarkModal(cb) {\n var _this9 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/deletemark.html').then(function (dom) {\n // Update nls for template\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this9.nls.modal('deleteMarkTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-desc\"), \"{{MODAL_DESC}}\", _this9.nls.modal('deleteMarkDesc'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#cancel-close\"), \"{{MODAL_CANCEL}}\", _this9.nls.nav('cancel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#delete-close\"), \"{{MODAL_DELETE}}\", _this9.nls.nav('delete'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Setup callback for confirm/cancel buttons\n\n document.getElementById('cancel-close').addEventListener('click', function (e) {\n _this9.closeModal(e);\n\n cb(false);\n }, false);\n document.getElementById('delete-close').addEventListener('click', function (e) {\n _this9.closeModal(e);\n\n cb(true);\n }, false);\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name userProfileModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The userProfileModal() method will request the user modal, which contains\n * the user preferences, and the user profile information\n *\n **/\n\n }, {\n key: \"userProfileModal\",\n value: function userProfileModal() {\n var _this10 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/user.html').then(function (dom) {\n // Update nls for template\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this10.nls.modal('userTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-user-modal-accuracy\"), \"{{ACCURACY_USER_MODAL}}\", _this10.nls.modal('userAccuracyPref'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-user-modal-debug\"), \"{{DEBUG_USER_MODAL}}\", _this10.nls.modal('userDebugPref'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-about-desc\"), \"{{BEERCRACKERZ_DESC}}\", _this10.nls.modal('aboutDesc'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Init modal checkbox state according to local storage preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true') {\n document.getElementById('high-accuracy-toggle').checked = true;\n }\n\n if (window.DEBUG === true || _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('app-debug') === 'true') {\n document.getElementById('debug-toggle').checked = true;\n }\n\n document.getElementById('high-accuracy-toggle').addEventListener('change', _this10.toggleHighAccuracy.bind(_this10));\n document.getElementById('debug-toggle').addEventListener('change', _this10.toggleDebug.bind(_this10));\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name hidShowModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The hidShowModal() method will request the hide show modal, which all\n * toggles for map elements ; labels/circles/spots/stores/bars\n *\n **/\n\n }, {\n key: \"hidShowModal\",\n value: function hidShowModal() {\n var _this11 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/hideshow.html').then(function (dom) {\n // Update template nls\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-title\"), \"{{MODAL_TITLE}}\", _this11.nls.modal('hideShowTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-labels\"), \"{{LABELS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowLabels'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-circles\"), \"{{CIRCLES_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowCircles'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-spots\"), \"{{SPOTS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowSpots'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-stores\"), \"{{STORES_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowStores'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-bars\"), \"{{BARS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowBars'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#modal-close-button\"), \"{{MODAL_CLOSE}}\", _this11.nls.nav('close'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Init modal checkbox state according to local storage preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true') {\n document.getElementById('label-toggle').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n document.getElementById('circle-toggle').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-spot') === 'true') {\n document.getElementById('show-spots').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-store') === 'true') {\n document.getElementById('show-stores').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-bar') === 'true') {\n document.getElementById('show-bars').checked = true;\n }\n\n document.getElementById('label-toggle').addEventListener('change', _this11.toggleLabel.bind(_this11));\n document.getElementById('circle-toggle').addEventListener('change', _this11.toggleCircle.bind(_this11));\n document.getElementById('show-spots').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'spot'));\n document.getElementById('show-stores').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'store'));\n document.getElementById('show-bars').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'bar'));\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name closeModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The closeModal() method will close any opened modal if the click event is\n * targeted on the modal overlay or on close buttons\n *\n * @param {Event} event The click event\n **/\n\n }, {\n key: \"closeModal\",\n value: function closeModal(event, force) {\n if (force === true || event.target.id === 'overlay' || event.target.id.indexOf('close') !== -1) {\n document.getElementById('overlay').style.opacity = 0;\n setTimeout(function () {\n document.getElementById('overlay').style.display = 'none';\n document.getElementById('overlay').innerHTML = '';\n }, 300);\n }\n } // ======================================================================== //\n // -------------------------- Map interaction ----------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name mapClicked\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The mapClicked() method is the callback used when the user clicked on the Leaflet.js map\n *\n * @param {Event} event The click event\n **/\n\n }, {\n key: \"mapClicked\",\n value: function mapClicked(event) {\n if (this._newMarker && this._newMarker.popupClosed) {\n // Avoid to open new marker right after popup closing\n this._newMarker = null;\n } else if (this._newMarker === null || !this._newMarker.isBeingDefined) {\n // Only create new marker if none is in progress, and that click is max range to add a marker\n var distance = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getDistanceBetweenCoords([this._user.lat, this._user.lng], [event.latlng.lat, event.latlng.lng]);\n\n if (distance < _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].NEW_MARKER_RANGE) {\n this._newMarker = this.definePOI(event.latlng, this._markerSaved.bind(this));\n } else {\n this._notification.raise(this.nls.notif('newMarkerOutside'));\n }\n }\n }\n /**\n * @method\n * @name _markerSaved\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _markerSaved() method is the callback used when a marker is created and added\n * to the map. It is the last method of a new marker proccess.\n *\n * @param {Object} options The new marker options\n **/\n\n }, {\n key: \"_markerSaved\",\n value: function _markerSaved(options) {\n // Save marke in marks and clusters for the map\n this._marks[options.type].push(options);\n\n this._clusters[options.type].addLayer(options.marker); // Notify user that new marker has been saved\n\n\n this._notification.raise(this.nls.notif(\"\".concat(options.type, \"Added\"))); // Update marker circles visibility according to user position\n\n\n this.updateMarkerCirclesVisibility(); // Clear new marker to let user add other stuff\n\n this._newMarker = null; // Save new marker in local storage, later to be sent to the server\n\n var marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"saved-\".concat(options.type))) || [];\n marks.push(this.formatSavedMarker(options));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(marks));\n }\n /**\n * @method\n * @name updateMarkerCirclesVisibility\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The updateMarkerCirclesVisibility() method will update the circle visibility for\n * all mark types (spots/stores/bars) and for the user marker\n *\n **/\n\n }, {\n key: \"updateMarkerCirclesVisibility\",\n value: function updateMarkerCirclesVisibility() {\n var _this12 = this;\n\n var _updateByType = function _updateByType(data) {\n // Check spots in user's proximity\n for (var i = 0; i < data.length; ++i) {\n // Only update circles that are in user view\n if (_this12._map.getBounds().contains(data[i].marker.getLatLng())) {\n var marker = data[i].marker;\n var distance = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getDistanceBetweenCoords([_this12._user.lat, _this12._user.lng], [marker.getLatLng().lat, marker.getLatLng().lng]); // Only show if user distance to marker is under circle radius\n\n if (distance < _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].CIRCLE_RADIUS && !data[i].circle.visible) {\n data[i].circle.visible = true;\n data[i].circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n } else if (distance >= _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].CIRCLE_RADIUS && data[i].circle.visible) {\n data[i].circle.visible = false;\n data[i].circle.setStyle({\n opacity: 0,\n fillOpacity: 0\n });\n }\n }\n }\n };\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n _updateByType(this._marks.spot);\n\n _updateByType(this._marks.store);\n\n _updateByType(this._marks.bar);\n\n _updateByType([this._user]);\n }\n } // ======================================================================== //\n // -------------------------- Marker edition ------------------------------ //\n // ======================================================================== //\n\n /**\n * @method\n * @name formatSavedMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method formats a mark returned from MapHelper so it can be parsed\n * using JSON.parse (in order to store it in local storage/database)\n *\n * @param {Object} mark The mark options from internal this._marks[type]\n **/\n\n }, {\n key: \"formatSavedMarker\",\n value: function formatSavedMarker(mark) {\n return {\n type: mark.type,\n lat: mark.lat,\n lng: mark.lng,\n name: mark.name,\n description: mark.description,\n user: mark.username || this.user.username,\n userId: mark.userId || this.user.id,\n dom: null,\n rate: mark.rate,\n marker: null,\n circle: null\n };\n }\n /**\n * @method\n * @name editMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method will open a mark edition modal\n *\n * @param {Object} options The mark options to edit\n **/\n\n }, {\n key: \"editMarker\",\n value: function editMarker(options) {\n this._map.closePopup();\n\n this.editMarkModal(options);\n }\n /**\n * @method\n * @name deleteMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method will delete a mark after prompting the user if he trully wants to\n *\n * @param {Object} options The mark options to delete\n **/\n\n }, {\n key: \"deleteMarker\",\n value: function deleteMarker(options) {\n var _this13 = this;\n\n this.deleteMarkModal(function (confirm) {\n if (confirm === true) {\n // Iterate through marks to find matching one (by coord as marks coordinates are unique)\n var marks = _this13._marks[options.type];\n\n for (var i = 0; i < marks.length; ++i) {\n // We found, remove circle, label and marker from map/clusters\n if (options.lat === marks[i].lat && options.lng === marks[i].lng) {\n _this13.setMarkerCircles([marks[i]], false);\n\n _this13.setMarkerLabels([marks[i]], false);\n\n _this13._clusters[options.type].removeLayer(marks[i].marker);\n\n marks.splice(i, 1);\n break;\n }\n } // Update internal marks array\n\n\n _this13._marks[options.type] = marks; // Format marks to be saved and then update user preference with\n\n var formattedMarks = [];\n\n for (var _i4 = 0; _i4 < _this13._marks[options.type].length; ++_i4) {\n formattedMarks.push(_this13.formatSavedMarker(_this13._marks[options.type][_i4]));\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(formattedMarks)); // Notify user through UI that marker has been successfully deleted\n\n _this13._notification.raise(_this13.nls.notif(\"\".concat(options.type, \"Deleted\")));\n }\n });\n } // ======================================================================== //\n // ---------------------------- Debug methods ----------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name addDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The addDebugUI() method appends the debug DOM element to the document body\n *\n **/\n\n }, {\n key: \"addDebugUI\",\n value: function addDebugUI() {\n document.body.appendChild(this._debugElement);\n }\n /**\n * @method\n * @name removeDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The removeDebugUI() method remove the debug DOM element from the document body\n *\n **/\n\n }, {\n key: \"removeDebugUI\",\n value: function removeDebugUI() {\n document.body.removeChild(this._debugElement);\n }\n /**\n * @method\n * @name updateDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The updateDebugUI() method will update informations held in the debug DOM\n *\n **/\n\n }, {\n key: \"updateDebugUI\",\n value: function updateDebugUI() {\n var options = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true' ? _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].HIGH_ACCURACY : _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].OPTIMIZED_ACCURACY;\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].updateDebugInterface(this._debugElement, this._user, options);\n }\n /**\n * @method\n * @name downloadData\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since August 2022\n * @description\n *
\n * The downloadData() method will save to user disk the saved spots as a JSON file\n *\n **/\n\n }, {\n key: \"downloadData\",\n value: function downloadData() {\n var dataString = \"data:text/json;charset=utf-8,\".concat(encodeURIComponent(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-spot')));\n var link = document.createElement('A');\n link.setAttribute('href', dataString);\n link.setAttribute('download', 'BeerCrackerzData.json');\n link.click();\n } // ======================================================================== //\n // ---------------------------- Class accessors --------------------------- //\n // ======================================================================== //\n\n /**\n * @public\n * @property {Object} map\n * Leaflet.js map getter\n **/\n\n }, {\n key: \"map\",\n get: function get() {\n return this._map;\n }\n /**\n * @public\n * @property {Object} marks\n * Leaflet.js marks that holds spot/store/bar marks as subkeys\n **/\n\n }, {\n key: \"marks\",\n get: function get() {\n return this._marks;\n }\n /**\n * @public\n * @property {Object} user\n * The session user object\n **/\n\n }, {\n key: \"user\",\n get: function get() {\n return this._user;\n }\n /**\n * @public\n * @property {Object} nls\n * The LangManager getter\n **/\n\n }, {\n key: \"nls\",\n get: function get() {\n return this._lang;\n }\n }]);\n\n return BeerCrackerz;\n}(_js_MapHelper_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BeerCrackerz);\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerz.js?"); + +/***/ }), + +/***/ "./src/js/MapHelper.js": +/*!*****************************!*\ + !*** ./src/js/MapHelper.js ***! + \*****************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/MarkerEnum.js */ \"./src/js/utils/MarkerEnum.js\");\n/* harmony import */ var _ui_Rating_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui/Rating.js */ \"./src/js/ui/Rating.js\");\n/* harmony import */ var _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils/Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\n\nvar MapHelper = /*#__PURE__*/function () {\n function MapHelper() {\n /* Mixin to be extended from the BeerCrackerz main class */\n\n _classCallCheck(this, MapHelper);\n } // ======================================================================== //\n // --------------------------- Marker helpers ----------------------------- //\n // ======================================================================== //\n\n\n _createClass(MapHelper, [{\n key: \"placeMarker\",\n value: function placeMarker(options) {\n var _this = this;\n\n var icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].black;\n\n if (options.type === 'store') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].blue;\n } else if (options.type === 'spot') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].green;\n } else if (options.type === 'bar') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].red;\n } else if (options.type === 'user') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].user;\n }\n\n var marker = window.L.marker([options.lat, options.lng], {\n icon: icon\n }).on('click', function () {\n // Disable center on lock if previously set to true\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('map-center-on-user') === 'true') {\n _this.toggleFocusLock();\n } // Actual fly to the marker\n\n\n _this.map.flyTo([options.lat, options.lng], 18);\n });\n\n if (options.dom) {\n marker.bindPopup(options.dom);\n } // All markers that are not spot/store/bar should be appended to the map\n\n\n if (['spot', 'store', 'bar'].indexOf(options.type) === -1) {\n marker.addTo(this.map);\n }\n\n return marker;\n }\n }, {\n key: \"drawUserMarker\",\n value: function drawUserMarker() {\n if (!this.user.marker) {\n // Create user marker if not existing\n this.user.type = 'user';\n this.user.marker = this.placeMarker(this.user); // Append circle around marker for accuracy and range for new marker\n\n this.user.radius = this.user.accuracy;\n this.user.circle = this.drawCircle(this.user);\n this.user.range = this.drawCircle({\n lat: this.user.lat,\n lng: this.user.lng,\n radius: _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].NEW_MARKER_RANGE,\n color: _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].RANGE_COLOR\n }); // Update circle opacity if pref is at true\n\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('poi-show-circle') === 'true') {\n this.user.circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n this.user.range.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n } // Callback on marker clicked to add marker on user position\n\n\n this.user.marker.on('click', this.mapClicked.bind(this));\n } else {\n // Update user marker position, range, and accuracy circle\n this.user.marker.setLatLng(this.user);\n this.user.range.setLatLng(this.user);\n this.user.circle.setLatLng(this.user);\n this.user.circle.setRadius(this.user.accuracy);\n }\n }\n }, {\n key: \"definePOI\",\n value: function definePOI(options, callback) {\n var _this2 = this;\n\n var dom = {\n wrapper: document.createElement('DIV'),\n title: document.createElement('P'),\n spot: document.createElement('BUTTON'),\n store: document.createElement('BUTTON'),\n bar: document.createElement('BUTTON')\n }; // Update class and inner HTMl content according to user's nls\n\n dom.wrapper.className = 'new-poi';\n dom.title.innerHTML = this.nls.map('newTitle');\n dom.spot.innerHTML = this.nls.map('newSpot');\n dom.store.innerHTML = this.nls.map('newStore');\n dom.bar.innerHTML = this.nls.map('newBar'); // Atach data type to each button (to be used in clicked callback)\n\n dom.spot.dataset.type = 'spot';\n dom.store.dataset.type = 'store';\n dom.bar.dataset.type = 'bar'; // DOM chaining\n\n dom.wrapper.appendChild(dom.title);\n dom.wrapper.appendChild(dom.spot);\n dom.wrapper.appendChild(dom.store);\n dom.wrapper.appendChild(dom.bar); // Update popup content with DOM elements\n\n options.dom = dom.wrapper; // Create temporary mark with wrapper content and open it to offer user the creation menu\n\n var marker = this.placeMarker(options).openPopup();\n options.marker = marker; // Attach marker to option so it can be manipulated in clicked callbacks\n\n options.addedCallback = callback; // Attach callback to be called when marker addition is done\n // Callback on button clicked (to open modal and define a new mark)\n\n var _prepareNewMark = function _prepareNewMark(e) {\n marker.isBeingDefined = true;\n marker.closePopup();\n\n _this2.defineMarkFactory(e.target.dataset.type, options);\n }; // Buttons click events\n\n\n dom.spot.addEventListener('click', _prepareNewMark);\n dom.store.addEventListener('click', _prepareNewMark);\n dom.bar.addEventListener('click', _prepareNewMark); // Listen to clicks outside of popup to close new mark\n\n marker.on('popupclose', function () {\n if (!marker.isBeingDefined) {\n marker.popupClosed = true;\n marker.removeFrom(_this2.map);\n }\n });\n return marker;\n } // ======================================================================== //\n // ---------------------- New mark in modal helper ------------------------ //\n // ======================================================================== //\n\n }, {\n key: \"defineMarkFactory\",\n value: function defineMarkFactory(type, options) {\n var _this3 = this;\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fetchTemplate(\"assets/html/modal/new\".concat(type, \".html\")).then(function (dom) {\n var name = dom.querySelector(\"#\".concat(type, \"-name\"));\n var description = dom.querySelector(\"#\".concat(type, \"-desc\"));\n var rating = new _ui_Rating_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"](dom.querySelector(\"#\".concat(type, \"-rating\")));\n var submit = dom.querySelector(\"#\".concat(type, \"-submit\"));\n var cancel = dom.querySelector(\"#\".concat(type, \"-cancel\"));\n var close = dom.querySelector('#modal-close'); // Update nls for template\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-title\")), \"{{\".concat(type.toUpperCase(), \"_TITLE}}\"), _this3.nls[type]('title'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-subtitle\")), \"{{\".concat(type.toUpperCase(), \"_SUBTITLE}}\"), _this3.nls[type]('subtitle'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-name\")), \"{{\".concat(type.toUpperCase(), \"_NAME}}\"), _this3.nls[type]('nameLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-desc\")), \"{{\".concat(type.toUpperCase(), \"_DESC}}\"), _this3.nls[type]('descLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-rate\")), \"{{\".concat(type.toUpperCase(), \"_RATE}}\"), _this3.nls[type]('rateLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(submit, \"{{\".concat(type.toUpperCase(), \"_SUBMIT}}\"), _this3.nls.nav('add'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(cancel, \"{{\".concat(type.toUpperCase(), \"_CANCEL}}\"), _this3.nls.nav('cancel')); // Method to clear modal and hide it, and remove temporary marker on the map\n\n var _cleanDefineUI = function _cleanDefineUI() {\n options.marker.isBeingDefined = false;\n options.marker.removeFrom(_this3.map); // Clear temporary black marker\n\n _this3.closeModal(null, true);\n }; // Submit or cancel event subscriptions\n\n\n submit.addEventListener('click', function () {\n if (name.value === '') {\n _this3._notification.raise(_this3.nls.notif('markNameEmpty'));\n } else {\n _cleanDefineUI();\n\n options.type = type;\n options.name = name.value, options.description = description.value;\n options.rate = rating.currentRate;\n\n _this3.markPopupFactory(options).then(function (dom) {\n options.dom = dom;\n options.marker = _this3.placeMarker(options); // Create final marker\n\n options.addedCallback(options);\n });\n }\n });\n cancel.addEventListener('click', _cleanDefineUI);\n close.addEventListener('click', _cleanDefineUI);\n\n _this3.newMarkModal(dom);\n });\n }\n }, {\n key: \"defineNewSpot\",\n value: function defineNewSpot(options) {\n this.defineMarkFactory('spot', options);\n }\n }, {\n key: \"defineNewStore\",\n value: function defineNewStore(options) {\n this.defineMarkFactory('store', options);\n }\n }, {\n key: \"defineNewBar\",\n value: function defineNewBar(options) {\n this.defineMarkFactory('bar', options);\n } // ======================================================================== //\n // ------------------------- Mark popup helper ---------------------------- //\n // ======================================================================== //\n\n }, {\n key: \"markPopupFactory\",\n value: function markPopupFactory(options) {\n var _this4 = this;\n\n return new Promise(function (resolve) {\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fetchTemplate(\"assets/html/popup/\".concat(options.type, \".html\")).then(function (dom) {\n var element = document.createElement('DIV');\n element.appendChild(dom);\n var user = options.user || _this4.user.username;\n\n var desc = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].stripDom(options.description) || _this4.nls.popup(\"\".concat(options.type, \"NoDesc\"));\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_NAME}}\"), _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].stripDom(options.name));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_FINDER}}\"), user);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_RATE}}\"), options.rate + 1);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_DESC}}\"), desc);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_FOUND_BY}}\"), _this4.nls.popup(\"\".concat(options.type, \"FoundBy\"))); // Fill mark rate (rating is in [0, 4] explaining the +1 in loop bound)\n\n var rate = element.querySelector(\"#\".concat(options.type, \"-rating\"));\n\n for (var i = 0; i < options.rate + 1; ++i) {\n rate.children[i].classList.add('active');\n } // Remove picture icon if user is not in range\n\n\n var distance = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getDistanceBetweenCoords([_this4.user.lat, _this4.user.lng], [options.lat, options.lng]);\n\n if (distance > _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].CIRCLE_RADIUS) {\n console.log('Too far'); //element.removeChild(element.querySelector(''));\n } // Remove edition buttons if marker is not user's one, this does not replace a server test for edition...\n\n\n if (user !== _this4.user.username) {\n element.removeChild(element.querySelector('#popup-edit'));\n } else {\n element.querySelector('#edit-mark').addEventListener('click', _this4.editMarker.bind(_this4, options), false);\n element.querySelector('#delete-mark').addEventListener('click', _this4.deleteMarker.bind(_this4, options), false);\n } // Append circle around marker\n\n\n options.color = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"][\"\".concat(options.type.toUpperCase(), \"_COLOR\")];\n options.circle = _this4.drawCircle(options); // Create label for new marker\n\n options.tooltip = window.L.tooltip({\n permanent: true,\n direction: 'center',\n className: 'marker-tooltip',\n interactive: true\n }).setContent(options.name).setLatLng(options.circle.getLatLng()); // Only make it visible if preference is to true\n\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('poi-marker-label') === 'true') {\n options.tooltip.addTo(_this4.map);\n } // Send back the popup\n\n\n resolve(element);\n });\n });\n }\n }, {\n key: \"drawCircle\",\n value: function drawCircle(options) {\n return window.L.circle(options, {\n color: options.color,\n fillColor: options.color,\n opacity: 0,\n // This needs to be updated according to user proximity\n fillOpacity: 0,\n // Same for this parameter\n radius: options.radius ? options.radius : _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].CIRCLE_RADIUS\n }).addTo(this.map);\n }\n }, {\n key: \"setMarkerCircles\",\n value: function setMarkerCircles(marks, visible) {\n for (var i = 0; i < marks.length; ++i) {\n // Here we update both opacity and add/remove circle from map\n if (visible) {\n marks[i].circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n marks[i].circle.addTo(this.map);\n } else {\n marks[i].circle.setStyle({\n opacity: 0,\n fillOpacity: 0\n });\n marks[i].circle.removeFrom(this.map);\n }\n }\n }\n }, {\n key: \"setMarkerLabels\",\n value: function setMarkerLabels(marks, visible) {\n for (var i = 0; i < marks.length; ++i) {\n if (visible) {\n marks[i].tooltip.addTo(this.map);\n } else {\n marks[i].tooltip.removeFrom(this.map);\n }\n }\n }\n }]);\n\n return MapHelper;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (MapHelper);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/MapHelper.js?"); + +/***/ }), + +/***/ "./src/js/ui/Notification.js": +/*!***********************************!*\ + !*** ./src/js/ui/Notification.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Notification = /*#__PURE__*/function () {\n function Notification() {\n _classCallCheck(this, Notification);\n\n this._container = document.querySelector('#notification-wrapper');\n this._message = document.querySelector('#notification-message');\n this._timeoutId = null;\n }\n\n _createClass(Notification, [{\n key: \"raise\",\n value: function raise(message) {\n var _this = this;\n\n clearTimeout(this._timeoutId);\n this._message.innerHTML = message;\n\n this._container.classList.add('opened');\n\n this._timeoutId = setTimeout(function () {\n _this._container.classList.remove('opened');\n\n _this._message.innerHTML = '';\n }, 2000);\n }\n }]);\n\n return Notification;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Notification);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/Notification.js?"); + +/***/ }), + +/***/ "./src/js/ui/Rating.js": +/*!*****************************!*\ + !*** ./src/js/ui/Rating.js ***! + \*****************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Rating = /*#__PURE__*/function () {\n function Rating(domList, rate) {\n _classCallCheck(this, Rating);\n\n this._container = null;\n this._items = [];\n this._currentRate = rate || 0; // Mostly for hover operations\n\n this._clicked = rate || -1; // To know when user clicked on a given star\n\n this._init(domList);\n\n this._events();\n }\n\n _createClass(Rating, [{\n key: \"_init\",\n value: function _init(domList) {\n this._container = domList;\n\n for (var i = 0; i < domList.children.length; ++i) {\n this._items.push(domList.children[i]);\n } // Init Rating with given rate\n\n\n for (var _i = 0; _i < this._currentRate + 1; ++_i) {\n this._items[_i].classList.add('active');\n\n this._items[_i].classList.add('selected');\n }\n }\n }, {\n key: \"_events\",\n value: function _events() {\n this._container.addEventListener('mouseover', this._containerHovered.bind(this), false);\n\n this._container.addEventListener('mouseout', this._pointerExit.bind(this), false);\n\n for (var i = 0; i < this._items.length; ++i) {\n this._items[i].addEventListener('click', this._starClicked.bind(this), false);\n }\n }\n }, {\n key: \"_containerHovered\",\n value: function _containerHovered(event) {\n if (event.target.tagName === 'IMG') {\n this._currentRate = parseInt(event.target.dataset.id);\n this._container.dataset.rate = this._currentRate;\n this.updateStars();\n }\n }\n }, {\n key: \"_pointerExit\",\n value: function _pointerExit() {\n this._currentRate = this._clicked === -1 ? 0 : this._clicked;\n this._container.dataset.rate = this._currentRate;\n this.updateStars();\n }\n }, {\n key: \"_starClicked\",\n value: function _starClicked(event) {\n this._currentRate = parseInt(event.target.dataset.id);\n this._container.dataset.rate = this._currentRate;\n this._clicked = this._currentRate;\n this.updateStars();\n }\n }, {\n key: \"updateStars\",\n value: function updateStars() {\n for (var i = 0; i < this._items.length; ++i) {\n if (i <= this._currentRate) {\n this._items[i].classList.add('active');\n\n if (i <= this._clicked) {\n this._items[i].classList.add('selected');\n }\n } else {\n this._items[i].classList.remove('active');\n\n this._items[i].classList.remove('selected');\n }\n }\n }\n }, {\n key: \"currentRate\",\n get: function get() {\n return this._currentRate;\n }\n }]);\n\n return Rating;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Rating);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/Rating.js?"); + +/***/ }), + +/***/ "./src/js/ui/ZoomSlider.js": +/*!*********************************!*\ + !*** ./src/js/ui/ZoomSlider.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar ZoomSlider = /*#__PURE__*/function () {\n function ZoomSlider(map) {\n _classCallCheck(this, ZoomSlider);\n\n this._map = map;\n this._container = document.querySelector('#zoom-slider');\n this._slider = document.querySelector('#slider-position');\n this._zoomRange = this._map.getMaxZoom() - this._map.getMinZoom();\n this._timeoutId = -1;\n\n this._events();\n }\n\n _createClass(ZoomSlider, [{\n key: \"_events\",\n value: function _events() {\n var _this = this;\n\n this._map.on('zoomstart', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n\n _this._container.classList.add('opened');\n });\n\n this._map.on('zoomend', function () {\n var correctedZoom = _this._map.getZoom() - _this._map.getMinZoom();\n\n _this._slider.style.height = \"\".concat(correctedZoom * 100 / _this._zoomRange, \"%\");\n _this._timeoutId = setTimeout(function () {\n return _this._container.classList.remove('opened');\n }, 1500);\n });\n\n this._map.on('zoom', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n\n var correctedZoom = _this._map.getZoom() - _this._map.getMinZoom();\n\n _this._slider.style.height = \"\".concat(correctedZoom * 100 / _this._zoomRange, \"%\");\n });\n\n this._container.addEventListener('mouseover', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n });\n\n this._container.addEventListener('mouseleave', function () {\n _this._timeoutId = setTimeout(function () {\n return _this._container.classList.remove('opened');\n }, 1500);\n });\n\n this._container.querySelector('#zoom-more').addEventListener('click', function () {\n _this._map.setZoom(_this._map.getZoom() + 1);\n });\n\n this._container.querySelector('#zoom-less').addEventListener('click', function () {\n _this._map.setZoom(_this._map.getZoom() - 1);\n });\n }\n }]);\n\n return ZoomSlider;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ZoomSlider);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/ZoomSlider.js?"); + +/***/ }), + +/***/ "./src/js/utils/LangManager.js": +/*!*************************************!*\ + !*** ./src/js/utils/LangManager.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _Utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar LangManager = /*#__PURE__*/function () {\n function LangManager(lang, cb) {\n _classCallCheck(this, LangManager);\n\n this._lang = _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SUPPORTED_LANGUAGE.indexOf(lang) !== -1 ? lang : 'en';\n this._values = {};\n\n this._init().then(cb);\n }\n\n _createClass(LangManager, [{\n key: \"_init\",\n value: function _init() {\n var _this = this;\n\n return new Promise(function (resolve, reject) {\n _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].fetchFile(\"assets/nls/\".concat(_this._lang, \".json\")).then(function (lang) {\n _this._values = JSON.parse(lang);\n resolve();\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"debug\",\n value: function debug(key) {\n return this._values.debug[key] || '';\n }\n }, {\n key: \"notif\",\n value: function notif(key) {\n return this._values.notif[key] || '';\n }\n }, {\n key: \"nav\",\n value: function nav(key) {\n return this._values.nav[key] || '';\n }\n }, {\n key: \"map\",\n value: function map(key) {\n return this._values.map[key] || '';\n }\n }, {\n key: \"spot\",\n value: function spot(key) {\n return this._values.spot[key] || '';\n }\n }, {\n key: \"store\",\n value: function store(key) {\n return this._values.store[key] || '';\n }\n }, {\n key: \"bar\",\n value: function bar(key) {\n return this._values.bar[key] || '';\n }\n }, {\n key: \"popup\",\n value: function popup(key) {\n return this._values.popup[key] || '';\n }\n }, {\n key: \"modal\",\n value: function modal(key) {\n return this._values.modal[key] || '';\n }\n }, {\n key: \"login\",\n value: function login(key) {\n return this._values.auth.login[key] || '';\n }\n }, {\n key: \"register\",\n value: function register(key) {\n return this._values.auth.register[key] || '';\n }\n }]);\n\n return LangManager;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (LangManager);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/LangManager.js?"); + +/***/ }), + +/***/ "./src/js/utils/MarkerEnum.js": +/*!************************************!*\ + !*** ./src/js/utils/MarkerEnum.js ***! + \************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Object.freeze({\n blue: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-blue.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n gold: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-gold.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n red: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-red.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n green: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-green.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n orange: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-orange.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n yellow: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-yellow.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n violet: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-violet.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n grey: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-grey.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n black: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-black.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n user: new window.L.Icon({\n iconUrl: 'assets/img/marker/user-position.png',\n shadowUrl: 'assets/img/marker/user-position-shadow.png',\n iconSize: [32, 32],\n iconAnchor: [16, 16],\n popupAnchor: [1, -34],\n shadowSize: [32, 32]\n })\n}));\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/MarkerEnum.js?"); + +/***/ }), + +/***/ "./src/js/utils/ProviderEnum.js": +/*!**************************************!*\ + !*** ./src/js/utils/ProviderEnum.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Object.freeze({\n planOsm: window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n attribution: '© OpenStreetMap',\n maxZoom: 21,\n maxNativeZoom: 19,\n // To ensure tiles are not unloaded when zooming after 19\n minZoom: 2 // Don't allow dezooming too far from map so it always stay fully visible\n\n }),\n\n /*planGeo: window.L.tileLayer('https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', {\n attribution: '© Geoportail France',\n apikey: 'choisirgeoportail',\n format: 'image/png',\n style: 'normal',\n minZoom: 2, // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19, // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21,\n }),*/\n satEsri: window.L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {\n attribution: '© Esri Imagery',\n minZoom: 2,\n // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19,\n // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21\n })\n /*satGeo: window.L.tileLayer('https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', {\n attribution: '© Geoportail France',\n apikey: 'choisirgeoportail',\n format: 'image/jpeg',\n style: 'normal',\n minZoom: 2, // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19, // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21 \n })*/\n\n}));\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/ProviderEnum.js?"); + +/***/ }), + +/***/ "./src/js/utils/Utils.js": +/*!*******************************!*\ + !*** ./src/js/utils/Utils.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Utils = /*#__PURE__*/function () {\n function Utils() {\n /* Not meant to be instantiated, all methods should be static */\n\n _classCallCheck(this, Utils);\n }\n\n _createClass(Utils, null, [{\n key: \"fetchTemplate\",\n value: function fetchTemplate(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(function (html) {\n resolve(document.createRange().createContextualFragment(html));\n })[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"fetchFile\",\n value: function fetchFile(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"getReq\",\n value: function getReq(url) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'GET',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default'\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"postReq\",\n value: function postReq(url, data) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'POST',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default',\n body: data\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"stripDom\",\n value: function stripDom(html) {\n var doc = new DOMParser().parseFromString(html, 'text/html');\n return doc.body.textContent || '';\n }\n }, {\n key: \"replaceString\",\n value: function replaceString(element, string, value) {\n element.innerHTML = element.innerHTML.replace(string, value);\n }\n }, {\n key: \"getDistanceBetweenCoords\",\n value: function getDistanceBetweenCoords(from, to) {\n // return distance in meters\n var lon1 = from[1] * Math.PI / 180,\n lat1 = from[0] * Math.PI / 180,\n lon2 = to[1] * Math.PI / 180,\n lat2 = to[0] * Math.PI / 180;\n var deltaLat = lat2 - lat1;\n var deltaLon = lon2 - lon1;\n var a = Math.pow(Math.sin(deltaLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2), 2);\n var c = 2 * Math.asin(Math.sqrt(a));\n var EARTH_RADIUS = 6371;\n return c * EARTH_RADIUS * 1000;\n }\n /** @method\n * @name precisionRound\n * @public\n * @memberof Utils\n * @author Arthur Beaulieu\n * @since September 2018\n * @description Do a Math.round with a given precision (ie amount of integers after the coma)\n * @param {nunmber} value - The value to precisely round\n * @param {number} precision - The number of integers after the coma\n * @return {number} - The rounded value */\n\n }, {\n key: \"precisionRound\",\n value: function precisionRound(value, precision) {\n var multiplier = Math.pow(10, precision || 0);\n return Math.round(value * multiplier) / multiplier;\n }\n }, {\n key: \"initDebugInterface\",\n value: function initDebugInterface() {\n var lang = window.BeerCrackerz.nls.debug.bind(window.BeerCrackerz.nls);\n var debugContainer = document.createElement('DIV');\n var userLat = document.createElement('P');\n var userLng = document.createElement('P');\n var updatesAmount = document.createElement('P');\n var userAccuracy = document.createElement('P');\n var highAccuracy = document.createElement('P');\n var maxAge = document.createElement('P');\n var posTimeout = document.createElement('P');\n var zoomLevel = document.createElement('P');\n var marks = document.createElement('P');\n var exportData = document.createElement('BUTTON');\n debugContainer.classList.add('debug-container');\n userLat.classList.add('debug-user-lat');\n userLng.classList.add('debug-user-lng');\n updatesAmount.classList.add('debug-updates-amount');\n userAccuracy.classList.add('debug-user-accuracy');\n highAccuracy.classList.add('debug-high-accuracy');\n maxAge.classList.add('debug-pos-max-age');\n posTimeout.classList.add('debug-pos-timeout');\n zoomLevel.classList.add('debug-zoom-level');\n marks.classList.add('debug-marks-amount');\n exportData.classList.add('debug-export-data');\n userLat.innerHTML = \"\".concat(lang('lat'), \" : -\");\n userLng.innerHTML = \"\".concat(lang('lng'), \" : -\");\n updatesAmount.innerHTML = \"\".concat(lang('updates'), \" : 0\");\n userAccuracy.innerHTML = \"\".concat(lang('accuracy'), \" : -\");\n highAccuracy.innerHTML = \"\".concat(lang('highAccuracy'), \" : -\");\n maxAge.innerHTML = \"\".concat(lang('posAge'), \" : -\");\n posTimeout.innerHTML = \"\".concat(lang('posTimeout'), \" : -\");\n zoomLevel.innerHTML = \"\".concat(lang('zoom'), \" : -\");\n marks.innerHTML = \"\".concat(lang('marks'), \" : -\");\n exportData.innerHTML = lang('export');\n debugContainer.appendChild(userLat);\n debugContainer.appendChild(userLng);\n debugContainer.appendChild(updatesAmount);\n debugContainer.appendChild(userAccuracy);\n debugContainer.appendChild(highAccuracy);\n debugContainer.appendChild(maxAge);\n debugContainer.appendChild(posTimeout);\n debugContainer.appendChild(zoomLevel);\n debugContainer.appendChild(marks);\n debugContainer.appendChild(exportData);\n exportData.addEventListener('click', window.BeerCrackerz.downloadData.bind(window.BeerCrackerz));\n return debugContainer;\n }\n }, {\n key: \"updateDebugInterface\",\n value: function updateDebugInterface(element, user, options) {\n if (window.DEBUG === true) {\n var bc = window.BeerCrackerz;\n var lang = bc.nls.debug.bind(bc.nls);\n var updates = parseInt(element.querySelector('.debug-updates-amount').innerHTML.split(' : ')[1]) + 1;\n var marks = bc.marks.spot.length + bc.marks.store.length + bc.marks.bar.length;\n element.querySelector('.debug-user-lat').innerHTML = \"\\n \".concat(lang('lat'), \" : \").concat(user.lat, \"\\n \");\n element.querySelector('.debug-user-lng').innerHTML = \"\\n \".concat(lang('lng'), \" : \").concat(user.lng, \"\\n \");\n element.querySelector('.debug-updates-amount').innerHTML = \"\\n \".concat(lang('updates'), \" : \").concat(updates, \"\\n \");\n element.querySelector('.debug-user-accuracy').innerHTML = \"\\n \".concat(lang('accuracy'), \" : \").concat(Utils.precisionRound(user.accuracy, 2), \"m\\n \");\n element.querySelector('.debug-high-accuracy').innerHTML = \"\\n \".concat(lang('highAccuracy'), \" : \").concat(options.enableHighAccuracy === true ? lang('enabled') : lang('disabled'), \"\\n \");\n element.querySelector('.debug-pos-max-age').innerHTML = \"\\n \".concat(lang('posAge'), \" : \").concat(options.maximumAge / 1000, \"s\\n \");\n element.querySelector('.debug-pos-timeout').innerHTML = \"\\n \".concat(lang('posTimeout'), \" : \").concat(options.timeout / 1000, \"s\\n \");\n element.querySelector('.debug-zoom-level').innerHTML = \"\\n \".concat(lang('zoom'), \" : \").concat(bc.map.getZoom(), \"\\n \");\n element.querySelector('.debug-marks-amount').innerHTML = \"\\n \".concat(lang('marks'), \" : \").concat(marks, \"\\n \");\n }\n }\n }, {\n key: \"getPreference\",\n value: function getPreference(pref) {\n return localStorage.getItem(pref) || null;\n }\n }, {\n key: \"setPreference\",\n value: function setPreference(pref, value) {\n localStorage.setItem(pref, value);\n }\n }, {\n key: \"RANGE_COLOR\",\n get: function get() {\n return '#ffd87d';\n }\n }, {\n key: \"USER_COLOR\",\n get: function get() {\n return '#63fff5';\n }\n }, {\n key: \"SPOT_COLOR\",\n get: function get() {\n return '#26ad23';\n }\n }, {\n key: \"STORE_COLOR\",\n get: function get() {\n return '#247dc9';\n }\n }, {\n key: \"BAR_COLOR\",\n get: function get() {\n return '#ca2a3d';\n }\n }, {\n key: \"CIRCLE_RADIUS\",\n get: function get() {\n return 100;\n }\n }, {\n key: \"NEW_MARKER_RANGE\",\n get: function get() {\n return 200;\n }\n }, {\n key: \"MAP_BOUNDS\",\n get: function get() {\n return window.L.latLngBounds(window.L.latLng(-89.98155760646617, -180), window.L.latLng(89.99346179538875, 180));\n }\n }, {\n key: \"HIGH_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: true,\n // More consuption, better position\n maximumAge: 1000,\n // A position will last 1s maximum\n timeout: 900 // A position is updated in 0.9s maximum\n\n };\n }\n }, {\n key: \"OPTIMIZED_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: false,\n // Less consuption\n maximumAge: 30000,\n // A position will last 30s maximum\n timeout: 29000 // A position is updated in 29s maximum\n\n };\n }\n }, {\n key: \"SUPPORTED_LANGUAGE\",\n get: function get() {\n return ['en', 'fr', 'es', 'de'];\n }\n }]);\n\n return Utils;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/Utils.js?"); + +/***/ }), + +/***/ "./src/BeerCrackerz.scss": +/*!*******************************!*\ + !*** ./src/BeerCrackerz.scss ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerz.scss?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/BeerCrackerz.js"); +/******/ window.BeerCrackerz = __webpack_exports__["default"]; +/******/ +/******/ })() +; \ No newline at end of file diff --git a/assets/dist/BeerCrackerzAuth.bundle.css b/front/assets/dist/BeerCrackerzAuth.bundle.css similarity index 87% rename from assets/dist/BeerCrackerzAuth.bundle.css rename to front/assets/dist/BeerCrackerzAuth.bundle.css index e1a088f..1c16b47 100644 --- a/assets/dist/BeerCrackerzAuth.bundle.css +++ b/front/assets/dist/BeerCrackerzAuth.bundle.css @@ -1 +1,4 @@ +/*!**********************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].use[2]!./node_modules/sass-loader/dist/cjs.js!./src/BeerCrackerzAuth.scss ***! + \**********************************************************************************************************************************************************************************************************************/ @-webkit-keyframes flashing-logo{0%{-webkit-text-fill-color:transparent;background:linear-gradient(60deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}15%{-webkit-text-fill-color:transparent;background:linear-gradient(120deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}58%{-webkit-text-fill-color:transparent;background:-webkit-gradient(linear,left top,left bottom,from(#97ea9b),color-stop(80%,#ad7fe6));background:linear-gradient(180deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1)}to{-webkit-text-fill-color:transparent;background:linear-gradient(240deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0;-webkit-transform:scale(1);transform:scale(1)}}@keyframes flashing-logo{0%{-webkit-text-fill-color:transparent;background:linear-gradient(60deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}15%{-webkit-text-fill-color:transparent;background:linear-gradient(120deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}58%{-webkit-text-fill-color:transparent;background:-webkit-gradient(linear,left top,left bottom,from(#97ea9b),color-stop(80%,#ad7fe6));background:linear-gradient(180deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1)}to{-webkit-text-fill-color:transparent;background:linear-gradient(240deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0;-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes drop-nav-link{0%{margin-bottom:20rem;-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}to{margin-bottom:0;-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes drop-nav-link{0%{margin-bottom:20rem;-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}to{margin-bottom:0;-webkit-transform:rotate(0);transform:rotate(0)}}@-webkit-keyframes beating{0%{-webkit-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.01);transform:scale(1.01)}20%{-webkit-transform:scale(1);transform:scale(1)}80%{-webkit-transform:scale(1);transform:scale(1)}90%{-webkit-transform:scale(1.02);transform:scale(1.02)}to{-webkit-transform:scale(1);transform:scale(1)}}@keyframes beating{0%{-webkit-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.01);transform:scale(1.01)}20%{-webkit-transform:scale(1);transform:scale(1)}80%{-webkit-transform:scale(1);transform:scale(1)}90%{-webkit-transform:scale(1.02);transform:scale(1.02)}to{-webkit-transform:scale(1);transform:scale(1)}}*{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}body,html{font-size:62.5%;height:100%;overflow:hidden;width:100%}body{background:#181818;color:#d4d4d4;font-family:sans-serif}h1{color:#181818;font-size:2.8rem;margin-bottom:1.2rem}h2{font-size:2.4rem}a{color:#a1ff86}a,label,p{font-size:1.2rem;margin-bottom:1.2rem}label,p{color:#2e2e2e}label{font-style:italic}input,textarea{border:1px solid #424242;border-radius:.5rem;display:block;margin:.5rem auto 1.2rem;padding:.5rem;-webkit-transition:border .2s;transition:border .2s;width:100%}input.error{border-color:#ff5454}button{background-color:hsla(0,0%,91%,.667);border:1px solid #424242;border-radius:.5rem;cursor:pointer;display:block;margin:.5rem auto;padding:.5rem;-webkit-transition:background-color .2s;transition:background-color .2s;width:100%}button:active,button:focus,button:hover{background-color:hsla(0,0%,85%,.667)}button.validate{background-color:rgba(161,255,134,.667)}button.cancel{background-color:hsla(0,100%,80%,.667)}body{background:#fff;position:relative}aside,body{height:100%;width:100%}aside{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:justify;-ms-flex-pack:justify;background-color:grey;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:space-between;max-width:40rem;position:absolute;right:0;text-align:center}aside h1{margin-bottom:0}aside header{margin-top:5rem}aside main{margin:0 4rem;text-align:left}aside main button{margin:2.9rem auto 1.2rem}aside main p{text-align:right}aside main .login-error{color:transparent;font-style:italic;font-weight:700;text-align:center;-webkit-transition:color .2s;transition:color .2s}aside main .login-error.visible{color:#ff5454}aside footer{margin-bottom:5rem} diff --git a/front/assets/dist/BeerCrackerzAuth.bundle.js b/front/assets/dist/BeerCrackerzAuth.bundle.js new file mode 100644 index 0000000..1bb8466 --- /dev/null +++ b/front/assets/dist/BeerCrackerzAuth.bundle.js @@ -0,0 +1,117 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/BeerCrackerzAuth.js": +/*!*********************************!*\ + !*** ./src/BeerCrackerzAuth.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _BeerCrackerzAuth_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BeerCrackerzAuth.scss */ \"./src/BeerCrackerzAuth.scss\");\n/* harmony import */ var _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/utils/LangManager.js */ \"./src/js/utils/LangManager.js\");\n/* harmony import */ var _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./js/utils/Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\n\nvar BeerCrackerzAuth = /*#__PURE__*/function () {\n function BeerCrackerzAuth() {\n _classCallCheck(this, BeerCrackerzAuth);\n\n var _init = function _init() {};\n\n if (document.body.className.includes('login')) {\n _init = this._handleLogin.bind(this);\n } else if (document.body.className.includes('register')) {\n _init = this._handleRegister.bind(this);\n } // The BeerCrackerz app is only initialized once nls are set up\n\n\n this._lang = new _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"](window.navigator.language.substring(0, 2), _init.bind(this));\n }\n\n _createClass(BeerCrackerzAuth, [{\n key: \"_handleLogin\",\n value: function _handleLogin() {\n var _this = this;\n\n // Update page nls according to browser language\n document.title = this.nls.login('headTitle');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_SUBTITLE}}', this.nls.login('subtitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_HIDDEN_ERROR}}', this.nls.login('hiddenError'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_USERNAME_LABEL}}', this.nls.login('username'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_USERNAME_PASSWORD}}', this.nls.login('password'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_BUTTON}}', this.nls.login('login'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_NOT_REGISTERED}}', this.nls.login('notRegistered'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_REGISTER}}', this.nls.login('register'));\n var error = document.getElementById('login-error');\n var username = document.getElementById('username');\n var password = document.getElementById('password'); // useful login method for field check and server response check\n\n var _frontFieldValidation = function _frontFieldValidation() {\n // Handling empty error cases\n if (username.value === '' && password.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('bothEmpty');\n username.classList.add('error');\n password.classList.add('error');\n return false;\n } else if (username.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('usernameEmpty');\n username.classList.add('error');\n return false;\n } else if (password.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('passwordEmpty');\n password.classList.add('error');\n return false;\n }\n\n return true;\n };\n\n var _backValidation = function _backValidation(response) {\n // Check response and handle status codes\n console.log(response); // If all front and back tests are ok, redirect to auth\n // If the user ma nually force redirection to authindex,\n // the server should reject the request as the user is not authenticated\n\n window.location = 'authindex.html';\n }; // Submit click event\n\n\n document.getElementById('login-submit').addEventListener('click', function () {\n // Reset error css classes\n error.classList.remove('visible');\n username.classList.remove('error');\n password.classList.remove('error');\n\n if (_frontFieldValidation()) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].postReq('/api/login/submit').then(_backValidation)[\"catch\"](function () {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('serverError');\n });\n }\n }, false);\n }\n }, {\n key: \"_handleRegister\",\n value: function _handleRegister() {\n var _this2 = this;\n\n // Update page nls according to browser language\n document.title = this.nls.register('headTitle');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_SUBTITLE}}', this.nls.register('subtitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_HIDDEN_ERROR}}', this.nls.register('hiddenError'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_LABEL}}', this.nls.register('username'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_PASSWORD_1}}', this.nls.register('password1'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_PASSWORD_2}}', this.nls.register('password2'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_BUTTON}}', this.nls.register('register'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_ALREADY_DONE}}', this.nls.register('notRegistered'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_LOGIN}}', this.nls.register('login'));\n var error = document.getElementById('register-error');\n var username = document.getElementById('username');\n var password1 = document.getElementById('password1');\n var password2 = document.getElementById('password2'); // useful login method for field check and server response check\n\n var _frontFieldValidation = function _frontFieldValidation() {\n // Handling empty error cases\n if (username.value === '' || password1.value === '' || password2.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('fieldEmpty');\n\n if (username.value === '') {\n username.classList.add('error');\n }\n\n if (password1.value === '') {\n password1.classList.add('error');\n }\n\n if (password2.value === '') {\n password2.classList.add('error');\n }\n\n return false;\n } else if (password1.value !== password2.value) {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('notMatchingPassword');\n password1.classList.add('error');\n password2.classList.add('error');\n return false;\n }\n\n return true;\n };\n\n var _backValidation = function _backValidation(response) {\n // Check response and handle status codes\n console.log(response); // If all front and back tests are ok, redirect to auth\n // If the user ma nually force redirection to authindex,\n // the server should reject the request as the user is not authenticated\n\n window.location = 'authindex.html';\n }; // Submit click event\n\n\n document.getElementById('register-submit').addEventListener('click', function () {\n // Reset error css classes\n error.classList.remove('visible');\n username.classList.remove('error');\n password1.classList.remove('error');\n password2.classList.remove('error');\n\n if (_frontFieldValidation()) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].postReq('/api/register/submit').then(_backValidation)[\"catch\"](function () {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('serverError');\n });\n }\n }, false);\n }\n }, {\n key: \"nls\",\n get: function get() {\n return this._lang;\n }\n }]);\n\n return BeerCrackerzAuth;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BeerCrackerzAuth);\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerzAuth.js?"); + +/***/ }), + +/***/ "./src/js/utils/LangManager.js": +/*!*************************************!*\ + !*** ./src/js/utils/LangManager.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _Utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar LangManager = /*#__PURE__*/function () {\n function LangManager(lang, cb) {\n _classCallCheck(this, LangManager);\n\n this._lang = _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SUPPORTED_LANGUAGE.indexOf(lang) !== -1 ? lang : 'en';\n this._values = {};\n\n this._init().then(cb);\n }\n\n _createClass(LangManager, [{\n key: \"_init\",\n value: function _init() {\n var _this = this;\n\n return new Promise(function (resolve, reject) {\n _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].fetchFile(\"assets/nls/\".concat(_this._lang, \".json\")).then(function (lang) {\n _this._values = JSON.parse(lang);\n resolve();\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"debug\",\n value: function debug(key) {\n return this._values.debug[key] || '';\n }\n }, {\n key: \"notif\",\n value: function notif(key) {\n return this._values.notif[key] || '';\n }\n }, {\n key: \"nav\",\n value: function nav(key) {\n return this._values.nav[key] || '';\n }\n }, {\n key: \"map\",\n value: function map(key) {\n return this._values.map[key] || '';\n }\n }, {\n key: \"spot\",\n value: function spot(key) {\n return this._values.spot[key] || '';\n }\n }, {\n key: \"store\",\n value: function store(key) {\n return this._values.store[key] || '';\n }\n }, {\n key: \"bar\",\n value: function bar(key) {\n return this._values.bar[key] || '';\n }\n }, {\n key: \"popup\",\n value: function popup(key) {\n return this._values.popup[key] || '';\n }\n }, {\n key: \"modal\",\n value: function modal(key) {\n return this._values.modal[key] || '';\n }\n }, {\n key: \"login\",\n value: function login(key) {\n return this._values.auth.login[key] || '';\n }\n }, {\n key: \"register\",\n value: function register(key) {\n return this._values.auth.register[key] || '';\n }\n }]);\n\n return LangManager;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (LangManager);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/LangManager.js?"); + +/***/ }), + +/***/ "./src/js/utils/Utils.js": +/*!*******************************!*\ + !*** ./src/js/utils/Utils.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Utils = /*#__PURE__*/function () {\n function Utils() {\n /* Not meant to be instantiated, all methods should be static */\n\n _classCallCheck(this, Utils);\n }\n\n _createClass(Utils, null, [{\n key: \"fetchTemplate\",\n value: function fetchTemplate(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(function (html) {\n resolve(document.createRange().createContextualFragment(html));\n })[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"fetchFile\",\n value: function fetchFile(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"getReq\",\n value: function getReq(url) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'GET',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default'\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"postReq\",\n value: function postReq(url, data) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'POST',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default',\n body: data\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"stripDom\",\n value: function stripDom(html) {\n var doc = new DOMParser().parseFromString(html, 'text/html');\n return doc.body.textContent || '';\n }\n }, {\n key: \"replaceString\",\n value: function replaceString(element, string, value) {\n element.innerHTML = element.innerHTML.replace(string, value);\n }\n }, {\n key: \"getDistanceBetweenCoords\",\n value: function getDistanceBetweenCoords(from, to) {\n // return distance in meters\n var lon1 = from[1] * Math.PI / 180,\n lat1 = from[0] * Math.PI / 180,\n lon2 = to[1] * Math.PI / 180,\n lat2 = to[0] * Math.PI / 180;\n var deltaLat = lat2 - lat1;\n var deltaLon = lon2 - lon1;\n var a = Math.pow(Math.sin(deltaLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2), 2);\n var c = 2 * Math.asin(Math.sqrt(a));\n var EARTH_RADIUS = 6371;\n return c * EARTH_RADIUS * 1000;\n }\n /** @method\n * @name precisionRound\n * @public\n * @memberof Utils\n * @author Arthur Beaulieu\n * @since September 2018\n * @description Do a Math.round with a given precision (ie amount of integers after the coma)\n * @param {nunmber} value - The value to precisely round\n * @param {number} precision - The number of integers after the coma\n * @return {number} - The rounded value */\n\n }, {\n key: \"precisionRound\",\n value: function precisionRound(value, precision) {\n var multiplier = Math.pow(10, precision || 0);\n return Math.round(value * multiplier) / multiplier;\n }\n }, {\n key: \"initDebugInterface\",\n value: function initDebugInterface() {\n var lang = window.BeerCrackerz.nls.debug.bind(window.BeerCrackerz.nls);\n var debugContainer = document.createElement('DIV');\n var userLat = document.createElement('P');\n var userLng = document.createElement('P');\n var updatesAmount = document.createElement('P');\n var userAccuracy = document.createElement('P');\n var highAccuracy = document.createElement('P');\n var maxAge = document.createElement('P');\n var posTimeout = document.createElement('P');\n var zoomLevel = document.createElement('P');\n var marks = document.createElement('P');\n var exportData = document.createElement('BUTTON');\n debugContainer.classList.add('debug-container');\n userLat.classList.add('debug-user-lat');\n userLng.classList.add('debug-user-lng');\n updatesAmount.classList.add('debug-updates-amount');\n userAccuracy.classList.add('debug-user-accuracy');\n highAccuracy.classList.add('debug-high-accuracy');\n maxAge.classList.add('debug-pos-max-age');\n posTimeout.classList.add('debug-pos-timeout');\n zoomLevel.classList.add('debug-zoom-level');\n marks.classList.add('debug-marks-amount');\n exportData.classList.add('debug-export-data');\n userLat.innerHTML = \"\".concat(lang('lat'), \" : -\");\n userLng.innerHTML = \"\".concat(lang('lng'), \" : -\");\n updatesAmount.innerHTML = \"\".concat(lang('updates'), \" : 0\");\n userAccuracy.innerHTML = \"\".concat(lang('accuracy'), \" : -\");\n highAccuracy.innerHTML = \"\".concat(lang('highAccuracy'), \" : -\");\n maxAge.innerHTML = \"\".concat(lang('posAge'), \" : -\");\n posTimeout.innerHTML = \"\".concat(lang('posTimeout'), \" : -\");\n zoomLevel.innerHTML = \"\".concat(lang('zoom'), \" : -\");\n marks.innerHTML = \"\".concat(lang('marks'), \" : -\");\n exportData.innerHTML = lang('export');\n debugContainer.appendChild(userLat);\n debugContainer.appendChild(userLng);\n debugContainer.appendChild(updatesAmount);\n debugContainer.appendChild(userAccuracy);\n debugContainer.appendChild(highAccuracy);\n debugContainer.appendChild(maxAge);\n debugContainer.appendChild(posTimeout);\n debugContainer.appendChild(zoomLevel);\n debugContainer.appendChild(marks);\n debugContainer.appendChild(exportData);\n exportData.addEventListener('click', window.BeerCrackerz.downloadData.bind(window.BeerCrackerz));\n return debugContainer;\n }\n }, {\n key: \"updateDebugInterface\",\n value: function updateDebugInterface(element, user, options) {\n if (window.DEBUG === true) {\n var bc = window.BeerCrackerz;\n var lang = bc.nls.debug.bind(bc.nls);\n var updates = parseInt(element.querySelector('.debug-updates-amount').innerHTML.split(' : ')[1]) + 1;\n var marks = bc.marks.spot.length + bc.marks.store.length + bc.marks.bar.length;\n element.querySelector('.debug-user-lat').innerHTML = \"\\n \".concat(lang('lat'), \" : \").concat(user.lat, \"\\n \");\n element.querySelector('.debug-user-lng').innerHTML = \"\\n \".concat(lang('lng'), \" : \").concat(user.lng, \"\\n \");\n element.querySelector('.debug-updates-amount').innerHTML = \"\\n \".concat(lang('updates'), \" : \").concat(updates, \"\\n \");\n element.querySelector('.debug-user-accuracy').innerHTML = \"\\n \".concat(lang('accuracy'), \" : \").concat(Utils.precisionRound(user.accuracy, 2), \"m\\n \");\n element.querySelector('.debug-high-accuracy').innerHTML = \"\\n \".concat(lang('highAccuracy'), \" : \").concat(options.enableHighAccuracy === true ? lang('enabled') : lang('disabled'), \"\\n \");\n element.querySelector('.debug-pos-max-age').innerHTML = \"\\n \".concat(lang('posAge'), \" : \").concat(options.maximumAge / 1000, \"s\\n \");\n element.querySelector('.debug-pos-timeout').innerHTML = \"\\n \".concat(lang('posTimeout'), \" : \").concat(options.timeout / 1000, \"s\\n \");\n element.querySelector('.debug-zoom-level').innerHTML = \"\\n \".concat(lang('zoom'), \" : \").concat(bc.map.getZoom(), \"\\n \");\n element.querySelector('.debug-marks-amount').innerHTML = \"\\n \".concat(lang('marks'), \" : \").concat(marks, \"\\n \");\n }\n }\n }, {\n key: \"getPreference\",\n value: function getPreference(pref) {\n return localStorage.getItem(pref) || null;\n }\n }, {\n key: \"setPreference\",\n value: function setPreference(pref, value) {\n localStorage.setItem(pref, value);\n }\n }, {\n key: \"RANGE_COLOR\",\n get: function get() {\n return '#ffd87d';\n }\n }, {\n key: \"USER_COLOR\",\n get: function get() {\n return '#63fff5';\n }\n }, {\n key: \"SPOT_COLOR\",\n get: function get() {\n return '#26ad23';\n }\n }, {\n key: \"STORE_COLOR\",\n get: function get() {\n return '#247dc9';\n }\n }, {\n key: \"BAR_COLOR\",\n get: function get() {\n return '#ca2a3d';\n }\n }, {\n key: \"CIRCLE_RADIUS\",\n get: function get() {\n return 100;\n }\n }, {\n key: \"NEW_MARKER_RANGE\",\n get: function get() {\n return 200;\n }\n }, {\n key: \"MAP_BOUNDS\",\n get: function get() {\n return window.L.latLngBounds(window.L.latLng(-89.98155760646617, -180), window.L.latLng(89.99346179538875, 180));\n }\n }, {\n key: \"HIGH_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: true,\n // More consuption, better position\n maximumAge: 1000,\n // A position will last 1s maximum\n timeout: 900 // A position is updated in 0.9s maximum\n\n };\n }\n }, {\n key: \"OPTIMIZED_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: false,\n // Less consuption\n maximumAge: 30000,\n // A position will last 30s maximum\n timeout: 29000 // A position is updated in 29s maximum\n\n };\n }\n }, {\n key: \"SUPPORTED_LANGUAGE\",\n get: function get() {\n return ['en', 'fr', 'es', 'de'];\n }\n }]);\n\n return Utils;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/Utils.js?"); + +/***/ }), + +/***/ "./src/BeerCrackerzAuth.scss": +/*!***********************************!*\ + !*** ./src/BeerCrackerzAuth.scss ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerzAuth.scss?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/BeerCrackerzAuth.js"); +/******/ window.BeerCrackerz = __webpack_exports__["default"]; +/******/ +/******/ })() +; \ No newline at end of file diff --git a/assets/html/modal/deletemark.html b/front/assets/html/modal/deletemark.html similarity index 100% rename from assets/html/modal/deletemark.html rename to front/assets/html/modal/deletemark.html diff --git a/assets/html/modal/editbar.html b/front/assets/html/modal/editbar.html similarity index 100% rename from assets/html/modal/editbar.html rename to front/assets/html/modal/editbar.html diff --git a/assets/html/modal/editspot.html b/front/assets/html/modal/editspot.html similarity index 100% rename from assets/html/modal/editspot.html rename to front/assets/html/modal/editspot.html diff --git a/assets/html/modal/editstore.html b/front/assets/html/modal/editstore.html similarity index 100% rename from assets/html/modal/editstore.html rename to front/assets/html/modal/editstore.html diff --git a/assets/html/modal/hideshow.html b/front/assets/html/modal/hideshow.html similarity index 100% rename from assets/html/modal/hideshow.html rename to front/assets/html/modal/hideshow.html diff --git a/assets/html/modal/newbar.html b/front/assets/html/modal/newbar.html similarity index 100% rename from assets/html/modal/newbar.html rename to front/assets/html/modal/newbar.html diff --git a/assets/html/modal/newspot.html b/front/assets/html/modal/newspot.html similarity index 100% rename from assets/html/modal/newspot.html rename to front/assets/html/modal/newspot.html diff --git a/assets/html/modal/newstore.html b/front/assets/html/modal/newstore.html similarity index 100% rename from assets/html/modal/newstore.html rename to front/assets/html/modal/newstore.html diff --git a/assets/html/modal/user.html b/front/assets/html/modal/user.html similarity index 100% rename from assets/html/modal/user.html rename to front/assets/html/modal/user.html diff --git a/assets/html/popup/bar.html b/front/assets/html/popup/bar.html similarity index 100% rename from assets/html/popup/bar.html rename to front/assets/html/popup/bar.html diff --git a/assets/html/popup/spot.html b/front/assets/html/popup/spot.html similarity index 100% rename from assets/html/popup/spot.html rename to front/assets/html/popup/spot.html diff --git a/assets/html/popup/store.html b/front/assets/html/popup/store.html similarity index 100% rename from assets/html/popup/store.html rename to front/assets/html/popup/store.html diff --git a/assets/img/favicon/android-icon-144x144.png b/front/assets/img/favicon/android-icon-144x144.png similarity index 100% rename from assets/img/favicon/android-icon-144x144.png rename to front/assets/img/favicon/android-icon-144x144.png diff --git a/assets/img/favicon/android-icon-192x192.png b/front/assets/img/favicon/android-icon-192x192.png similarity index 100% rename from assets/img/favicon/android-icon-192x192.png rename to front/assets/img/favicon/android-icon-192x192.png diff --git a/assets/img/favicon/android-icon-36x36.png b/front/assets/img/favicon/android-icon-36x36.png similarity index 100% rename from assets/img/favicon/android-icon-36x36.png rename to front/assets/img/favicon/android-icon-36x36.png diff --git a/assets/img/favicon/android-icon-48x48.png b/front/assets/img/favicon/android-icon-48x48.png similarity index 100% rename from assets/img/favicon/android-icon-48x48.png rename to front/assets/img/favicon/android-icon-48x48.png diff --git a/assets/img/favicon/android-icon-72x72.png b/front/assets/img/favicon/android-icon-72x72.png similarity index 100% rename from assets/img/favicon/android-icon-72x72.png rename to front/assets/img/favicon/android-icon-72x72.png diff --git a/assets/img/favicon/android-icon-96x96.png b/front/assets/img/favicon/android-icon-96x96.png similarity index 100% rename from assets/img/favicon/android-icon-96x96.png rename to front/assets/img/favicon/android-icon-96x96.png diff --git a/assets/img/favicon/apple-icon-114x114.png b/front/assets/img/favicon/apple-icon-114x114.png similarity index 100% rename from assets/img/favicon/apple-icon-114x114.png rename to front/assets/img/favicon/apple-icon-114x114.png diff --git a/assets/img/favicon/apple-icon-120x120.png b/front/assets/img/favicon/apple-icon-120x120.png similarity index 100% rename from assets/img/favicon/apple-icon-120x120.png rename to front/assets/img/favicon/apple-icon-120x120.png diff --git a/assets/img/favicon/apple-icon-144x144.png b/front/assets/img/favicon/apple-icon-144x144.png similarity index 100% rename from assets/img/favicon/apple-icon-144x144.png rename to front/assets/img/favicon/apple-icon-144x144.png diff --git a/assets/img/favicon/apple-icon-152x152.png b/front/assets/img/favicon/apple-icon-152x152.png similarity index 100% rename from assets/img/favicon/apple-icon-152x152.png rename to front/assets/img/favicon/apple-icon-152x152.png diff --git a/assets/img/favicon/apple-icon-180x180.png b/front/assets/img/favicon/apple-icon-180x180.png similarity index 100% rename from assets/img/favicon/apple-icon-180x180.png rename to front/assets/img/favicon/apple-icon-180x180.png diff --git a/assets/img/favicon/apple-icon-57x57.png b/front/assets/img/favicon/apple-icon-57x57.png similarity index 100% rename from assets/img/favicon/apple-icon-57x57.png rename to front/assets/img/favicon/apple-icon-57x57.png diff --git a/assets/img/favicon/apple-icon-60x60.png b/front/assets/img/favicon/apple-icon-60x60.png similarity index 100% rename from assets/img/favicon/apple-icon-60x60.png rename to front/assets/img/favicon/apple-icon-60x60.png diff --git a/assets/img/favicon/apple-icon-72x72.png b/front/assets/img/favicon/apple-icon-72x72.png similarity index 100% rename from assets/img/favicon/apple-icon-72x72.png rename to front/assets/img/favicon/apple-icon-72x72.png diff --git a/assets/img/favicon/apple-icon-76x76.png b/front/assets/img/favicon/apple-icon-76x76.png similarity index 100% rename from assets/img/favicon/apple-icon-76x76.png rename to front/assets/img/favicon/apple-icon-76x76.png diff --git a/assets/img/favicon/apple-icon-precomposed.png b/front/assets/img/favicon/apple-icon-precomposed.png similarity index 100% rename from assets/img/favicon/apple-icon-precomposed.png rename to front/assets/img/favicon/apple-icon-precomposed.png diff --git a/assets/img/favicon/apple-icon.png b/front/assets/img/favicon/apple-icon.png similarity index 100% rename from assets/img/favicon/apple-icon.png rename to front/assets/img/favicon/apple-icon.png diff --git a/assets/img/favicon/browserconfig.xml b/front/assets/img/favicon/browserconfig.xml similarity index 100% rename from assets/img/favicon/browserconfig.xml rename to front/assets/img/favicon/browserconfig.xml diff --git a/assets/img/favicon/favicon-16x16.png b/front/assets/img/favicon/favicon-16x16.png similarity index 100% rename from assets/img/favicon/favicon-16x16.png rename to front/assets/img/favicon/favicon-16x16.png diff --git a/assets/img/favicon/favicon-32x32.png b/front/assets/img/favicon/favicon-32x32.png similarity index 100% rename from assets/img/favicon/favicon-32x32.png rename to front/assets/img/favicon/favicon-32x32.png diff --git a/assets/img/favicon/favicon-96x96.png b/front/assets/img/favicon/favicon-96x96.png similarity index 100% rename from assets/img/favicon/favicon-96x96.png rename to front/assets/img/favicon/favicon-96x96.png diff --git a/assets/img/favicon/favicon.ico b/front/assets/img/favicon/favicon.ico similarity index 100% rename from assets/img/favicon/favicon.ico rename to front/assets/img/favicon/favicon.ico diff --git a/assets/img/favicon/manifest.json b/front/assets/img/favicon/manifest.json similarity index 100% rename from assets/img/favicon/manifest.json rename to front/assets/img/favicon/manifest.json diff --git a/assets/img/favicon/ms-icon-144x144.png b/front/assets/img/favicon/ms-icon-144x144.png similarity index 100% rename from assets/img/favicon/ms-icon-144x144.png rename to front/assets/img/favicon/ms-icon-144x144.png diff --git a/assets/img/favicon/ms-icon-150x150.png b/front/assets/img/favicon/ms-icon-150x150.png similarity index 100% rename from assets/img/favicon/ms-icon-150x150.png rename to front/assets/img/favicon/ms-icon-150x150.png diff --git a/assets/img/favicon/ms-icon-310x310.png b/front/assets/img/favicon/ms-icon-310x310.png similarity index 100% rename from assets/img/favicon/ms-icon-310x310.png rename to front/assets/img/favicon/ms-icon-310x310.png diff --git a/assets/img/favicon/ms-icon-70x70.png b/front/assets/img/favicon/ms-icon-70x70.png similarity index 100% rename from assets/img/favicon/ms-icon-70x70.png rename to front/assets/img/favicon/ms-icon-70x70.png diff --git a/assets/img/logo-small.png b/front/assets/img/logo-small.png similarity index 100% rename from assets/img/logo-small.png rename to front/assets/img/logo-small.png diff --git a/assets/img/logo-social.png b/front/assets/img/logo-social.png similarity index 100% rename from assets/img/logo-social.png rename to front/assets/img/logo-social.png diff --git a/assets/img/logo-text.png b/front/assets/img/logo-text.png similarity index 100% rename from assets/img/logo-text.png rename to front/assets/img/logo-text.png diff --git a/assets/img/logo.png b/front/assets/img/logo.png similarity index 100% rename from assets/img/logo.png rename to front/assets/img/logo.png diff --git a/assets/img/logo.svg b/front/assets/img/logo.svg similarity index 100% rename from assets/img/logo.svg rename to front/assets/img/logo.svg diff --git a/assets/img/logo/center.svg b/front/assets/img/logo/center.svg similarity index 100% rename from assets/img/logo/center.svg rename to front/assets/img/logo/center.svg diff --git a/assets/img/logo/circle.svg b/front/assets/img/logo/circle.svg similarity index 100% rename from assets/img/logo/circle.svg rename to front/assets/img/logo/circle.svg diff --git a/assets/img/logo/comment.svg b/front/assets/img/logo/comment.svg similarity index 100% rename from assets/img/logo/comment.svg rename to front/assets/img/logo/comment.svg diff --git a/assets/img/logo/debug.svg b/front/assets/img/logo/debug.svg similarity index 100% rename from assets/img/logo/debug.svg rename to front/assets/img/logo/debug.svg diff --git a/assets/img/logo/delete.svg b/front/assets/img/logo/delete.svg similarity index 100% rename from assets/img/logo/delete.svg rename to front/assets/img/logo/delete.svg diff --git a/assets/img/logo/dollar.svg b/front/assets/img/logo/dollar.svg similarity index 100% rename from assets/img/logo/dollar.svg rename to front/assets/img/logo/dollar.svg diff --git a/assets/img/logo/edit.svg b/front/assets/img/logo/edit.svg similarity index 100% rename from assets/img/logo/edit.svg rename to front/assets/img/logo/edit.svg diff --git a/assets/img/logo/hide.svg b/front/assets/img/logo/hide.svg similarity index 100% rename from assets/img/logo/hide.svg rename to front/assets/img/logo/hide.svg diff --git a/assets/img/logo/info.svg b/front/assets/img/logo/info.svg similarity index 100% rename from assets/img/logo/info.svg rename to front/assets/img/logo/info.svg diff --git a/assets/img/logo/label.svg b/front/assets/img/logo/label.svg similarity index 100% rename from assets/img/logo/label.svg rename to front/assets/img/logo/label.svg diff --git a/assets/img/logo/photo.svg b/front/assets/img/logo/photo.svg similarity index 100% rename from assets/img/logo/photo.svg rename to front/assets/img/logo/photo.svg diff --git a/assets/img/logo/precision.svg b/front/assets/img/logo/precision.svg similarity index 100% rename from assets/img/logo/precision.svg rename to front/assets/img/logo/precision.svg diff --git a/assets/img/logo/star.svg b/front/assets/img/logo/star.svg similarity index 100% rename from assets/img/logo/star.svg rename to front/assets/img/logo/star.svg diff --git a/assets/img/marker/cluster-icon-blue.png b/front/assets/img/marker/cluster-icon-blue.png similarity index 100% rename from assets/img/marker/cluster-icon-blue.png rename to front/assets/img/marker/cluster-icon-blue.png diff --git a/assets/img/marker/cluster-icon-green.png b/front/assets/img/marker/cluster-icon-green.png similarity index 100% rename from assets/img/marker/cluster-icon-green.png rename to front/assets/img/marker/cluster-icon-green.png diff --git a/assets/img/marker/cluster-icon-red.png b/front/assets/img/marker/cluster-icon-red.png similarity index 100% rename from assets/img/marker/cluster-icon-red.png rename to front/assets/img/marker/cluster-icon-red.png diff --git a/assets/img/marker/marker-icon-black.png b/front/assets/img/marker/marker-icon-black.png similarity index 100% rename from assets/img/marker/marker-icon-black.png rename to front/assets/img/marker/marker-icon-black.png diff --git a/assets/img/marker/marker-icon-blue.png b/front/assets/img/marker/marker-icon-blue.png similarity index 100% rename from assets/img/marker/marker-icon-blue.png rename to front/assets/img/marker/marker-icon-blue.png diff --git a/assets/img/marker/marker-icon-gold.png b/front/assets/img/marker/marker-icon-gold.png similarity index 100% rename from assets/img/marker/marker-icon-gold.png rename to front/assets/img/marker/marker-icon-gold.png diff --git a/assets/img/marker/marker-icon-green.png b/front/assets/img/marker/marker-icon-green.png similarity index 100% rename from assets/img/marker/marker-icon-green.png rename to front/assets/img/marker/marker-icon-green.png diff --git a/assets/img/marker/marker-icon-grey.png b/front/assets/img/marker/marker-icon-grey.png similarity index 100% rename from assets/img/marker/marker-icon-grey.png rename to front/assets/img/marker/marker-icon-grey.png diff --git a/assets/img/marker/marker-icon-orange.png b/front/assets/img/marker/marker-icon-orange.png similarity index 100% rename from assets/img/marker/marker-icon-orange.png rename to front/assets/img/marker/marker-icon-orange.png diff --git a/assets/img/marker/marker-icon-red.png b/front/assets/img/marker/marker-icon-red.png similarity index 100% rename from assets/img/marker/marker-icon-red.png rename to front/assets/img/marker/marker-icon-red.png diff --git a/assets/img/marker/marker-icon-violet.png b/front/assets/img/marker/marker-icon-violet.png similarity index 100% rename from assets/img/marker/marker-icon-violet.png rename to front/assets/img/marker/marker-icon-violet.png diff --git a/assets/img/marker/marker-icon-yellow.png b/front/assets/img/marker/marker-icon-yellow.png similarity index 100% rename from assets/img/marker/marker-icon-yellow.png rename to front/assets/img/marker/marker-icon-yellow.png diff --git a/assets/img/marker/marker-shadow.png b/front/assets/img/marker/marker-shadow.png similarity index 100% rename from assets/img/marker/marker-shadow.png rename to front/assets/img/marker/marker-shadow.png diff --git a/assets/img/marker/user-position-shadow.png b/front/assets/img/marker/user-position-shadow.png similarity index 100% rename from assets/img/marker/user-position-shadow.png rename to front/assets/img/marker/user-position-shadow.png diff --git a/assets/img/marker/user-position.png b/front/assets/img/marker/user-position.png similarity index 100% rename from assets/img/marker/user-position.png rename to front/assets/img/marker/user-position.png diff --git a/assets/nls/de.json b/front/assets/nls/de.json similarity index 100% rename from assets/nls/de.json rename to front/assets/nls/de.json diff --git a/assets/nls/en.json b/front/assets/nls/en.json similarity index 100% rename from assets/nls/en.json rename to front/assets/nls/en.json diff --git a/assets/nls/es.json b/front/assets/nls/es.json similarity index 100% rename from assets/nls/es.json rename to front/assets/nls/es.json diff --git a/assets/nls/fr.json b/front/assets/nls/fr.json similarity index 100% rename from assets/nls/fr.json rename to front/assets/nls/fr.json diff --git a/authindex.html b/front/authindex.html similarity index 100% rename from authindex.html rename to front/authindex.html diff --git a/doc/beercrackerz/0.0.1/BeerCrackerz.html b/front/doc/beercrackerz/0.0.1/BeerCrackerz.html similarity index 100% rename from doc/beercrackerz/0.0.1/BeerCrackerz.html rename to front/doc/beercrackerz/0.0.1/BeerCrackerz.html diff --git a/doc/beercrackerz/0.0.1/BeerCrackerz.js.html b/front/doc/beercrackerz/0.0.1/BeerCrackerz.js.html similarity index 100% rename from doc/beercrackerz/0.0.1/BeerCrackerz.js.html rename to front/doc/beercrackerz/0.0.1/BeerCrackerz.js.html diff --git a/doc/beercrackerz/0.0.1/Utils.js.html b/front/doc/beercrackerz/0.0.1/Utils.js.html similarity index 100% rename from doc/beercrackerz/0.0.1/Utils.js.html rename to front/doc/beercrackerz/0.0.1/Utils.js.html diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Bold-webfont.woff diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-BoldItalic-webfont.woff diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Italic-webfont.woff diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Light-webfont.woff diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-LightItalic-webfont.woff diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.eot b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.eot similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.eot rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.eot diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.svg b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.svg similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.svg rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.svg diff --git a/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.woff b/front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.woff similarity index 100% rename from doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.woff rename to front/doc/beercrackerz/0.0.1/fonts/OpenSans-Regular-webfont.woff diff --git a/doc/beercrackerz/0.0.1/global.html b/front/doc/beercrackerz/0.0.1/global.html similarity index 100% rename from doc/beercrackerz/0.0.1/global.html rename to front/doc/beercrackerz/0.0.1/global.html diff --git a/doc/beercrackerz/0.0.1/index.html b/front/doc/beercrackerz/0.0.1/index.html similarity index 100% rename from doc/beercrackerz/0.0.1/index.html rename to front/doc/beercrackerz/0.0.1/index.html diff --git a/doc/beercrackerz/0.0.1/js_Utils.js.html b/front/doc/beercrackerz/0.0.1/js_Utils.js.html similarity index 100% rename from doc/beercrackerz/0.0.1/js_Utils.js.html rename to front/doc/beercrackerz/0.0.1/js_Utils.js.html diff --git a/doc/beercrackerz/0.0.1/js_utils_Utils.js.html b/front/doc/beercrackerz/0.0.1/js_utils_Utils.js.html similarity index 100% rename from doc/beercrackerz/0.0.1/js_utils_Utils.js.html rename to front/doc/beercrackerz/0.0.1/js_utils_Utils.js.html diff --git a/doc/beercrackerz/0.0.1/module-BeerCrackerz.html b/front/doc/beercrackerz/0.0.1/module-BeerCrackerz.html similarity index 100% rename from doc/beercrackerz/0.0.1/module-BeerCrackerz.html rename to front/doc/beercrackerz/0.0.1/module-BeerCrackerz.html diff --git a/doc/beercrackerz/0.0.1/scripts/linenumber.js b/front/doc/beercrackerz/0.0.1/scripts/linenumber.js similarity index 100% rename from doc/beercrackerz/0.0.1/scripts/linenumber.js rename to front/doc/beercrackerz/0.0.1/scripts/linenumber.js diff --git a/doc/beercrackerz/0.0.1/scripts/prettify/Apache-License-2.0.txt b/front/doc/beercrackerz/0.0.1/scripts/prettify/Apache-License-2.0.txt similarity index 100% rename from doc/beercrackerz/0.0.1/scripts/prettify/Apache-License-2.0.txt rename to front/doc/beercrackerz/0.0.1/scripts/prettify/Apache-License-2.0.txt diff --git a/doc/beercrackerz/0.0.1/scripts/prettify/lang-css.js b/front/doc/beercrackerz/0.0.1/scripts/prettify/lang-css.js similarity index 100% rename from doc/beercrackerz/0.0.1/scripts/prettify/lang-css.js rename to front/doc/beercrackerz/0.0.1/scripts/prettify/lang-css.js diff --git a/doc/beercrackerz/0.0.1/scripts/prettify/prettify.js b/front/doc/beercrackerz/0.0.1/scripts/prettify/prettify.js similarity index 100% rename from doc/beercrackerz/0.0.1/scripts/prettify/prettify.js rename to front/doc/beercrackerz/0.0.1/scripts/prettify/prettify.js diff --git a/doc/beercrackerz/0.0.1/styles/jsdoc-default.css b/front/doc/beercrackerz/0.0.1/styles/jsdoc-default.css similarity index 100% rename from doc/beercrackerz/0.0.1/styles/jsdoc-default.css rename to front/doc/beercrackerz/0.0.1/styles/jsdoc-default.css diff --git a/doc/beercrackerz/0.0.1/styles/prettify-jsdoc.css b/front/doc/beercrackerz/0.0.1/styles/prettify-jsdoc.css similarity index 100% rename from doc/beercrackerz/0.0.1/styles/prettify-jsdoc.css rename to front/doc/beercrackerz/0.0.1/styles/prettify-jsdoc.css diff --git a/doc/beercrackerz/0.0.1/styles/prettify-tomorrow.css b/front/doc/beercrackerz/0.0.1/styles/prettify-tomorrow.css similarity index 100% rename from doc/beercrackerz/0.0.1/styles/prettify-tomorrow.css rename to front/doc/beercrackerz/0.0.1/styles/prettify-tomorrow.css diff --git a/doc/jsDoc.json b/front/doc/jsDoc.json similarity index 100% rename from doc/jsDoc.json rename to front/doc/jsDoc.json diff --git a/index.html b/front/index.html similarity index 100% rename from index.html rename to front/index.html diff --git a/login.html b/front/login.html similarity index 100% rename from login.html rename to front/login.html diff --git a/package-lock.json b/front/package-lock.json similarity index 100% rename from package-lock.json rename to front/package-lock.json diff --git a/package.json b/front/package.json similarity index 100% rename from package.json rename to front/package.json diff --git a/register.html b/front/register.html similarity index 100% rename from register.html rename to front/register.html diff --git a/src/BeerCrackerz.js b/front/src/BeerCrackerz.js similarity index 100% rename from src/BeerCrackerz.js rename to front/src/BeerCrackerz.js diff --git a/src/BeerCrackerz.scss b/front/src/BeerCrackerz.scss similarity index 100% rename from src/BeerCrackerz.scss rename to front/src/BeerCrackerz.scss diff --git a/src/BeerCrackerzAuth.js b/front/src/BeerCrackerzAuth.js similarity index 100% rename from src/BeerCrackerzAuth.js rename to front/src/BeerCrackerzAuth.js diff --git a/src/BeerCrackerzAuth.scss b/front/src/BeerCrackerzAuth.scss similarity index 100% rename from src/BeerCrackerzAuth.scss rename to front/src/BeerCrackerzAuth.scss diff --git a/src/js/MapHelper.js b/front/src/js/MapHelper.js similarity index 100% rename from src/js/MapHelper.js rename to front/src/js/MapHelper.js diff --git a/src/js/ui/Notification.js b/front/src/js/ui/Notification.js similarity index 100% rename from src/js/ui/Notification.js rename to front/src/js/ui/Notification.js diff --git a/src/js/ui/Rating.js b/front/src/js/ui/Rating.js similarity index 100% rename from src/js/ui/Rating.js rename to front/src/js/ui/Rating.js diff --git a/src/js/ui/ZoomSlider.js b/front/src/js/ui/ZoomSlider.js similarity index 100% rename from src/js/ui/ZoomSlider.js rename to front/src/js/ui/ZoomSlider.js diff --git a/src/js/utils/LangManager.js b/front/src/js/utils/LangManager.js similarity index 100% rename from src/js/utils/LangManager.js rename to front/src/js/utils/LangManager.js diff --git a/src/js/utils/MarkerEnum.js b/front/src/js/utils/MarkerEnum.js similarity index 100% rename from src/js/utils/MarkerEnum.js rename to front/src/js/utils/MarkerEnum.js diff --git a/src/js/utils/ProviderEnum.js b/front/src/js/utils/ProviderEnum.js similarity index 100% rename from src/js/utils/ProviderEnum.js rename to front/src/js/utils/ProviderEnum.js diff --git a/src/js/utils/Utils.js b/front/src/js/utils/Utils.js similarity index 100% rename from src/js/utils/Utils.js rename to front/src/js/utils/Utils.js diff --git a/src/scss/_base.scss b/front/src/scss/_base.scss similarity index 100% rename from src/scss/_base.scss rename to front/src/scss/_base.scss diff --git a/src/scss/_keyframes.scss b/front/src/scss/_keyframes.scss similarity index 100% rename from src/scss/_keyframes.scss rename to front/src/scss/_keyframes.scss diff --git a/src/scss/_responsive.scss b/front/src/scss/_responsive.scss similarity index 100% rename from src/scss/_responsive.scss rename to front/src/scss/_responsive.scss diff --git a/webpack/.eslintrc b/front/webpack/.eslintrc similarity index 100% rename from webpack/.eslintrc rename to front/webpack/.eslintrc diff --git a/webpack/loaders.js b/front/webpack/loaders.js similarity index 100% rename from webpack/loaders.js rename to front/webpack/loaders.js diff --git a/webpack/plugins.js b/front/webpack/plugins.js similarity index 100% rename from webpack/plugins.js rename to front/webpack/plugins.js diff --git a/webpack/postcss.config.js b/front/webpack/postcss.config.js similarity index 100% rename from webpack/postcss.config.js rename to front/webpack/postcss.config.js diff --git a/webpack/stylelint.config.js b/front/webpack/stylelint.config.js similarity index 100% rename from webpack/stylelint.config.js rename to front/webpack/stylelint.config.js diff --git a/webpack/webpack.common.js b/front/webpack/webpack.common.js similarity index 100% rename from webpack/webpack.common.js rename to front/webpack/webpack.common.js diff --git a/webpack/webpack.dev.js b/front/webpack/webpack.dev.js similarity index 100% rename from webpack/webpack.dev.js rename to front/webpack/webpack.dev.js diff --git a/webpack/webpack.prod.js b/front/webpack/webpack.prod.js similarity index 100% rename from webpack/webpack.prod.js rename to front/webpack/webpack.prod.js From ab7995293a992ba0d7be460e8c50f60bd2960e77 Mon Sep 17 00:00:00 2001 From: Raphael Beekmann
\n * This component handles the whole BeerCrackerz app. It includes the map manipulation,\n * the geolocation API to update the user position and process any map events that are\n * relevant to an UX stand point. For more information, please consult the application\n * description page at https://about.beercrackerz.org/\n *\n **/\n function BeerCrackerz() {\n var _this;\n\n _classCallCheck(this, BeerCrackerz);\n\n _this = _super.call(this);\n /**\n * The core Leaflet.js map\n * @type {Object}\n * @private\n **/\n\n _this._map = null;\n /**\n * The zoom slider handler\n * @type {Object}\n * @private\n **/\n\n _this._zoomSlider = null;\n /**\n * The notification handler\n * @type {Object}\n * @private\n **/\n\n _this._notification = null;\n /**\n * The user object holds everything useful to ensure a proper session\n * @type {Object}\n * @private\n **/\n\n _this._user = {\n lat: 48.853121540141096,\n // Default lat to Paris Notre-Dame latitude\n lng: 2.3498955769881156,\n // Default lng to Paris Notre-Dame longitude\n accuracy: 0,\n // Accuracy in meter given by geolocation API\n marker: null,\n // The user marker on map\n circle: null,\n // The accuracy circle around the user marker\n range: null,\n // The range in which user can add a new marker\n color: _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].USER_COLOR,\n // The color to use for circle (match the user marker color)\n id: -1,\n username: ''\n };\n /**\n * The stored marks for spots, stores and bars\n * @type {Object}\n * @private\n **/\n\n _this._marks = {\n spot: [],\n store: [],\n bar: []\n };\n /**\n * The stored clusters for markers, see Leaflet.markercluster plugin\n * @type {Object}\n * @private\n **/\n\n _this._clusters = {\n spot: {},\n store: {},\n bar: {}\n };\n /**\n * The temporary marker for new marks only\n * @type {Object}\n * @private\n **/\n\n _this._newMarker = null;\n /**\n * The debug DOM object\n * @type {Object}\n * @private\n **/\n\n _this._debugElement = null;\n /**\n * ID for geolocation watch callback\n * @type {Number}\n * @private\n **/\n\n _this._watchId = null;\n /**\n * Flag to know if a zoom action is occuring on map\n * @type {Boolean}\n * @private\n **/\n\n _this._isZooming = false;\n /**\n * The LangManager must be instantiated to handle nls accross the app\n * @type {Boolean}\n * @private\n **/\n // The BeerCrackerz app is only initialized once nls are set up\n\n _this._lang = new _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"](window.navigator.language.substring(0, 2), _this._init.bind(_assertThisInitialized(_this)));\n return _this;\n } // ======================================================================== //\n // ----------------- Application initialization sequence ------------------ //\n // ======================================================================== //\n\n /**\n * @method\n * @name _init\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _init() method is designed to properly configure the user session, according\n * to its saved preferences and its position. It first build the debug interface,\n * then loads the user preferences, then create the map and finally, events are listened.\n *\n **/\n\n\n _createClass(BeerCrackerz, [{\n key: \"_init\",\n value: function _init() {\n this._debugElement = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].initDebugInterface();\n this._notification = new _js_ui_Notification_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"]();\n\n this._initUser().then(this._initPreferences.bind(this)).then(this._initGeolocation.bind(this)).then(this._initMap.bind(this)).then(this._initEvents.bind(this)).then(this._initMarkers.bind(this));\n }\n /**\n * @method\n * @name _initUser\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _init() method initialize the user object according to its information\n * and statistic so the UI can be properly built.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initUser\",\n value: function _initUser() {\n var _this2 = this;\n\n return new Promise(function (resolve) {\n // TODO fill user information from server\n _this2._user.id = 42;\n _this2._user.username = 'messmaker';\n resolve();\n });\n }\n /**\n * @method\n * @name _initPreferences\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initPreferences() will initialize user preference if they are not set yet,\n * it will also update the UI according to user preferences ; debug DOM visible,\n * update the command classList for selected ones.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initPreferences\",\n value: function _initPreferences() {\n var _this3 = this;\n\n return new Promise(function (resolve) {\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-spot') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-spot', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-store') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-store', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-bar') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-bar', true);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer') === null) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-plan-layer', true);\n }\n\n if (window.DEBUG === true || _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('app-debug') === 'true') {\n window.DEBUG = true; // Ensure to set global flag if preference comes from local storage\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('app-debug', true); // Ensure to set local storage preference if debug flag was added to the url\n\n _this3.addDebugUI();\n } // Update icon class if center on preference is set to true\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n document.getElementById('center-on').classList.add('lock-center-on');\n }\n\n resolve();\n });\n }\n /**\n * @method\n * @name _initGeolocation\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initGeolocation() method will request from browser the location authorization.\n * Once granted, an event listener is set on any position update, so it can update the\n * map state and the markers position. This method can be called again, only if the\n * geolocation watch has been cleared ; for example when updating the accuracy options.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initGeolocation\",\n value: function _initGeolocation() {\n var _this4 = this;\n\n return new Promise(function (resolve) {\n if ('geolocation' in navigator) {\n var options = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true' ? _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].HIGH_ACCURACY : _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].OPTIMIZED_ACCURACY;\n _this4._watchId = navigator.geolocation.watchPosition(function (position) {\n // Update saved user position\n _this4._user.lat = position.coords.latitude;\n _this4._user.lng = position.coords.longitude;\n _this4._user.accuracy = position.coords.accuracy; // Only draw marker if map is already created\n\n if (_this4._map) {\n _this4.drawUserMarker();\n\n _this4.updateMarkerCirclesVisibility(); // Update map position if focus lock is active\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true' && !_this4._isZooming) {\n _this4._map.setView(_this4._user);\n } // Updating debug info\n\n\n _this4.updateDebugUI();\n }\n\n resolve();\n }, resolve, options);\n } else {\n _this4._notification.raise(_this4.nls.notif('geolocationError'));\n\n resolve();\n }\n });\n }\n /**\n * @method\n * @name _initMap\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initMap() method will create the Leaflet.js map with two base layers (plan/satellite),\n * add scale control, remove zoom control and set map bounds.\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initMap\",\n value: function _initMap() {\n var _this5 = this;\n\n return new Promise(function (resolve) {\n // Use main div to inject OSM into\n _this5._map = window.L.map('beer-crakerz-map', {\n zoomControl: false\n }).setView([_this5._user.lat, _this5._user.lng], 18); // Add meter and feet scale on map\n\n window.L.control.scale().addTo(_this5._map); // Place user marker on the map\n\n _this5.drawUserMarker(); // Add OSM credits to the map next to leaflet credits\n\n\n var osm = _js_utils_ProviderEnum_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].planOsm; //const plan = Providers.planGeo;\n\n var esri = _js_utils_ProviderEnum_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].satEsri; //const geo = Providers.satGeo;\n // Prevent panning outside of the world's edge\n\n _this5._map.setMaxBounds(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].MAP_BOUNDS); // Add layer group to interface\n\n\n var baseMaps = {};\n baseMaps[\"
\".concat(_this5.nls.map('planLayerOSM'), \"
\")] = osm; //baseMaps[`${this.nls.map('planLayerGeo')}
`] = plan; \n\n baseMaps[\"\".concat(_this5.nls.map('satLayerEsri'), \"
\")] = esri; //baseMaps[`${this.nls.map('satLayerGeo')}
`] = geo;\n // Append layer depending on user preference\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer')) {\n switch (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-plan-layer')) {\n case _this5.nls.map('planLayerOSM'):\n osm.addTo(_this5._map);\n break;\n\n /*case this.nls.map('planLayerGeo'):\n plan.addTo(this._map);\n break;*/\n\n case _this5.nls.map('satLayerEsri'):\n esri.addTo(_this5._map);\n break;\n\n /*case this.nls.map('satLayerGeo'):\n geo.addTo(this._map);\n break;*/\n\n default:\n osm.addTo(_this5._map);\n break;\n }\n } else {\n // No saved pref, fallback on OSM base map\n osm.addTo(_this5._map);\n } // Add layer switch radio on bottom right of the map\n\n\n window.L.control.layers(baseMaps, {}, {\n position: 'bottomright'\n }).addTo(_this5._map); // Init zoom slider when map has been created\n\n _this5._zoomSlider = new _js_ui_ZoomSlider_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"](_this5._map);\n resolve();\n });\n }\n /**\n * @method\n * @name _initEvents\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *\n * The _initEvents() method will listen to all required events to manipulate the map. Those events\n * are both for commands and for map events (click, drag, zoom and layer change).\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initEvents\",\n value: function _initEvents() {\n var _this6 = this;\n\n return new Promise(function (resolve) {\n // Command events\n document.getElementById('user-profile').addEventListener('click', _this6.userProfileModal.bind(_this6));\n document.getElementById('hide-show').addEventListener('click', _this6.hidShowModal.bind(_this6));\n document.getElementById('center-on').addEventListener('click', _this6.toggleFocusLock.bind(_this6));\n document.getElementById('overlay').addEventListener('click', _this6.closeModal.bind(_this6)); // Subscribe to click event on map to react\n\n _this6._map.on('click', _this6.mapClicked.bind(_this6)); // Map is dragged by user mouse/finger\n\n\n _this6._map.on('drag', function () {\n // Constrain pan to the map bounds\n _this6._map.panInsideBounds(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].MAP_BOUNDS, {\n animate: true\n }); // Disable lock focus if user drags the map\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n _this6.toggleFocusLock();\n }\n }); // Map events\n\n\n _this6._map.on('zoomstart', function () {\n _this6._isZooming = true;\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n _this6.setMarkerCircles(_this6._marks.spot, false);\n\n _this6.setMarkerCircles(_this6._marks.store, false);\n\n _this6.setMarkerCircles(_this6._marks.bar, false);\n\n _this6.setMarkerCircles([_this6._user], false);\n\n _this6.setMarkerCircles([{\n circle: _this6._user.range\n }], false);\n }\n });\n\n _this6._map.on('zoomend', function () {\n _this6._isZooming = false;\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n if (_this6._map.getZoom() >= 15) {\n _this6.setMarkerCircles(_this6._marks.spot, true);\n\n _this6.setMarkerCircles(_this6._marks.store, true);\n\n _this6.setMarkerCircles(_this6._marks.bar, true);\n\n _this6.setMarkerCircles([_this6._user], true);\n\n _this6.setMarkerCircles([{\n circle: _this6._user.range\n }], true);\n }\n } // Auto hide labels if zoom level is too high (and restore it when needed)\n\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true') {\n if (_this6._map.getZoom() < 15) {\n _this6.setMarkerLabels(_this6._marks.spot, false);\n\n _this6.setMarkerLabels(_this6._marks.store, false);\n\n _this6.setMarkerLabels(_this6._marks.bar, false);\n } else {\n _this6.setMarkerLabels(_this6._marks.spot, true);\n\n _this6.setMarkerLabels(_this6._marks.store, true);\n\n _this6.setMarkerLabels(_this6._marks.bar, true);\n }\n } // Updating debug info\n\n\n _this6.updateDebugUI();\n });\n\n _this6._map.on('baselayerchange', function (event) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-plan-layer', _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].stripDom(event.name));\n });\n\n resolve();\n });\n }\n /**\n * @method\n * @name _initMarkers\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _initEvents() method will initialize all saved marker into the map.\n * Markers must be retrieved from server with a specific format to ensure it works\n *\n * @returns {Promise} A Promise resolved when preferences are set\n **/\n\n }, {\n key: \"_initMarkers\",\n value: function _initMarkers() {\n var _this7 = this;\n\n return new Promise(function (resolve) {\n // Init map clusters for marks to be displayed (disable clustering at opened popup zoom level)\n var clusterOptions = {\n animateAddingMarkers: true,\n disableClusteringAtZoom: 18,\n spiderfyOnMaxZoom: false\n };\n _this7._clusters.spot = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n }));\n _this7._clusters.store = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n }));\n _this7._clusters.bar = new window.L.MarkerClusterGroup(Object.assign(clusterOptions, {\n iconCreateFunction: function iconCreateFunction(cluster) {\n return window.L.divIcon({\n className: 'cluster-icon-wrapper',\n html: \"\\n \\n \".concat(cluster.getChildCount(), \"\\n \")\n });\n }\n })); // Append clusters to the map depending on user preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-spot\") === 'true') {\n _this7._map.addLayer(_this7._clusters.spot);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-store\") === 'true') {\n _this7._map.addLayer(_this7._clusters.store);\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-bar\") === 'true') {\n _this7._map.addLayer(_this7._clusters.bar);\n } // Load data from local storage, later to be fetched from server\n\n\n var iterateMarkers = function iterateMarkers(mark) {\n _this7.markPopupFactory(mark).then(function (dom) {\n mark.dom = dom;\n mark.marker = _this7.placeMarker(mark);\n\n _this7._marks[mark.type].push(mark);\n\n _this7._clusters[mark.type].addLayer(mark.marker);\n });\n };\n\n var marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-spot')) || [];\n\n for (var i = 0; i < marks.length; ++i) {\n iterateMarkers(marks[i]);\n }\n\n marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-store')) || [];\n\n for (var _i = 0; _i < marks.length; ++_i) {\n iterateMarkers(marks[_i]);\n }\n\n marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-bar')) || [];\n\n for (var _i2 = 0; _i2 < marks.length; ++_i2) {\n iterateMarkers(marks[_i2]);\n }\n\n resolve();\n });\n } // ======================================================================== //\n // ------------------------- Toggle for map items ------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name toggleFocusLock\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleFocusLock() method will, depending on user preference, lock or unlock\n * the map centering around the user marker at each position refresh. This way the user\n * can roam while the map is following its position.\n *\n **/\n\n }, {\n key: \"toggleFocusLock\",\n value: function toggleFocusLock() {\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-center-on-user') === 'true') {\n this._notification.raise(this.nls.notif(\"unlockFocusOn\"));\n\n document.getElementById('center-on').classList.remove('lock-center-on');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-center-on-user', 'false');\n } else {\n this._notification.raise(this.nls.notif(\"lockFocusOn\"));\n\n document.getElementById('center-on').classList.add('lock-center-on');\n\n this._map.flyTo([this._user.lat, this._user.lng], 18);\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-center-on-user', 'true');\n }\n }\n /**\n * @method\n * @name toggleLabel\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleLabel() method will, depending on user preference, display or not\n * the labels attached to spots/stores/bars marks. This label is basically the\n * mark name given by its creator.\n *\n **/\n\n }, {\n key: \"toggleLabel\",\n value: function toggleLabel() {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true');\n this.setMarkerLabels(this._marks.spot, visible);\n this.setMarkerLabels(this._marks.store, visible);\n this.setMarkerLabels(this._marks.bar, visible);\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-marker-label', visible);\n }\n /**\n * @method\n * @name toggleCircle\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleCircle() method will, depending on user preference, display or not\n * the circles around the spots/stores/bars marks. This circle indicates the minimal\n * distance which allow the user to make updates on the mark information\n *\n **/\n\n }, {\n key: \"toggleCircle\",\n value: function toggleCircle() {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true');\n this.setMarkerCircles(this._marks.spot, visible);\n this.setMarkerCircles(this._marks.store, visible);\n this.setMarkerCircles(this._marks.bar, visible);\n this.setMarkerCircles([this._user], visible);\n this.setMarkerCircles([{\n circle: this._user.range\n }], visible);\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('poi-show-circle', visible);\n }\n /**\n * @method\n * @name toggleMarkers\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleMarkers() method will, depending on user preference, display or not\n * a given mark type. This way, the user can fine tune what is displayed on the map.\n * A mark type in spots/stores/bars must be given as an argument\n *\n * @param {String} type The mark type in spots/tores/bars\n **/\n\n }, {\n key: \"toggleMarkers\",\n value: function toggleMarkers(type) {\n var visible = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"poi-show-\".concat(type)) === 'true');\n\n if (visible === true) {\n this._map.addLayer(this._clusters[type]);\n } else {\n this._map.removeLayer(this._clusters[type]);\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"poi-show-\".concat(type), visible);\n }\n /**\n * @method\n * @name toggleHighAccuracy\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleHighAccuracy() method will, depending on user preference, update the\n * geolocation accuracy between optimized and high. The high settings might cause\n * more memory and processing consumption, but gives better results. It will clear\n * any previous position watch on the geolocation API so it can subscribe a new one\n * with the new accuracy parameters (see Utils for values)\n *\n **/\n\n }, {\n key: \"toggleHighAccuracy\",\n value: function toggleHighAccuracy() {\n var high = !(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('map-high-accuracy', high);\n navigator.geolocation.clearWatch(this._watchId);\n\n this._initGeolocation().then(this.updateDebugUI.bind(this));\n }\n /**\n * @method\n * @name toggleDebug\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The toggleDebug() method will, depending on user preference, add or remove\n * the debug DOM element to the user interface. The debug DOM display several\n * useful information to identify an issue with the geolocation API\n *\n **/\n\n }, {\n key: \"toggleDebug\",\n value: function toggleDebug() {\n var visible = !window.DEBUG;\n window.DEBUG = visible;\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference('app-debug', visible);\n\n if (visible) {\n this.addDebugUI();\n } else {\n this.removeDebugUI();\n }\n } // ======================================================================== //\n // ----------------- App modals display and interaction ------------------- //\n // ======================================================================== //\n\n }, {\n key: \"newMarkModal\",\n value: function newMarkModal(dom) {\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex';\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n }\n }, {\n key: \"editMarkModal\",\n value: function editMarkModal(options) {\n var _this8 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate(\"assets/html/modal/edit\".concat(options.type, \".html\")).then(function (dom) {\n var name = dom.querySelector(\"#\".concat(options.type, \"-name\"));\n var description = dom.querySelector(\"#\".concat(options.type, \"-desc\"));\n var submit = dom.querySelector(\"#\".concat(options.type, \"-submit\"));\n var cancel = dom.querySelector(\"#\".concat(options.type, \"-cancel\"));\n var rate = dom.querySelector(\"#\".concat(options.type, \"-rating\"));\n var rating = new _js_ui_Rating_js__WEBPACK_IMPORTED_MODULE_6__[\"default\"](rate, options.rate); // Update nls for template\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this8.nls.modal(\"\".concat(options.type, \"EditTitle\")));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-name\")), \"{{\".concat(options.type.toUpperCase(), \"_NAME}}\"), _this8.nls[options.type]('nameLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-desc\")), \"{{\".concat(options.type.toUpperCase(), \"_DESC}}\"), _this8.nls[options.type]('descLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(options.type, \"-rate\")), \"{{\".concat(options.type.toUpperCase(), \"_RATE}}\"), _this8.nls[options.type]('rateLabel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(submit, \"{{\".concat(options.type.toUpperCase(), \"_SUBMIT}}\"), _this8.nls.nav('add'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(cancel, \"{{\".concat(options.type.toUpperCase(), \"_CANCEL}}\"), _this8.nls.nav('cancel'));\n name.value = options.name;\n description.value = options.description;\n submit.addEventListener('click', function () {\n // Iterate through marks to find matching one (by coord as marks coordinates are unique)\n for (var i = 0; i < _this8._marks[options.type].length; ++i) {\n // We found, remove circle, label and marker from map/clusters\n if (options.lat === _this8._marks[options.type][i].lat && options.lng === _this8._marks[options.type][i].lng) {\n _this8._marks[options.type][i].name = name.value;\n _this8._marks[options.type][i].description = description.value;\n _this8._marks[options.type][i].rate = rating.currentRate;\n options.tooltip.removeFrom(_this8.map);\n\n _this8.markPopupFactory(options).then(function (dom) {\n options.dom = dom;\n options.marker.setPopupContent(options.dom);\n });\n\n break;\n }\n } // Format marks to be saved and then update user preference with\n\n\n var formattedMarks = [];\n\n for (var _i3 = 0; _i3 < _this8._marks[options.type].length; ++_i3) {\n formattedMarks.push(_this8.formatSavedMarker(_this8._marks[options.type][_i3]));\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(formattedMarks)); // Notify user through UI that marker has been successfully deleted\n\n _this8._notification.raise(_this8.nls.notif(\"\".concat(options.type, \"Deleted\")));\n\n _this8.closeModal(null, true);\n });\n cancel.addEventListener('click', _this8.closeModal.bind(_this8, null, true));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex';\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name deleteMarkModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * The deleteMarkModal() method will request the mark delete modal, which prompts\n * the user a confirmation to actually delete the mark\n *\n * @param {Function} cb The function to callback with true or false depending on user's choice\n **/\n\n }, {\n key: \"deleteMarkModal\",\n value: function deleteMarkModal(cb) {\n var _this9 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/deletemark.html').then(function (dom) {\n // Update nls for template\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this9.nls.modal('deleteMarkTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-desc\"), \"{{MODAL_DESC}}\", _this9.nls.modal('deleteMarkDesc'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#cancel-close\"), \"{{MODAL_CANCEL}}\", _this9.nls.nav('cancel'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#delete-close\"), \"{{MODAL_DELETE}}\", _this9.nls.nav('delete'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Setup callback for confirm/cancel buttons\n\n document.getElementById('cancel-close').addEventListener('click', function (e) {\n _this9.closeModal(e);\n\n cb(false);\n }, false);\n document.getElementById('delete-close').addEventListener('click', function (e) {\n _this9.closeModal(e);\n\n cb(true);\n }, false);\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name userProfileModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The userProfileModal() method will request the user modal, which contains\n * the user preferences, and the user profile information\n *\n **/\n\n }, {\n key: \"userProfileModal\",\n value: function userProfileModal() {\n var _this10 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/user.html').then(function (dom) {\n // Update nls for template\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-modal-title\"), \"{{MODAL_TITLE}}\", _this10.nls.modal('userTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-user-modal-accuracy\"), \"{{ACCURACY_USER_MODAL}}\", _this10.nls.modal('userAccuracyPref'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-user-modal-debug\"), \"{{DEBUG_USER_MODAL}}\", _this10.nls.modal('userDebugPref'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-about-desc\"), \"{{BEERCRACKERZ_DESC}}\", _this10.nls.modal('aboutDesc'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Init modal checkbox state according to local storage preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true') {\n document.getElementById('high-accuracy-toggle').checked = true;\n }\n\n if (window.DEBUG === true || _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('app-debug') === 'true') {\n document.getElementById('debug-toggle').checked = true;\n }\n\n document.getElementById('high-accuracy-toggle').addEventListener('change', _this10.toggleHighAccuracy.bind(_this10));\n document.getElementById('debug-toggle').addEventListener('change', _this10.toggleDebug.bind(_this10));\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name hidShowModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The hidShowModal() method will request the hide show modal, which all\n * toggles for map elements ; labels/circles/spots/stores/bars\n *\n **/\n\n }, {\n key: \"hidShowModal\",\n value: function hidShowModal() {\n var _this11 = this;\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].fetchTemplate('assets/html/modal/hideshow.html').then(function (dom) {\n // Update template nls\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-title\"), \"{{MODAL_TITLE}}\", _this11.nls.modal('hideShowTitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-labels\"), \"{{LABELS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowLabels'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-circles\"), \"{{CIRCLES_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowCircles'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-spots\"), \"{{SPOTS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowSpots'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-stores\"), \"{{STORES_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowStores'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#nls-hideshow-modal-bars\"), \"{{BARS_HIDESHOW_MODAL}}\", _this11.nls.modal('hideShowBars'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].replaceString(dom.querySelector(\"#modal-close-button\"), \"{{MODAL_CLOSE}}\", _this11.nls.nav('close'));\n document.getElementById('overlay').appendChild(dom);\n document.getElementById('overlay').style.display = 'flex'; // Init modal checkbox state according to local storage preferences\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-marker-label') === 'true') {\n document.getElementById('label-toggle').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n document.getElementById('circle-toggle').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-spot') === 'true') {\n document.getElementById('show-spots').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-store') === 'true') {\n document.getElementById('show-stores').checked = true;\n }\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-bar') === 'true') {\n document.getElementById('show-bars').checked = true;\n }\n\n document.getElementById('label-toggle').addEventListener('change', _this11.toggleLabel.bind(_this11));\n document.getElementById('circle-toggle').addEventListener('change', _this11.toggleCircle.bind(_this11));\n document.getElementById('show-spots').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'spot'));\n document.getElementById('show-stores').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'store'));\n document.getElementById('show-bars').addEventListener('change', _this11.toggleMarkers.bind(_this11, 'bar'));\n setTimeout(function () {\n return document.getElementById('overlay').style.opacity = 1;\n }, 50);\n });\n }\n /**\n * @method\n * @name closeModal\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The closeModal() method will close any opened modal if the click event is\n * targeted on the modal overlay or on close buttons\n *\n * @param {Event} event The click event\n **/\n\n }, {\n key: \"closeModal\",\n value: function closeModal(event, force) {\n if (force === true || event.target.id === 'overlay' || event.target.id.indexOf('close') !== -1) {\n document.getElementById('overlay').style.opacity = 0;\n setTimeout(function () {\n document.getElementById('overlay').style.display = 'none';\n document.getElementById('overlay').innerHTML = '';\n }, 300);\n }\n } // ======================================================================== //\n // -------------------------- Map interaction ----------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name mapClicked\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The mapClicked() method is the callback used when the user clicked on the Leaflet.js map\n *\n * @param {Event} event The click event\n **/\n\n }, {\n key: \"mapClicked\",\n value: function mapClicked(event) {\n if (this._newMarker && this._newMarker.popupClosed) {\n // Avoid to open new marker right after popup closing\n this._newMarker = null;\n } else if (this._newMarker === null || !this._newMarker.isBeingDefined) {\n // Only create new marker if none is in progress, and that click is max range to add a marker\n var distance = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getDistanceBetweenCoords([this._user.lat, this._user.lng], [event.latlng.lat, event.latlng.lng]);\n\n if (distance < _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].NEW_MARKER_RANGE) {\n this._newMarker = this.definePOI(event.latlng, this._markerSaved.bind(this));\n } else {\n this._notification.raise(this.nls.notif('newMarkerOutside'));\n }\n }\n }\n /**\n * @method\n * @name _markerSaved\n * @private\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The _markerSaved() method is the callback used when a marker is created and added\n * to the map. It is the last method of a new marker proccess.\n *\n * @param {Object} options The new marker options\n **/\n\n }, {\n key: \"_markerSaved\",\n value: function _markerSaved(options) {\n // Save marke in marks and clusters for the map\n this._marks[options.type].push(options);\n\n this._clusters[options.type].addLayer(options.marker); // Notify user that new marker has been saved\n\n\n this._notification.raise(this.nls.notif(\"\".concat(options.type, \"Added\"))); // Update marker circles visibility according to user position\n\n\n this.updateMarkerCirclesVisibility(); // Clear new marker to let user add other stuff\n\n this._newMarker = null; // Save new marker in local storage, later to be sent to the server\n\n var marks = JSON.parse(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference(\"saved-\".concat(options.type))) || [];\n marks.push(this.formatSavedMarker(options));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(marks));\n }\n /**\n * @method\n * @name updateMarkerCirclesVisibility\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The updateMarkerCirclesVisibility() method will update the circle visibility for\n * all mark types (spots/stores/bars) and for the user marker\n *\n **/\n\n }, {\n key: \"updateMarkerCirclesVisibility\",\n value: function updateMarkerCirclesVisibility() {\n var _this12 = this;\n\n var _updateByType = function _updateByType(data) {\n // Check spots in user's proximity\n for (var i = 0; i < data.length; ++i) {\n // Only update circles that are in user view\n if (_this12._map.getBounds().contains(data[i].marker.getLatLng())) {\n var marker = data[i].marker;\n var distance = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getDistanceBetweenCoords([_this12._user.lat, _this12._user.lng], [marker.getLatLng().lat, marker.getLatLng().lng]); // Only show if user distance to marker is under circle radius\n\n if (distance < _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].CIRCLE_RADIUS && !data[i].circle.visible) {\n data[i].circle.visible = true;\n data[i].circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n } else if (distance >= _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].CIRCLE_RADIUS && data[i].circle.visible) {\n data[i].circle.visible = false;\n data[i].circle.setStyle({\n opacity: 0,\n fillOpacity: 0\n });\n }\n }\n }\n };\n\n if (_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('poi-show-circle') === 'true') {\n _updateByType(this._marks.spot);\n\n _updateByType(this._marks.store);\n\n _updateByType(this._marks.bar);\n\n _updateByType([this._user]);\n }\n } // ======================================================================== //\n // -------------------------- Marker edition ------------------------------ //\n // ======================================================================== //\n\n /**\n * @method\n * @name formatSavedMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method formats a mark returned from MapHelper so it can be parsed\n * using JSON.parse (in order to store it in local storage/database)\n *\n * @param {Object} mark The mark options from internal this._marks[type]\n **/\n\n }, {\n key: \"formatSavedMarker\",\n value: function formatSavedMarker(mark) {\n return {\n type: mark.type,\n lat: mark.lat,\n lng: mark.lng,\n name: mark.name,\n description: mark.description,\n user: mark.username || this.user.username,\n userId: mark.userId || this.user.id,\n dom: null,\n rate: mark.rate,\n marker: null,\n circle: null\n };\n }\n /**\n * @method\n * @name editMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method will open a mark edition modal\n *\n * @param {Object} options The mark options to edit\n **/\n\n }, {\n key: \"editMarker\",\n value: function editMarker(options) {\n this._map.closePopup();\n\n this.editMarkModal(options);\n }\n /**\n * @method\n * @name deleteMarker\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since February 2022\n * @description\n *
\n * This method will delete a mark after prompting the user if he trully wants to\n *\n * @param {Object} options The mark options to delete\n **/\n\n }, {\n key: \"deleteMarker\",\n value: function deleteMarker(options) {\n var _this13 = this;\n\n this.deleteMarkModal(function (confirm) {\n if (confirm === true) {\n // Iterate through marks to find matching one (by coord as marks coordinates are unique)\n var marks = _this13._marks[options.type];\n\n for (var i = 0; i < marks.length; ++i) {\n // We found, remove circle, label and marker from map/clusters\n if (options.lat === marks[i].lat && options.lng === marks[i].lng) {\n _this13.setMarkerCircles([marks[i]], false);\n\n _this13.setMarkerLabels([marks[i]], false);\n\n _this13._clusters[options.type].removeLayer(marks[i].marker);\n\n marks.splice(i, 1);\n break;\n }\n } // Update internal marks array\n\n\n _this13._marks[options.type] = marks; // Format marks to be saved and then update user preference with\n\n var formattedMarks = [];\n\n for (var _i4 = 0; _i4 < _this13._marks[options.type].length; ++_i4) {\n formattedMarks.push(_this13.formatSavedMarker(_this13._marks[options.type][_i4]));\n }\n\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].setPreference(\"saved-\".concat(options.type), JSON.stringify(formattedMarks)); // Notify user through UI that marker has been successfully deleted\n\n _this13._notification.raise(_this13.nls.notif(\"\".concat(options.type, \"Deleted\")));\n }\n });\n } // ======================================================================== //\n // ---------------------------- Debug methods ----------------------------- //\n // ======================================================================== //\n\n /**\n * @method\n * @name addDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The addDebugUI() method appends the debug DOM element to the document body\n *\n **/\n\n }, {\n key: \"addDebugUI\",\n value: function addDebugUI() {\n document.body.appendChild(this._debugElement);\n }\n /**\n * @method\n * @name removeDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The removeDebugUI() method remove the debug DOM element from the document body\n *\n **/\n\n }, {\n key: \"removeDebugUI\",\n value: function removeDebugUI() {\n document.body.removeChild(this._debugElement);\n }\n /**\n * @method\n * @name updateDebugUI\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since January 2022\n * @description\n *
\n * The updateDebugUI() method will update informations held in the debug DOM\n *\n **/\n\n }, {\n key: \"updateDebugUI\",\n value: function updateDebugUI() {\n var options = _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('map-high-accuracy') === 'true' ? _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].HIGH_ACCURACY : _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].OPTIMIZED_ACCURACY;\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].updateDebugInterface(this._debugElement, this._user, options);\n }\n /**\n * @method\n * @name downloadData\n * @public\n * @memberof BeerCrackerz\n * @author Arthur Beaulieu\n * @since August 2022\n * @description\n *
\n * The downloadData() method will save to user disk the saved spots as a JSON file\n *\n **/\n\n }, {\n key: \"downloadData\",\n value: function downloadData() {\n var dataString = \"data:text/json;charset=utf-8,\".concat(encodeURIComponent(_js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getPreference('saved-spot')));\n var link = document.createElement('A');\n link.setAttribute('href', dataString);\n link.setAttribute('download', 'BeerCrackerzData.json');\n link.click();\n } // ======================================================================== //\n // ---------------------------- Class accessors --------------------------- //\n // ======================================================================== //\n\n /**\n * @public\n * @property {Object} map\n * Leaflet.js map getter\n **/\n\n }, {\n key: \"map\",\n get: function get() {\n return this._map;\n }\n /**\n * @public\n * @property {Object} marks\n * Leaflet.js marks that holds spot/store/bar marks as subkeys\n **/\n\n }, {\n key: \"marks\",\n get: function get() {\n return this._marks;\n }\n /**\n * @public\n * @property {Object} user\n * The session user object\n **/\n\n }, {\n key: \"user\",\n get: function get() {\n return this._user;\n }\n /**\n * @public\n * @property {Object} nls\n * The LangManager getter\n **/\n\n }, {\n key: \"nls\",\n get: function get() {\n return this._lang;\n }\n }]);\n\n return BeerCrackerz;\n}(_js_MapHelper_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BeerCrackerz);\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerz.js?"); + +/***/ }), + +/***/ "./src/js/MapHelper.js": +/*!*****************************!*\ + !*** ./src/js/MapHelper.js ***! + \*****************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/MarkerEnum.js */ \"./src/js/utils/MarkerEnum.js\");\n/* harmony import */ var _ui_Rating_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui/Rating.js */ \"./src/js/ui/Rating.js\");\n/* harmony import */ var _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils/Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\n\nvar MapHelper = /*#__PURE__*/function () {\n function MapHelper() {\n /* Mixin to be extended from the BeerCrackerz main class */\n\n _classCallCheck(this, MapHelper);\n } // ======================================================================== //\n // --------------------------- Marker helpers ----------------------------- //\n // ======================================================================== //\n\n\n _createClass(MapHelper, [{\n key: \"placeMarker\",\n value: function placeMarker(options) {\n var _this = this;\n\n var icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].black;\n\n if (options.type === 'store') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].blue;\n } else if (options.type === 'spot') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].green;\n } else if (options.type === 'bar') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].red;\n } else if (options.type === 'user') {\n icon = _utils_MarkerEnum_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].user;\n }\n\n var marker = window.L.marker([options.lat, options.lng], {\n icon: icon\n }).on('click', function () {\n // Disable center on lock if previously set to true\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('map-center-on-user') === 'true') {\n _this.toggleFocusLock();\n } // Actual fly to the marker\n\n\n _this.map.flyTo([options.lat, options.lng], 18);\n });\n\n if (options.dom) {\n marker.bindPopup(options.dom);\n } // All markers that are not spot/store/bar should be appended to the map\n\n\n if (['spot', 'store', 'bar'].indexOf(options.type) === -1) {\n marker.addTo(this.map);\n }\n\n return marker;\n }\n }, {\n key: \"drawUserMarker\",\n value: function drawUserMarker() {\n if (!this.user.marker) {\n // Create user marker if not existing\n this.user.type = 'user';\n this.user.marker = this.placeMarker(this.user); // Append circle around marker for accuracy and range for new marker\n\n this.user.radius = this.user.accuracy;\n this.user.circle = this.drawCircle(this.user);\n this.user.range = this.drawCircle({\n lat: this.user.lat,\n lng: this.user.lng,\n radius: _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].NEW_MARKER_RANGE,\n color: _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].RANGE_COLOR\n }); // Update circle opacity if pref is at true\n\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('poi-show-circle') === 'true') {\n this.user.circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n this.user.range.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n } // Callback on marker clicked to add marker on user position\n\n\n this.user.marker.on('click', this.mapClicked.bind(this));\n } else {\n // Update user marker position, range, and accuracy circle\n this.user.marker.setLatLng(this.user);\n this.user.range.setLatLng(this.user);\n this.user.circle.setLatLng(this.user);\n this.user.circle.setRadius(this.user.accuracy);\n }\n }\n }, {\n key: \"definePOI\",\n value: function definePOI(options, callback) {\n var _this2 = this;\n\n var dom = {\n wrapper: document.createElement('DIV'),\n title: document.createElement('P'),\n spot: document.createElement('BUTTON'),\n store: document.createElement('BUTTON'),\n bar: document.createElement('BUTTON')\n }; // Update class and inner HTMl content according to user's nls\n\n dom.wrapper.className = 'new-poi';\n dom.title.innerHTML = this.nls.map('newTitle');\n dom.spot.innerHTML = this.nls.map('newSpot');\n dom.store.innerHTML = this.nls.map('newStore');\n dom.bar.innerHTML = this.nls.map('newBar'); // Atach data type to each button (to be used in clicked callback)\n\n dom.spot.dataset.type = 'spot';\n dom.store.dataset.type = 'store';\n dom.bar.dataset.type = 'bar'; // DOM chaining\n\n dom.wrapper.appendChild(dom.title);\n dom.wrapper.appendChild(dom.spot);\n dom.wrapper.appendChild(dom.store);\n dom.wrapper.appendChild(dom.bar); // Update popup content with DOM elements\n\n options.dom = dom.wrapper; // Create temporary mark with wrapper content and open it to offer user the creation menu\n\n var marker = this.placeMarker(options).openPopup();\n options.marker = marker; // Attach marker to option so it can be manipulated in clicked callbacks\n\n options.addedCallback = callback; // Attach callback to be called when marker addition is done\n // Callback on button clicked (to open modal and define a new mark)\n\n var _prepareNewMark = function _prepareNewMark(e) {\n marker.isBeingDefined = true;\n marker.closePopup();\n\n _this2.defineMarkFactory(e.target.dataset.type, options);\n }; // Buttons click events\n\n\n dom.spot.addEventListener('click', _prepareNewMark);\n dom.store.addEventListener('click', _prepareNewMark);\n dom.bar.addEventListener('click', _prepareNewMark); // Listen to clicks outside of popup to close new mark\n\n marker.on('popupclose', function () {\n if (!marker.isBeingDefined) {\n marker.popupClosed = true;\n marker.removeFrom(_this2.map);\n }\n });\n return marker;\n } // ======================================================================== //\n // ---------------------- New mark in modal helper ------------------------ //\n // ======================================================================== //\n\n }, {\n key: \"defineMarkFactory\",\n value: function defineMarkFactory(type, options) {\n var _this3 = this;\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fetchTemplate(\"assets/html/modal/new\".concat(type, \".html\")).then(function (dom) {\n var name = dom.querySelector(\"#\".concat(type, \"-name\"));\n var description = dom.querySelector(\"#\".concat(type, \"-desc\"));\n var rating = new _ui_Rating_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"](dom.querySelector(\"#\".concat(type, \"-rating\")));\n var submit = dom.querySelector(\"#\".concat(type, \"-submit\"));\n var cancel = dom.querySelector(\"#\".concat(type, \"-cancel\"));\n var close = dom.querySelector('#modal-close'); // Update nls for template\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-title\")), \"{{\".concat(type.toUpperCase(), \"_TITLE}}\"), _this3.nls[type]('title'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-subtitle\")), \"{{\".concat(type.toUpperCase(), \"_SUBTITLE}}\"), _this3.nls[type]('subtitle'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-name\")), \"{{\".concat(type.toUpperCase(), \"_NAME}}\"), _this3.nls[type]('nameLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-desc\")), \"{{\".concat(type.toUpperCase(), \"_DESC}}\"), _this3.nls[type]('descLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(dom.querySelector(\"#nls-\".concat(type, \"-rate\")), \"{{\".concat(type.toUpperCase(), \"_RATE}}\"), _this3.nls[type]('rateLabel'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(submit, \"{{\".concat(type.toUpperCase(), \"_SUBMIT}}\"), _this3.nls.nav('add'));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(cancel, \"{{\".concat(type.toUpperCase(), \"_CANCEL}}\"), _this3.nls.nav('cancel')); // Method to clear modal and hide it, and remove temporary marker on the map\n\n var _cleanDefineUI = function _cleanDefineUI() {\n options.marker.isBeingDefined = false;\n options.marker.removeFrom(_this3.map); // Clear temporary black marker\n\n _this3.closeModal(null, true);\n }; // Submit or cancel event subscriptions\n\n\n submit.addEventListener('click', function () {\n if (name.value === '') {\n _this3._notification.raise(_this3.nls.notif('markNameEmpty'));\n } else {\n _cleanDefineUI();\n\n options.type = type;\n options.name = name.value, options.description = description.value;\n options.rate = rating.currentRate;\n\n _this3.markPopupFactory(options).then(function (dom) {\n options.dom = dom;\n options.marker = _this3.placeMarker(options); // Create final marker\n\n options.addedCallback(options);\n });\n }\n });\n cancel.addEventListener('click', _cleanDefineUI);\n close.addEventListener('click', _cleanDefineUI);\n\n _this3.newMarkModal(dom);\n });\n }\n }, {\n key: \"defineNewSpot\",\n value: function defineNewSpot(options) {\n this.defineMarkFactory('spot', options);\n }\n }, {\n key: \"defineNewStore\",\n value: function defineNewStore(options) {\n this.defineMarkFactory('store', options);\n }\n }, {\n key: \"defineNewBar\",\n value: function defineNewBar(options) {\n this.defineMarkFactory('bar', options);\n } // ======================================================================== //\n // ------------------------- Mark popup helper ---------------------------- //\n // ======================================================================== //\n\n }, {\n key: \"markPopupFactory\",\n value: function markPopupFactory(options) {\n var _this4 = this;\n\n return new Promise(function (resolve) {\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fetchTemplate(\"assets/html/popup/\".concat(options.type, \".html\")).then(function (dom) {\n var element = document.createElement('DIV');\n element.appendChild(dom);\n var user = options.user || _this4.user.username;\n\n var desc = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].stripDom(options.description) || _this4.nls.popup(\"\".concat(options.type, \"NoDesc\"));\n\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_NAME}}\"), _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].stripDom(options.name));\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_FINDER}}\"), user);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_RATE}}\"), options.rate + 1);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_DESC}}\"), desc);\n _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(element, \"{{\".concat(options.type.toUpperCase(), \"_FOUND_BY}}\"), _this4.nls.popup(\"\".concat(options.type, \"FoundBy\"))); // Fill mark rate (rating is in [0, 4] explaining the +1 in loop bound)\n\n var rate = element.querySelector(\"#\".concat(options.type, \"-rating\"));\n\n for (var i = 0; i < options.rate + 1; ++i) {\n rate.children[i].classList.add('active');\n } // Remove picture icon if user is not in range\n\n\n var distance = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getDistanceBetweenCoords([_this4.user.lat, _this4.user.lng], [options.lat, options.lng]);\n\n if (distance > _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].CIRCLE_RADIUS) {\n console.log('Too far'); //element.removeChild(element.querySelector(''));\n } // Remove edition buttons if marker is not user's one, this does not replace a server test for edition...\n\n\n if (user !== _this4.user.username) {\n element.removeChild(element.querySelector('#popup-edit'));\n } else {\n element.querySelector('#edit-mark').addEventListener('click', _this4.editMarker.bind(_this4, options), false);\n element.querySelector('#delete-mark').addEventListener('click', _this4.deleteMarker.bind(_this4, options), false);\n } // Append circle around marker\n\n\n options.color = _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"][\"\".concat(options.type.toUpperCase(), \"_COLOR\")];\n options.circle = _this4.drawCircle(options); // Create label for new marker\n\n options.tooltip = window.L.tooltip({\n permanent: true,\n direction: 'center',\n className: 'marker-tooltip',\n interactive: true\n }).setContent(options.name).setLatLng(options.circle.getLatLng()); // Only make it visible if preference is to true\n\n if (_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].getPreference('poi-marker-label') === 'true') {\n options.tooltip.addTo(_this4.map);\n } // Send back the popup\n\n\n resolve(element);\n });\n });\n }\n }, {\n key: \"drawCircle\",\n value: function drawCircle(options) {\n return window.L.circle(options, {\n color: options.color,\n fillColor: options.color,\n opacity: 0,\n // This needs to be updated according to user proximity\n fillOpacity: 0,\n // Same for this parameter\n radius: options.radius ? options.radius : _utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].CIRCLE_RADIUS\n }).addTo(this.map);\n }\n }, {\n key: \"setMarkerCircles\",\n value: function setMarkerCircles(marks, visible) {\n for (var i = 0; i < marks.length; ++i) {\n // Here we update both opacity and add/remove circle from map\n if (visible) {\n marks[i].circle.setStyle({\n opacity: 1,\n fillOpacity: 0.1\n });\n marks[i].circle.addTo(this.map);\n } else {\n marks[i].circle.setStyle({\n opacity: 0,\n fillOpacity: 0\n });\n marks[i].circle.removeFrom(this.map);\n }\n }\n }\n }, {\n key: \"setMarkerLabels\",\n value: function setMarkerLabels(marks, visible) {\n for (var i = 0; i < marks.length; ++i) {\n if (visible) {\n marks[i].tooltip.addTo(this.map);\n } else {\n marks[i].tooltip.removeFrom(this.map);\n }\n }\n }\n }]);\n\n return MapHelper;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (MapHelper);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/MapHelper.js?"); + +/***/ }), + +/***/ "./src/js/ui/Notification.js": +/*!***********************************!*\ + !*** ./src/js/ui/Notification.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Notification = /*#__PURE__*/function () {\n function Notification() {\n _classCallCheck(this, Notification);\n\n this._container = document.querySelector('#notification-wrapper');\n this._message = document.querySelector('#notification-message');\n this._timeoutId = null;\n }\n\n _createClass(Notification, [{\n key: \"raise\",\n value: function raise(message) {\n var _this = this;\n\n clearTimeout(this._timeoutId);\n this._message.innerHTML = message;\n\n this._container.classList.add('opened');\n\n this._timeoutId = setTimeout(function () {\n _this._container.classList.remove('opened');\n\n _this._message.innerHTML = '';\n }, 2000);\n }\n }]);\n\n return Notification;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Notification);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/Notification.js?"); + +/***/ }), + +/***/ "./src/js/ui/Rating.js": +/*!*****************************!*\ + !*** ./src/js/ui/Rating.js ***! + \*****************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Rating = /*#__PURE__*/function () {\n function Rating(domList, rate) {\n _classCallCheck(this, Rating);\n\n this._container = null;\n this._items = [];\n this._currentRate = rate || 0; // Mostly for hover operations\n\n this._clicked = rate || -1; // To know when user clicked on a given star\n\n this._init(domList);\n\n this._events();\n }\n\n _createClass(Rating, [{\n key: \"_init\",\n value: function _init(domList) {\n this._container = domList;\n\n for (var i = 0; i < domList.children.length; ++i) {\n this._items.push(domList.children[i]);\n } // Init Rating with given rate\n\n\n for (var _i = 0; _i < this._currentRate + 1; ++_i) {\n this._items[_i].classList.add('active');\n\n this._items[_i].classList.add('selected');\n }\n }\n }, {\n key: \"_events\",\n value: function _events() {\n this._container.addEventListener('mouseover', this._containerHovered.bind(this), false);\n\n this._container.addEventListener('mouseout', this._pointerExit.bind(this), false);\n\n for (var i = 0; i < this._items.length; ++i) {\n this._items[i].addEventListener('click', this._starClicked.bind(this), false);\n }\n }\n }, {\n key: \"_containerHovered\",\n value: function _containerHovered(event) {\n if (event.target.tagName === 'IMG') {\n this._currentRate = parseInt(event.target.dataset.id);\n this._container.dataset.rate = this._currentRate;\n this.updateStars();\n }\n }\n }, {\n key: \"_pointerExit\",\n value: function _pointerExit() {\n this._currentRate = this._clicked === -1 ? 0 : this._clicked;\n this._container.dataset.rate = this._currentRate;\n this.updateStars();\n }\n }, {\n key: \"_starClicked\",\n value: function _starClicked(event) {\n this._currentRate = parseInt(event.target.dataset.id);\n this._container.dataset.rate = this._currentRate;\n this._clicked = this._currentRate;\n this.updateStars();\n }\n }, {\n key: \"updateStars\",\n value: function updateStars() {\n for (var i = 0; i < this._items.length; ++i) {\n if (i <= this._currentRate) {\n this._items[i].classList.add('active');\n\n if (i <= this._clicked) {\n this._items[i].classList.add('selected');\n }\n } else {\n this._items[i].classList.remove('active');\n\n this._items[i].classList.remove('selected');\n }\n }\n }\n }, {\n key: \"currentRate\",\n get: function get() {\n return this._currentRate;\n }\n }]);\n\n return Rating;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Rating);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/Rating.js?"); + +/***/ }), + +/***/ "./src/js/ui/ZoomSlider.js": +/*!*********************************!*\ + !*** ./src/js/ui/ZoomSlider.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar ZoomSlider = /*#__PURE__*/function () {\n function ZoomSlider(map) {\n _classCallCheck(this, ZoomSlider);\n\n this._map = map;\n this._container = document.querySelector('#zoom-slider');\n this._slider = document.querySelector('#slider-position');\n this._zoomRange = this._map.getMaxZoom() - this._map.getMinZoom();\n this._timeoutId = -1;\n\n this._events();\n }\n\n _createClass(ZoomSlider, [{\n key: \"_events\",\n value: function _events() {\n var _this = this;\n\n this._map.on('zoomstart', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n\n _this._container.classList.add('opened');\n });\n\n this._map.on('zoomend', function () {\n var correctedZoom = _this._map.getZoom() - _this._map.getMinZoom();\n\n _this._slider.style.height = \"\".concat(correctedZoom * 100 / _this._zoomRange, \"%\");\n _this._timeoutId = setTimeout(function () {\n return _this._container.classList.remove('opened');\n }, 1500);\n });\n\n this._map.on('zoom', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n\n var correctedZoom = _this._map.getZoom() - _this._map.getMinZoom();\n\n _this._slider.style.height = \"\".concat(correctedZoom * 100 / _this._zoomRange, \"%\");\n });\n\n this._container.addEventListener('mouseover', function () {\n clearTimeout(_this._timeoutId);\n _this._timeoutId = -1;\n });\n\n this._container.addEventListener('mouseleave', function () {\n _this._timeoutId = setTimeout(function () {\n return _this._container.classList.remove('opened');\n }, 1500);\n });\n\n this._container.querySelector('#zoom-more').addEventListener('click', function () {\n _this._map.setZoom(_this._map.getZoom() + 1);\n });\n\n this._container.querySelector('#zoom-less').addEventListener('click', function () {\n _this._map.setZoom(_this._map.getZoom() - 1);\n });\n }\n }]);\n\n return ZoomSlider;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ZoomSlider);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/ui/ZoomSlider.js?"); + +/***/ }), + +/***/ "./src/js/utils/LangManager.js": +/*!*************************************!*\ + !*** ./src/js/utils/LangManager.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _Utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar LangManager = /*#__PURE__*/function () {\n function LangManager(lang, cb) {\n _classCallCheck(this, LangManager);\n\n this._lang = _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SUPPORTED_LANGUAGE.indexOf(lang) !== -1 ? lang : 'en';\n this._values = {};\n\n this._init().then(cb);\n }\n\n _createClass(LangManager, [{\n key: \"_init\",\n value: function _init() {\n var _this = this;\n\n return new Promise(function (resolve, reject) {\n _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].fetchFile(\"assets/nls/\".concat(_this._lang, \".json\")).then(function (lang) {\n _this._values = JSON.parse(lang);\n resolve();\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"debug\",\n value: function debug(key) {\n return this._values.debug[key] || '';\n }\n }, {\n key: \"notif\",\n value: function notif(key) {\n return this._values.notif[key] || '';\n }\n }, {\n key: \"nav\",\n value: function nav(key) {\n return this._values.nav[key] || '';\n }\n }, {\n key: \"map\",\n value: function map(key) {\n return this._values.map[key] || '';\n }\n }, {\n key: \"spot\",\n value: function spot(key) {\n return this._values.spot[key] || '';\n }\n }, {\n key: \"store\",\n value: function store(key) {\n return this._values.store[key] || '';\n }\n }, {\n key: \"bar\",\n value: function bar(key) {\n return this._values.bar[key] || '';\n }\n }, {\n key: \"popup\",\n value: function popup(key) {\n return this._values.popup[key] || '';\n }\n }, {\n key: \"modal\",\n value: function modal(key) {\n return this._values.modal[key] || '';\n }\n }, {\n key: \"login\",\n value: function login(key) {\n return this._values.auth.login[key] || '';\n }\n }, {\n key: \"register\",\n value: function register(key) {\n return this._values.auth.register[key] || '';\n }\n }]);\n\n return LangManager;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (LangManager);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/LangManager.js?"); + +/***/ }), + +/***/ "./src/js/utils/MarkerEnum.js": +/*!************************************!*\ + !*** ./src/js/utils/MarkerEnum.js ***! + \************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Object.freeze({\n blue: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-blue.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n gold: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-gold.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n red: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-red.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n green: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-green.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n orange: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-orange.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n yellow: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-yellow.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n violet: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-violet.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n grey: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-grey.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n black: new window.L.Icon({\n iconUrl: 'assets/img/marker/marker-icon-black.png',\n shadowUrl: 'assets/img/marker/marker-shadow.png',\n iconSize: [25, 41],\n iconAnchor: [12, 41],\n popupAnchor: [1, -34],\n shadowSize: [41, 41]\n }),\n user: new window.L.Icon({\n iconUrl: 'assets/img/marker/user-position.png',\n shadowUrl: 'assets/img/marker/user-position-shadow.png',\n iconSize: [32, 32],\n iconAnchor: [16, 16],\n popupAnchor: [1, -34],\n shadowSize: [32, 32]\n })\n}));\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/MarkerEnum.js?"); + +/***/ }), + +/***/ "./src/js/utils/ProviderEnum.js": +/*!**************************************!*\ + !*** ./src/js/utils/ProviderEnum.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Object.freeze({\n planOsm: window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n attribution: '© OpenStreetMap',\n maxZoom: 21,\n maxNativeZoom: 19,\n // To ensure tiles are not unloaded when zooming after 19\n minZoom: 2 // Don't allow dezooming too far from map so it always stay fully visible\n\n }),\n\n /*planGeo: window.L.tileLayer('https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', {\n attribution: '© Geoportail France',\n apikey: 'choisirgeoportail',\n format: 'image/png',\n style: 'normal',\n minZoom: 2, // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19, // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21,\n }),*/\n satEsri: window.L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {\n attribution: '© Esri Imagery',\n minZoom: 2,\n // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19,\n // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21\n })\n /*satGeo: window.L.tileLayer('https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', {\n attribution: '© Geoportail France',\n apikey: 'choisirgeoportail',\n format: 'image/jpeg',\n style: 'normal',\n minZoom: 2, // Don't allow dezooming too far from map so it always stay fully visible\n maxNativeZoom: 19, // To ensure tiles are not unloaded when zooming after 19\n maxZoom: 21 \n })*/\n\n}));\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/ProviderEnum.js?"); + +/***/ }), + +/***/ "./src/js/utils/Utils.js": +/*!*******************************!*\ + !*** ./src/js/utils/Utils.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Utils = /*#__PURE__*/function () {\n function Utils() {\n /* Not meant to be instantiated, all methods should be static */\n\n _classCallCheck(this, Utils);\n }\n\n _createClass(Utils, null, [{\n key: \"fetchTemplate\",\n value: function fetchTemplate(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(function (html) {\n resolve(document.createRange().createContextualFragment(html));\n })[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"fetchFile\",\n value: function fetchFile(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"getReq\",\n value: function getReq(url) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'GET',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default'\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"postReq\",\n value: function postReq(url, data) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'POST',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default',\n body: data\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"stripDom\",\n value: function stripDom(html) {\n var doc = new DOMParser().parseFromString(html, 'text/html');\n return doc.body.textContent || '';\n }\n }, {\n key: \"replaceString\",\n value: function replaceString(element, string, value) {\n element.innerHTML = element.innerHTML.replace(string, value);\n }\n }, {\n key: \"getDistanceBetweenCoords\",\n value: function getDistanceBetweenCoords(from, to) {\n // return distance in meters\n var lon1 = from[1] * Math.PI / 180,\n lat1 = from[0] * Math.PI / 180,\n lon2 = to[1] * Math.PI / 180,\n lat2 = to[0] * Math.PI / 180;\n var deltaLat = lat2 - lat1;\n var deltaLon = lon2 - lon1;\n var a = Math.pow(Math.sin(deltaLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2), 2);\n var c = 2 * Math.asin(Math.sqrt(a));\n var EARTH_RADIUS = 6371;\n return c * EARTH_RADIUS * 1000;\n }\n /** @method\n * @name precisionRound\n * @public\n * @memberof Utils\n * @author Arthur Beaulieu\n * @since September 2018\n * @description Do a Math.round with a given precision (ie amount of integers after the coma)\n * @param {nunmber} value - The value to precisely round\n * @param {number} precision - The number of integers after the coma\n * @return {number} - The rounded value */\n\n }, {\n key: \"precisionRound\",\n value: function precisionRound(value, precision) {\n var multiplier = Math.pow(10, precision || 0);\n return Math.round(value * multiplier) / multiplier;\n }\n }, {\n key: \"initDebugInterface\",\n value: function initDebugInterface() {\n var lang = window.BeerCrackerz.nls.debug.bind(window.BeerCrackerz.nls);\n var debugContainer = document.createElement('DIV');\n var userLat = document.createElement('P');\n var userLng = document.createElement('P');\n var updatesAmount = document.createElement('P');\n var userAccuracy = document.createElement('P');\n var highAccuracy = document.createElement('P');\n var maxAge = document.createElement('P');\n var posTimeout = document.createElement('P');\n var zoomLevel = document.createElement('P');\n var marks = document.createElement('P');\n var exportData = document.createElement('BUTTON');\n debugContainer.classList.add('debug-container');\n userLat.classList.add('debug-user-lat');\n userLng.classList.add('debug-user-lng');\n updatesAmount.classList.add('debug-updates-amount');\n userAccuracy.classList.add('debug-user-accuracy');\n highAccuracy.classList.add('debug-high-accuracy');\n maxAge.classList.add('debug-pos-max-age');\n posTimeout.classList.add('debug-pos-timeout');\n zoomLevel.classList.add('debug-zoom-level');\n marks.classList.add('debug-marks-amount');\n exportData.classList.add('debug-export-data');\n userLat.innerHTML = \"\".concat(lang('lat'), \" : -\");\n userLng.innerHTML = \"\".concat(lang('lng'), \" : -\");\n updatesAmount.innerHTML = \"\".concat(lang('updates'), \" : 0\");\n userAccuracy.innerHTML = \"\".concat(lang('accuracy'), \" : -\");\n highAccuracy.innerHTML = \"\".concat(lang('highAccuracy'), \" : -\");\n maxAge.innerHTML = \"\".concat(lang('posAge'), \" : -\");\n posTimeout.innerHTML = \"\".concat(lang('posTimeout'), \" : -\");\n zoomLevel.innerHTML = \"\".concat(lang('zoom'), \" : -\");\n marks.innerHTML = \"\".concat(lang('marks'), \" : -\");\n exportData.innerHTML = lang('export');\n debugContainer.appendChild(userLat);\n debugContainer.appendChild(userLng);\n debugContainer.appendChild(updatesAmount);\n debugContainer.appendChild(userAccuracy);\n debugContainer.appendChild(highAccuracy);\n debugContainer.appendChild(maxAge);\n debugContainer.appendChild(posTimeout);\n debugContainer.appendChild(zoomLevel);\n debugContainer.appendChild(marks);\n debugContainer.appendChild(exportData);\n exportData.addEventListener('click', window.BeerCrackerz.downloadData.bind(window.BeerCrackerz));\n return debugContainer;\n }\n }, {\n key: \"updateDebugInterface\",\n value: function updateDebugInterface(element, user, options) {\n if (window.DEBUG === true) {\n var bc = window.BeerCrackerz;\n var lang = bc.nls.debug.bind(bc.nls);\n var updates = parseInt(element.querySelector('.debug-updates-amount').innerHTML.split(' : ')[1]) + 1;\n var marks = bc.marks.spot.length + bc.marks.store.length + bc.marks.bar.length;\n element.querySelector('.debug-user-lat').innerHTML = \"\\n \".concat(lang('lat'), \" : \").concat(user.lat, \"\\n \");\n element.querySelector('.debug-user-lng').innerHTML = \"\\n \".concat(lang('lng'), \" : \").concat(user.lng, \"\\n \");\n element.querySelector('.debug-updates-amount').innerHTML = \"\\n \".concat(lang('updates'), \" : \").concat(updates, \"\\n \");\n element.querySelector('.debug-user-accuracy').innerHTML = \"\\n \".concat(lang('accuracy'), \" : \").concat(Utils.precisionRound(user.accuracy, 2), \"m\\n \");\n element.querySelector('.debug-high-accuracy').innerHTML = \"\\n \".concat(lang('highAccuracy'), \" : \").concat(options.enableHighAccuracy === true ? lang('enabled') : lang('disabled'), \"\\n \");\n element.querySelector('.debug-pos-max-age').innerHTML = \"\\n \".concat(lang('posAge'), \" : \").concat(options.maximumAge / 1000, \"s\\n \");\n element.querySelector('.debug-pos-timeout').innerHTML = \"\\n \".concat(lang('posTimeout'), \" : \").concat(options.timeout / 1000, \"s\\n \");\n element.querySelector('.debug-zoom-level').innerHTML = \"\\n \".concat(lang('zoom'), \" : \").concat(bc.map.getZoom(), \"\\n \");\n element.querySelector('.debug-marks-amount').innerHTML = \"\\n \".concat(lang('marks'), \" : \").concat(marks, \"\\n \");\n }\n }\n }, {\n key: \"getPreference\",\n value: function getPreference(pref) {\n return localStorage.getItem(pref) || null;\n }\n }, {\n key: \"setPreference\",\n value: function setPreference(pref, value) {\n localStorage.setItem(pref, value);\n }\n }, {\n key: \"RANGE_COLOR\",\n get: function get() {\n return '#ffd87d';\n }\n }, {\n key: \"USER_COLOR\",\n get: function get() {\n return '#63fff5';\n }\n }, {\n key: \"SPOT_COLOR\",\n get: function get() {\n return '#26ad23';\n }\n }, {\n key: \"STORE_COLOR\",\n get: function get() {\n return '#247dc9';\n }\n }, {\n key: \"BAR_COLOR\",\n get: function get() {\n return '#ca2a3d';\n }\n }, {\n key: \"CIRCLE_RADIUS\",\n get: function get() {\n return 100;\n }\n }, {\n key: \"NEW_MARKER_RANGE\",\n get: function get() {\n return 200;\n }\n }, {\n key: \"MAP_BOUNDS\",\n get: function get() {\n return window.L.latLngBounds(window.L.latLng(-89.98155760646617, -180), window.L.latLng(89.99346179538875, 180));\n }\n }, {\n key: \"HIGH_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: true,\n // More consuption, better position\n maximumAge: 1000,\n // A position will last 1s maximum\n timeout: 900 // A position is updated in 0.9s maximum\n\n };\n }\n }, {\n key: \"OPTIMIZED_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: false,\n // Less consuption\n maximumAge: 30000,\n // A position will last 30s maximum\n timeout: 29000 // A position is updated in 29s maximum\n\n };\n }\n }, {\n key: \"SUPPORTED_LANGUAGE\",\n get: function get() {\n return ['en', 'fr', 'es', 'de'];\n }\n }]);\n\n return Utils;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/Utils.js?"); + +/***/ }), + +/***/ "./src/BeerCrackerz.scss": +/*!*******************************!*\ + !*** ./src/BeerCrackerz.scss ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerz.scss?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/BeerCrackerz.js"); +/******/ window.BeerCrackerz = __webpack_exports__["default"]; +/******/ +/******/ })() +; \ No newline at end of file diff --git a/static/dist/BeerCrackerzAuth.bundle.css b/static/dist/BeerCrackerzAuth.bundle.css new file mode 100755 index 0000000..1c16b47 --- /dev/null +++ b/static/dist/BeerCrackerzAuth.bundle.css @@ -0,0 +1,4 @@ +/*!**********************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].use[2]!./node_modules/sass-loader/dist/cjs.js!./src/BeerCrackerzAuth.scss ***! + \**********************************************************************************************************************************************************************************************************************/ +@-webkit-keyframes flashing-logo{0%{-webkit-text-fill-color:transparent;background:linear-gradient(60deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}15%{-webkit-text-fill-color:transparent;background:linear-gradient(120deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}58%{-webkit-text-fill-color:transparent;background:-webkit-gradient(linear,left top,left bottom,from(#97ea9b),color-stop(80%,#ad7fe6));background:linear-gradient(180deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1)}to{-webkit-text-fill-color:transparent;background:linear-gradient(240deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0;-webkit-transform:scale(1);transform:scale(1)}}@keyframes flashing-logo{0%{-webkit-text-fill-color:transparent;background:linear-gradient(60deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}15%{-webkit-text-fill-color:transparent;background:linear-gradient(120deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0}58%{-webkit-text-fill-color:transparent;background:-webkit-gradient(linear,left top,left bottom,from(#97ea9b),color-stop(80%,#ad7fe6));background:linear-gradient(180deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1)}to{-webkit-text-fill-color:transparent;background:linear-gradient(240deg,#97ea9b,#ad7fe6 80%);-webkit-background-clip:text;background-clip:text;opacity:0;-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes drop-nav-link{0%{margin-bottom:20rem;-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}to{margin-bottom:0;-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes drop-nav-link{0%{margin-bottom:20rem;-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}to{margin-bottom:0;-webkit-transform:rotate(0);transform:rotate(0)}}@-webkit-keyframes beating{0%{-webkit-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.01);transform:scale(1.01)}20%{-webkit-transform:scale(1);transform:scale(1)}80%{-webkit-transform:scale(1);transform:scale(1)}90%{-webkit-transform:scale(1.02);transform:scale(1.02)}to{-webkit-transform:scale(1);transform:scale(1)}}@keyframes beating{0%{-webkit-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.01);transform:scale(1.01)}20%{-webkit-transform:scale(1);transform:scale(1)}80%{-webkit-transform:scale(1);transform:scale(1)}90%{-webkit-transform:scale(1.02);transform:scale(1.02)}to{-webkit-transform:scale(1);transform:scale(1)}}*{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}body,html{font-size:62.5%;height:100%;overflow:hidden;width:100%}body{background:#181818;color:#d4d4d4;font-family:sans-serif}h1{color:#181818;font-size:2.8rem;margin-bottom:1.2rem}h2{font-size:2.4rem}a{color:#a1ff86}a,label,p{font-size:1.2rem;margin-bottom:1.2rem}label,p{color:#2e2e2e}label{font-style:italic}input,textarea{border:1px solid #424242;border-radius:.5rem;display:block;margin:.5rem auto 1.2rem;padding:.5rem;-webkit-transition:border .2s;transition:border .2s;width:100%}input.error{border-color:#ff5454}button{background-color:hsla(0,0%,91%,.667);border:1px solid #424242;border-radius:.5rem;cursor:pointer;display:block;margin:.5rem auto;padding:.5rem;-webkit-transition:background-color .2s;transition:background-color .2s;width:100%}button:active,button:focus,button:hover{background-color:hsla(0,0%,85%,.667)}button.validate{background-color:rgba(161,255,134,.667)}button.cancel{background-color:hsla(0,100%,80%,.667)}body{background:#fff;position:relative}aside,body{height:100%;width:100%}aside{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:justify;-ms-flex-pack:justify;background-color:grey;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:space-between;max-width:40rem;position:absolute;right:0;text-align:center}aside h1{margin-bottom:0}aside header{margin-top:5rem}aside main{margin:0 4rem;text-align:left}aside main button{margin:2.9rem auto 1.2rem}aside main p{text-align:right}aside main .login-error{color:transparent;font-style:italic;font-weight:700;text-align:center;-webkit-transition:color .2s;transition:color .2s}aside main .login-error.visible{color:#ff5454}aside footer{margin-bottom:5rem} diff --git a/static/dist/BeerCrackerzAuth.bundle.js b/static/dist/BeerCrackerzAuth.bundle.js new file mode 100755 index 0000000..1bb8466 --- /dev/null +++ b/static/dist/BeerCrackerzAuth.bundle.js @@ -0,0 +1,117 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/BeerCrackerzAuth.js": +/*!*********************************!*\ + !*** ./src/BeerCrackerzAuth.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _BeerCrackerzAuth_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BeerCrackerzAuth.scss */ \"./src/BeerCrackerzAuth.scss\");\n/* harmony import */ var _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/utils/LangManager.js */ \"./src/js/utils/LangManager.js\");\n/* harmony import */ var _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./js/utils/Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\n\n\nvar BeerCrackerzAuth = /*#__PURE__*/function () {\n function BeerCrackerzAuth() {\n _classCallCheck(this, BeerCrackerzAuth);\n\n var _init = function _init() {};\n\n if (document.body.className.includes('login')) {\n _init = this._handleLogin.bind(this);\n } else if (document.body.className.includes('register')) {\n _init = this._handleRegister.bind(this);\n } // The BeerCrackerz app is only initialized once nls are set up\n\n\n this._lang = new _js_utils_LangManager_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"](window.navigator.language.substring(0, 2), _init.bind(this));\n }\n\n _createClass(BeerCrackerzAuth, [{\n key: \"_handleLogin\",\n value: function _handleLogin() {\n var _this = this;\n\n // Update page nls according to browser language\n document.title = this.nls.login('headTitle');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_SUBTITLE}}', this.nls.login('subtitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_HIDDEN_ERROR}}', this.nls.login('hiddenError'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_USERNAME_LABEL}}', this.nls.login('username'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_USERNAME_PASSWORD}}', this.nls.login('password'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_BUTTON}}', this.nls.login('login'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_NOT_REGISTERED}}', this.nls.login('notRegistered'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{LOGIN_REGISTER}}', this.nls.login('register'));\n var error = document.getElementById('login-error');\n var username = document.getElementById('username');\n var password = document.getElementById('password'); // useful login method for field check and server response check\n\n var _frontFieldValidation = function _frontFieldValidation() {\n // Handling empty error cases\n if (username.value === '' && password.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('bothEmpty');\n username.classList.add('error');\n password.classList.add('error');\n return false;\n } else if (username.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('usernameEmpty');\n username.classList.add('error');\n return false;\n } else if (password.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('passwordEmpty');\n password.classList.add('error');\n return false;\n }\n\n return true;\n };\n\n var _backValidation = function _backValidation(response) {\n // Check response and handle status codes\n console.log(response); // If all front and back tests are ok, redirect to auth\n // If the user ma nually force redirection to authindex,\n // the server should reject the request as the user is not authenticated\n\n window.location = 'authindex.html';\n }; // Submit click event\n\n\n document.getElementById('login-submit').addEventListener('click', function () {\n // Reset error css classes\n error.classList.remove('visible');\n username.classList.remove('error');\n password.classList.remove('error');\n\n if (_frontFieldValidation()) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].postReq('/api/login/submit').then(_backValidation)[\"catch\"](function () {\n error.classList.add('visible');\n error.innerHTML = _this.nls.login('serverError');\n });\n }\n }, false);\n }\n }, {\n key: \"_handleRegister\",\n value: function _handleRegister() {\n var _this2 = this;\n\n // Update page nls according to browser language\n document.title = this.nls.register('headTitle');\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_SUBTITLE}}', this.nls.register('subtitle'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_HIDDEN_ERROR}}', this.nls.register('hiddenError'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_LABEL}}', this.nls.register('username'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_PASSWORD_1}}', this.nls.register('password1'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_USERNAME_PASSWORD_2}}', this.nls.register('password2'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_BUTTON}}', this.nls.register('register'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_ALREADY_DONE}}', this.nls.register('notRegistered'));\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].replaceString(document.body, '{{REGISTER_LOGIN}}', this.nls.register('login'));\n var error = document.getElementById('register-error');\n var username = document.getElementById('username');\n var password1 = document.getElementById('password1');\n var password2 = document.getElementById('password2'); // useful login method for field check and server response check\n\n var _frontFieldValidation = function _frontFieldValidation() {\n // Handling empty error cases\n if (username.value === '' || password1.value === '' || password2.value === '') {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('fieldEmpty');\n\n if (username.value === '') {\n username.classList.add('error');\n }\n\n if (password1.value === '') {\n password1.classList.add('error');\n }\n\n if (password2.value === '') {\n password2.classList.add('error');\n }\n\n return false;\n } else if (password1.value !== password2.value) {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('notMatchingPassword');\n password1.classList.add('error');\n password2.classList.add('error');\n return false;\n }\n\n return true;\n };\n\n var _backValidation = function _backValidation(response) {\n // Check response and handle status codes\n console.log(response); // If all front and back tests are ok, redirect to auth\n // If the user ma nually force redirection to authindex,\n // the server should reject the request as the user is not authenticated\n\n window.location = 'authindex.html';\n }; // Submit click event\n\n\n document.getElementById('register-submit').addEventListener('click', function () {\n // Reset error css classes\n error.classList.remove('visible');\n username.classList.remove('error');\n password1.classList.remove('error');\n password2.classList.remove('error');\n\n if (_frontFieldValidation()) {\n _js_utils_Utils_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].postReq('/api/register/submit').then(_backValidation)[\"catch\"](function () {\n error.classList.add('visible');\n error.innerHTML = _this2.nls.register('serverError');\n });\n }\n }, false);\n }\n }, {\n key: \"nls\",\n get: function get() {\n return this._lang;\n }\n }]);\n\n return BeerCrackerzAuth;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BeerCrackerzAuth);\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerzAuth.js?"); + +/***/ }), + +/***/ "./src/js/utils/LangManager.js": +/*!*************************************!*\ + !*** ./src/js/utils/LangManager.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _Utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Utils.js */ \"./src/js/utils/Utils.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar LangManager = /*#__PURE__*/function () {\n function LangManager(lang, cb) {\n _classCallCheck(this, LangManager);\n\n this._lang = _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SUPPORTED_LANGUAGE.indexOf(lang) !== -1 ? lang : 'en';\n this._values = {};\n\n this._init().then(cb);\n }\n\n _createClass(LangManager, [{\n key: \"_init\",\n value: function _init() {\n var _this = this;\n\n return new Promise(function (resolve, reject) {\n _Utils_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].fetchFile(\"assets/nls/\".concat(_this._lang, \".json\")).then(function (lang) {\n _this._values = JSON.parse(lang);\n resolve();\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"debug\",\n value: function debug(key) {\n return this._values.debug[key] || '';\n }\n }, {\n key: \"notif\",\n value: function notif(key) {\n return this._values.notif[key] || '';\n }\n }, {\n key: \"nav\",\n value: function nav(key) {\n return this._values.nav[key] || '';\n }\n }, {\n key: \"map\",\n value: function map(key) {\n return this._values.map[key] || '';\n }\n }, {\n key: \"spot\",\n value: function spot(key) {\n return this._values.spot[key] || '';\n }\n }, {\n key: \"store\",\n value: function store(key) {\n return this._values.store[key] || '';\n }\n }, {\n key: \"bar\",\n value: function bar(key) {\n return this._values.bar[key] || '';\n }\n }, {\n key: \"popup\",\n value: function popup(key) {\n return this._values.popup[key] || '';\n }\n }, {\n key: \"modal\",\n value: function modal(key) {\n return this._values.modal[key] || '';\n }\n }, {\n key: \"login\",\n value: function login(key) {\n return this._values.auth.login[key] || '';\n }\n }, {\n key: \"register\",\n value: function register(key) {\n return this._values.auth.register[key] || '';\n }\n }]);\n\n return LangManager;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (LangManager);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/LangManager.js?"); + +/***/ }), + +/***/ "./src/js/utils/Utils.js": +/*!*******************************!*\ + !*** ./src/js/utils/Utils.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Utils = /*#__PURE__*/function () {\n function Utils() {\n /* Not meant to be instantiated, all methods should be static */\n\n _classCallCheck(this, Utils);\n }\n\n _createClass(Utils, null, [{\n key: \"fetchTemplate\",\n value: function fetchTemplate(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(function (html) {\n resolve(document.createRange().createContextualFragment(html));\n })[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"fetchFile\",\n value: function fetchFile(url) {\n return new Promise(function (resolve, reject) {\n fetch(url).then(function (data) {\n data.text().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"getReq\",\n value: function getReq(url) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'GET',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default'\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"postReq\",\n value: function postReq(url, data) {\n return new Promise(function (resolve, reject) {\n var options = {\n method: 'POST',\n headers: new Headers(),\n mode: 'cors',\n cache: 'default',\n body: data\n };\n fetch(url, options).then(function (data) {\n data.json().then(resolve)[\"catch\"](reject);\n })[\"catch\"](reject);\n });\n }\n }, {\n key: \"stripDom\",\n value: function stripDom(html) {\n var doc = new DOMParser().parseFromString(html, 'text/html');\n return doc.body.textContent || '';\n }\n }, {\n key: \"replaceString\",\n value: function replaceString(element, string, value) {\n element.innerHTML = element.innerHTML.replace(string, value);\n }\n }, {\n key: \"getDistanceBetweenCoords\",\n value: function getDistanceBetweenCoords(from, to) {\n // return distance in meters\n var lon1 = from[1] * Math.PI / 180,\n lat1 = from[0] * Math.PI / 180,\n lon2 = to[1] * Math.PI / 180,\n lat2 = to[0] * Math.PI / 180;\n var deltaLat = lat2 - lat1;\n var deltaLon = lon2 - lon1;\n var a = Math.pow(Math.sin(deltaLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2), 2);\n var c = 2 * Math.asin(Math.sqrt(a));\n var EARTH_RADIUS = 6371;\n return c * EARTH_RADIUS * 1000;\n }\n /** @method\n * @name precisionRound\n * @public\n * @memberof Utils\n * @author Arthur Beaulieu\n * @since September 2018\n * @description Do a Math.round with a given precision (ie amount of integers after the coma)\n * @param {nunmber} value - The value to precisely round\n * @param {number} precision - The number of integers after the coma\n * @return {number} - The rounded value */\n\n }, {\n key: \"precisionRound\",\n value: function precisionRound(value, precision) {\n var multiplier = Math.pow(10, precision || 0);\n return Math.round(value * multiplier) / multiplier;\n }\n }, {\n key: \"initDebugInterface\",\n value: function initDebugInterface() {\n var lang = window.BeerCrackerz.nls.debug.bind(window.BeerCrackerz.nls);\n var debugContainer = document.createElement('DIV');\n var userLat = document.createElement('P');\n var userLng = document.createElement('P');\n var updatesAmount = document.createElement('P');\n var userAccuracy = document.createElement('P');\n var highAccuracy = document.createElement('P');\n var maxAge = document.createElement('P');\n var posTimeout = document.createElement('P');\n var zoomLevel = document.createElement('P');\n var marks = document.createElement('P');\n var exportData = document.createElement('BUTTON');\n debugContainer.classList.add('debug-container');\n userLat.classList.add('debug-user-lat');\n userLng.classList.add('debug-user-lng');\n updatesAmount.classList.add('debug-updates-amount');\n userAccuracy.classList.add('debug-user-accuracy');\n highAccuracy.classList.add('debug-high-accuracy');\n maxAge.classList.add('debug-pos-max-age');\n posTimeout.classList.add('debug-pos-timeout');\n zoomLevel.classList.add('debug-zoom-level');\n marks.classList.add('debug-marks-amount');\n exportData.classList.add('debug-export-data');\n userLat.innerHTML = \"\".concat(lang('lat'), \" : -\");\n userLng.innerHTML = \"\".concat(lang('lng'), \" : -\");\n updatesAmount.innerHTML = \"\".concat(lang('updates'), \" : 0\");\n userAccuracy.innerHTML = \"\".concat(lang('accuracy'), \" : -\");\n highAccuracy.innerHTML = \"\".concat(lang('highAccuracy'), \" : -\");\n maxAge.innerHTML = \"\".concat(lang('posAge'), \" : -\");\n posTimeout.innerHTML = \"\".concat(lang('posTimeout'), \" : -\");\n zoomLevel.innerHTML = \"\".concat(lang('zoom'), \" : -\");\n marks.innerHTML = \"\".concat(lang('marks'), \" : -\");\n exportData.innerHTML = lang('export');\n debugContainer.appendChild(userLat);\n debugContainer.appendChild(userLng);\n debugContainer.appendChild(updatesAmount);\n debugContainer.appendChild(userAccuracy);\n debugContainer.appendChild(highAccuracy);\n debugContainer.appendChild(maxAge);\n debugContainer.appendChild(posTimeout);\n debugContainer.appendChild(zoomLevel);\n debugContainer.appendChild(marks);\n debugContainer.appendChild(exportData);\n exportData.addEventListener('click', window.BeerCrackerz.downloadData.bind(window.BeerCrackerz));\n return debugContainer;\n }\n }, {\n key: \"updateDebugInterface\",\n value: function updateDebugInterface(element, user, options) {\n if (window.DEBUG === true) {\n var bc = window.BeerCrackerz;\n var lang = bc.nls.debug.bind(bc.nls);\n var updates = parseInt(element.querySelector('.debug-updates-amount').innerHTML.split(' : ')[1]) + 1;\n var marks = bc.marks.spot.length + bc.marks.store.length + bc.marks.bar.length;\n element.querySelector('.debug-user-lat').innerHTML = \"\\n \".concat(lang('lat'), \" : \").concat(user.lat, \"\\n \");\n element.querySelector('.debug-user-lng').innerHTML = \"\\n \".concat(lang('lng'), \" : \").concat(user.lng, \"\\n \");\n element.querySelector('.debug-updates-amount').innerHTML = \"\\n \".concat(lang('updates'), \" : \").concat(updates, \"\\n \");\n element.querySelector('.debug-user-accuracy').innerHTML = \"\\n \".concat(lang('accuracy'), \" : \").concat(Utils.precisionRound(user.accuracy, 2), \"m\\n \");\n element.querySelector('.debug-high-accuracy').innerHTML = \"\\n \".concat(lang('highAccuracy'), \" : \").concat(options.enableHighAccuracy === true ? lang('enabled') : lang('disabled'), \"\\n \");\n element.querySelector('.debug-pos-max-age').innerHTML = \"\\n \".concat(lang('posAge'), \" : \").concat(options.maximumAge / 1000, \"s\\n \");\n element.querySelector('.debug-pos-timeout').innerHTML = \"\\n \".concat(lang('posTimeout'), \" : \").concat(options.timeout / 1000, \"s\\n \");\n element.querySelector('.debug-zoom-level').innerHTML = \"\\n \".concat(lang('zoom'), \" : \").concat(bc.map.getZoom(), \"\\n \");\n element.querySelector('.debug-marks-amount').innerHTML = \"\\n \".concat(lang('marks'), \" : \").concat(marks, \"\\n \");\n }\n }\n }, {\n key: \"getPreference\",\n value: function getPreference(pref) {\n return localStorage.getItem(pref) || null;\n }\n }, {\n key: \"setPreference\",\n value: function setPreference(pref, value) {\n localStorage.setItem(pref, value);\n }\n }, {\n key: \"RANGE_COLOR\",\n get: function get() {\n return '#ffd87d';\n }\n }, {\n key: \"USER_COLOR\",\n get: function get() {\n return '#63fff5';\n }\n }, {\n key: \"SPOT_COLOR\",\n get: function get() {\n return '#26ad23';\n }\n }, {\n key: \"STORE_COLOR\",\n get: function get() {\n return '#247dc9';\n }\n }, {\n key: \"BAR_COLOR\",\n get: function get() {\n return '#ca2a3d';\n }\n }, {\n key: \"CIRCLE_RADIUS\",\n get: function get() {\n return 100;\n }\n }, {\n key: \"NEW_MARKER_RANGE\",\n get: function get() {\n return 200;\n }\n }, {\n key: \"MAP_BOUNDS\",\n get: function get() {\n return window.L.latLngBounds(window.L.latLng(-89.98155760646617, -180), window.L.latLng(89.99346179538875, 180));\n }\n }, {\n key: \"HIGH_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: true,\n // More consuption, better position\n maximumAge: 1000,\n // A position will last 1s maximum\n timeout: 900 // A position is updated in 0.9s maximum\n\n };\n }\n }, {\n key: \"OPTIMIZED_ACCURACY\",\n get: function get() {\n return {\n enableHighAccuracy: false,\n // Less consuption\n maximumAge: 30000,\n // A position will last 30s maximum\n timeout: 29000 // A position is updated in 29s maximum\n\n };\n }\n }, {\n key: \"SUPPORTED_LANGUAGE\",\n get: function get() {\n return ['en', 'fr', 'es', 'de'];\n }\n }]);\n\n return Utils;\n}();\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);\n\n//# sourceURL=webpack://BeerCrackerz/./src/js/utils/Utils.js?"); + +/***/ }), + +/***/ "./src/BeerCrackerzAuth.scss": +/*!***********************************!*\ + !*** ./src/BeerCrackerzAuth.scss ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://BeerCrackerz/./src/BeerCrackerzAuth.scss?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/BeerCrackerzAuth.js"); +/******/ window.BeerCrackerz = __webpack_exports__["default"]; +/******/ +/******/ })() +; \ No newline at end of file diff --git a/static/html/modal/deletemark.html b/static/html/modal/deletemark.html new file mode 100755 index 0000000..90c09b0 --- /dev/null +++ b/static/html/modal/deletemark.html @@ -0,0 +1,9 @@ +
×
+{{MODAL_DESC}}
+ +×
+×
+×
+×
+{{BAR_SUBTITLE}}
+ + + + + + + +×
+{{SPOT_SUBTITLE}}
+ + + + + + + +×
+{{STORE_SUBTITLE}}
+ + + + + + + +{{BAR_FOUND_BY}} {{BAR_FINDER}}
+ +{{SPOT_FOUND_BY}} {{SPOT_FINDER}}
+ +{{STORE_FOUND_BY}} {{STORE_FINDER}}
+ +FoUIbv
zxSie=)N9}1SQPd6v9i7W;p^A0$F|vsbM=1tFe*6yi|xV*4Ofm;af&I!Z7HIL(R2>f
zm87#Nv4=Li6