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.