-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpopup.js
More file actions
222 lines (199 loc) · 7.33 KB
/
popup.js
File metadata and controls
222 lines (199 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/**
* Validates the format of a Coda API key
* @param {string} apiKey - The API key to validate
* @returns {boolean} True if valid format, false otherwise
*/
function isValidApiKey(apiKey) {
// Coda API keys typically have a specific format
return apiKey && apiKey.length >= 30 && /^[a-zA-Z0-9-_]+$/.test(apiKey);
}
/**
* Shows a status message to the user
* @param {string} message - The message to display
* @param {string} type - The message type ('loading', 'success', 'error')
*/
function showStatus(message, type = 'loading') {
const statusDiv = document.getElementById('status');
statusDiv.textContent = message;
statusDiv.className = `status ${type}`;
}
/**
* Handles keyboard events for better accessibility
* @param {KeyboardEvent} event - The keyboard event
*/
function handleKeyPress(event) {
if (event.key === 'Enter') {
const setupView = document.getElementById('setup-view');
if (!setupView.classList.includes('hidden')) {
document.getElementById('save-key').click();
} else {
document.getElementById('export-page').click();
}
}
}
/**
* Initialize the popup when DOM is loaded
*/
document.addEventListener('DOMContentLoaded', async () => {
const setupView = document.getElementById('setup-view');
const exportView = document.getElementById('export-view');
const apiKeyInput = document.getElementById('api-key');
const saveKeyButton = document.getElementById('save-key');
const exportButton = document.getElementById('export-page');
const changeKeyButton = document.getElementById('change-key');
const statusDiv = document.getElementById('status');
const cancelSetupButton = document.getElementById('cancel-setup');
const setupTitle = document.getElementById('setup-title');
const setupDescription = document.getElementById('setup-description');
// Add keyboard event listener
document.addEventListener('keypress', handleKeyPress);
/**
* Shows the setup form with appropriate text and buttons
* @param {boolean} isChangingKey - True if changing existing key, false for initial setup
*/
function showSetupForm(isChangingKey = false) {
if (isChangingKey) {
setupTitle.textContent = 'Change API Key';
setupDescription.innerHTML =
'Enter a new Coda API key to replace the existing one.<br/>Visit <a href="https://coda.io/account" target="_blank">https://coda.io/account</a> to generate a new key.';
cancelSetupButton.classList.remove('hidden');
} else {
setupTitle.textContent = 'Setup API Key';
setupDescription.innerHTML =
'To export Coda pages, you\'ll need a Coda API key.<br/>Visit <a href="https://coda.io/account" target="_blank">https://coda.io/account</a> to generate a new key.';
cancelSetupButton.classList.add('hidden');
}
setupView.classList.remove('hidden');
exportView.classList.add('hidden');
apiKeyInput.value = '';
apiKeyInput.focus();
statusDiv.textContent = '';
}
// Check if API key is already configured
try {
const result = await chrome.storage.local.get(['codaApiKey']);
if (result.codaApiKey) {
setupView.classList.add('hidden');
exportView.classList.remove('hidden');
} else {
showSetupForm(false);
}
} catch (error) {
console.error('Failed to check API key:', error);
showStatus('Failed to load settings. Please refresh.', 'error');
}
/**
* Handles saving the API key
*/
saveKeyButton.addEventListener('click', async () => {
const apiKey = apiKeyInput.value.trim();
// Validate API key
if (!apiKey) {
showStatus('Please enter your Coda API key', 'error');
apiKeyInput.focus();
return;
}
if (!isValidApiKey(apiKey)) {
showStatus('Invalid API key format. Please check your key.', 'error');
apiKeyInput.focus();
return;
}
// Show loading state
saveKeyButton.disabled = true;
saveKeyButton.textContent = 'Saving...';
showStatus('Saving API key...', 'loading');
try {
await chrome.storage.local.set({ codaApiKey: apiKey });
setupView.classList.add('hidden');
exportView.classList.remove('hidden');
apiKeyInput.value = '';
showStatus('API key saved successfully!', 'success');
// Clear success message after 2 seconds
setTimeout(() => showStatus('', ''), 2000);
} catch (error) {
console.error('Failed to save API key:', error);
showStatus('Failed to save API key. Please try again.', 'error');
} finally {
saveKeyButton.disabled = false;
saveKeyButton.textContent = 'Save API Key';
}
});
/**
* Handles changing the API key
*/
changeKeyButton.addEventListener('click', async () => {
showSetupForm(true);
});
/**
* Handle cancel setup button
*/
cancelSetupButton.addEventListener('click', () => {
setupView.classList.add('hidden');
exportView.classList.remove('hidden');
apiKeyInput.value = '';
statusDiv.textContent = '';
});
/**
* Handles the export button click
*/
exportButton.addEventListener('click', async () => {
// Disable button during export
exportButton.disabled = true;
const originalText = exportButton.textContent;
exportButton.textContent = 'Exporting...';
showStatus('Initializing export...', 'loading');
// Add a small delay if this is a repeated export (helps with Coda API quirks)
if (exportButton.dataset.lastExport) {
const timeSinceLastExport = Date.now() - parseInt(exportButton.dataset.lastExport);
if (timeSinceLastExport < 2000) {
await new Promise((resolve) => setTimeout(resolve, 2000 - timeSinceLastExport));
}
}
try {
// Get current tab
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
// Validate that we're on a Coda page
if (!tab.url || !tab.url.includes('coda.io')) {
showStatus('Please navigate to a Coda page to export', 'error');
return;
}
// Update status
showStatus('Connecting to Coda API...', 'loading');
// Send export request to background script
const response = await chrome.runtime.sendMessage({
action: 'exportPage',
url: tab.url,
});
if (response.success) {
showStatus('Export successful! Starting download...', 'success');
// Record successful export time
exportButton.dataset.lastExport = Date.now();
// Initiate download
try {
await chrome.downloads.download({
url: response.downloadUrl,
filename: response.filename || 'coda-export.md',
saveAs: false,
});
// Show success for a few seconds then clear
setTimeout(() => {
showStatus('Ready to export', 'success');
setTimeout(() => showStatus('', ''), 2000);
}, 2000);
} catch (downloadError) {
console.error('Download failed:', downloadError);
showStatus('Export completed but download failed. Check your downloads.', 'error');
}
} else {
showStatus(response.error || 'Export failed. Please try again.', 'error');
}
} catch (error) {
console.error('Export error:', error);
showStatus('An unexpected error occurred. Please try again.', 'error');
} finally {
// Re-enable button
exportButton.disabled = false;
exportButton.textContent = originalText;
}
});
});