Spaces:
No application file
No application file
import MjmlService from "grapesjs-preset-mautic/dist/mjml/mjml.service"; | |
import ContentService from 'grapesjs-preset-mautic/dist/content.service'; | |
export default class StorageService { | |
constructor(editor, mode) { | |
this.editor = editor; | |
this.mode = mode; | |
this.maxStorageItems = 10; | |
this.init(); | |
} | |
init() { | |
this.storageKey = 'gjs-storage'; | |
this.restoreMessage = null; | |
const stackItemId = this.getStackItemId(); | |
const storageItem = this.getStorageItemById(stackItemId); | |
const editorContent = this.getEditorContent(); | |
if (storageItem && editorContent !== storageItem.content) { | |
this.displayRestoreMessage(storageItem); | |
} | |
this.editor.on("update", () => this.handleUpdate()); | |
this.addFormSubmitListeners(); | |
} | |
displayRestoreMessage(storedContent) { | |
const buttonContainer = document.createElement('div'); | |
buttonContainer.className = 'alert-growl-buttons'; | |
const restoreButton = document.createElement('button'); | |
restoreButton.innerHTML = '<i class="ri-arrow-go-back-line"></i> ' + Mautic.translate('mautic.core.builder.storage.restore.button') | |
restoreButton.className = 'btn btn-primary'; | |
const dismissButton = document.createElement('button'); | |
dismissButton.innerHTML = Mautic.translate('mautic.core.builder.storage.dismiss.button') | |
dismissButton.className = 'btn btn-default'; | |
buttonContainer.append(restoreButton, dismissButton); | |
const formattedDateTime = this.formatDateTime(storedContent.date); | |
const message = Mautic.translate('mautic.core.builder.storage.restore.message', { | |
date: formattedDateTime | |
}); | |
const flashMessage = Mautic.addInfoFlashMessage(message); | |
flashMessage.append(buttonContainer); | |
const closeButton = flashMessage.querySelector('button.close') | |
this.addMessageEventListeners(restoreButton, dismissButton, closeButton); | |
Mautic.setFlashes(flashMessage, false); | |
this.restoreMessage = flashMessage; | |
} | |
dismissRestoreMessage() { | |
if (this.restoreMessage instanceof Element) { | |
this.restoreMessage.remove(); | |
} | |
this.restoreMessage = null; | |
} | |
addMessageEventListeners(restoreButton, dismissButtom, closeButton) { | |
restoreButton.addEventListener('click', (event) => { | |
this.load(); | |
this.dismissRestoreMessage(); | |
event.preventDefault(); | |
}); | |
dismissButtom.addEventListener('click', (event) => { | |
this.handleUpdate(); | |
this.dismissRestoreMessage(); | |
this.removeStorageItemById(this.getStackItemId()); | |
event.preventDefault(); | |
}); | |
closeButton.addEventListener('click', () => { | |
this.handleUpdate(); | |
}); | |
this.editor.on('hide', () => this.dismissRestoreMessage()); | |
} | |
addFormSubmitListeners() { | |
mQuery(this.getForm()).on('submit:success', (e, requestUrl, response) => { | |
const lastRequestUrlPart = requestUrl.split('/').pop(); | |
const lastResponseUrlPart = response.route.split('/').pop(); | |
// Check if the form was submitted for a new entity and the response contains the entity id | |
// The success response code alone does not guarantee that the form was saved, | |
// so we need to validate the URL changes and the presence of the entity id | |
if (lastRequestUrlPart === 'new' && !isNaN(lastResponseUrlPart)){ | |
// Remove the local storage item for the newly created entity after successful form submission | |
this.removeStorageItemById(`gjs-${this.mode}-${Mautic.builderTheme}-new`); | |
} | |
}); | |
} | |
handleUpdate() { | |
// update the storage content only when the restore prompt is not available | |
if (!this.restoreMessage) { | |
const editorContent = this.getEditorContent(); | |
const dateTime = new Date().toISOString(); | |
const stackItemId = this.getStackItemId(); | |
const contentWithDateTime = { id: stackItemId, content: editorContent, date: dateTime }; | |
this.saveStorageItem(contentWithDateTime); | |
} | |
} | |
load() { | |
const stackItemId = this.getStackItemId(); | |
const storageItem = this.getStorageItemById(stackItemId); | |
if (storageItem) { | |
this.editor.setComponents(storageItem.content); | |
} | |
} | |
getEditorContent() { | |
let content; | |
if (ContentService.isMjmlMode(this.editor)) { | |
content = MjmlService.getEditorMjmlContent(this.editor); | |
} else { | |
content = ContentService.getEditorHtmlContent(this.editor); | |
} | |
return content; | |
} | |
getStackItemId() { | |
const entityId = this.getFormEntityId(this.mode === 'page' ? 'page' : 'emailform') | |
return `gjs-${this.mode}-${Mautic.builderTheme}-${entityId}`; | |
} | |
saveStorageItem(item) { | |
const stack = JSON.parse(localStorage.getItem(this.storageKey)) || []; | |
const index = stack.findIndex(existingItem => existingItem.id === item.id); | |
if (index !== -1) { | |
// If the item already exists, update it | |
stack[index] = item; | |
} else { | |
// If the item doesn't exist, push it to the stack | |
if (stack.length >= this.maxStorageItems) { | |
// Ensure that the stack does not exceed the maximum allowed number of items | |
// to prevent web storage from exceeding its 10MiB per domain limit | |
stack.pop(); // Remove the oldest item | |
} | |
stack.push(item); | |
} | |
stack.sort((a, b) => new Date(b.date) - new Date(a.date)); | |
localStorage.setItem(this.storageKey, JSON.stringify(stack)); | |
} | |
getStorageItemById(id) { | |
const stack = JSON.parse(localStorage.getItem(this.storageKey)) || []; | |
return stack.find(item => item.id === id); | |
} | |
removeStorageItemById(id) { | |
const stack = JSON.parse(localStorage.getItem(this.storageKey)) || []; | |
const index = stack.findIndex(item => item.id === id); | |
if (index !== -1) { | |
stack.splice(index, 1); | |
localStorage.setItem(this.storageKey, JSON.stringify(stack)); | |
} | |
} | |
formatDateTime(dateTime) { | |
return new Date(dateTime).toISOString().slice(0, 16).replace('T', ' '); | |
} | |
getFormEntityId(name) { | |
const form = document.querySelector(`form[name="${name}"]`); | |
const actionUrl = form.getAttribute('action'); | |
const urlParts = actionUrl.split('/'); | |
const lastPart = urlParts.pop(); | |
if (isNaN(lastPart)) { | |
return 'new'; | |
} else { | |
return lastPart; | |
} | |
} | |
getForm() { | |
return document.querySelector(this.mode === 'page' ? 'form[name="page"]' : 'form[name="emailform"]') | |
} | |
} |