Spaces:
Running
Running
ปรับตำแหน้งฟิลด์ไม่ได้
Browse files
script.js
CHANGED
|
@@ -100,13 +100,14 @@ function setupGlobalListeners() {
|
|
| 100 |
document.getElementById('zoom-in').addEventListener('click', zoomIn);
|
| 101 |
document.getElementById('zoom-out').addEventListener('click', zoomOut);
|
| 102 |
document.getElementById('current-pg').addEventListener('change', (e) => goToPage(e.target.value));
|
| 103 |
-
|
| 104 |
// Property Controls
|
| 105 |
['prop-x', 'prop-y', 'prop-size', 'prop-weight', 'prop-color'].forEach(id => {
|
| 106 |
-
document.getElementById(id)
|
|
|
|
|
|
|
|
|
|
| 107 |
});
|
| 108 |
-
|
| 109 |
-
// Modals
|
| 110 |
document.querySelectorAll('.close-modal, #btn-qr-cancel').forEach(btn => {
|
| 111 |
btn.addEventListener('click', (e) => {
|
| 112 |
const modal = e.target.closest('.fixed.z-\\[200\\]'); // Select modal wrapper
|
|
@@ -265,7 +266,6 @@ function switchTab(tab) {
|
|
| 265 |
state.scale = 1;
|
| 266 |
updateZoomDisplay();
|
| 267 |
}
|
| 268 |
-
|
| 269 |
// --- Design Mode & Drag & Drop ---
|
| 270 |
function toggleDesignMode() {
|
| 271 |
state.designMode = !state.designMode;
|
|
@@ -303,6 +303,7 @@ function updateFieldPositionsFromState() {
|
|
| 303 |
});
|
| 304 |
}
|
| 305 |
}
|
|
|
|
| 306 |
function selectField(id) {
|
| 307 |
if (!state.designMode) return;
|
| 308 |
deselectField();
|
|
@@ -318,8 +319,8 @@ function selectField(id) {
|
|
| 318 |
if (controls) controls.style.display = 'block';
|
| 319 |
|
| 320 |
document.getElementById('prop-id').textContent = id;
|
| 321 |
-
document.getElementById('prop-x').value = parseFloat(el.style.left);
|
| 322 |
-
document.getElementById('prop-y').value = parseFloat(el.style.top);
|
| 323 |
|
| 324 |
if (el.tagName === 'IMG') {
|
| 325 |
document.getElementById('prop-size').parentElement.style.display = 'none';
|
|
@@ -332,7 +333,7 @@ function selectField(id) {
|
|
| 332 |
|
| 333 |
document.getElementById('prop-size').value = parseFloat(el.style.fontSize) || 14;
|
| 334 |
document.getElementById('prop-weight').value = el.style.fontWeight || 'normal';
|
| 335 |
-
document.getElementById('prop-color').value = rgbToHex(el.style.color);
|
| 336 |
}
|
| 337 |
}
|
| 338 |
}
|
|
@@ -343,35 +344,45 @@ function deselectField() {
|
|
| 343 |
if (el) el.classList.remove('selected');
|
| 344 |
}
|
| 345 |
state.selectedFieldId = null;
|
| 346 |
-
document.getElementById('no-field-selected')
|
| 347 |
-
document.getElementById('field-controls')
|
|
|
|
|
|
|
| 348 |
}
|
| 349 |
|
| 350 |
function updateFieldFromInputs() {
|
| 351 |
if (!state.selectedFieldId) return;
|
| 352 |
const el = document.getElementById(state.selectedFieldId);
|
|
|
|
|
|
|
| 353 |
const x = parseFloat(document.getElementById('prop-x').value) || 0;
|
| 354 |
const y = parseFloat(document.getElementById('prop-y').value) || 0;
|
| 355 |
|
| 356 |
el.style.left = x + 'px';
|
| 357 |
el.style.top = y + 'px';
|
| 358 |
|
| 359 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
|
| 361 |
if (el.tagName !== 'IMG') {
|
| 362 |
-
const size = document.getElementById('prop-size').value;
|
| 363 |
-
const color = document.getElementById('prop-color').value;
|
| 364 |
-
const weight = document.getElementById('prop-weight').value;
|
| 365 |
|
| 366 |
el.style.fontSize = size + 'px';
|
| 367 |
el.style.color = color;
|
| 368 |
el.style.fontWeight = weight;
|
| 369 |
|
| 370 |
-
state.fieldConfig[state.selectedFieldId] =
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
};
|
| 374 |
}
|
|
|
|
| 375 |
saveFieldConfig();
|
| 376 |
}
|
| 377 |
|
|
@@ -397,14 +408,16 @@ function onMouseMove(e) {
|
|
| 397 |
const parent = dragInfo.el.parentElement;
|
| 398 |
const pRect = parent.getBoundingClientRect();
|
| 399 |
|
| 400 |
-
// Calculate new position relative to parent, compensating for zoom
|
| 401 |
-
// Since .page has transform, we need to adjust coordinates or use unscaled logic
|
| 402 |
-
// Simplified: Assuming 1:1 for now, or accounting for page scale
|
| 403 |
let scale = state.scale;
|
| 404 |
|
| 405 |
let newLeft = (e.clientX - pRect.left - dragInfo.offsetX) / scale;
|
| 406 |
let newTop = (e.clientY - pRect.top - dragInfo.offsetY) / scale;
|
| 407 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
dragInfo.el.style.left = newLeft + 'px';
|
| 409 |
dragInfo.el.style.top = newTop + 'px';
|
| 410 |
|
|
@@ -418,17 +431,16 @@ function onMouseMove(e) {
|
|
| 418 |
function onMouseUp() {
|
| 419 |
if (dragInfo.active && dragInfo.el) {
|
| 420 |
// Save config on drop
|
| 421 |
-
state.fieldConfig[dragInfo.el.id]
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
saveFieldConfig();
|
| 427 |
}
|
| 428 |
dragInfo.active = false;
|
| 429 |
dragInfo.el = null;
|
| 430 |
}
|
| 431 |
-
|
| 432 |
// --- Layout Config ---
|
| 433 |
function saveFieldConfig() {
|
| 434 |
localStorage.setItem('pdf_field_config', JSON.stringify(state.fieldConfig));
|
|
@@ -438,14 +450,18 @@ function saveFieldConfig() {
|
|
| 438 |
function loadFieldConfig() {
|
| 439 |
const saved = localStorage.getItem('pdf_field_config');
|
| 440 |
if (saved) {
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 449 |
}
|
| 450 |
loadLayoutFromStorage();
|
| 451 |
}
|
|
@@ -495,6 +511,7 @@ function saveLayoutToStorage() {
|
|
| 495 |
});
|
| 496 |
|
| 497 |
state.currentLayoutConfig = layoutData;
|
|
|
|
| 498 |
return layoutData;
|
| 499 |
}
|
| 500 |
|
|
@@ -502,8 +519,9 @@ function loadLayoutFromStorage() {
|
|
| 502 |
const saved = localStorage.getItem('pdf_layout_config');
|
| 503 |
if (saved) {
|
| 504 |
try {
|
| 505 |
-
|
| 506 |
-
|
|
|
|
| 507 |
state.isLayoutLoaded = true;
|
| 508 |
} catch (e) {
|
| 509 |
console.warn('Failed to load layout config:', e);
|
|
@@ -512,6 +530,8 @@ function loadLayoutFromStorage() {
|
|
| 512 |
}
|
| 513 |
|
| 514 |
function applyLayoutConfig(config) {
|
|
|
|
|
|
|
| 515 |
// Apply field configurations
|
| 516 |
Object.keys(config.fields).forEach(fieldId => {
|
| 517 |
const fieldConfig = config.fields[fieldId];
|
|
|
|
| 100 |
document.getElementById('zoom-in').addEventListener('click', zoomIn);
|
| 101 |
document.getElementById('zoom-out').addEventListener('click', zoomOut);
|
| 102 |
document.getElementById('current-pg').addEventListener('change', (e) => goToPage(e.target.value));
|
|
|
|
| 103 |
// Property Controls
|
| 104 |
['prop-x', 'prop-y', 'prop-size', 'prop-weight', 'prop-color'].forEach(id => {
|
| 105 |
+
const el = document.getElementById(id);
|
| 106 |
+
if (el) {
|
| 107 |
+
el.addEventListener('input', updateFieldFromInputs);
|
| 108 |
+
}
|
| 109 |
});
|
| 110 |
+
// Modals
|
|
|
|
| 111 |
document.querySelectorAll('.close-modal, #btn-qr-cancel').forEach(btn => {
|
| 112 |
btn.addEventListener('click', (e) => {
|
| 113 |
const modal = e.target.closest('.fixed.z-\\[200\\]'); // Select modal wrapper
|
|
|
|
| 266 |
state.scale = 1;
|
| 267 |
updateZoomDisplay();
|
| 268 |
}
|
|
|
|
| 269 |
// --- Design Mode & Drag & Drop ---
|
| 270 |
function toggleDesignMode() {
|
| 271 |
state.designMode = !state.designMode;
|
|
|
|
| 303 |
});
|
| 304 |
}
|
| 305 |
}
|
| 306 |
+
|
| 307 |
function selectField(id) {
|
| 308 |
if (!state.designMode) return;
|
| 309 |
deselectField();
|
|
|
|
| 319 |
if (controls) controls.style.display = 'block';
|
| 320 |
|
| 321 |
document.getElementById('prop-id').textContent = id;
|
| 322 |
+
document.getElementById('prop-x').value = parseFloat(el.style.left) || 0;
|
| 323 |
+
document.getElementById('prop-y').value = parseFloat(el.style.top) || 0;
|
| 324 |
|
| 325 |
if (el.tagName === 'IMG') {
|
| 326 |
document.getElementById('prop-size').parentElement.style.display = 'none';
|
|
|
|
| 333 |
|
| 334 |
document.getElementById('prop-size').value = parseFloat(el.style.fontSize) || 14;
|
| 335 |
document.getElementById('prop-weight').value = el.style.fontWeight || 'normal';
|
| 336 |
+
document.getElementById('prop-color').value = rgbToHex(el.style.color) || '#000000';
|
| 337 |
}
|
| 338 |
}
|
| 339 |
}
|
|
|
|
| 344 |
if (el) el.classList.remove('selected');
|
| 345 |
}
|
| 346 |
state.selectedFieldId = null;
|
| 347 |
+
const noSel = document.getElementById('no-field-selected');
|
| 348 |
+
const controls = document.getElementById('field-controls');
|
| 349 |
+
if (noSel) noSel.style.display = 'block';
|
| 350 |
+
if (controls) controls.style.display = 'none';
|
| 351 |
}
|
| 352 |
|
| 353 |
function updateFieldFromInputs() {
|
| 354 |
if (!state.selectedFieldId) return;
|
| 355 |
const el = document.getElementById(state.selectedFieldId);
|
| 356 |
+
if (!el) return;
|
| 357 |
+
|
| 358 |
const x = parseFloat(document.getElementById('prop-x').value) || 0;
|
| 359 |
const y = parseFloat(document.getElementById('prop-y').value) || 0;
|
| 360 |
|
| 361 |
el.style.left = x + 'px';
|
| 362 |
el.style.top = y + 'px';
|
| 363 |
|
| 364 |
+
// Update state.fieldConfig
|
| 365 |
+
if (!state.fieldConfig[state.selectedFieldId]) {
|
| 366 |
+
state.fieldConfig[state.selectedFieldId] = {};
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
state.fieldConfig[state.selectedFieldId].top = y + 'px';
|
| 370 |
+
state.fieldConfig[state.selectedFieldId].left = x + 'px';
|
| 371 |
|
| 372 |
if (el.tagName !== 'IMG') {
|
| 373 |
+
const size = document.getElementById('prop-size').value || '14';
|
| 374 |
+
const color = document.getElementById('prop-color').value || '#000000';
|
| 375 |
+
const weight = document.getElementById('prop-weight').value || 'normal';
|
| 376 |
|
| 377 |
el.style.fontSize = size + 'px';
|
| 378 |
el.style.color = color;
|
| 379 |
el.style.fontWeight = weight;
|
| 380 |
|
| 381 |
+
state.fieldConfig[state.selectedFieldId].fontSize = size + 'px';
|
| 382 |
+
state.fieldConfig[state.selectedFieldId].color = color;
|
| 383 |
+
state.fieldConfig[state.selectedFieldId].fontWeight = weight;
|
|
|
|
| 384 |
}
|
| 385 |
+
|
| 386 |
saveFieldConfig();
|
| 387 |
}
|
| 388 |
|
|
|
|
| 408 |
const parent = dragInfo.el.parentElement;
|
| 409 |
const pRect = parent.getBoundingClientRect();
|
| 410 |
|
| 411 |
+
// Calculate new position relative to parent, compensating for zoom
|
|
|
|
|
|
|
| 412 |
let scale = state.scale;
|
| 413 |
|
| 414 |
let newLeft = (e.clientX - pRect.left - dragInfo.offsetX) / scale;
|
| 415 |
let newTop = (e.clientY - pRect.top - dragInfo.offsetY) / scale;
|
| 416 |
|
| 417 |
+
// Ensure non-negative positions
|
| 418 |
+
newLeft = Math.max(0, newLeft);
|
| 419 |
+
newTop = Math.max(0, newTop);
|
| 420 |
+
|
| 421 |
dragInfo.el.style.left = newLeft + 'px';
|
| 422 |
dragInfo.el.style.top = newTop + 'px';
|
| 423 |
|
|
|
|
| 431 |
function onMouseUp() {
|
| 432 |
if (dragInfo.active && dragInfo.el) {
|
| 433 |
// Save config on drop
|
| 434 |
+
if (!state.fieldConfig[dragInfo.el.id]) {
|
| 435 |
+
state.fieldConfig[dragInfo.el.id] = {};
|
| 436 |
+
}
|
| 437 |
+
state.fieldConfig[dragInfo.el.id].left = dragInfo.el.style.left;
|
| 438 |
+
state.fieldConfig[dragInfo.el.id].top = dragInfo.el.style.top;
|
| 439 |
saveFieldConfig();
|
| 440 |
}
|
| 441 |
dragInfo.active = false;
|
| 442 |
dragInfo.el = null;
|
| 443 |
}
|
|
|
|
| 444 |
// --- Layout Config ---
|
| 445 |
function saveFieldConfig() {
|
| 446 |
localStorage.setItem('pdf_field_config', JSON.stringify(state.fieldConfig));
|
|
|
|
| 450 |
function loadFieldConfig() {
|
| 451 |
const saved = localStorage.getItem('pdf_field_config');
|
| 452 |
if (saved) {
|
| 453 |
+
try {
|
| 454 |
+
state.fieldConfig = JSON.parse(saved);
|
| 455 |
+
Object.keys(state.fieldConfig).forEach(id => {
|
| 456 |
+
const el = document.getElementById(id);
|
| 457 |
+
const cfg = state.fieldConfig[id];
|
| 458 |
+
if (el && cfg) {
|
| 459 |
+
Object.assign(el.style, cfg);
|
| 460 |
+
}
|
| 461 |
+
});
|
| 462 |
+
} catch (e) {
|
| 463 |
+
console.warn('Failed to load field config:', e);
|
| 464 |
+
}
|
| 465 |
}
|
| 466 |
loadLayoutFromStorage();
|
| 467 |
}
|
|
|
|
| 511 |
});
|
| 512 |
|
| 513 |
state.currentLayoutConfig = layoutData;
|
| 514 |
+
localStorage.setItem('pdf_layout_config', JSON.stringify(layoutData));
|
| 515 |
return layoutData;
|
| 516 |
}
|
| 517 |
|
|
|
|
| 519 |
const saved = localStorage.getItem('pdf_layout_config');
|
| 520 |
if (saved) {
|
| 521 |
try {
|
| 522 |
+
const parsed = JSON.parse(saved);
|
| 523 |
+
state.currentLayoutConfig = parsed;
|
| 524 |
+
applyLayoutConfig(parsed);
|
| 525 |
state.isLayoutLoaded = true;
|
| 526 |
} catch (e) {
|
| 527 |
console.warn('Failed to load layout config:', e);
|
|
|
|
| 530 |
}
|
| 531 |
|
| 532 |
function applyLayoutConfig(config) {
|
| 533 |
+
if (!config || !config.fields) return;
|
| 534 |
+
|
| 535 |
// Apply field configurations
|
| 536 |
Object.keys(config.fields).forEach(fieldId => {
|
| 537 |
const fieldConfig = config.fields[fieldId];
|