refactor: clean ONLYOFFICE integration - remove workarounds, follow standard pattern
This commit is contained in:
@@ -693,14 +693,4 @@ function formatDate(d) {
|
||||
}
|
||||
|
||||
// Initial load
|
||||
loadDashboard();
|
||||
|
||||
// Restore active page after an ONLYOFFICE editor close triggered a page reload
|
||||
(function() {
|
||||
var returnPage = sessionStorage.getItem('returnPage');
|
||||
if (returnPage) {
|
||||
sessionStorage.removeItem('returnPage');
|
||||
var link = document.querySelector('[data-page="' + returnPage + '"]');
|
||||
if (link) link.click();
|
||||
}
|
||||
})();
|
||||
loadDashboard();
|
||||
@@ -263,56 +263,34 @@ async function loadOnlyofficeTemplates() {
|
||||
// Force save the document
|
||||
function forceSaveOnlyoffice() {
|
||||
if (onlyofficeEditorInstance) {
|
||||
// The ONLYOFFICE editor's onSave event will trigger the callback
|
||||
// which saves the file to our backend
|
||||
toast('Saving... changes will be stored automatically');
|
||||
}
|
||||
}
|
||||
|
||||
// Close the editor and clean up
|
||||
// Close the editor — standard ONLYOFFICE teardown
|
||||
function closeOnlyofficeEditor() {
|
||||
if (onlyofficeEditorInstance) {
|
||||
try {
|
||||
onlyofficeEditorInstance.destroyEditor();
|
||||
} catch (e) {
|
||||
console.error('Error closing editor:', e);
|
||||
}
|
||||
try { onlyofficeEditorInstance.destroyEditor(); } catch (e) {}
|
||||
onlyofficeEditorInstance = null;
|
||||
}
|
||||
closeModal();
|
||||
// Reload the page to clear ONLYOFFICE's in-memory state.
|
||||
// Save the active page so the user returns to Templates automatically
|
||||
sessionStorage.setItem('returnPage', 'templates');
|
||||
// Wait 2 seconds for the save callback (status=2) to complete
|
||||
// on our backend before reloading the page
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
loadOnlyofficeTemplates();
|
||||
}
|
||||
|
||||
// Open ONLYOFFICE editor in a modal
|
||||
async function openOnlyofficeEditor(templateId, templateName) {
|
||||
// If there's a previous editor instance still lingering, destroy it first
|
||||
if (onlyofficeEditorInstance) {
|
||||
try { onlyofficeEditorInstance.destroyEditor(); } catch (e) {}
|
||||
onlyofficeEditorInstance = null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the JWT-signed editor config from our backend
|
||||
// Add cache-buster to prevent browser caching the old config
|
||||
const cacheBuster = Date.now();
|
||||
const resp = await fetch(ONLYOFFICE_API + '/' + templateId + '/config?cb=' + cacheBuster);
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json();
|
||||
throw new Error(err.error || 'Failed to get editor config');
|
||||
}
|
||||
const data = await resp.json();
|
||||
const config = data.config;
|
||||
const onlyofficeUrl = data.onlyofficeUrl;
|
||||
// Fetch JWT-signed config from backend (cache-busted)
|
||||
const resp = await fetch(ONLYOFFICE_API + '/' + templateId + '/config?cb=' + Date.now());
|
||||
if (!resp.ok) throw new Error((await resp.json()).error || 'Failed to get config');
|
||||
const { config, onlyofficeUrl } = await resp.json();
|
||||
|
||||
// Build the editor modal with a unique container ID each time
|
||||
// so ONLYOFFICE never reuses a cached DOM element
|
||||
// Unique container ID per session
|
||||
const containerId = 'oo-editor-' + Date.now();
|
||||
const body = `
|
||||
<div class="flex-between mb-16">
|
||||
@@ -327,26 +305,19 @@ async function openOnlyofficeEditor(templateId, templateName) {
|
||||
`;
|
||||
showModal(body, '', 'xlarge');
|
||||
|
||||
// Load ONLYOFFICE API script - force fresh load each time
|
||||
// Remove old script to force ONLYOFFICE to reload API.js from server
|
||||
const oldScript = document.getElementById('onlyoffice-api-script');
|
||||
if (oldScript) oldScript.remove();
|
||||
|
||||
// Reload with cache-buster so ONLYOFFICE gets fresh API state
|
||||
const scriptBuster = Date.now();
|
||||
const scriptUrl = onlyofficeUrl + '/web-apps/apps/api/documents/api.js?cb=' + scriptBuster;
|
||||
await new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.id = 'onlyoffice-api-script';
|
||||
script.src = scriptUrl;
|
||||
script.onload = resolve;
|
||||
script.onerror = () => reject(new Error('Failed to load ONLYOFFICE API from ' + scriptUrl));
|
||||
document.head.appendChild(script);
|
||||
// Load ONLYOFFICE API script (once)
|
||||
if (typeof DocsAPI === 'undefined') {
|
||||
await new Promise((resolve, reject) => {
|
||||
const s = document.createElement('script');
|
||||
s.src = onlyofficeUrl + '/web-apps/apps/api/documents/api.js';
|
||||
s.onload = resolve;
|
||||
s.onerror = () => reject(new Error('Failed to load ONLYOFFICE API'));
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
|
||||
// Initialize the ONLYOFFICE editor
|
||||
}
|
||||
|
||||
if (typeof DocsAPI === 'undefined' || !DocsAPI.DocEditor) {
|
||||
throw new Error('ONLYOFFICE API not loaded. Check that the server is running at ' + onlyofficeUrl);
|
||||
throw new Error('ONLYOFFICE API not loaded');
|
||||
}
|
||||
|
||||
onlyofficeEditorInstance = new DocsAPI.DocEditor(containerId, {
|
||||
@@ -354,30 +325,11 @@ async function openOnlyofficeEditor(templateId, templateName) {
|
||||
width: '100%',
|
||||
height: '800px',
|
||||
events: {
|
||||
onAppReady: function() {
|
||||
console.log('ONLYOFFICE editor ready');
|
||||
},
|
||||
onDocumentReady: function() {
|
||||
console.log('Document loaded in editor');
|
||||
// Inject CSS into ONLYOFFICE iframe to hide the logo
|
||||
try {
|
||||
var iframe = document.getElementById(containerId).querySelector('iframe');
|
||||
if (iframe && iframe.contentDocument) {
|
||||
var style = iframe.contentDocument.createElement('style');
|
||||
style.textContent = '#header-logo { display: none !important; }';
|
||||
iframe.contentDocument.head.appendChild(style);
|
||||
}
|
||||
} catch(e) {
|
||||
console.log('Could not inject CSS into iframe:', e);
|
||||
}
|
||||
},
|
||||
onSave: function(event) {
|
||||
toast('Document saved successfully');
|
||||
// Reload the templates list
|
||||
onSave: function() {
|
||||
toast('Document saved');
|
||||
loadOnlyofficeTemplates();
|
||||
},
|
||||
onError: function(event) {
|
||||
console.error('ONLYOFFICE error:', event);
|
||||
toast('Editor error: ' + (event.data?.errorDescription || 'unknown'), 'error');
|
||||
},
|
||||
},
|
||||
@@ -386,21 +338,22 @@ async function openOnlyofficeEditor(templateId, templateName) {
|
||||
toast('Failed to open editor: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize when templates page is active
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const templatesPage = document.getElementById('page-templates');
|
||||
if (templatesPage) {
|
||||
// Check on initial load (page may already be active from sessionStorage restore)
|
||||
if (!templatesPage) return;
|
||||
|
||||
if (templatesPage.classList.contains('active')) {
|
||||
checkOnlyofficeStatus();
|
||||
loadOnlyofficeTemplates();
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
if (templatesPage.classList.contains('active')) {
|
||||
checkOnlyofficeStatus();
|
||||
loadOnlyofficeTemplates();
|
||||
}
|
||||
// Also watch for future tab switches
|
||||
const observer = new MutationObserver(() => {
|
||||
if (templatesPage.classList.contains('active')) {
|
||||
checkOnlyofficeStatus();
|
||||
loadOnlyofficeTemplates();
|
||||
}
|
||||
});
|
||||
observer.observe(templatesPage, { attributes: true, attributeFilter: ['class'] });
|
||||
}
|
||||
});
|
||||
observer.observe(templatesPage, { attributes: true, attributeFilter: ['class'] });
|
||||
});
|
||||
@@ -139,7 +139,7 @@
|
||||
<!-- Modals -->
|
||||
<div class="modal-overlay" id="modal-overlay"></div>
|
||||
|
||||
<script src="/static/app.js?v=10"></script>
|
||||
<script src="/static/carbone.js?v=10"></script>
|
||||
<script src="/static/app.js?v=11"></script>
|
||||
<script src="/static/carbone.js?v=11"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user