Initial commit of MyWorkspace - contains multiple projects and global workspace configuration
This commit is contained in:
682
Linkding Browser Extension/LinkdingSync/background.html
Normal file
682
Linkding Browser Extension/LinkdingSync/background.html
Normal file
@@ -0,0 +1,682 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LinkdingSync Settings</title>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
header p {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="url"],
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: #2196f3;
|
||||
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
min-height: 80px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 12px;
|
||||
color: #777;
|
||||
margin-top: 6px;
|
||||
padding: 8px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.hint code {
|
||||
background: #e0e0e0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sync-options {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.sync-option {
|
||||
padding: 12px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sync-option:hover {
|
||||
border-color: #2196f3;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.sync-option.selected {
|
||||
border-color: #2196f3;
|
||||
background: #e3f2fd;
|
||||
color: #1565c0;
|
||||
}
|
||||
|
||||
.sync-option .description {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
margin-top: 4px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.sync-info {
|
||||
padding: 16px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
font-size: 13px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-family: monospace;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: white;
|
||||
color: #666;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #ffebee;
|
||||
color: #c62828;
|
||||
border: 1px solid #ffcdd2;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #ffcdd2;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.save-status {
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.save-status.success {
|
||||
background: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.save-status.error {
|
||||
background: #ffebee;
|
||||
color: #c62828;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.reset-section {
|
||||
padding: 16px;
|
||||
border-top: 2px solid #e0e0e0;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.reset-section button {
|
||||
margin-top: 8px;
|
||||
padding: 8px 16px;
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.reset-section button:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>⚙️ LinkdingSync Settings</h1>
|
||||
<p>Configure your bookmark synchronization</p>
|
||||
</header>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-title">Connection Settings</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server-url">Linkding Server URL</label>
|
||||
<input type="url" id="server-url" placeholder="https://links.blabber1565.com" value="https://links.blabber1565.com">
|
||||
<div class="hint">
|
||||
Enter your Linkding instance URL. This should point to the root of your Linkding installation.<br>
|
||||
Example: <code>https://links.blabber1565.com</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="api-key">API Token</label>
|
||||
<input type="text" id="api-key" placeholder="Enter your API token">
|
||||
<div class="hint">
|
||||
Get your API token from Linkding Settings → Advanced → API Token<br>
|
||||
This token is stored locally in your browser's storage.<br>
|
||||
<code>Settings</code> → <code>Advanced</code> → <code>API Token</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-title">Bundle Configuration</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="bundle-tag">Bundle Tag</label>
|
||||
<input type="text" id="bundle-tag" placeholder="bundle_personal_firefox_1">
|
||||
<div class="hint">
|
||||
This tag defines which bookmarks belong to which bundle in Linkding.<br>
|
||||
All bookmarks with this tag will appear in the corresponding Linkding bundle.<br>
|
||||
Example: <code>bundle_personal_firefox_1</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-title">Synchronization Options</div>
|
||||
|
||||
<div class="sync-options">
|
||||
<div class="sync-option selected" data-mode="bi-directional">
|
||||
<strong>Bi-Directional</strong>
|
||||
<span class="description">Keep both versions<br>Additions/updates replicate both ways</span>
|
||||
</div>
|
||||
<div class="sync-option" data-mode="write-only">
|
||||
<strong>Write-Only</strong>
|
||||
<span class="description">Browser is authoritative<br>Updates push to Linkding only</span>
|
||||
</div>
|
||||
<div class="sync-option" data-mode="read-only">
|
||||
<strong>Read-Only</strong>
|
||||
<span class="description">Linkding is authoritative<br>Download from Linkding only</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="sync-timestamp">Last Sync</label>
|
||||
<div class="info-value" id="sync-timestamp">-</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="auto-tags">Auto-Generate Tags</label>
|
||||
<select id="auto-tags">
|
||||
<option value="false" selected>Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
<div class="hint">
|
||||
When enabled, extracts folder names from bookmark path as tag suggestions.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-title">Actions</div>
|
||||
|
||||
<button class="btn btn-primary" id="save-btn">💾 Save Settings</button>
|
||||
<div id="save-status" class="save-status"></div>
|
||||
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-secondary" id="test-connection-btn">🔌 Test Connection</button>
|
||||
<button class="btn btn-secondary" id="refresh-bundles-btn">🔄 Refresh Bundles</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-title">Connection Info</div>
|
||||
|
||||
<div class="sync-info">
|
||||
<div class="info-row">
|
||||
<span class="info-label">Server URL:</span>
|
||||
<span class="info-value" id="info-server-url">-</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Bundle Tag:</span>
|
||||
<span class="info-value" id="info-bundle-tag">-</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Sync Mode:</span>
|
||||
<span class="info-value" id="info-sync-mode">-</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">API Token Set:</span>
|
||||
<span class="info-value" id="info-api-token">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reset-section">
|
||||
<p>Need to reset your configuration?</p>
|
||||
<button id="reset-config-btn">Reset All Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const Utils = {
|
||||
formatTimestamp(timestamp) {
|
||||
if (!timestamp) return 'Never';
|
||||
|
||||
const date = new Date(timestamp);
|
||||
const options = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZoneName: 'short'
|
||||
};
|
||||
|
||||
return date.toLocaleDateString('en-US', options);
|
||||
},
|
||||
|
||||
showMessage(message, type = 'info') {
|
||||
const types = {
|
||||
info: { color: '#2196f3', icon: 'ℹ️' },
|
||||
success: { color: '#4caf50', icon: '✓' },
|
||||
warning: { color: '#ff9800', icon: '⚠️' },
|
||||
error: { color: '#f44336', icon: '✕' }
|
||||
};
|
||||
|
||||
const style = types[type] || types.info;
|
||||
|
||||
const existing = document.getElementById('notification-area');
|
||||
if (existing) existing.remove();
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.id = 'notification-area';
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: ${style.color};
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
z-index: 9999;
|
||||
font-size: 13px;
|
||||
max-width: 90vw;
|
||||
text-align: center;
|
||||
`;
|
||||
notification.textContent = `${style.icon} ${message}`;
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 4000);
|
||||
}
|
||||
};
|
||||
|
||||
const storage = {
|
||||
get: browser.storage.local.get.bind(browser.storage.local),
|
||||
set: browser.storage.local.set.bind(browser.storage.local),
|
||||
clear: browser.storage.local.clear.bind(browser.storage.local)
|
||||
};
|
||||
|
||||
const api = {
|
||||
getBundles: async function() {
|
||||
const response = await fetch(`${window.linkdingSyncBaseURL}api/bookmarks/?limit=100&any=any`, {
|
||||
headers: { 'Authorization': `Token ${window.linkdingSyncApiKey}` }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return { results: [], count: 0 };
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
},
|
||||
|
||||
getBundle: async function(bundleTag) {
|
||||
const response = await fetch(`${window.linkdingSyncBaseURL}api/bookmarks/?limit=1000&any=${encodeURIComponent(bundleTag)}`, {
|
||||
headers: { 'Authorization': `Token ${window.linkdingSyncApiKey}` }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return { results: [], count: 0 };
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
};
|
||||
|
||||
const store = {
|
||||
get: async function(keys) {
|
||||
const data = await storage.get(keys);
|
||||
return {
|
||||
serverUrl: data.serverUrl || 'https://links.blabber1565.com',
|
||||
apiKey: data.apiKey || '',
|
||||
bundleTag: data.bundleTag || '',
|
||||
syncMode: data.syncMode || 'bi-directional',
|
||||
autoGenerateTags: data.autoGenerateTags || false,
|
||||
lastSyncTime: data.lastSyncTime || null
|
||||
};
|
||||
},
|
||||
|
||||
set: async function(config) {
|
||||
await storage.set(config);
|
||||
},
|
||||
|
||||
clear: async function() {
|
||||
await storage.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize UI
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
try {
|
||||
const config = await store.get();
|
||||
|
||||
// Populate form
|
||||
document.getElementById('server-url').value = config.serverUrl;
|
||||
document.getElementById('api-key').value = config.apiKey;
|
||||
document.getElementById('bundle-tag').value = config.bundleTag || 'bundle_personal_firefox_1';
|
||||
|
||||
// Sync mode selection
|
||||
const syncOptions = document.querySelectorAll('.sync-option');
|
||||
syncOptions.forEach(option => {
|
||||
option.addEventListener('click', () => {
|
||||
syncOptions.forEach(o => o.classList.remove('selected'));
|
||||
option.classList.add('selected');
|
||||
document.getElementById('info-sync-mode').textContent = option.querySelector('strong').textContent;
|
||||
config.syncMode = option.dataset.mode;
|
||||
store.set({ syncMode: option.dataset.mode });
|
||||
});
|
||||
});
|
||||
|
||||
// Highlight selected sync mode
|
||||
const selectedMode = document.querySelector(`.sync-option[data-mode="${config.syncMode}"]`);
|
||||
if (selectedMode) {
|
||||
syncOptions.forEach(o => o.classList.remove('selected'));
|
||||
selectedMode.classList.add('selected');
|
||||
}
|
||||
|
||||
// Populate info
|
||||
document.getElementById('info-server-url').textContent = config.serverUrl;
|
||||
document.getElementById('info-bundle-tag').textContent = config.bundleTag || '-';
|
||||
document.getElementById('info-sync-mode').textContent = config.syncMode || 'bi-directional';
|
||||
document.getElementById('info-api-token').textContent = config.apiKey ? '✓' : '-';
|
||||
document.getElementById('sync-timestamp').textContent = Utils.formatTimestamp(config.lastSyncTime);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Load config error:', error);
|
||||
}
|
||||
|
||||
// Save button
|
||||
document.getElementById('save-btn').addEventListener('click', async () => {
|
||||
const serverUrl = document.getElementById('server-url').value.trim();
|
||||
const apiKey = document.getElementById('api-key').value.trim();
|
||||
const bundleTag = document.getElementById('bundle-tag').value.trim();
|
||||
const selectedMode = document.querySelector('.sync-option.selected');
|
||||
|
||||
if (!apiKey) {
|
||||
Utils.showMessage('Please enter an API token', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!serverUrl) {
|
||||
Utils.showMessage('Please enter a server URL', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
serverUrl: serverUrl,
|
||||
apiKey: apiKey,
|
||||
bundleTag: bundleTag || 'bundle_default',
|
||||
syncMode: selectedMode ? selectedMode.dataset.mode : 'bi-directional',
|
||||
autoGenerateTags: document.getElementById('auto-tags').value === 'true' ? true : false
|
||||
};
|
||||
|
||||
try {
|
||||
await store.set(config);
|
||||
Utils.showMessage('Settings saved!', 'success');
|
||||
|
||||
// Update info display
|
||||
document.getElementById('info-server-url').textContent = config.serverUrl;
|
||||
document.getElementById('info-bundle-tag').textContent = config.bundleTag || '-';
|
||||
document.getElementById('info-sync-mode').textContent = config.syncMode || 'bi-directional';
|
||||
document.getElementById('info-api-token').textContent = config.apiKey ? '✓' : '-';
|
||||
document.getElementById('sync-timestamp').textContent = Utils.formatTimestamp(config.lastSyncTime);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Save error:', error);
|
||||
Utils.showMessage('Failed to save settings: ' + error.message, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Test connection
|
||||
document.getElementById('test-connection-btn').addEventListener('click', async () => {
|
||||
const config = await store.get();
|
||||
|
||||
if (!config.serverUrl || !config.apiKey) {
|
||||
Utils.showMessage('Please configure connection first', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${config.serverUrl}api/bookmarks/?limit=1`, {
|
||||
headers: { 'Authorization': `Token ${config.apiKey}` }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
Utils.showMessage('Connection successful!', 'success');
|
||||
} else {
|
||||
Utils.showMessage('Connection failed: HTTP ' + response.status, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
Utils.showMessage('Connection error: ' + error.message, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh bundles
|
||||
document.getElementById('refresh-bundles-btn').addEventListener('click', async () => {
|
||||
const config = await store.get();
|
||||
|
||||
if (!config.bundleTag) {
|
||||
Utils.showMessage('Please configure bundle tag first', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await api.getBundle(config.bundleTag);
|
||||
Utils.showMessage(`Found ${result.count || 0} bookmarks`, 'success');
|
||||
} catch (error) {
|
||||
Utils.showMessage('Failed to refresh: ' + error.message, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Reset config
|
||||
document.getElementById('reset-config-btn').addEventListener('click', async () => {
|
||||
if (confirm('This will delete all settings. Continue?')) {
|
||||
await store.clear();
|
||||
Utils.showMessage('Settings cleared', 'info');
|
||||
|
||||
// Clear form
|
||||
document.getElementById('server-url').value = 'https://links.blabber1565.com';
|
||||
document.getElementById('api-key').value = '';
|
||||
document.getElementById('bundle-tag').value = 'bundle_personal_firefox_1';
|
||||
|
||||
// Reset info
|
||||
document.getElementById('info-server-url').textContent = '-';
|
||||
document.getElementById('info-bundle-tag').textContent = '-';
|
||||
document.getElementById('info-sync-mode').textContent = 'bi-directional';
|
||||
document.getElementById('info-api-token').textContent = '-';
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-update bundle tag display when changed
|
||||
document.getElementById('bundle-tag').addEventListener('change', (e) => {
|
||||
document.getElementById('info-bundle-tag').textContent = e.target.value || '-';
|
||||
});
|
||||
|
||||
// Listen for storage changes
|
||||
browser.storage.onChanged.addListener((changes, area) => {
|
||||
if (area === 'local' && changes.bundleTag) {
|
||||
document.getElementById('bundle-tag').value = changes.bundleTag.newValue;
|
||||
document.getElementById('info-bundle-tag').textContent = changes.bundleTag.newValue || '-';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user