PageSourceSearch

https://yangnyeong.co.kr/assets/js/pagemedia.js

js yangnyeong.co.kr collected 2026-10-08 23:49:51 UTC 5,537 bytes, 116 lines download raw bytes

1/* 정적페이지 본문의 이미지 확대 보기.
2   레거시 본문에 onclick="image_popup('...')" 이 남아 있어(연혁 페이지) 같은 이름으로 노출한다.
3   본문 내 이미지는 클릭만으로도 열리도록 함께 처리. */
4(function () {
5    var box = null, img = null;
6
7    function build() {
8        if (box) return;
9        box = document.createElement('div');
10        box.className = 'lightbox';
11        box.innerHTML =
12            '<button class="lb-btn lb-close" type="button" aria-label="닫기">✕</button>' +
13            '<figure class="lb-stage"><img class="lb-img" alt=""></figure>';
14        img = box.querySelector('.lb-img');
15
16        box.addEventListener('click', function (e) { if (e.target === box || e.target.closest('.lb-close')) close(); });
17        document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
18        document.body.appendChild(box);
19    }
20
21    function close() {
22        if (!box) return;
23        box.classList.remove('on');
24        document.body.style.overflow = '';
25    }
26
27    window.image_popup = function (url) {
28        if (!url) return;
29        build();
30        img.src = url;
31        box.classList.add('on');
32        document.body.style.overflow = 'hidden';
33    };
34
35    /* 레거시 표는 셀 폭이 고정된 것이 많아 좁은 화면에서 페이지를 밀어낸다.
36       바깥 표만 가로 스크롤 상자로 감싸 본문 폭 안에서 스크롤되게 한다. */
37    document.addEventListener('DOMContentLoaded', function () {
38        document.querySelectorAll('.page-body table').forEach(function (t) {
39            if (t.parentElement.closest('table')) return;                    // 중첩 표는 바깥 것만
40            if (t.parentElement.classList.contains('table-scroll')) return;
41            var wrap = document.createElement('div');
42            wrap.className = 'table-scroll';
43            t.parentElement.insertBefore(wrap, t);
44            wrap.appendChild(t);
45        });
46    });
47
48    document.addEventListener('DOMContentLoaded', function () {
49        document.querySelectorAll('.page-body img').forEach(function (el) {
50            if (el.closest('a')) return;                       // 이미 링크가 걸린 이미지는 그대로
51            if (el.hasAttribute('data-nozoom')) return;        // 원본이 작아 확대해도 얻을 것이 없는 사진
52            if (el.naturalWidth && el.naturalWidth < 200) return;
53            el.style.cursor = 'zoom-in';
54            if (el.hasAttribute('onclick')) return;            // 레거시 onclick 이 있으면 중복 방지
55            el.addEventListener('click', function () { window.image_popup(el.currentSrc || el.src); });
56        });
57    });
58
59    /* 복사 버튼 — 오시는 길의 주소, 후원 안내의 후원계좌처럼
60       "손으로 옮겨 적기 번거로운 값" 옆에 붙는다.
61       원래 map.js 안에 있던 것을 [data-copy] 공통 처리로 옮겼다. */
62    function legacyCopy(text) {
63        var ta = document.createElement('textarea');
64        ta.value = text; ta.style.cssText = 'position:fixed;left:-9999px;top:0';
65        document.body.appendChild(ta); ta.focus(); ta.select();
66        var ok = false;
67        try { ok = document.execCommand('copy'); } catch (e) {}
68        ta.remove();
69        return ok;
70    }
71
72    // 버튼에서 가장 가까운 실시간 영역을 찾는다(마크업마다 감싸는 깊이가 달라 3단계까지 거슬러 본다)
73    function findStatus(btn) {
74        var n = btn.parentElement, i = 0;
75        while (n && i++ < 3) {
76            var s = n.querySelector('[role="status"]');
77            if (s) return s;
78            n = n.parentElement;
79        }
80        return null;
81    }
82
83    document.addEventListener('DOMContentLoaded', function () {
84        document.querySelectorAll('[data-copy]').forEach(function (btn) {
85            var baseLabel = btn.textContent;                 // 최초 라벨을 한 번만 잡는다(연타 시 임시라벨 오염 방지)
86            var statusBox = findStatus(btn);
87            var doneMsg   = btn.dataset.copyMsg || '복사했습니다.';
88            var restoreTimer = null;
89
90            function flash(ok) {
91                if (restoreTimer) clearTimeout(restoreTimer); // 이전 복원 예약을 취소해 상태가 얼지 않게 한다
92                btn.textContent = ok ? '복사됨' : '복사 실패';
93                btn.classList.toggle('done', ok);
94                if (statusBox) statusBox.textContent = ok ? doneMsg : '복사하지 못했습니다.';
95                restoreTimer = setTimeout(function () {
96                    btn.textContent = baseLabel;
97                    btn.classList.remove('done');
98                    if (statusBox) statusBox.textContent = '';
99                }, 1500);
100            }
101
102            btn.addEventListener('click', function () {
103                var text = btn.dataset.copy || '';
104                // clipboard API 가 거부돼도 execCommand 로 반드시 폴백한다
105                if (navigator.clipboard && navigator.clipboard.writeText) {
106                    navigator.clipboard.writeText(text).then(
107                        function () { flash(true); },
108                        function () { flash(legacyCopy(text)); }
109                    );
110                } else {
111                    flash(legacyCopy(text));
112                }
113            });
114        });
115    });
116})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.