PageSourceSearch

https://www.kitech.re.kr/js/common.js

js kitech.re.kr collected 2026-09-24 09:38:26 UTC 10,910 bytes, 304 lines download raw bytes

1const Utils = {
2    dateFormat: (data, format) => {
3        if (!data?.valueOf()) return '';
4        if (format === undefined)
5            format = 'yyyy-MM-dd HH:mm:ss';
6
7        let weekName = ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'];
8        let weekNameMin = ['일', '월', '화', '수', '목', '금', '토'];
9        let d = typeof data === 'object' ? data : new Date(data);
10
11        return format.replace(/(yyyy|yy|MM|dd|E|e|HH|hh|mm|ss|a\/p)/gi, $1 => {
12            switch ($1) {
13                case 'yyyy': return String(d.getFullYear());
14                case   'yy': return String(d.getFullYear() % 100).padStart(2, '0');
15                case   'MM': return String(d.getMonth() + 1).padStart(2, '0');
16                case   'dd': return String(d.getDate()).padStart(2, '0');
17                case    'E': return weekName[d.getDay()];
18                case    'e': return weekNameMin[d.getDay()];
19                case   'HH': return String(d.getHours()).padStart(2, '0');
20                case   'hh': return String(d.getHours() % 12 === 0 ? 12 : d.getHours() % 12);
21                case   'mm': return String(d.getMinutes()).padStart(2, '0');
22                case   'ss': return String(d.getSeconds()).padStart(2, '0');
23                case  'a/p': return d.getHours() < 12 ? '오전' : '오후';
24                default    : return $1;
25            }
26        });
27    },
28    telephoneFormat: (inputString) => {
29        let cleaned = ('' + inputString).replace(/\D/g, '');
30        let regExp = /^(01[016789]|02|03[1-3]|04[1-4]|050[1-9]|05[1-5]|06[1-4]|0[78]0|13[0-9]{2}|1[56][0-9]{2})([0-9]+)?([0-9]{4})/;
31        let match = cleaned.match(regExp);
32
33        if (/^[01]/.test(cleaned) === false) return '';
34        if (match === null) return cleaned.substring(0, 8);
35
36        if (match[2] !== undefined && match[2].length > 4) {
37            match[3] = match[2].substring(4) + match[3].substring(0, 3);
38            match[2] = match[2].substring(0, 4);
39        }
40
41        if (match[3] !== undefined && match[3].length > 4) {
42            match[3] = match[3].substring(0, 4);
43        }
44
45        if (match[1].startsWith('1') === true && match[2] !== undefined) {
46            match[3] = match[2].substring(0) + match[3].substring(0, 3);
47            match[2] = undefined;
48        }
49
50        return [match[1], match[2], match[3]].filter(Boolean).join('-');
51    },
52    priceFormat: (number) => {
53        // 숫자를 문자열로 변환
54        let numberString = '' + number;
55        // 정수부분과 소수점 이하 부분으로 분리
56        let parts = numberString.split('.');
57        // 정규 표현식을 사용하여 정수부분에 세 자리마다 콤마 추가
58        parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
59        // 소수점 이하 부분과 합쳐서 반환
60        return parts.join('.');
61    },
62    parseJwt: (token) => {
63        let splitToken = token.split('.');
64        if (splitToken.length !== 3)
65            return {};
66
67        return JSON.parse(decodeURIComponent(atob(splitToken[1]).split('').map(chr =>
68            '%' + ('00' + chr.charCodeAt(0).toString(16)).slice(-2)).join('')));
69    },
70    stripNumber: (inputString) => {
71        return ('' + inputString).replace(/\D/g, '');
72    },
73    getCookie: (key) => {
74        let value = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
75        return value !== null ? value[2] : null;
76    },
77    setCookie: (key, value, options = {}) => {
78        options = {
79            path: '/',
80            ...options
81        };
82
83        if (options.expires instanceof Date)
84            options.expires = options.expires.toUTCString();
85
86        let updatedCookie = encodeURIComponent(key) + "=" + encodeURIComponent(value);
87
88        for (let optionKey in options) {
89            updatedCookie += "; " + optionKey;
90            let optionValue = options[optionKey];
91            if (optionValue !== true)
92                updatedCookie += "=" + optionValue;
93        }
94
95        document.cookie = updatedCookie;
96    },
97    removeCookie: (key) => Utils.setCookie(key, '', { 'max-age': -1 }),
98    toggleItem(arr, value) {
99        let newArr = (arr === undefined || arr === null) ? [] : (Array.isArray(arr) ? [...arr] : [arr]);
100
101        newArr.includes(value) ? (newArr = newArr.filter(item => item !== value)) : newArr.push(value);
102
103        return newArr;
104    },
105    removeEmptyKeys: (obj) => {
106        let newObj = {};
107
108        for (let key in obj) {
109            if (obj[key] !== undefined && obj[key] !== null && obj[key] !== '')
110                newObj[key] = obj[key];
111        }
112
113        return newObj;
114    },
115    address: function (zipcode, addr, detail) {
116        if (zipcode && detail) {
117            return zipcode + ' ) ' + addr + ',' + detail
118        } else if (zipcode) {
119            return zipcode + ' ) ' + addr
120        } else if (detail) {
121            return addr + ',' + detail
122        } else {
123            return addr
124        }
125    },
126    loadExternalScript: function (src) {
127        return new Promise((resolve, reject) => {
128            if (document.querySelector(`script[src="${src}"]`)) {
129                resolve();
130                return;
131            }
132
133            const script = document.createElement('script');
134            script.src = src;
135            script.onload = resolve;
136            script.onerror = reject;
137            document.head.appendChild(script);
138        });
139    },
140    isMobile: () => {
141        return /Android|iPhone/.test(navigator.userAgent);
142    }
143};
144
145function handleFetchResponse(response) {
146    if (!response.ok) {
147        return response.json()
148            .then(result => { throw result; })
149            .catch(error => { throw error; });
150    }
151    if (response.ok && response.redirected === true && response.url.includes('/login') === true) {
152        throw { expired: true };
153    }
154
155    return response.json();
156}
157function handleFetchError(error) {
158    console.error('error', error);
159    let errorMessage = '네트워크 오류가 발생했습니다.';
160
161    if (error !== undefined) {
162        if (Array.isArray(error.errors) === true) {
163            errorMessage = error.errors.map(err => `- ${err.message}`).join('\n');
164        }
165        else if (error.message !== undefined) {
166            errorMessage = error.message;
167        }
168        else if (error.error !== undefined) {
169            errorMessage = error.error;
170        }
171        if (error.expired === true) {
172            alert('세션이 만료되었습니다. 다시 로그인해 주세요.');
173            location.reload();
174            return;
175        }
176    }
177
178    alert(errorMessage);
179}
180
181/** 파일 업로드 */
182function uploadFiles($inputFile, source) {
183    if ($inputFile.files.length === 0) return Promise.reject();
184
185    const inputName = $inputFile.getAttribute('data-name') || 'fileUUIDs';
186    const preview = $inputFile.getAttribute('data-preview');
187    const maxFiles = parseInt($inputFile.getAttribute('data-max-files') || 99);
188    source = source ? source : ($inputFile.getAttribute('data-source') || null);
189
190    const uploadedFileCount = document.querySelectorAll(`#${preview} [data-uuid]`).length;
191    if ($inputFile.files.length + uploadedFileCount > maxFiles) {
192        alert(`최대 ${maxFiles}개까지 업로드 가능합니다.`);
193        setTimeout(() => {
194            $inputFile.value = null;
195        }, 100);
196        return Promise.reject();
197    }
198
199    const formData = new FormData();
200    if (source != null) {
201        formData.append('source', source);
202        Array.prototype.forEach.call($inputFile.files, file => formData.append('files', file));
203    }
204
205    return fetch('/api/v1/attachment', {
206        method: 'POST',
207        body: formData
208    })
209        .then(handleFetchResponse)
210        .then(result => {
211            return {
212                ...result.data,
213                options: {
214                    inputName, preview
215                }
216            };
217        })
218        .catch(handleFetchError)
219        .finally(() => {
220            setTimeout(() => {
221                $inputFile.value = null;
222            }, 100);
223        });
224}
225
226/** 파일 삭제 */
227function deleteFile(uuid, isActual = false) {
228    if (confirm('파일을 삭제하시겠습니까?') === false)
229        return;
230
231    const $elements = document.querySelectorAll(`[data-uuid="${uuid}"]`);
232    const removeElements = () => {
233        $elements.forEach($element => {
234            const label = $element.closest('.field')?.querySelector('.file-name');
235            if (label !== undefined) label.textContent = '파일을 선택해 주세요.';
236            $element.remove();
237        });
238    }
239
240    if (isActual === true) {
241        return fetch(`/api/v1/attachment/${uuid}`, {
242            method: 'DELETE'
243        })
244            .then(handleFetchResponse)
245            .then(result => {
246                removeElements();
247                return true;
248            })
249            .catch(handleFetchError);
250    } else {
251        removeElements();
252        return Promise.resolve(true);
253    }
254}
255
256/** 템플릿 문자열 치환 */
257function replaceTemplate(template, data) {
258    const templateString = template.innerHTML;
259    const pattern = /{{\s*(\w+)\s*}}/g;
260
261    let html = templateString.replace(pattern, (match, key) => data[key] || '');
262    return html.replace("src=\"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\" data-", "");
263}
264
265document.addEventListener('DOMContentLoaded', () => {
266    const telephoneNumberElements = document.querySelectorAll('[data-telephone]');
267    telephoneNumberElements.forEach((element) => {
268        if (typeof element.value === 'string') {
269            element.value = Utils.telephoneFormat(element.value);
270            element.addEventListener('input', (event) => {
271                event.target.value = Utils.telephoneFormat(event.target.value);
272            });
273        }
274        else {
275            element.textContent = Utils.telephoneFormat(element.dataset.telephone);
276        }
277    });
278
279    document.querySelectorAll('.datepicker-single').forEach(($container) => {
280        $container.querySelectorAll('input[type="text"]').forEach(($input) => {
281            new Datepicker($input, {
282                autohide: true,
283                language: 'ko',
284                todayHighlight: true,
285                clearButton: true,
286                todayButton: true,
287                todayButtonMode: 1, // select
288            });
289            $input.autocomplete = 'off';
290        });
291    });
292    document.querySelectorAll('.datepicker-range').forEach(($container) => {
293        new DateRangePicker($container, {
294            autohide: true,
295            language: 'ko',
296            todayHighlight: true,
297            clearButton: true,
298            todayButton: true,
299            todayButtonMode: 1, // select
300            allowOneSidedRange: true,
301        });
302        $container.rangepicker.inputs.forEach(($element) => $element.autocomplete = 'off');
303    });
304});

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.