/**
* Storage Service - บริการสำหรับจัดเก็บข้อมูลใน localStorage
*/
(function(global) {
'use strict';
/**
* คลาส StorageService
* บริการสำหรับจัดเก็บข้อมูลใน localStorage
*/
class StorageService {
constructor(editor) {
this.editor = editor;
this.prefix = 'editor_';
this.encryptionEnabled = false;
this.encryptionKey = null;
}
/**
* บันทึกข้อมูล
* @param {string} key - คีย์
* @param {*} data - ข้อมูลที่จะบันทึก
* @param {Object} options - ตัวเลือก (optional)
*/
save(key, data, options = {}) {
try {
const prefixedKey = this.prefix + key;
// แปลงข้อมูลเป็น JSON
let serializedData = JSON.stringify({
data,
timestamp: Date.now(),
version: options.version || '1.0.0'
});
// เข้ารหัสถ้าเปิดใช้งาน
if (this.encryptionEnabled) {
serializedData = this.encrypt(serializedData);
}
// บันทึกใน localStorage
localStorage.setItem(prefixedKey, serializedData);
// ส่งเหตุการณ์
this.editor.emit('storage:saved', {key, data});
if (this.editor.config.debug) {
console.log(`Data saved to storage: ${key}`);
}
return true;
} catch (error) {
console.error(`Failed to save data to storage: ${key}`, error);
// ส่งเหตุการณ์
this.editor.emit('storage:save-error', {key, error});
return false;
}
}
/**
* โหลดข้อมูล
* @param {string} key - คีย์
* @param {*} defaultValue - ค่าเริ่มต้น (optional)
* @param {Object} options - ตัวเลือก (optional)
* @returns {*} ข้อมูลที่โหลด
*/
load(key, defaultValue = null, options = {}) {
try {
const prefixedKey = this.prefix + key;
// โหลดจาก localStorage
let serializedData = localStorage.getItem(prefixedKey);
if (!serializedData) {
return defaultValue;
}
// ถอดรหัสถ้าเปิดใช้งาน
if (this.encryptionEnabled) {
serializedData = this.decrypt(serializedData);
}
// แปลงจาก JSON
const parsedData = JSON.parse(serializedData);
// ตรวจสอบเวอร์ชัน
if (options.version && parsedData.version !== options.version) {
console.warn(`Version mismatch for ${key}: expected ${options.version}, got ${parsedData.version}`);
// ส่งเหตุการณ์
this.editor.emit('storage:version-mismatch', {
key,
expected: options.version,
actual: parsedData.version
});
return defaultValue;
}
// ส่งเหตุการณ์
this.editor.emit('storage:loaded', {key, data: parsedData.data});
if (this.editor.config.debug) {
console.log(`Data loaded from storage: ${key}`);
}
return parsedData.data;
} catch (error) {
console.error(`Failed to load data from storage: ${key}`, error);
// ส่งเหตุการณ์
this.editor.emit('storage:load-error', {key, error});
return defaultValue;
}
}
/**
* ลบข้อมูล
* @param {string} key - คีย์
* @returns {boolean} สำเร็จหรือไม่
*/
remove(key) {
try {
const prefixedKey = this.prefix + key;
// ตรวจสอบว่ามีข้อมูลหรือไม่
if (!localStorage.getItem(prefixedKey)) {
return false;
}
// ลบข้อมูล
localStorage.removeItem(prefixedKey);
// ส่งเหตุการณ์
this.editor.emit('storage:removed', {key});
if (this.editor.config.debug) {
console.log(`Data removed from storage: ${key}`);
}
return true;
} catch (error) {
console.error(`Failed to remove data from storage: ${key}`, error);
// ส่งเหตุการณ์
this.editor.emit('storage:remove-error', {key, error});
return false;
}
}
/**
* ตรวจสอบว่ามีข้อมูลหรือไม่
* @param {string} key - คีย์
* @returns {boolean} มีข้อมูลหรือไม่
*/
exists(key) {
const prefixedKey = this.prefix + key;
return localStorage.getItem(prefixedKey) !== null;
}
/**
* รับคีย์ทั้งหมด
* @returns {Array} รายการคีย์ทั้งหมด
*/
getAllKeys() {
const keys = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith(this.prefix)) {
// ลบ prefix
keys.push(key.substring(this.prefix.length));
}
}
return keys;
}
/**
* ล้างข้อมูลทั้งหมด
*/
clear() {
const keys = this.getAllKeys();
keys.forEach(key => {
this.remove(key);
});
// ส่งเหตุการณ์
this.editor.emit('storage:cleared');
if (this.editor.config.debug) {
console.log('All data cleared from storage');
}
}
/**
* รับขนาดข้อมูลทั้งหมด
* @returns {number} ขนาดข้อมูล (bytes)
*/
getSize() {
let size = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key) && key.startsWith(this.prefix)) {
size += localStorage[key].length + key.length;
}
}
return size;
}
/**
* ตั้งค่าการเข้ารหัส
* @param {boolean} enabled - เปิดใช้งานหรือไม่
* @param {string} key - คีย์เข้ารหัส (optional)
*/
setEncryption(enabled, key = null) {
this.encryptionEnabled = enabled;
if (enabled && key) {
this.encryptionKey = key;
}
}
/**
* เข้ารหัสข้อมูล
* @param {string} data - ข้อมูลที่จะเข้ารหัส
* @returns {string} ข้อมูลที่เข้ารหัสแล้ว
*/
encrypt(data) {
if (!this.encryptionEnabled || !this.encryptionKey) {
return data;
}
try {
// ใช้งานง่ายๆ ด้วย XOR
let encrypted = '';
for (let i = 0; i < data.length; i++) {
const charCode = data.charCodeAt(i);
const keyChar = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
encrypted += String.fromCharCode(charCode ^ keyChar);
}
// แปลงเป็น Base64
return btoa(encrypted);
} catch (error) {
console.error('Failed to encrypt data:', error);
return data;
}
}
/**
* ถอดรหัสข้อมูล
* @param {string} encryptedData - ข้อมูลที่เข้ารหัส
* @returns {string} ข้อมูลที่ถอดรหัสแล้ว
*/
decrypt(encryptedData) {
if (!this.encryptionEnabled || !this.encryptionKey) {
return encryptedData;
}
try {
// แปลงจาก Base64
const data = atob(encryptedData);
// ใช้งานง่ายๆ ด้วย XOR
let decrypted = '';
for (let i = 0; i < data.length; i++) {
const charCode = data.charCodeAt(i);
const keyChar = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
decrypted += String.fromCharCode(charCode ^ keyChar);
}
return decrypted;
} catch (error) {
console.error('Failed to decrypt data:', error);
return encryptedData;
}
}
/**
* ส่งออกข้อมูลเป็นไฟล์
* @param {string} key - คีย์
* @param {string} filename - ชื่อไฟล์
* @param {string} type - ประเภทไฟล์ (optional)
*/
exportToFile(key, filename, type = 'application/json') {
try {
const data = this.load(key);
if (data === null) {
throw new Error(`Data not found for key: ${key}`);
}
// สร้าง Blob
const blob = new Blob([JSON.stringify(data, null, 2)], {type});
// สร้าง URL
const url = URL.createObjectURL(blob);
// สร้างลิงก์ดาวน์โหลด
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// ลบ URL
URL.revokeObjectURL(url);
// ส่งเหตุการณ์
this.editor.emit('storage:exported', {key, filename});
return true;
} catch (error) {
console.error(`Failed to export data to file: ${key}`, error);
// ส่งเหตุการณ์
this.editor.emit('storage:export-error', {key, error});
return false;
}
}
/**
* นำเข้าข้อมูลจากไฟล์
* @param {string} key - คีย์
* @param {File} file - ไฟล์ที่จะนำเข้า
* @returns {Promise} Promise ที่ส่งคืนผลการนำเข้า
*/
importFromFile(key, file) {
return new Promise((resolve, reject) => {
try {
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = JSON.parse(e.target.result);
// บันทึกข้อมูล
const success = this.save(key, data);
if (success) {
// ส่งเหตุการณ์
this.editor.emit('storage:imported', {key, file});
resolve(data);
} else {
reject(new Error(`Failed to save imported data for key: ${key}`));
}
} catch (error) {
reject(new Error(`Failed to parse imported file: ${error.message}`));
}
};
reader.onerror = () => {
reject(new Error('Failed to read file'));
};
reader.readAsText(file);
} catch (error) {
reject(error);
}
});
}
}
// เปิดเผยคลาส StorageService ทั่วโลก
global.StorageService = StorageService;
})(typeof window !== 'undefined' ? window : this);