first commit 2
This commit is contained in:
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// 1. 설정 파일 로드
|
||||
$config_path = __DIR__ . '/config.php';
|
||||
if (file_exists($config_path)) include_once($config_path);
|
||||
|
||||
// 2. 데이터 가져오기
|
||||
$target_bo_table = '';
|
||||
$target_wr_id = '';
|
||||
|
||||
if (isset($ebook_bo_table) && $ebook_bo_table) {
|
||||
$target_bo_table = $ebook_bo_table;
|
||||
} elseif (isset($ebook_config['bo_table'])) {
|
||||
$target_bo_table = $ebook_config['bo_table'];
|
||||
}
|
||||
|
||||
if (isset($ebook_wr_id) && $ebook_wr_id) {
|
||||
$target_wr_id = $ebook_wr_id;
|
||||
} elseif (isset($ebook_config['wr_id'])) {
|
||||
$target_wr_id = $ebook_config['wr_id'];
|
||||
}
|
||||
|
||||
// 옵션값
|
||||
$use_download = isset($use_download) ? $use_download : (isset($ebook_config['use_download']) ? $ebook_config['use_download'] : true);
|
||||
$use_print = isset($use_print) ? $use_print : (isset($ebook_config['use_print']) ? $ebook_config['use_print'] : true);
|
||||
|
||||
$pdfjs_url = G5_THEME_URL . '/js/pdfjs';
|
||||
$pdf_file_url = '';
|
||||
$pdf_download_url = '';
|
||||
|
||||
if ($target_bo_table && $target_wr_id) {
|
||||
$sql = " SELECT * FROM {$g5['board_file_table']} WHERE bo_table = '{$target_bo_table}' AND wr_id = '{$target_wr_id}' ORDER BY bf_no ASC ";
|
||||
$result = sql_query($sql);
|
||||
for ($i=0; $row=sql_fetch_array($result); $i++) {
|
||||
if (isset($row['bf_file']) && preg_match('/\.pdf$/i', $row['bf_file'])) {
|
||||
$pdf_file_url = G5_DATA_URL . '/file/' . $target_bo_table . '/' . urlencode($row['bf_file']);
|
||||
$pdf_download_url = $pdf_file_url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ebook_id = 'ebook_' . uniqid();
|
||||
$popup_url = G5_THEME_URL . '/rb.custom/ebook_section/popup.php?bo_table=' . $target_bo_table . '&wr_id=' . $target_wr_id;
|
||||
?>
|
||||
|
||||
<!-- Rebuilder 표준 구조 -->
|
||||
<div class="rb_layout_box" data-id="ebook_section" data-title="E-Book">
|
||||
<?php if (isset($is_admin) && $is_admin) { ?>
|
||||
<div class="rb_module_set">
|
||||
<a href="javascript:;" onclick="set_module_send(this);" class="btn_module_setup"><i class="fa fa-cog"></i></a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="ebook-section" id="<?php echo $ebook_id; ?>" data-theme="light">
|
||||
<?php if ($pdf_file_url): ?>
|
||||
|
||||
<div class="ebook-loading-overlay" style="display:flex;">
|
||||
<div class="spinner"></div>
|
||||
<p class="loading-text">E-Book을 준비 중입니다... (0%)</p>
|
||||
</div>
|
||||
|
||||
<div class="page-loading-alert" style="display:none;">잠시만 기다려 주세요...</div>
|
||||
|
||||
<div class="nav-arrow nav-prev" title="이전 페이지"><i class="fa fa-chevron-left"></i></div>
|
||||
<div class="nav-arrow nav-next" title="다음 페이지"><i class="fa fa-chevron-right"></i></div>
|
||||
|
||||
<div class="flipbook-viewport loading">
|
||||
<div class="container">
|
||||
<div class="flipbook"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ebook-controls loading">
|
||||
<div class="control-group">
|
||||
<button id="prev-btn" class="btn" title="이전 페이지"><i class="fa fa-chevron-left"></i></button>
|
||||
<div class="page-input-wrap">
|
||||
<input type="number" class="page-input" value="1" min="1"> / <span class="loaded-pages">0</span><span class="total-pages-wrap">(<span class="total-pages">0</span>)</span>
|
||||
</div>
|
||||
<button id="next-btn" class="btn" title="다음 페이지"><i class="fa fa-chevron-right"></i></button>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<button id="zoom-out-btn" class="btn" title="축소"><i class="fa fa-search-minus"></i></button>
|
||||
<span class="zoom-level" title="현재 배율">100%</span>
|
||||
<button id="zoom-reset-btn" class="btn" title="배율 초기화"><i class="fa fa-compress"></i></button>
|
||||
<button id="zoom-in-btn" class="btn" title="확대"><i class="fa fa-search-plus"></i></button>
|
||||
|
||||
<button id="dark-mode-btn" class="btn" title="다크 모드"><i class="fa fa-moon"></i></button>
|
||||
|
||||
<?php if ($use_print): ?>
|
||||
<button id="print-btn" class="btn" title="PDF 인쇄"><i class="fa fa-print"></i></button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($use_download): ?>
|
||||
<a href="<?php echo $pdf_download_url; ?>" class="btn download-btn" download target="_blank" title="PDF 다운로드">
|
||||
<i class="fa fa-download"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php echo $popup_url; ?>" class="btn popup-btn" target="_blank" onclick="window.open(this.href, 'ebook_popup', 'width=1200,height=800'); return false;" title="새 창으로 보기">
|
||||
<i class="fa fa-expand"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe id="print-frame-<?php echo $ebook_id; ?>" style="display:none;"></iframe>
|
||||
|
||||
<?php else: ?>
|
||||
<div class="ebook-empty">
|
||||
PDF 파일이 없습니다.<br>
|
||||
<?php if ($target_bo_table && $target_wr_id): ?>
|
||||
게시판: <?php echo $target_bo_table; ?>, 게시물: <?php echo $target_wr_id; ?>
|
||||
<?php else: ?>
|
||||
설정 파일(config.php)을 확인해주세요.
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet" href="<?php echo G5_THEME_URL; ?>/rb.custom/ebook_section/module.css?ver=<?php echo G5_CSS_VER; ?>">
|
||||
|
||||
<script src="<?php echo $pdfjs_url; ?>/pdf.min.js"></script>
|
||||
<script src="<?php echo G5_THEME_URL; ?>/rb.custom/ebook_section/turnjs4/lib/turn.min.js"></script>
|
||||
|
||||
<script>
|
||||
(function($) {
|
||||
if (!'<?php echo $pdf_file_url; ?>') return;
|
||||
|
||||
var resizeTimer; // 💡 [추가] 리사이즈 타이머 변수
|
||||
var pdfDoc = null;
|
||||
var pageCount = 0;
|
||||
var currentScale = 1.0;
|
||||
var initialLoadCount = 6;
|
||||
var loadedPageCount = 0;
|
||||
var renderedCount = 0;
|
||||
var isInitialized = false;
|
||||
|
||||
var $container = $('#<?php echo $ebook_id; ?>');
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '<?php echo $pdfjs_url; ?>/pdf.worker.min.js';
|
||||
|
||||
function startEbookProcess() {
|
||||
var $flipbook = $container.find('.flipbook');
|
||||
|
||||
if ($flipbook.turn('is')) {
|
||||
$flipbook.turn('destroy');
|
||||
}
|
||||
$flipbook.empty();
|
||||
$container.find('.ebook-loading-overlay').show();
|
||||
$container.find('.flipbook-viewport, .ebook-controls').addClass('loading');
|
||||
|
||||
var containerWidth = $container.width();
|
||||
if (!containerWidth || containerWidth < 100) containerWidth = 900;
|
||||
|
||||
var maxWidth = <?php echo isset($ebook_config['width']) ? $ebook_config['width'] : 1200; ?>;
|
||||
var maxHeight = <?php echo isset($ebook_config['height']) ? $ebook_config['height'] : 800; ?>;
|
||||
|
||||
var targetWidth = Math.min(containerWidth - 40, maxWidth);
|
||||
var bookWidth, bookHeight;
|
||||
|
||||
// 💡 [수정] 로딩 관련 변수 초기화
|
||||
renderedCount = 0;
|
||||
isInitialized = false;
|
||||
loadedPageCount = 0;
|
||||
$container.find('.loading-text').text('E-Book을 준비 중입니다... (0%)');
|
||||
|
||||
function run(pdf) {
|
||||
pdfDoc = pdf;
|
||||
pageCount = pdf.numPages;
|
||||
$container.find('.total-pages').text(pageCount);
|
||||
$container.find('.page-input').attr('max', pageCount);
|
||||
|
||||
pdf.getPage(1).then(function(page) {
|
||||
var viewport = page.getViewport({ scale: 1 });
|
||||
var pageRatio = viewport.width / viewport.height;
|
||||
var bookRatio = pageRatio * 2;
|
||||
|
||||
bookWidth = targetWidth;
|
||||
bookHeight = bookWidth / bookRatio;
|
||||
|
||||
if (bookHeight > maxHeight) {
|
||||
bookHeight = maxHeight;
|
||||
bookWidth = bookHeight * bookRatio;
|
||||
}
|
||||
|
||||
var initialPromises = [];
|
||||
var loadLimit = Math.min(pageCount, initialLoadCount);
|
||||
|
||||
for (var i = 1; i <= loadLimit; i++) {
|
||||
initialPromises.push(renderPage(i, bookWidth, bookHeight, true, loadLimit));
|
||||
}
|
||||
|
||||
Promise.all(initialPromises).then(function(pages) {
|
||||
pages.forEach(function(pageDiv) {
|
||||
$flipbook.append(pageDiv);
|
||||
});
|
||||
|
||||
initTurnJs(bookWidth, bookHeight);
|
||||
isInitialized = true;
|
||||
loadedPageCount = loadLimit;
|
||||
updatePageDisplay();
|
||||
|
||||
$container.find('.ebook-loading-overlay').fadeOut(500);
|
||||
$container.find('.flipbook-viewport, .ebook-controls').removeClass('loading');
|
||||
|
||||
if (pageCount > initialLoadCount) {
|
||||
loadRemainingPages(initialLoadCount + 1, bookWidth, bookHeight);
|
||||
} else {
|
||||
updatePageDisplay(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (pdfDoc) {
|
||||
run(pdfDoc);
|
||||
} else {
|
||||
pdfjsLib.getDocument('<?php echo $pdf_file_url; ?>').promise.then(run);
|
||||
}
|
||||
}
|
||||
|
||||
function loadRemainingPages(pageNum, bookWidth, bookHeight) {
|
||||
if (pageNum > pageCount) {
|
||||
updatePageDisplay(true);
|
||||
return;
|
||||
}
|
||||
renderPage(pageNum, bookWidth, bookHeight, false).then(function(pageDiv) {
|
||||
var $flipbook = $container.find('.flipbook');
|
||||
if ($flipbook.turn('is')) {
|
||||
$flipbook.turn('addPage', pageDiv, pageNum);
|
||||
}
|
||||
loadedPageCount = pageNum;
|
||||
updatePageDisplay();
|
||||
loadRemainingPages(pageNum + 1, bookWidth, bookHeight);
|
||||
});
|
||||
}
|
||||
|
||||
function updatePageDisplay(isComplete = false) {
|
||||
if (isComplete) {
|
||||
$container.find('.total-pages-wrap').hide();
|
||||
$container.find('.loaded-pages').text(pageCount);
|
||||
} else {
|
||||
$container.find('.loaded-pages').text(loadedPageCount);
|
||||
$container.find('.total-pages-wrap').show();
|
||||
}
|
||||
}
|
||||
|
||||
function renderPage(num, bookWidth, bookHeight, isInitial, loadLimit) {
|
||||
return pdfDoc.getPage(num).then(function(page) {
|
||||
var viewport = page.getViewport({ scale: 1.5 });
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
var pageWidth = bookWidth / 2;
|
||||
var pageHeight = bookHeight;
|
||||
var scaleX = pageWidth / viewport.width;
|
||||
var scaleY = pageHeight / viewport.height;
|
||||
var fitScale = Math.max(scaleX, scaleY);
|
||||
var fitViewport = page.getViewport({ scale: fitScale });
|
||||
|
||||
canvas.height = pageHeight;
|
||||
canvas.width = pageWidth;
|
||||
|
||||
var pageDiv = $('<div />').append(canvas);
|
||||
|
||||
var renderContext = { canvasContext: ctx, viewport: fitViewport };
|
||||
|
||||
return page.render(renderContext).promise.then(function() {
|
||||
if (isInitial) {
|
||||
renderedCount++;
|
||||
var percent = Math.round((renderedCount / loadLimit) * 100);
|
||||
$container.find('.loading-text').text('E-Book을 준비 중입니다... (' + percent + '%)');
|
||||
}
|
||||
return pageDiv;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initTurnJs(bookWidth, bookHeight) {
|
||||
var $flipbook = $container.find('.flipbook');
|
||||
if (typeof $flipbook.turn !== 'function') return;
|
||||
if ($flipbook.turn('is')) $flipbook.turn('destroy');
|
||||
|
||||
$flipbook.turn({
|
||||
width: bookWidth,
|
||||
height: bookHeight,
|
||||
autoCenter: true,
|
||||
gradients: true,
|
||||
acceleration: true,
|
||||
elevation: 50,
|
||||
display: 'double',
|
||||
pages: pageCount,
|
||||
when: {
|
||||
turned: function(event, page, view) {
|
||||
$container.find('.page-input').val(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 초기 실행
|
||||
startEbookProcess();
|
||||
|
||||
// 💡 [추가] 화면 리사이즈 시 이북 다시 로드
|
||||
$(window).on('resize', function() {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(startEbookProcess, 250);
|
||||
});
|
||||
|
||||
// 이벤트 핸들러
|
||||
$container.find('#prev-btn, .nav-prev').click(function() { $container.find('.flipbook').turn('previous'); });
|
||||
$container.find('#next-btn, .nav-next').click(function() { $container.find('.flipbook').turn('next'); });
|
||||
$container.find('.page-input').on('change keyup', function(e) {
|
||||
if (e.type === 'keyup' && e.keyCode !== 13) return;
|
||||
var page = parseInt($(this).val());
|
||||
if (page > 0 && page <= pageCount) $container.find('.flipbook').turn('page', page);
|
||||
});
|
||||
function updateZoom() {
|
||||
$container.find('.flipbook-viewport').css('transform', 'scale(' + currentScale + ')');
|
||||
$container.find('.zoom-level').text(Math.round(currentScale * 100) + '%');
|
||||
}
|
||||
$container.find('#zoom-in-btn').click(function() { if (currentScale < 2.0) { currentScale += 0.2; updateZoom(); } });
|
||||
$container.find('#zoom-out-btn').click(function() { if (currentScale > 0.6) { currentScale -= 0.2; updateZoom(); } });
|
||||
$container.find('#zoom-reset-btn').click(function() { currentScale = 1.0; updateZoom(); });
|
||||
$container.find('#dark-mode-btn').click(function() {
|
||||
var currentTheme = $container.attr('data-theme');
|
||||
var newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
||||
$container.attr('data-theme', newTheme);
|
||||
$(this).find('i').toggleClass('fa-sun fa-moon');
|
||||
});
|
||||
$container.find('#print-btn').click(function() {
|
||||
var $iframe = $container.find('iframe');
|
||||
$iframe.attr('src', '<?php echo $pdf_file_url; ?>');
|
||||
$iframe.on('load', function() {
|
||||
try { this.contentWindow.print(); }
|
||||
catch (e) { window.open('<?php echo $pdf_file_url; ?>', '_blank').print(); }
|
||||
});
|
||||
});
|
||||
var wheelTimeout;
|
||||
$container.on('wheel', function(e) {
|
||||
e.preventDefault();
|
||||
if (wheelTimeout) return;
|
||||
wheelTimeout = setTimeout(function() { wheelTimeout = null; }, 300);
|
||||
if (e.originalEvent.deltaY > 0) $container.find('.flipbook').turn('next');
|
||||
else $container.find('.flipbook').turn('previous');
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
Reference in New Issue
Block a user