]> git.openstreetmap.org Git - nominatim-ui.git/blob - src/state/AppState.svelte.js
Convert page stores into global applicaton state (#292)
[nominatim-ui.git] / src / state / AppState.svelte.js
1 import { untrack } from 'svelte';
2 import { generate_nominatim_api_url } from '../lib/api_utils.js';
3 import { identifyLinkInQuery } from '../lib/helpers.js';
4
5 const default_pagename = Nominatim_Config.Reverse_Only ? 'reverse' : 'search';
6 const pagenames = [
7   default_pagename,
8   'reverse',
9   'details',
10   'deletable',
11   'polygons',
12   'status',
13   'about'
14 ];
15
16 class AppState {
17   page = $state();
18
19   lastApiRequestURL = $state(null);
20   errorMessage = $state(null);
21   requestProgress = $state('finish');
22
23   constructor() {
24     this.refreshPage();
25   }
26
27   refreshPage(pagename, params) {
28     if (typeof pagename === 'undefined') {
29       pagename = window.location.pathname.replace('.html', '').replace(/^.*\//, '');
30
31       if (!pagenames.includes(pagename)) pagename = default_pagename;
32
33       params = new URLSearchParams(window.location.search);
34     } else {
35       if (!pagenames.includes(pagename)) pagename = default_pagename;
36
37       if (typeof params === 'undefined') {
38         params = new URLSearchParams();
39       }
40
41       let param_str = params.toString();
42       if (param_str) {
43         param_str = '?' + param_str;
44       }
45       let new_url = pagename + '.html' + param_str;
46
47       if (window.location.protocol.match(/^http/)) {
48         window.history.pushState([], '', new_url);
49       } else {
50         window.location.href = new_url;
51       }
52     }
53
54     if (pagename === 'search' && params.has('q')) {
55       const arrTypeAndId = identifyLinkInQuery(params.get('q'));
56       if (arrTypeAndId instanceof Array) {
57         pagename = 'details';
58         params = new URLSearchParams({osmtype: arrTypeAndId[0], osmid: arrTypeAndId[1]});
59       }
60     }
61
62     untrack(() => {
63       this.page = { tab: pagename, params: params };
64       this.lastApiRequestURL = null;
65       this.errorMessage = null;
66     });
67   }
68
69   async fetchFromApi(endpoint_name, params, callback) {
70     const api_url = generate_nominatim_api_url(endpoint_name, params);
71
72     const mock_api_error = (new URLSearchParams(window.location.search)).get('mock_api_error');
73
74     this.requestProgress = 'start';
75     if (endpoint_name !== 'status') this.lastApiRequestURL = null;
76
77     try {
78       await fetch(api_url, { headers: Nominatim_Config.Nominatim_API_Endpoint_Headers || {} })
79         .then(async (response) => {
80           if ((!((response.status >= 200 && response.status < 300) || response.status === 404))
81               || mock_api_error === 'fetch'
82           ) {
83             this.errorMessage = `Error fetching data from ${api_url} (${response.statusText})`;
84             return undefined;
85           }
86
87           // Parse JSON here instead of returning a promise so we can catch possible
88           // errors.
89           var data;
90           try {
91             if (mock_api_error === 'parse') {
92               data = JSON.parse('{');
93             } else {
94               data = await response.json();
95             }
96           } catch (err) {
97             // e.g. 'JSON.parse: unexpected non-whitespace character after JSON data at line 1'
98             this.errorMessage = `Error parsing JSON data from ${api_url} (${err})`;
99             return undefined;
100           }
101           return data;
102         })
103         .then((data) => {
104           if (data) {
105             if (data.error) {
106               this.errorMessage = data.error.message;
107             }
108             callback(data);
109           }
110           this.requestProgress = 'finish';
111         });
112     } catch (error) {
113       this.errorMessage = `Error fetching data from ${api_url} (${error})`;
114       this.requestProgress = 'finish';
115     }
116
117     if (endpoint_name !== 'status') this.lastApiRequestURL = api_url;
118   }
119 }
120
121 export const appState = new AppState();