PageSourceSearch

https://creation.kr/js/post_comment.js?1790771010

js creation.kr collected 2026-10-01 15:35:05 UTC 42,877 bytes, 1,241 lines download raw bytes

1
2var POST_COMMENT = function(){
3
4	var post_code,total_count,comment_count_obj,comment_form,comment_body, comment_area,child_comment_code,use_sub_secret_comment;
5	var $comment_container;
6	var comment_img_box;
7
8	var main_comment_image, comment_image, sub_comment_image , use_secret_comment;
9
10	var commentInit = function(code){
11		post_code = code;
12		comment_count_obj = $('#comment_count');
13		total_count = Math.round(comment_count_obj.text());
14		$comment_container = $('#comment_container');
15		comment_form = $('#comment_form');
16		comment_body = $('#comment_body');
17		comment_area = $('#comment_area');
18		comment_img_box = $('#comment_img_box');
19		use_secret_comment = $('#use_secret_comment');
20		captcha_answer = $('#captcha_answer');
21		captcha_key = $('#captcha_key');
22		captcha_img = $('#captcha_img');
23
24		main_comment_image = [];
25		comment_image = {};
26		sub_comment_image = {};
27
28		$secret = comment_form.find('._secret');
29		$secret.on('click', function(){
30			if($secret.hasClass('active')){
31				$secret.removeClass('active');
32				$secret.val('N');
33				use_secret_comment.val('N');
34			}else{
35				$secret.addClass('active');
36				$secret.val('Y');
37				use_secret_comment.val('Y');
38			}
39		});
40
41
42		/*
43		comment_area.off('input keyup  paste change','._comment_textarea')
44			.on('input keyup  paste change','._comment_textarea', function (e) {
45				var input = $(this);
46				setTimeout(function(){
47					input.limitLength({max_byte:3000});
48				}, 0);
49		});
50
51		comment_area.off('keydown.enter','._comment_textarea')
52			.on('keydown.enter','._comment_textarea', function (e) {
53				if (e.keyCode == 13) {
54					var target = $('#'+$(this).data('action'));
55					target.click();
56					e.preventDefault();
57				}
58			});
59			*/
60
61		comment_area.off('input keyup keydown paste change','._comment_nick')
62			.on('input keyup keydown paste change','._comment_nick', function () {
63				var input = $(this);
64				setTimeout(function(){
65					input.limitLength({max_byte:30});
66				}, 0);
67			});
68
69		/*
70		comment_area.off('input keyup keydown paste change','._comment_password')
71			.on('input keyup keydown paste change','._comment_password', function () {
72				var input = $(this);
73				setTimeout(function(){
74					input.limitLength({max_byte:30});
75				}, 0);
76			});
77			*/
78
79
80		$("#comment_image_upload_btn").fileupload({
81			url: '/ajax/comment_image_upload.cm',
82			dataType: 'json',
83			singleFileUploads:false,
84			limitMultiFileUploads: 5,
85			dropZone: null,
86			maxFileSize : 20000000, //20mb
87			limitMultiFileUploadSize : 110000000, //110 mb
88			start: function (e, data) {},
89			progress: function (e, data) {},
90			done: function (e, data) {
91				$("#comment_image_box").show();
92				$.each(data.result.comment_images,function(i,file){
93					var url = CDN_UPLOAD_URL+file.url;
94					var html ='<span class="file-add"><input type="hidden" name="tmp_img[]" value="'+file.tmp_idx+'"><div class="file-add-bg" style="background: url('+url+') no-repeat center center;"></div><em class="del" onclick="POST_COMMENT.removeCommentImg($(this))"></em></span>';
95					$("#comment_image_box").append(html);
96
97				});
98			},
99			fail: function (e, data) {
100			}
101		});
102
103		autosize(comment_area.find('.textarea_block textarea'));
104
105		//$("#comment_image_box").sortable({
106		//	placeholder: 'ui-state-highlight'
107		//});
108	};
109
110	var removeCommentImg = function(obj){
111		var box_obj = obj.parent().parent();
112		obj.parent().remove();
113		if(box_obj.find('.file-add').length == 0)box_obj.hide();
114	};
115
116	var updateAttachToolPosition = function(form,editor){
117		var $tool = form.find('._attach_tool');
118		var scroll_top = editor.$window.scrollTop();
119		var el_offset = editor.$el.offset();
120
121		var boundingRect;
122
123		var range = editor.selection.ranges(0);
124		if (range && range.collapsed && editor.selection.inEditor()) {
125			var remove = false;
126
127			editor.markers.remove();
128			if (editor.$el.find('.fr-marker').length == 0) {
129				editor.markers.insert();
130				remove = true;
131			}
132
133			var $marker = editor.$el.find('.fr-marker:first');
134			$marker.css('line-height','inherit');
135			$marker.css('display', 'inline');
136			var offset = $marker.offset();
137			boundingRect = {};
138			boundingRect.left = offset.left;
139			boundingRect.width = 0;
140			boundingRect.height = parseInt($marker.css('line-height'), 10) || 20;
141
142			var marker_tag_name = $marker.parent().prop("tagName");
143			marker_tag_name = marker_tag_name.toLowerCase();
144			if($.inArray(marker_tag_name, ['p','span','h1','h2','h3','h4','h5','h6','h7','h8','strong','b','font','a','i'])) {
145				var outer_h = Math.round($marker.parent().outerHeight());
146				boundingRect.height = outer_h;
147			}
148			boundingRect.top = offset.top - $(editor.original_window).scrollTop();
149			boundingRect.right = 1;
150			boundingRect.bottom = 1;
151			boundingRect.ok = true;
152			$marker.css('display', 'none');
153
154			if (remove) editor.markers.remove();
155		}
156		else if (range) {
157			boundingRect = range.getBoundingClientRect();
158		}
159
160		var attach_tool_left = el_offset.left-boundingRect.left;
161		$tool[attach_tool_left ==0?'show':'hide']();
162		var attach_tool_top = scroll_top+boundingRect.top-el_offset.top + (boundingRect.height/2) - ($tool.outerHeight()/2);
163		$tool.css('top',attach_tool_top);
164	};
165
166	var hideAttachTool = function(obj){
167		obj.find('._attach_tool').removeClass('open');
168	};
169
170
171	var commentIncreaseTotalCount = function(){
172		total_count++;
173		comment_count_obj.text(total_count);
174	};
175
176	var commentDecreaseTotalCount = function(decrease_count = 1){
177		total_count -= decrease_count;
178		comment_count_obj.text(total_count);
179	};
180
181	var is_writing = false;
182
183	/**
184	 * 댓글 등록 **성공** 처리. 등록 응답에만 쓴다 — 새로고침은 이 처리를 타지 않는다
185	 * (새로고침이 저장을 부르면 화면이 "저장된 것처럼" 움직여 그대로 오해가 된다).
186	 */
187	var applyCommentAddSuccess = function(result){
188		comment_body.val('');
189		$("#comment_image_box").empty().hide();
190		commentFormHide();
191		commentIncreaseTotalCount();
192		if(result.comment_sorting_type == 'forward_new_comment'){
193			$comment_container.prepend(result.html);
194			moveToCommentListTop();
195		}else {
196			$comment_container.find('div.comment_list div.comment:last').length === 0 ? $comment_container.append(result.html) : $comment_container.find('div.comment_list div.comment:last').after(result.html);
197		}
198		autosize.update($('.comment_textarea').find('#comment_body'));
199
200		// 요구받았던 캡차는 한 번 쓰면 끝난다(키도 서버에서 소비됐다) — 블록을 걷어낸다.
201		captchaChallengeBlock(comment_form).remove();
202	};
203
204	var commentAdd = function(){
205		if(!is_writing){
206			var data = comment_form.serializeObject();
207
208			if (data.captcha_key) {
209				if (data.body.length > 0 && data.captcha_answer.length === 0) {
210					refreshCaptchaForSubmit('comment');
211					alert(getLocalizeString("설명_보안문자입력", "", "보안 문자를 입력해 주세요."));
212					return;
213				}
214			}
215
216			var menu_url = window.location.pathname;
217			data.menu_url = menu_url;
218			$.ajax({
219				type:'post',
220				data:data,
221				url:'/ajax/post_comment_add.cm',
222				dataType:'json',
223				success:function(result){
224          tokenRefresh(comment_form, result.refresh_token, result.refresh_token_key);
225					if(result.msg=='SUCCESS') {
226						applyCommentAddSuccess(result);
227					}else {
228						// 애매한 스팸 점수면 서버가 문자 캡차를 요구한다 — 문구와 함께 캡차를 띄운다.
229						if (result.captcha_required) applyCaptchaChallenge(result, 'comment');
230						alert(result.msg);
231					}
232
233					is_writing = false;
234				},
235				complete:function(){
236					if (data.captcha_key) {
237						refreshCaptchaAfterSubmit('comment');
238					}
239				}
240			});
241			is_writing = true;
242		}
243	};
244
245	var refreshCaptcha = function(form_type = 'comment', code){
246		var sub_form_captcha_answer = $('#sub_form_captcha_answer_'+code);
247		var sub_form_captcha_key = $('#sub_form_captcha_key_'+code);
248		var sub_form_captcha_img = $('#sub_form_captcha_img_'+code);
249
250		$.ajax({
251			type:'post',
252			data:{
253				'captcha_key': form_type == 'comment' ? captcha_key.val() : sub_form_captcha_key.val(),
254				'target': 'comment',
255			},
256			url:'/ajax/refresh_captcha.cm',
257			dataType:'json',
258			success:function(result){
259				if (result.msg == 'SUCCESS') {
260					if (form_type == 'comment') {
261						captcha_answer.val('');
262						captcha_img.attr('src', result.captcha_img);
263						captcha_key.val(result.key);
264					} else if (form_type == 'sub_form') {
265						sub_form_captcha_answer.val('');
266						sub_form_captcha_img.attr('src', result.captcha_img);
267						sub_form_captcha_key.val(result.key);
268					}
269				} else {
270					alert(result.msg);
271				}
272			}
273		});
274	};
275
276	// ── 요구형 문자 캡차 — 서버가 애매한 스팸 점수(0.50 이상·임계 미만)에서 요구한다 ──────
277	// 사이트가 캡차를 켠 경우의 블록(.captcha_block·.sub_form_captcha_block)은 **서버가** 그려서
278	// 항상 폼 안에 있다. 여기서 만드는 블록은 요구받았을 때만 생기고, 입력칸 이름은 같다
279	// (captcha_key·captcha_answer) — 그래서 폼 직렬화에 그대로 실려 서버가 검증한다.
280	var CAPTCHA_CHALLENGE_ATTR = 'data-fo-captcha-challenge';
281
282	// 사이트 캡차 화면(site_ui.cls)이 쓰는 새로고침 아이콘과 같은 모양이다.
283	var CAPTCHA_CHALLENGE_REFRESH_ICON = '<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">'
284		+ '<path d="M1 0.5H27C27.2761 0.5 27.5 0.723857 27.5 1V27C27.5 27.2761 27.2761 27.5 27 27.5H1C0.723858 27.5 0.5 27.2761 0.5 27V1C0.5 0.723858 0.723857 0.5 1 0.5Z" fill="white"/>'
285		+ '<path d="M1 0.5H27C27.2761 0.5 27.5 0.723857 27.5 1V27C27.5 27.2761 27.2761 27.5 27 27.5H1C0.723858 27.5 0.5 27.2761 0.5 27V1C0.5 0.723858 0.723857 0.5 1 0.5Z" stroke="#BCC0C6"/>'
286		+ '<path d="M15.3333 7.3335C15.3333 7.3335 15.8995 7.41438 18.2426 9.75752C20.5858 12.1007 20.5858 15.8997 18.2426 18.2428C17.4125 19.073 16.3995 19.609 15.3333 19.8509M15.3333 7.3335L19.3333 7.3335M15.3333 7.3335L15.3333 11.3335M12.6667 20.6667C12.6667 20.6667 12.1005 20.5858 9.75736 18.2427C7.41421 15.8995 7.41421 12.1005 9.75736 9.75739C10.5875 8.92721 11.6005 8.39116 12.6667 8.14925M12.6667 20.6667L8.66667 20.6668M12.6667 20.6667L12.6667 16.6668" stroke="#4B515B" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>'
287		+ '</svg>';
288
289	// 그 폼의 요구 블록(없으면 빈 jQuery). 폼마다 하나만 만든다.
290	var captchaChallengeBlock = function(form){
291		return form.find('[' + CAPTCHA_CHALLENGE_ATTR + ']');
292	};
293
294	// 폼 고르기 — 일반 댓글은 #comment_form, 대댓글은 그 댓글의 답글 폼이다.
295	var captchaChallengeForm = function(form_type, code){
296		if (form_type == 'sub_form' && code) return $('#' + code).find('._add_sub_form_' + code);
297
298		return comment_form;
299	};
300
301	var createCaptchaChallengeBlock = function(){
302		var block = $('<div class="captcha_block" ' + CAPTCHA_CHALLENGE_ATTR + '="1" style="display: none;"></div>');
303		var row = $('<div style="display: flex; align-items: center;"></div>');
304		var holder = $('<div style="display: inline-flex; align-items: center; gap: 8px; margin-right: 16px;"></div>');
305		var refresh = $('<div class="_captcha_challenge_refresh" style="cursor: pointer; width: 28px; height: 28px;"></div>');
306
307		refresh.html(CAPTCHA_CHALLENGE_REFRESH_ICON);
308		holder.append($('<img width="113" height="30" alt="" />')).append(refresh);
309		row.append(holder)
310			.append('<input type="hidden" name="captcha_key" />')
311			.append('<input type="text" name="captcha_answer" class="capcha_input" />');
312		block.append(row).append('<span class="captcha_description"></span>');
313
314		// 문구는 기존 LOCALIZE 키를 그대로 쓴다(새 키를 만들지 않는다). 값은 **속성·텍스트로**
315		// 넣는다 — 문자열 조합으로 HTML 에 끼우면 현지화 문구가 마크업을 흔들 수 있다.
316		block.find('input[name="captcha_answer"]').attr('placeholder', getLocalizeString('설명_보안문자입력', '', '보안 문자를 입력해 주세요.'));
317		block.find('.captcha_description').text(getLocalizeString('설명_공백없이입력대소문자구분', '', '공백 없이 입력해 주세요. 대소문자를 구분합니다.'));
318
319		return block;
320	};
321
322	// 서버 요구 응답(captcha_required·captcha_img·key)을 그 폼에 반영한다.
323	var applyCaptchaChallenge = function(result, form_type, code){
324		var form = captchaChallengeForm(form_type, code);
325
326		// 그릴 수 없는 응답이면 문구만 남는다(등록을 막지 않는다 — 서버가 저장 여부를 정한다).
327		if (form.length === 0 || !result.captcha_img || !result.key) return;
328
329		var block = captchaChallengeBlock(form);
330
331		if (block.length === 0) {
332			block = createCaptchaChallengeBlock();
333			block.find('._captcha_challenge_refresh').on('click', function(){
334				refreshCaptchaChallenge(form_type, code);
335			});
336			form.append(block);
337		}
338
339		block.find('img').attr('src', result.captcha_img);
340		block.find('input[name="captcha_key"]').val(result.key);
341		block.find('input[name="captcha_answer"]').val('');
342		block.css('display', 'flex');
343	};
344
345	// 새로고침 — **발급 전용 엔드포인트**로 새 이미지·키만 받는다.
346	//
347	// 댓글 등록 경로(post_comment_add.cm)를 다시 태우면 안 된다: 새로고침이 판정·게이트를 다시
348	// 태우고, 그 사이 판정이 통과하면(캐시 만료·판정 실패) **실제로 댓글이 저장된다** — 사용자는
349	// 캡차만 새로 받으려 했는데 글이 올라간다. 그래서 폼을 직렬화해 보내지 않는다(본문·이미지가
350	// 실려 나가면 그 자체가 저장 요청의 재료다). 서버는 이 키의 결속 표식을 선점(DEL)한 요청에만
351	// 새 캡차를 발급하므로, 이미 쓴 키로는 발급되지 않고 문구만 돌아온다.
352	var refreshCaptchaChallenge = function(form_type, code){
353		var form = captchaChallengeForm(form_type, code);
354		var block = captchaChallengeBlock(form);
355		if (form.length === 0 || block.length === 0) return;
356
357		$.ajax({
358			type:'post',
359			data:{
360				'captcha_key': block.find('input[name="captcha_key"]').val(),
361				'target': 'comment',
362				'band_captcha': '1'
363			},
364			url:'/ajax/refresh_captcha.cm',
365			dataType:'json',
366			success:function(result){
367				if (result.msg == 'SUCCESS') {
368					// 새 이미지·새 키를 그대로 반영한다(입력칸은 비운다).
369					applyCaptchaChallenge(result, form_type, code);
370				} else {
371					alert(result.msg);
372				}
373			}
374		});
375	};
376
377	// 캡차를 다시 그리는 자리 — 요구형 캡차가 떠 있으면 그것을, 아니면 사이트 캡차를 갱신한다.
378	var refreshCaptchaForSubmit = function(form_type, code){
379		if (captchaChallengeBlock(captchaChallengeForm(form_type, code)).length > 0) {
380			refreshCaptchaChallenge(form_type, code);
381			return;
382		}
383
384		if (form_type == 'sub_form') refreshCaptcha('sub_form', code);
385		else refreshCaptcha();
386	};
387
388	/**
389	 * 등록 **시도 뒤**의 갱신 — master 와 같이 사이트 캡차만 새로 받는다.
390	 *
391	 *  - 요구형 캡차가 떠 있으면 아무것도 하지 않는다: 등록 실패 응답에 서버가 **이미 새 캡차를
392	 *    담아 줬고**(그 키의 결속 표식도 갓 발급됐다), 여기서 다시 부르면 표식만 소모된다.
393	 *  - 사이트 캡차가 없는 폼도 건드리지 않는다: 보낼 키가 없어 서버가 오류 문구를 돌려주고,
394	 *    그 문구가 **등록에 성공한 직후에** alert 로 뜬다.
395	 */
396	var refreshCaptchaAfterSubmit = function(form_type, code){
397		if (captchaChallengeBlock(captchaChallengeForm(form_type, code)).length > 0) return;
398
399		if (form_type == 'sub_form') {
400			if ($('#sub_form_captcha_key_'+code).length > 0) refreshCaptcha('sub_form', code);
401			return;
402		}
403
404		if (captcha_key.length > 0) refreshCaptcha();
405	};
406
407	var commentFormHide = function(){
408		$comment_container = $('#comment_container');
409
410		$comment_container.find('._comment_area').show();
411		$comment_container.find('._sub_comment_wrap').show();
412		$comment_container.find('._sub_form').hide();
413		$comment_container.find('._comment_edit_form').hide();
414		$comment_container.find('.write').show();
415	};
416
417	var commentShowEdit = function(code, interlock_type){
418		var obj = $('#'+code);
419		var comment_edit_body = obj.find('._comment_edit_body_'+code);
420		var comment_wrap = obj.find('._comment_wrap_'+code);
421
422		comment_image[code] = [];
423		comment_edit_body.data('org_body',comment_edit_body.val());
424		commentFormHide();
425		comment_wrap.find('._comment_area').hide();
426		comment_wrap.find('.write').hide();
427
428		$.ajax({
429			type:'post',
430			data: {'code' : code, 'board_type': interlock_type},
431			url:'/ajax/append_post_comment_html.cm',
432			dataType:'json',
433			success:function(res){
434				obj.find('._comment_edit_form_'+code).html(res.html);
435				autosize.update(obj.find('._comment_edit_body'));
436				if(comment_wrap.find("._comment_body img").length>0) $("#comment_image_modify_box_"+code).show();
437				$("#comment_image_upload_modify_btn_"+code).fileupload({
438					url: '/ajax/comment_image_upload.cm',
439					dataType: 'json',
440					singleFileUploads:false,
441					limitMultiFileUploads: 5,
442					dropZone: null,
443					maxFileSize : 20000000, //20mb
444					limitMultiFileUploadSize : 110000000, //110 mb
445					start: function (e, data) {},
446					progress: function (e, data) {},
447					done: function (e, data) {
448						$("#comment_image_modify_box_"+code).show();
449						$.each(data.result.comment_images,function(i,file){
450							var url = CDN_UPLOAD_URL+file.url;
451							var html ='<span class="file-add"><input type="hidden" name="tmp_img[]" value="'+file.tmp_idx+'"><div class="file-add-bg" style="background: url('+url+') no-repeat center center;"></div><em class="del" onclick="POST_COMMENT.removeCommentImg($(this))"></em></span>';
452							$("#comment_image_modify_box_"+code).append(html);
453
454						});
455					},
456					fail: function (e, data) {
457					}
458				});
459				autosize(comment_area.find('.textarea_block textarea'));
460			}
461		});
462
463		obj.find('._comment_edit_form_'+code).show();
464
465	};
466
467	var commentEdit = function(code){
468		var obj = $('#'+code);
469		var comment_edit_body = obj.find('._comment_edit_body_'+code);
470
471		var form = obj.find('._comment_edit_form_'+code+' ._edit_form');
472
473		var comment_body = obj.find('._comment_wrap_'+code+' ._comment_body_'+code);
474
475
476		var data = form.serializeObject();
477
478		var new_img = form.find("input[name='tmp_img[]']");
479		var org_img = form.find("input[name='org_img[]']");
480		var img_old_cnt = form.find("input[name='org_image_old_cnt']");
481		var secret_comment = form.find("input[name='secret_comment']");
482
483		if((comment_edit_body.val() == comment_edit_body.data('org_body')) && (new_img.length == 0) && (img_old_cnt.val() == org_img.length) && secret_comment.val() == secret_comment.attr('orig')) {
484			commentFormHide();
485			return;
486		}
487		$.ajax({
488			type:'post',
489			data:data,
490			url:'/ajax/post_comment_add.cm',
491			dataType:'json',
492			success:function(result){
493        tokenRefresh(form, result.refresh_token, result.refresh_token_key);
494				if(result.msg=='SUCCESS') {
495					comment_edit_body.data('org_body', result.data.body);
496					comment_body.html('<div>'+result.data.body+'</div>');
497					comment_body.append(result.data.img_html);
498					switch(secret_comment.val()){
499						case 'Y':
500							$('#icon_' + code).show();
501							break;
502						case 'N':
503							$('#icon_' + code).hide();
504							break;
505					}
506					commentFormHide();
507					commentDestroyEdit(code);
508				}else
509					alert(result.msg);
510			}
511		});
512
513	};
514
515	var commentEditMap = function(code){
516		var obj = $('#'+code);
517		var comment_edit_body = obj.find('._comment_edit_body_'+code);
518
519		var form = obj.find('._comment_edit_form_'+code+' ._edit_form');
520
521		var comment_body = obj.find('._comment_wrap_'+code+' ._comment_body_'+code);
522
523
524		var data = form.serializeObject();
525
526		var new_img = form.find("input[name='tmp_img[]']");
527		var org_img = form.find("input[name='org_img[]']");
528		var img_old_cnt = form.find("input[name='org_image_old_cnt']");
529
530		if((comment_edit_body.val() == comment_edit_body.data('org_body')) && (new_img.length == 0) && (img_old_cnt.val() == org_img.length)) {
531			commentFormHide();
532			return;
533		}
534		$.ajax({
535			type:'post',
536			data:data,
537			url:'/ajax/map_comment_add.cm',
538			dataType:'json',
539			success:function(result){
540				if(result.msg=='SUCCESS') {
541					comment_edit_body.data('org_body', result.data.body);
542					comment_body.html(result.data.body);
543					comment_body.append(result.data.img_html);
544					commentFormHide();
545					commentDestroyEdit(code);
546				}else
547					alert(result.msg);
548			}
549		});
550	};
551
552	var commentDestroyEdit = function(code){
553		var obj = $('#'+code);
554		comment_image[code] = [];
555	};
556
557	var commentDestroyAddEditor = function(code){
558		var obj = $('._add_sub_form_'+code);
559		comment_image[code] = [];
560		var comment_edit_body = obj.find('._comment_add_body_'+code);
561		comment_edit_body.val('');
562	};
563
564	var commentCancelEdit = function(code){
565		var obj = $('#'+code);
566		var comment_edit_body = obj.find('._comment_edit_body_'+code);
567		comment_edit_body.val(comment_edit_body.data('org_body'));
568		commentFormHide();
569		commentDestroyEdit(code);
570	};
571
572	var commentShowSubForm = function(code){
573		var obj = $('#'+code);
574		var sub_form = obj.find('._sub_form_'+code);
575
576		var use_sub_secret_comment = sub_form.find('#use_sub_secret_comment');
577		$sub_secret = sub_form.find('._secret');
578		$sub_secret.on('click', function(){
579			if($sub_secret.hasClass('active')){
580				$sub_secret.removeClass('active');
581				$sub_secret.val('N');
582				use_sub_secret_comment.val('N');
583			}else{
584				$sub_secret.addClass('active');
585				$sub_secret.val('Y');
586				use_sub_secret_comment.val('Y');
587			}
588		});
589
590		commentFormHide();
591		if(sub_form.data('show')=='Y'){
592			sub_form.data('show', 'N');
593			$('body').off('mouseup.sub_comment');
594		}else {
595			sub_form.data('show', 'Y');
596			obj.find('._sub_form_' + code).show();
597			sub_comment_image[code] = [];
598			var comment_add_body = obj.find('._comment_add_body_' + code);
599
600			$('body').off('mouseup.sub_comment')
601				.on('mouseup.sub_comment', function (e) {
602					var $c_target = $(e.target);
603					var $s_form = $c_target.closest('._sub_form_' + code+', ._show_sub_form_btn_'+code);
604					if ($s_form.length == 0) {
605
606						var text = comment_add_body.val();
607						sub_form.data('show', 'N');
608						if(text == '') {
609							$('body').off('mouseup.sub_comment');
610							commentFormHide();
611						}
612					}
613				});
614		}
615		$("#comment_image_upload_btn_"+code).fileupload({
616			url: '/ajax/comment_image_upload.cm',
617			dataType: 'json',
618			singleFileUploads:false,
619			limitMultiFileUploads: 5,
620			dropZone: null,
621			maxFileSize : 20000000, //20mb
622			limitMultiFileUploadSize : 110000000, //110 mb
623			start: function (e, data) {},
624			progress: function (e, data) {},
625			done: function (e, data) {
626				$("#comment_image_box_"+code).show();
627				$.each(data.result.comment_images,function(i,file){
628					var url = CDN_UPLOAD_URL+file.url;
629					var html ='<span class="file-add"><input type="hidden" name="tmp_img[]" value="'+file.tmp_idx+'"><div class="file-add-bg" style="background: url('+url+') no-repeat center center;"></div><em class="del" onclick="POST_COMMENT.removeCommentImg($(this))"></em></span>';
630					$("#comment_image_box_"+code).append(html);
631
632				});
633			},
634			fail: function (e, data) {
635			}
636		});
637	};
638
639	/**
640	 * 대댓글 등록 성공 처리. 위 댓글 등록과 같은 이유로 분리한다(캡차 새로고침도 쓴다).
641	 */
642	var applyCommentAddSubSuccess = function(result, code){
643		var obj = $('#'+code);
644		var comment_sub_body = obj.find('._comment_add_body_'+code);
645		var $image_box = obj.find('#comment_image_box_'+code);
646
647		comment_sub_body.val('');
648		commentFormHide();
649		commentAddSubHTML(result.data.parent_code !='' ? result.data.parent_code : result.data.code,result.html);
650		commentDestroyAddEditor(code);
651		//self.location.hash=result.data.code;
652
653		$image_box.empty();
654
655		// 요구받았던 캡차는 한 번 쓰면 끝난다(키도 서버에서 소비됐다) — 블록을 걷어낸다.
656		captchaChallengeBlock(obj.find('._add_sub_form_'+code)).remove();
657	};
658
659	var commentAddSub = function(code){
660		var obj = $('#'+code);
661		var comment_sub_body = obj.find('._comment_add_body_'+code);
662		var form = obj.find('._add_sub_form_'+code);
663		var $image_box = obj.find('#comment_image_box_'+code);
664		var data = form.serializeObject();
665
666		var tmp_img = {'temp_images':sub_comment_image[code]};
667		data = $.extend(data,tmp_img);
668
669		if (data.captcha_key) {
670			if (data.body.length > 0 && data.captcha_answer.length === 0) {
671				refreshCaptchaForSubmit('sub_form', code);
672				alert(getLocalizeString('설명_보안문자입력','','보안 문자를 입력해 주세요.'));
673				return;
674			}
675		}
676
677		$.ajax({
678			type:'post',
679			data:data,
680			url:'/ajax/post_comment_add.cm',
681			dataType:'json',
682			success:function(result){
683				tokenRefresh(form, result.refresh_token, result.refresh_token_key);
684
685				if(result.msg=='SUCCESS') {
686					applyCommentAddSubSuccess(result, code);
687				} else {
688					// 애매한 스팸 점수면 서버가 문자 캡차를 요구한다 — 문구와 함께 캡차를 띄운다.
689					if (result.captcha_required) applyCaptchaChallenge(result, 'sub_form', code);
690					alert(result.msg);
691				}
692			},
693			complete:function(){
694				if (data.captcha_key) {
695					refreshCaptchaAfterSubmit('sub_form', code);
696				}
697			}
698		});
699	};
700
701  var tokenRefresh = function(form, refresh_token, refresh_token_key){
702    form.find('input[name="comment_token"]').val(refresh_token ? refresh_token : "");
703    form.find('input[name="comment_token_key"]').val(refresh_token_key ? refresh_token_key : "");
704  };
705  
706	var commentMapAddSub = function(code){
707		var obj = $('#'+code);
708		var comment_sub_body = obj.find('._comment_add_body_'+code);
709		var form = obj.find('._add_sub_form_'+code);
710		var data = form.serializeObject();
711
712		var tmp_img = {'temp_images':sub_comment_image[code]};
713		data = $.extend(data,tmp_img);
714
715		$.ajax({
716			type:'post',
717			data:data,
718			url:'/ajax/map_comment_add.cm',
719			dataType:'json',
720			success:function(result){
721				if(result.msg=='SUCCESS') {
722					comment_sub_body.val('');
723					commentFormHide();
724					if(result.map_listing == 'map'){
725						var map_sub_comment_count = 0;
726						map_sub_comment_count = Math.round($('#list_'+result.list_idx).find('#comment_count').text());
727						map_sub_comment_count++;
728						$('#list_'+result.list_idx).find('#comment_count').text(map_sub_comment_count);
729						$('#comment_area').find('#comment_count').text(map_sub_comment_count);
730						$('#list_pop_'+result.list_idx).find('#comment_count').text(map_sub_comment_count);
731						var sub_code = result.data.parent_code !='' ? result.data.parent_code : result.data.code;
732						var comment_sub_list = $('#'+sub_code).find('._comment_sub_list');
733						comment_sub_list.append(result.html);
734						commentIncreaseTotalCount();
735					}else{
736						commentAddSubHTML(result.data.parent_code !='' ? result.data.parent_code : result.data.code,result.html);
737					}
738					commentDestroyAddEditor(code);
739					//self.location.hash=result.data.code;
740				}else
741					alert(result.msg);
742			}
743		});
744	};
745
746	var commentShowSubEdit = function(code){
747		var obj = $('#'+code);
748		var comment_edit_body = obj.find('._comment_sub_edit_body');
749		comment_edit_body.data('org_body',comment_edit_body.val());
750		comment_edit_body.focus();
751		commentFormHide();
752		obj.find('._comment_sub_wrap').hide();
753		obj.find('._comment_sub_edit_form').show();
754
755		$("#comment_image_upload_modify_btn_"+code).fileupload({
756			url: '/ajax/comment_image_upload.cm',
757			dataType: 'json',
758			singleFileUploads:false,
759			limitMultiFileUploads: 5,
760			dropZone: null,
761			maxFileSize : 20000000, //20mb
762			limitMultiFileUploadSize : 110000000, //110 mb
763			start: function (e, data) {},
764			progress: function (e, data) {},
765			done: function (e, data) {
766				$("#comment_image_modify_box_"+code).show();
767				$.each(data.result.comment_images,function(i,file){
768					var url = CDN_UPLOAD_URL+file.url;
769					var html ='<span class="file-add"><input type="hidden" name="tmp_img[]" value="'+file.tmp_idx+'"><div class="file-add-bg" style="background: url('+url+') no-repeat center center;"></div><em class="del" onclick="POST_COMMENT.removeCommentImg($(this))"></em></span>';
770					$("#comment_image_modify_box_"+code).append(html);
771
772				});
773			},
774			fail: function (e, data) {
775			}
776		});
777
778	};
779
780	var commentCancelSubEdit = function(code){
781		var obj = $('#'+code);
782		var comment_edit_body = obj.find('._comment_sub_edit_body');
783		comment_edit_body.val(comment_edit_body.data('org_body'));
784		commentFormHide();
785
786	};
787
788	var commentSubEdit = function(code){
789		var obj = $('#'+code);
790		var comment_edit_body = obj.find('._comment_sub_edit_body');
791		var comment_body = obj.find('._comment_sub_body');
792		var form = obj.find('._sub_edit_form');
793		var data = form.serializeObject();
794		if(comment_edit_body.val() == comment_edit_body.data('org_body')) {
795			commentFormHide();
796			return;
797		}
798		$.ajax({
799			type:'post',
800			data:data,
801			url:'/ajax/post_comment_add.cm',
802			dataType:'json',
803			success:function(result){
804				if(result.msg=='SUCCESS') {
805					comment_edit_body.data('org_body', result.data.body);
806					comment_body.html($.nl2br(result.data.body));
807					commentFormHide();
808				}else
809					alert(result.msg);
810			}
811		});
812
813	};
814
815	var commentAddHTML = function(html){
816		commentIncreaseTotalCount();
817		comment_container.append(html);
818	};
819
820
821	var commentConfirmShow = function(event, code , type, interlock_type, use_interlock_board){
822		$post_secret_password = $('#post_secret_password');
823
824		if($post_secret_password.length==0){
825			$post_secret_password = $('<div class="remove-pop" id="post_secret_password" style="position:absolute; left:0;top:0;z-index:99999;"><p>' + LOCALIZE.설명_작성시등록하신비밀번호를입력해주세요() + '</p><div class="input_area"><input type="password" placeholder="' + LOCALIZE.설명_비밀번호() + '"><button class="btn btn-primary _confirm">' + LOCALIZE.버튼_확인닫기() + '</button></div></div>').hide();
826			$('body').append($post_secret_password);
827		}
828			var $post_link = $(event.target);
829
830			var top = $post_link.offset().top;
831			var left = $post_link.offset().left;
832
833			$post_secret_password.css({
834				position : 'absolute',
835				top : top,
836				left : left
837			});
838		$post_secret_password.find('input').val('');
839			$post_secret_password.show();
840			$post_secret_password.off('click','._confirm')
841				.on('click','._confirm',function(){
842					var secret_pass = $post_secret_password.find('input').val();
843					$post_secret_password.hide();
844					switch(type){
845						case 'show' : commentShow(code,secret_pass,interlock_type);
846						break;
847						case 'delete' : commentDelete(code,secret_pass,interlock_type,use_interlock_board);
848						break;
849						case 'edit' :  commentEditShow(code,secret_pass,interlock_type);
850						break;
851					}
852				});
853
854			$('body').off('mousedown.post_secret')
855				.on('mousedown.post_secret',function(e){
856					var $tmp = $(e.target).closest('#post_secret_password');
857					if($tmp.length==0) {
858						$post_secret_password.hide();
859						$('body').off('click.post_secret');
860					}
861				});
862	};
863
864	var commentMapConfirmShow = function(event, code, type, interlock_type){
865		$post_secret_password = $('#post_secret_password');
866		if($post_secret_password.length==0){
867			$post_secret_password = $('<div class="remove-pop" id="post_secret_password" style="position:absolute; left:0;top:0;z-index:99999;"><p>'+LOCALIZE.설명_작성시등록하신비밀번호를입력해주세요()+'</p><div class="input_area"><input type="password" placeholder="'+LOCALIZE.설명_비밀번호()+'"><button class="btn btn-primary _confirm">'+LOCALIZE.버튼_확인닫기()+'</button></div></div>').hide();
868			$('body').append($post_secret_password);
869		}
870		var $post_link = $(event.target);
871
872		var top = $post_link.offset().top;
873		var left = $post_link.offset().left;
874
875		$post_secret_password.css({
876			position : 'absolute',
877			top : top,
878			left : left
879		});
880
881		$post_secret_password.find('input').val('');
882		$post_secret_password.show();
883		$post_secret_password.off('click','._confirm')
884			.on('click','._confirm',function(){
885				var secret_pass = $post_secret_password.find('input').val();
886				$post_secret_password.hide();
887				switch(type){
888					case 'show'   : commentMapShow(code,secret_pass);
889					break;
890					case 'delete' : commentMapDelete(code,secret_pass);
891					break;
892					case 'edit'   : commentEditShow(code,secret_pass,interlock_type);
893					break;
894				}
895			});
896		$('body').off('mousedown.post_secret')
897			.on('mousedown.post_secret',function(e){
898				var $tmp = $(e.target).closest('#post_secret_password');
899				if($tmp.length==0) {
900					$post_secret_password.hide();
901					$('body').off('click.post_secret');
902				}
903			});
904	};
905
906	var commentDelete = function(code,secret_pass,interlock_type,use_interlock_board){
907		var obj = $('#'+code);
908		var comment_wrap = obj.find('._comment_wrap_'+code);
909		if(confirm(LOCALIZE.설명_삭제하시겠습니까())){
910			$.ajax({
911				type:'post',
912				data:{
913					code:code,
914					post_code:post_code,
915					secret_pass:secret_pass,
916					interlock_type:interlock_type,
917					use_interlock_board:use_interlock_board
918				},
919				url:'/ajax/post_comment_delete.cm',
920				dataType:'json',
921				success:function(result){
922					if(result.msg == 'SUCCESS'){
923						if(result.mode == 'delete'){
924							comment_wrap.html(LOCALIZE.설명_삭제된_댓글_입니다());
925						}else {
926							obj.remove();
927						}
928						commentDecreaseTotalCount();
929					}else{
930						alert(result.msg);
931					}
932				}
933			});
934		}
935	};
936
937	var commentShow = function(code,secret_pass,interlock_type){
938		$.ajax({
939			type : 'POST',
940			data : {code : code, post_code : post_code, secret_pass : secret_pass, show: 'Y', board_type:interlock_type},
941			url : ('/ajax/post_comment_show.cm'),
942			dataType : 'json',
943			success : function(result){
944				if(result.msg == 'SUCCESS'){
945					$("._comment_body_"+code).find("#secret_comment_text").text(result.html);
946					$("._comment_body_"+code).find($("img")).attr("src",result.img_url);
947					if(result.isSubComment){
948						for(var i in result.sub_comment){
949							var sub_data = result.sub_comment[i];
950							$('._comment_body_'+sub_data.code).html(sub_data.html);
951						}
952					}
953				}else
954					alert(result.msg);
955			}
956		});
957
958	};
959	var commentEditShow = function(code,secret_pass,interlock_type){
960		$.ajax({
961			type : 'POST',
962			data : {code : code, post_code : post_code, secret_pass : secret_pass, board_type : interlock_type},
963			url : ('/ajax/post_comment_show.cm'),
964			dataType : 'json',
965			success : function(result){
966				if(result.msg == 'SUCCESS'){
967					commentShowEdit(code,interlock_type);
968				}else
969					alert(result.msg);
970			}
971		});
972	};
973
974	var commentMapShow = function(code, secret_pass){
975		$.ajax({
976			type : 'POST',
977			data : {code : code, post_code : post_code, secret_pass : secret_pass},
978			url : ('/ajax/post_map_comment_show.cm'),
979			dataType : 'json',
980			success : function(result){
981				if(result.msg == 'SUCCESS'){
982					$("._comment_body_"+code).find("#secret_comment_text").text(result.html);
983					$("._comment_body_"+code).find($("img")).attr("src",result.img_url);
984					if(result.isSubComment){
985						for(var i in result.sub_comment){
986							var sub_data = result.sub_comment[i];
987							$('._comment_body_'+sub_data.code).html(sub_data.html);
988						}
989					}
990				}else
991					alert(result.msg);
992			}
993		});
994	};
995
996	var commentMapDelete = function(code,secret_pass){
997		var obj = $('#'+code);
998		var comment_wrap = obj.find('._comment_wrap_'+code);
999		if(confirm(LOCALIZE.설명_삭제하시겠습니까())){
1000			$.ajax({
1001				type:'post',
1002				data:{code:code,post_code :post_code,secret_pass:secret_pass},
1003				url:'/ajax/map_comment_delete.cm',
1004				dataType:'json',
1005				success:function(result){
1006					if(result.msg == 'SUCCESS'){
1007						if(result.mode == 'delete'){
1008							comment_wrap.html(LOCALIZE.설명_삭제된_댓글_입니다());
1009						}else {
1010							obj.remove();
1011						}
1012						if(result.map_listing == 'map'){
1013							var map_comment_count = 0;
1014							map_comment_count = Math.round($('#list_'+result.list_idx).find('#comment_count').text());
1015							map_comment_count--;
1016							$('#list_'+result.list_idx).find('#comment_count').text(map_comment_count);
1017							$('#comment_area').find('#comment_count').text(map_comment_count);
1018							$('#list_pop_'+result.list_idx).find('#comment_count').text(map_comment_count);
1019						}else{
1020							commentDecreaseTotalCount(result.decrease_count);
1021						}
1022					}else{
1023						alert(result.msg);
1024					}
1025				}
1026			});
1027		}
1028	};
1029
1030
1031	var commentAddSubHTML = function(code,html){
1032		var obj = $('#'+code);
1033		var comment_sub_list = obj.find('._comment_sub_list');
1034		comment_sub_list.append(html);
1035		commentIncreaseTotalCount();
1036	};
1037
1038	var commentToggleSub = function (parent_comment_id){
1039		var parent_obj = $('#'+parent_comment_id);
1040		var loaded = parent_obj.data('sub_loaded');
1041		var sub_open = parent_obj.data('sub_open');
1042		var sub_comment_wrap = parent_obj.find('._sub_comment_wrap');
1043		var sub_comment_list = parent_obj.find('._sub_comment_list');
1044		var arrow_icon = parent_obj.find('._arrow_icon');
1045		if(typeof loaded == 'undefined' || loaded == false){
1046			$.ajax({
1047				type:'post',
1048				data:{code : parent_comment_id},
1049				url:'/ajax/getChildComment.cm',
1050				dataType:'json',
1051				success:function(data){
1052					var html = $(data.html);
1053					sub_comment_list.append(html);
1054					sub_comment_wrap.show();
1055					arrow_icon.removeClass('zmdi-chevron-down').removeClass('zmdi-chevron-down').removeClass('zmdi-chevron-down');
1056					arrow_icon.addClass('zmdi-chevron-up');
1057					parent_obj.data('sub_loaded', true);
1058					parent_obj.data('sub_open', true);
1059				}
1060			});
1061		}else{
1062			if(typeof sub_open == 'undefined' || sub_open == false){
1063				sub_comment_wrap.show();
1064				arrow_icon.removeClass('zmdi-chevron-down').removeClass('zmdi-chevron-down').removeClass('zmdi-chevron-down');
1065				arrow_icon.addClass('zmdi-chevron-up');
1066				parent_obj.data('sub_loaded', true);
1067			}else{
1068				sub_comment_wrap.hide();
1069				arrow_icon.removeClass('zmdi-chevron-up').removeClass('zmdi-chevron-up').removeClass('zmdi-chevron-up');
1070				arrow_icon.addClass('zmdi-chevron-down');
1071				parent_obj.data('sub_loaded', false);
1072			}
1073		}
1074	};
1075
1076	var commentMapAdd = function(){
1077		var data = comment_form.serializeObject();
1078		$.ajax({
1079			type:'post',
1080			data:data,
1081			url:'/ajax/map_comment_add.cm',
1082			dataType:'json',
1083			success:function(result){
1084				if(result.msg=='SUCCESS') {
1085					comment_body.val('');
1086					$("#comment_image_box").empty().hide();
1087					commentFormHide();
1088					if(result.map_listing == 'map'){
1089						var map_comment_count = 0;
1090						map_comment_count = result.comment_cnt;
1091						$('#list_'+result.list_idx).find('._comment_count').text(map_comment_count);
1092						$('#comment_area').find('#comment_count').text(map_comment_count);
1093						$('#list_pop_'+result.list_idx).find('._comment_count').text(map_comment_count);
1094						if(result.map_comment_sort == 'asc' || !result.map_comment_sort){
1095							$comment_container.find('div.comment_list div.comment:last').length === 0 ? $comment_container.append(result.html) : $comment_container.find('div.comment_list div.comment:last').after(result.html);
1096						}else{
1097							$comment_container.prepend(result.html);
1098							moveToCommentListTop();
1099						}
1100						autosize.update($('.comment_textarea').find('#comment_body'));
1101					}else{
1102						commentAddHTML(result.html);
1103					}
1104				}else
1105					alert(result.msg);
1106			}
1107		});
1108	};
1109
1110	var getCommentListByCurrentPagingNum = function(current_page, is_move_to_comment_list_top){
1111		var is_loaded = false;
1112		if(is_loaded === false){ // 재호출 방지
1113			is_loaded = true;
1114			$.ajax({
1115				type:'post',
1116				data:{
1117					'board_code': comment_form.find("input[name='board_code']").val(),
1118					'post_code': post_code,
1119					'current_page':current_page
1120				},
1121				url:'/ajax/post_comment_paging.cm',
1122				dataType:'json',
1123				success:function(result){
1124					is_loaded = false;
1125					if(result.msg === 'SUCCESS') {
1126						$comment_container.html(result.html);
1127						if(is_move_to_comment_list_top) moveToCommentListTop();
1128					}else{
1129						alert(result.msg);
1130					}
1131				}
1132			});
1133		}
1134	};
1135
1136	var moveToCommentListTop = function(){
1137		var $modal_widget_fullboard = $('.modal_widget_fullboard');
1138		var $pos_comment_container = $('#comment_container');
1139
1140		// 위젯 위치 세팅
1141		if($modal_widget_fullboard.length > 0){
1142			$modal_widget_fullboard.scrollTop($('.comment-block').position().top);
1143		}else if($pos_comment_container.length > 0){
1144			// 스크롤 고정 메뉴 확인
1145			var fixed_header_section = $("._fixed_header_section");
1146			var header_height = 0;
1147
1148			if(fixed_header_section.length > 0){
1149				for(var i = 0; i < fixed_header_section.length; i++){
1150					header_height += 2 * fixed_header_section[i].offsetHeight;
1151				}
1152			}
1153			// 상단 고정 메뉴 확인
1154			var new_fixed_header = $('#doz_header_wrap').find('._new_fixed_header');
1155			if(new_fixed_header.length > 0){
1156				header_height += new_fixed_header.height();
1157			}
1158
1159			$(window).scrollTop($('.comment-block').offset().top - header_height -15);
1160		}
1161	};
1162
1163	return {
1164		init : function(code){
1165			commentInit(code);
1166		},
1167		toggleSub : function(code){
1168			commentToggleSub(code);
1169		},
1170		showEdit : function(code, board_type){
1171			commentShowEdit(code, board_type);
1172		},
1173		showSubForm : function(code){
1174			commentShowSubForm(code);
1175		},
1176		showAtForm : function(code){
1177			commentShowAtForm(code);
1178		},
1179		edit : function(code){
1180			commentEdit(code);
1181		},
1182		editMap : function(code){
1183			commentEditMap(code);
1184		},
1185		cancelEdit : function (code){
1186			commentCancelEdit(code);
1187		},
1188		addSub : function(code){
1189			commentAddSub(code);
1190		},
1191		addMapSub : function(code){
1192			commentMapAddSub(code);
1193		},
1194		addAt : function(code){
1195			commentAddAt(code);
1196		},
1197		showSubEdit : function(code){
1198			commentShowSubEdit(code);
1199		},
1200		cancelSubEdit : function (code){
1201			commentCancelSubEdit(code);
1202		},
1203		subEdit : function(code){
1204			commentSubEdit(code);
1205		},
1206		confirmShow : function(e,code,type,interlock_type,use_interlock_board){
1207			commentConfirmShow(e,code,type,interlock_type,use_interlock_board);
1208		},
1209		mapConfirmShow : function(e, code, type, interlock_type){
1210			commentMapConfirmShow(e, code , type, interlock_type)
1211		},
1212		confirmMapDelete : function(e,code){
1213			commentConfirmMapDelete(e,code);
1214		},
1215		'delete' : function(code, pass,interlock_type,use_interlock_board){
1216			commentDelete(code,pass,interlock_type,use_interlock_board);
1217		},
1218		deleteMap : function(code,pass){
1219			commentMapDelete(code,pass);
1220		},
1221		add : function(){
1222			commentAdd();
1223		},
1224		mapAdd : function(){
1225			commentMapAdd();
1226		},
1227		removeCommentImg : function(obj){
1228			removeCommentImg(obj)
1229		},
1230		getCommentListByCurrentPagingNum : function(current_page, is_move_to_comment_list_top){
1231			getCommentListByCurrentPagingNum(current_page, is_move_to_comment_list_top);
1232		},
1233		refreshCaptcha : function(){
1234			refreshCaptcha();
1235		},
1236		refreshCaptchaSubForm: function(code) {
1237			refreshCaptcha('sub_form', code);
1238		}
1239	}
1240
1241}();

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.