@@ -18,14 +18,21 @@ export default class CssSnippetStore extends Plugin {
18
18
19
19
async onload ( ) {
20
20
// Start the mutation observer when the plugin is loaded.
21
- this . injectWhenSettingsLoaded ( ) ;
21
+ this . injectBrowseButton ( ) ;
22
22
23
23
24
24
// fetching list of snippets
25
- const url = "https://raw.githubusercontent.com/xavwe/obsidian-css-snippet-store/refs/heads/ main/snippets.json"
25
+ const url = "https://raw.githubusercontent.com/xavwe/obsidian-css-snippet-store/main/snippets.json"
26
26
try {
27
- if ( navigator . onLine ) {
28
- const response = await fetch ( url ) ;
27
+ if ( await isOnline ( ) ) {
28
+ const response = await fetchWithTimeout ( url ) ;
29
+ if ( ! response . ok ) {
30
+ throw new Error ( `Network response was not ok: ${ response . statusText } ` ) ;
31
+ }
32
+ /*
33
+ if (!response.headers.get('content-type')?.includes('application/json')) {
34
+ throw new Error("Unexpected content type");
35
+ }*/
29
36
this . snippets = await response . json ( ) ;
30
37
} else {
31
38
new Notice ( `No Internet connection...` ) ;
@@ -37,7 +44,7 @@ export default class CssSnippetStore extends Plugin {
37
44
}
38
45
}
39
46
40
- injectWhenSettingsLoaded ( ) {
47
+ injectBrowseButton ( ) {
41
48
this . observer = new MutationObserver ( ( ) => {
42
49
const settingItems = Array . from ( document . querySelectorAll ( '.setting-item' ) ) ;
43
50
@@ -61,29 +68,34 @@ export default class CssSnippetStore extends Plugin {
61
68
62
69
controlElement . appendChild ( customButton ) ;
63
70
71
+ customButton . textContent = 'Browse' ;
72
+ customButton . className = "mod-cta my-custom-button" ;
73
+
64
74
// Function to update the button text based on connectivity
65
75
66
76
67
77
// Initial check
78
+ /*
68
79
updateButtonLabel(customButton);
80
+ */
69
81
70
- // Update on connectivity change
82
+ /* // Update on connectivity change
71
83
window.addEventListener('online', () => updateButtonLabel(customButton));
72
- window . addEventListener ( 'offline' , ( ) => updateButtonLabel ( customButton ) ) ;
84
+ window.addEventListener('offline', () => updateButtonLabel(customButton));*/
73
85
}
74
86
}
75
87
}
76
88
} ) ;
77
89
78
- function updateButtonLabel ( button : HTMLButtonElement ) {
79
- if ( navigator . onLine ) {
90
+ /* function updateButtonLabel(button: HTMLButtonElement) {
91
+ if (true ) {
80
92
button.textContent = 'Browse';
81
93
button.className = "mod-cta my-custom-button";
82
94
} else {
83
95
button.textContent = 'No Internet';
84
96
button.className = "";
85
97
}
86
- }
98
+ }*/
87
99
88
100
this . observer . observe ( document . body , {
89
101
childList : true ,
@@ -173,7 +185,7 @@ class CssSnippetStoreModal extends Modal {
173
185
174
186
contentEl . createEl ( 'h1' , { text : 'CSS Snippet Store' } ) ;
175
187
176
- // --- Search bar ---
188
+ // Search bar
177
189
const searchInput = contentEl . createEl ( 'input' , {
178
190
type : 'text' ,
179
191
placeholder : 'Search snippets...' ,
@@ -185,7 +197,7 @@ class CssSnippetStoreModal extends Modal {
185
197
186
198
const grid = contentEl . createEl ( 'div' , { cls : 'community-items-container' } ) ;
187
199
188
- // --- Render Function ---
200
+ // Render Function
189
201
const renderSnippets = ( filter : string = "" ) => {
190
202
grid . empty ( ) ;
191
203
const lowerFilter = filter . toLowerCase ( ) ;
@@ -224,8 +236,15 @@ class CssSnippetStoreModal extends Modal {
224
236
button . addEventListener ( 'click' , async ( ) => {
225
237
const url = `https://raw.githubusercontent.com/${ snippet . repo } /refs/heads/main/${ snippet . folder } /snippet.css` ;
226
238
try {
227
- if ( navigator . onLine ) {
228
- const response = await fetch ( url ) ;
239
+ if ( await isOnline ( ) ) {
240
+ const response = await fetchWithTimeout ( url ) ;
241
+ if ( ! response . ok ) {
242
+ throw new Error ( `Network response was not ok: ${ response . statusText } ` ) ;
243
+ }
244
+ /*
245
+ if (!response.headers.get('content-type')?.includes('text/css')) {
246
+ throw new Error("Expected CSS content");
247
+ }*/
229
248
const code = await response . text ( ) ;
230
249
await this . install ( snippet . id , code ) ;
231
250
this . close ( ) ;
@@ -257,4 +276,30 @@ class CssSnippetStoreModal extends Modal {
257
276
const { contentEl } = this ;
258
277
contentEl . empty ( ) ;
259
278
}
279
+ }
280
+
281
+ function fetchWithTimeout ( resource : RequestInfo , options : RequestInit = { } , timeout = 10000 ) : Promise < Response > {
282
+ return Promise . race ( [
283
+ fetch ( resource , options ) ,
284
+ new Promise < Response > ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( "Request timed out" ) ) , timeout ) )
285
+ ] ) ;
286
+ }
287
+
288
+
289
+ export async function isOnline ( timeout = 3000 ) : Promise < boolean > {
290
+ try {
291
+ const controller = new AbortController ( ) ;
292
+ const id = setTimeout ( ( ) => controller . abort ( ) , timeout ) ;
293
+
294
+ await fetch ( "https://ping.archlinux.org" , {
295
+ method : "GET" ,
296
+ mode : "no-cors" ,
297
+ signal : controller . signal ,
298
+ cache : "no-store"
299
+ } ) ;
300
+ clearTimeout ( id ) ;
301
+ return true ;
302
+ } catch ( e ) {
303
+ return false ;
304
+ }
260
305
}
0 commit comments