PageSourceSearch

https://www.happycampus.com/js/main.js?jsVer=20260921.1

js happycampus.com collected 2026-09-24 09:09:11 UTC 19,867 bytes, 653 lines download raw bytes

1/**
2 * 메인페이지용
3 **/
4Mainpage = {
5	/**
6	 * 상단 Hot Keyword 이동
7	 **/
8	hotKeywordCurrentIndex: 1,
9	hotKeywordBoxCount: null,
10	hotKeywordMove: function(direction){
11		if(this.hotKeywordBoxCount == null){
12			this.hotKeywordBoxCount = $('div.best_lst').length;
13		}
14		if(direction == 0){
15			this.hotKeywordCurrentIndex = (this.hotKeywordCurrentIndex == 1) ? this.hotKeywordBoxCount : --this.hotKeywordCurrentIndex;
16		}
17		else{ // next
18			this.hotKeywordCurrentIndex = (this.hotKeywordCurrentIndex == this.hotKeywordBoxCount) ? 1 : ++this.hotKeywordCurrentIndex;
19		}
20		$('div.best_lst').hide();
21		$('#hotkeyword'+ this.hotKeywordCurrentIndex).show();
22	},
23	gnbCategoryBoxToggle: function(){
24		var box = $('#gnbAllCategories');
25		box.toggle();
26		if(box.css('display') == 'none'){
27			$('#gnbMoreButton').removeClass('on');
28		}
29		else{
30			if(typeof closeFlashBanner == 'function'){
31				closeFlashBanner('video');
32			}
33			$('#gnbMoreButton').addClass('on');
34		}
35	},
36	/**
37	 * 문서목록 탭 선택 활성화
38	 * @param categorySeq
39	 */
40	activeDocList: function(categorySeq){
41		$('.doc_tab > ul > li[id^=docListLabel]').removeClass('active');
42		$('#docListLabel' + categorySeq).addClass('active');
43		$('div.content02[id^=docListContent]').hide();
44		$('#docListContent' + categorySeq).show();
45	},
46	/**
47	 * 동영상강좌 탭 선택 활성화
48	 * @param categorySeq
49	 */
50	activeElearningList: function(categorySeq){
51		$('#id_lecture_sections > li[id^=elearningListLabel]').removeClass('active');
52		$('#elearningListLabel' + categorySeq).addClass('active');
53		$('div.research_data[id^=elearningListContent]').hide();
54		$('#elearningListContent' + categorySeq).show();
55	},
56	/**
57	 * 서식 탭 선택 활성화
58	 * @param categorySeq
59	 */
60	activeFormList: function(categorySeq){
61		$('#formLabels > li[id^=formListLabel]').removeClass('active');
62		$('#formListLabel' + categorySeq).addClass('active');
63		$('div[id^=formListContent]').hide();
64		$('#formListContent' + categorySeq).show();
65	},
66	categories: [], // 자동 롤링시 관리될 카테고리 목록
67	pauseCategories: [], // 일시 정지 카테고리 목록
68	categoryIndex: [], // 현재 보여지는 카테고리 번호
69	categorySubIndex: 0, // 카테고리 하위 페이지 번호
70	/**
71	 * 자동 탭 롤링 시작
72	 * @param type
73	 * @param initCategories
74	 */
75	startRollingList: function(type, initCategories){
76		this.categories[type] = initCategories;
77		this.categoryIndex[type] = 0;
78		this.pauseCategories[type] = false;
79		setInterval("Mainpage.nextList('" + type + "', true)", 5000);
80	},
81	/**
82	 * 자동 탭 롤링 일시정지
83	 * @param type
84	 */
85	pauseRollingList:function(type){
86		this.pauseCategories[type] = true;
87		var targetBoxId = (type == 'elearning') ? 'mainElearningBox' : 'mainFormBox';
88		$('#'+targetBoxId).mouseleave(function(){ Mainpage.resumeRollingList(type); });
89	},
90	/**
91	 * 이시정지 되었던 탭 롤링 재개
92	 * @param type
93	 */
94	resumeRollingList:function(type){
95		this.pauseCategories[type] = false;
96	},
97	/**
98	 * 다음 탭 목록으로 이동
99	 * @param type
100	 * @param auto
101	 */
102	nextList: function(type,auto){
103		if(auto === true && this.pauseCategories[type] == true){ // 자동변경인데 일시정지 세팅중이면 중단
104			return;
105		}
106		++this.categoryIndex[type];
107		if(this.categoryIndex[type] == this.categories[type].length){
108			this.categoryIndex[type] = 0;
109		}
110		if(type == 'elearning'){
111			this.activeElearningList(this.categories[type][this.categoryIndex[type]]);
112		}
113		else if(type == 'form'){
114			this.activeFormList(this.categories[type][this.categoryIndex[type]]);
115		}
116	},
117	/**
118	 * 탭 내부 이전 하위 페이지로 이동
119	 * @param categorySeq
120	 */
121	prevSubList: function(categorySeq){
122		var maxLength = $('ul[id^=docListContentSub' +  categorySeq + ']').length;
123		if(this.categorySubIndex <= 0){
124			this.categorySubIndex = (maxLength-1);
125		}
126		else{
127			--this.categorySubIndex;
128		}
129		$('ul[id^=docListContentSub' +  categorySeq + ']').hide();
130		$('#docListContentSub' +  categorySeq + '_' + this.categorySubIndex).show();
131	},
132	/**
133	 * 탭 내부 다음 하위 페이지로 이동
134	 * @param categorySeq
135	 */
136	nextSubList: function(categorySeq){
137		var maxLength = $('ul[id^=docListContentSub' +  categorySeq + ']').length;
138		++this.categorySubIndex;
139		if(this.categorySubIndex >= maxLength){
140			this.categorySubIndex = 0;
141		}
142		$('ul[id^=docListContentSub' +  categorySeq + ']').hide();
143		$('#docListContentSub' +  categorySeq + '_' + this.categorySubIndex).show();
144	},
145	/**
146	 * 판매자 이메일 인증 완료 메세지
147	 */
148	popEmailVerifySuccess: function() {
149		Common.showHelp('', 'emailVerifySuccessMsg', '/help/?p=emailVerifySuccessMsg', 391, 166, null, 'center', 'bottom');
150	},
151	/**
152	 * 판매자 미인증 대기자료 안내 메세지
153	 */
154	popEmailVerifyMember: function() {
155		Common.showHelp('', 'emailVerifyMsg', '/help/?p=emailVerifyMsg', 391, 166, null, 'center', 'bottom');
156	},
157	/**
158	 * 해피에디터 자동변환 안내 메세지
159	 */
160	openAutoNoteNoti: function(){
161		Common.showHelp('', 'autoNoteNotiPop', '/help/?p=autoNoteNotiPop', 352, 299, null, 'center', 'bottom');
162	},
163	/**
164	 * 페이스북 홍보 안내 팝업
165	 */
166	openPromotionFacebookPopup: function(){
167		Common.showHelp('', 'promotionFacebookPop', '/help/?p=promotionFacebookPop', 900, 700, null, 'center', 'bottom');
168	},
169	/**
170	 * 판매자 인증 필요 안내 닫기
171	 */
172	closeAuthForm: function(){
173		$('#id_user_mail_auth').hide();
174	},
175	/**
176	 * 2016 판매자 이벤트 팝업 메세지
177	 */
178	openAdieu2016: function() {
179		Common.showHelp('', 'adieu2016', '/help/?p=adieu2016', 593, 461, null, 'center', 'bottom');
180	},
181	/**
182	 * 2016 판매자 이벤트 팝업 닫기
183	 */
184	closeAdieu2016: function(){
185		$('#adieu2016').hide();
186	},
187	/**
188	 * 2016 판매자 이벤트 하루동안 열지 않기
189	 */
190	closeTodayAdieu2016: function(){
191		Common.setCookie('adieu2016', 'y' , 1, '/'); // 1 = 하루 동안 이 문서 열지 않음.
192		$('#adieu2016').hide();
193	},
194	/**
195	 * 2016 판매자 이벤트 팝업 메세지(모바일)
196	 */
197	openAdieu2016m: function() {
198		Common.showHelp('', 'adieu2016', '/help/?p=adieu2016m', 290, 260, null, 'center', 'bottom');
199	},
200	/**
201	 * 2016 판매자 이벤트 하루동안 열지 않기(모바일)
202	 */
203	closeTodayAdieu2016m: function(){
204		Common.setCookie('adieu2016m', 'y' , 1, '/'); // 1 = 하루 동안 이 문서 열지 않음.
205		$('#adieu2016Pop').hide();
206	},
207
208	currentCatetoryType: 'themeSquare', // 현재 선택된 카테고리 유형
209	/**
210	 * 로그인 후 자동변환 안내 팝업 닫음
211	 */
212	closeAutoHcDocNotiPopup : function() {
213		if($('#doNotOpen').prop('checked')) {
214			Common.setCookie('autoHcDocPopupFlag', 'close' , 365, '/');
215		}
216		$('#autoNoteNotiPop').hide();
217	},
218	/**
219	 * 로그인 후 페이스북 홍보 팝업 닫음
220	 */
221	closePromotionFacebookPopup : function() {
222		$('#closeSmallPop').hide();
223		$('#promotionFacebookPop').hide();
224	},
225    /**
226     * 로그인 후 페이스북 홍보 팝업 하루 닫음
227     */
228    entireClosePromotionFacebookPopup : function(){
229        Common.setCookie('promotionFacebookPopupFlag', 'close' , 1, '/');
230        $('#closeSmallPop').hide();
231        $('#promotionFacebookPop').hide();
232    },
233	/**
234	 * 로그인 후 제목 일괄된 리스트에서 보류된 리스트 안내 팝업 닫음
235	 */
236	closeTempTitleNotiPopup : function() {
237		if($('#doNotOpenTempTitleList').prop('checked')) {
238			//Common.setCookie('tempDocTitlePopupFlag', 'close' , 365, '/');
239			$.ajax({
240				type: 'post',
241				url: '/site/checkDeniedTempTitle/',
242				data: {},
243				async: false,
244				dataType: 'json',
245				success: function (json) {
246					if(json.code <= 0){
247						alert(json.msg);
248						return false;
249					}
250				},
251				error: function () {
252					alert('XHR 호출 오류');
253				}
254			});
255		}
256		$('#tempTitleNotiPop').hide();
257	},
258	/**
259	 * 하단 카테고리 유형을 변경한다.
260	 * @param type
261	 */
262	changeBottomCategory: function(type){
263		if(type == 'themeSquare'){
264			$('#site_map_tab1').removeClass('off');
265			$('#site_map_tab1').addClass('selected');
266
267			$('#site_map_tab2').removeClass('selected');
268			$('#site_map_tab2').addClass('off');
269
270			$('#site_map_theme_list').show();
271			$('#site_map_kndata_list').hide();
272		}
273		else{ // kndata
274			$('#site_map_tab1').removeClass('selected');
275			$('#site_map_tab1').addClass('off');
276
277			$('#site_map_tab2').removeClass('off');
278			$('#site_map_tab2').addClass('selected');
279
280			$('#site_map_theme_list').hide();
281			$('#site_map_kndata_list').show();
282		}
283		this.currentCatetoryType = type;
284	},
285	/**
286	 * 현재 선택된 카테고리 메뉴로 이동
287	 */
288	goCurrentCategory: function(){
289		Common.goUrl('/' + this.currentCatetoryType + '/?viewAll=on', null);
290	},
291	/**
292	 * 하단 카테고리 노출 상태를 변경한다.
293	 */
294	toggleBottomCategory: function(){
295		$('#sitemapBox').toggle();
296		if($('#sitemapBox').css('display') == 'none'){
297			$('#site_map_button_icon').attr('src', '/images/common/bullet/2009_bul_arrow08.gif');
298		}
299		else{
300			$('#site_map_button_icon').attr('src', '/images/common/bullet/2009_bul_arrow07.gif');
301		}
302	},
303
304	/**
305	 * 로그인 폼검증
306	 * @returns {boolean}
307	 */
308	'loginFormValidation':function(){
309		if( Common.trim($("input#memberId").val()) == '' ){
310			alert("아이디를 입력하세요");
311			$("input#memberId").focus();
312			return false;
313		}
314		if( Common.trim($("input#passwd").val()) == '' ){
315			alert("비밀번호를 입력하세요");
316			$("input#passwd").focus();
317			return false;
318		}
319		return true;
320	},
321
322	/**
323	 * 메인 로그인 입력폼 포커스 이동시 BG 조정
324	 */
325	loginFormFocus:function (obj, type) {
326		if (type == 'focus') {
327			if (obj.id == 'memberId') {
328				$('#labelMemberId').text('');
329			}
330			else if (obj.id == 'passwd') {
331				$('#labelPasswd').text('');
332			}
333		}
334		else {
335			if (obj.id == 'memberId') {
336				if ($(obj).val() == '') {
337					$('#labelMemberId').text('아이디');
338				}
339			}
340			else if (obj.id == 'passwd') {
341				if ($(obj).val() == '') {
342					$('#labelPasswd').text('비밀번호');
343				}
344			}
345			if ($('#passwd').val()) $('#labelPasswd').text('');
346		}
347		Common.clearSearchBoxAutoFocus();
348	},
349	/**
350	 * 방송통신대 판매자 팝업 노출
351	 */
352	popNewCategoryNotice: function() {
353		Common.showHelp('', 'newCategoryNotice', '/help/?p=newCategoryNotice', 540, 750, null, 'center', 'bottom');
354	},
355	/**
356	 * 방송통신대 판매자 팝업 노출 닫기
357	 */
358	closeNewCategoryNotice : function() {
359		if($('#checkNewCategoryNotice').is(":checked") == true) {
360			Common.setCookie("cookieNewCategoryNoticePop", "done" , 7); //1=하루 동안 이 문서 열지 않음.
361		}
362		$('#newCategoryNotice').hide();
363	},
364	/**
365	 * 메인페이지 로그인 방식 토글
366	 */
367	toggleLoginType : function(type) {
368		if (type == 'happycampus') {
369			$('#tabHappycampus').attr('class', 'on');
370			$('#tabNaver').attr('class', 'off');
371			$('#loginHappycampus').show();
372			$('#loginNaver').hide();
373		} else {
374			$('#tabNaver').attr('class', 'on');
375			$('#tabHappycampus').attr('class', 'off');
376			$('#loginNaver').show();
377			$('#loginHappycampus').hide();
378		}
379	},
380	/**
381	 * 로그인 포커스 레이블 숨김
382	 */
383	'loginInputLabelView':function(){
384		if( $("#memberId").val() != "" ){
385			$("#label_id").hide();
386		} else {
387			$("#label_id").show();
388		}
389		if( $("#passwd").val() != "" ){
390			$("#label_pw").hide();
391		} else {
392			$("#label_pw").show();
393		}
394	},
395
396	/**
397	 * 전체보기 문서광장 브런치 오버시 하위 카테고리 노출
398	 * @param code
399	 */
400	'docSubCateChange':function(code){
401		$('#docCateBranchSet ul li a').removeClass('on');
402		$('#docCateBranchSet ul li a.'+code).addClass('on');
403		$('#docCateSubSet ul').hide();
404		$('#cateListSub_'+code).show();
405	},
406	'themeSubCateChange':function(code){
407		$('#themeCateBranchSet ul li a').removeClass('on');
408		$('#themeCateBranchSet ul li a.on_'+code).addClass('on');
409		$('#themeCateSubSet ul').hide();
410		$('#themeCateListSub_'+code).show();
411	},
412	/**
413	 * 해당 code 의 카테고리 박스를 오픈한다.
414	 * @param code
415	 */
416	OPENSUBIMTE : null,
417	'openSubCateBox':function(code){
418		if( $('#totalCateW .total_cate_con:visible').length == 0 ){
419			if( Mainpage.OPENSUBIMTE == null ){
420				Mainpage.OPENSUBIMTE = window.setTimeout(function(){
421					$('#totalCateW .total_cate_con').hide();
422					$('#slideToggleBox ul li a').removeClass('on');
423					$('#totalCateContent').hide();
424					$('#slideToggleBox .total_cate').removeClass('on');
425					$('#subCate_'+code).stop().slideDown(100);
426					$('#cateBtn_'+code+' a').addClass('on');
427					$('#totalCateBtn .total_cate').attr('onclick', 'Mainpage.allCateOpen(); return false;');
428				}, 350);
429			}
430		} else {
431			$('#totalCateW .total_cate_con').hide();
432			$('#slideToggleBox ul li a').removeClass('on');
433			$('#totalCateContent').hide();
434			$('#slideToggleBox .total_cate').removeClass('on');
435			$('#subCate_'+code).stop().show();
436			$('#cateBtn_'+code+' a').addClass('on');
437		}
438	},
439	/**
440	 * 전체 카테고리 열기
441	 */
442	'allCateOpen':function(){
443		$('#totalCateW .total_cate_con').hide();
444		$('#slideToggleBox ul li a').removeClass('on');
445
446		$('#totalCateContent').stop().slideDown(100);
447		$('#slideToggleBox .total_cate').addClass('on');
448
449		$('#totalCateBtn .total_cate').attr('onclick', 'Mainpage.allCate
449Close(); return false;');
450	},
451	/**
452	 * 전체 카테고리 닫기
453	 */
454	'allCateClose':function(){
455		Mainpage.OPENSUBIMTE = null;
456		$('#totalCateContent').stop().slideUp(100);
457		$('#slideToggleBox .total_cate').removeClass('on');
458		$('#totalCateBtn .total_cate').attr('onclick', 'Mainpage.allCateOpen(); return false;');
459	},
460	fileHandlerForFacebook : null,	//페이스북 홍보를 위해 회원들이 업로드하는 파일을 저장하기 위한 변수
461	/**
462	 * 페이스북 홍보 파일 양식 다운로드
463	 */
464	'downloadFormForFacebook' : function() {
465		$.ajax({
466			url:'/site/promotionFacebookFormDownload',
467			dataType:'json',
468			type:'POST',
469			success:function(result){
470				if(result.code < 0){
471					alert(result.msg);
472					return false;
473				}else{
474					Common.goUrl(result.downloadInfo,'_blank');
475				}
476			}
477		});
478	},
479	/**
480	 * 페이스북 홍보 파일 업로드 팝업
481	 */
482	'openPromotionFacebookFilePop' : function() {
483		var html = "";
484        html += '<div id="closeSmallPop" class="popupFrame" style="border: 1px solid rgb(36, 45, 67); border-image: none; width: 400px;">';
485        html += '<div class="p_ntop">';
486        html += '<h1 class="ptit">페이스북에 홍보자료 등록</h1>';
487        html += '<a class="p_nclose" href="javascript:;" onclick="$(\'#closeSmallPop\').hide();">닫기</a>';
488        html += '</div>';
489        html += '<div class="containerPopup">';
490        html += '<dl class="reply_dell">';
491        html += '<dt class="noline">양식을 업로드 하세요.</dt>';
492        html += '<dd><input style="width: 350px; height: 26px;" onchange="Mainpage.temporarilyRegisterFile(event)" id="file" type="file"></dd>';
493        html += '<dt class="noline">자료 상세페이지 URL을 입력하세요.</dt>';
494        html += '<dd><input style="width: 350px; height: 26px;" type="text" id="url" class="input_b"></dd>';
495        html += '</dl>';
496        html += '</div>';
497        html += '<div class="cBtns">';
498        html += '<a class="btn_fun_b" href="javascript:;" onclick="Mainpage.registerPromotionContent();">등록</a>';
499        html += '<a class="btn_fun_w" href="javascript:;" onclick="$(\'#closeSmallPop\').hide();">취소</a>';
500        html += '</div>';
501        html += '</div>';
502
503		Common.openLayerBox('registerPopup', html, 352, 200);
504	},
505	/**
506	 * 페이스북 홍보 파일을 임시 저장
507	 * @param event
508	 */
509	'temporarilyRegisterFile' :function(event) {
510		var files = event.target.files;
511		if (files.length == 1) {
512			this.fileHandlerForFacebook = files[0];
513		}
514	},
515	/**
516	 * 페이스북 홍보 파일 업로드
517	 */
518	'registerPromotionContent' : function() {
519		var inputFile = new FormData();
520		inputFile.append('inputFile',this.fileHandlerForFacebook);
521
522		$.ajax({
523			type: 'post',
524			url: '/site/registerPromotionContent/',
525			data:  inputFile,
526			cache: false,
527			async: true,
528			processData: false,
529			contentType: false,
530			dataType: 'json',
531			success: function (json) {
532				if(json.code < 0){
533					alert(json.msg);
534				}else{
535					$.ajax({
536						type: 'post',
537						url: '/site/registerPromotionUrl/',
538						data:  {'url': $('#url').val(), 'key' : json.code},
539						cache: false,
540						async: true,
541						dataType: 'json',
542						success: function (json) {
543							if(json.code < 0){
544								alert(json.msg);
545							}else{
546								alert("등록 되었습니다.");
547								$('#closeSmallPop').hide();
548							}
549						},
550						error: function () {
551							alert('XHR 호출 오류[2]');
552						}
553					});
554				}
555				this.fileHandlerForFacebook = null;
556				inputFile.append('inputFile',this.fileHandlerForFacebook);
557			},
558			error: function () {
559				alert('XHR 호출 오류');
560			}
561		});
562	},
563};
564
565$(document).ready(function(){
566	/* 로그인 포커스 */
567	$("#label_id").hide();
568	$("#label_pw").hide();
569	Mainpage.loginInputLabelView();
570	$("form .login input").keyup(function(){
571		Mainpage.loginInputLabelView();
572	});
573	$("form .login input").change(function(){
574		Mainpage.loginInputLabelView();
575	});
576	// 카테고리를 벗어낫을때
577	$('#leaveCheckBox').bind('mouseleave', function(){
578		window.clearTimeout(Mainpage.OPENSUBIMTE);
579		Mainpage.OPENSUBIMTE = null;
580		$('#totalCateW .total_cate_con').stop().slideUp(100);
581		$('#slideToggleBox ul li a.c_btn').removeClass('on');
582	});
583
584
585	// 메인 검색바 START
586	const searchInput = document.getElementById('inputQu');
587	const recentSearchesContainer = document.getElementById('searchFront');
588	const btnClose = document.querySelector('#searchKeywordAreaClose.BtnClose button');
589	const noRecentSearches = document.getElementById('NoRecentSearches');
590
591	// 검색창에서 focus가 빠져나갔을 때, RecentSearches가 보이지 않으면 border 색 변경
592	searchInput.addEventListener('blur', function () {
593		if (recentSearchesContainer.style.display === 'none') {
594			searchInput.closest('.TextInput_2').classList.remove('Focused');
595			searchInput.closest('.TextInput_2').classList.add('NoFocused');
596		}
597	});
598
599	// 닫기 버튼 클릭 시 최근 검색어 목록 닫기
600	btnClose.addEventListener('click', function () {
601		recentSearchesContainer.style.display = 'none';
602		searchInput.closest('.TextInput_2').classList.remove('Focused');
603		searchInput.closest('.TextInput_2').classList.add('NoFocused');
604	});
605
606	// 바깥 영역 클릭 시 검색창의 보더 색상 원래대로, 최근 검색어 목록 닫기
607	document.addEventListener('click', function (event) {
608		if (!searchInput.contains(event.target) && !recentSearchesContainer.contains(event.target)) {
609			recentSearchesContainer.style.display = 'none';
610			searchInput.closest('.TextInput_2').classList.remove('Focused');
611			searchInput.closest('.TextInput_2').classList.add('NoFocused');
612		}
613	});
614	// 메인 검색바 END
615
616	// 메인 검색 하위 메뉴 START
617	const btnOpenMenu = document.querySelector('.BtnOpenMenu');
618	const mainMenu = document.querySelector('.MainMenu');
619	const subMenu = document.querySelector('#MainSubMenu');
620
621	function openMenu() {
622		btnOpenMenu.style.fontWeight = '700';
623		mainMenu.classList.add('On');
624		subMenu.style.display = 'block';
625	}
626
627	function closeMenu() {
628		btnOpenMenu.style.fontWeight = '500';
629		mainMenu.classList.remove('On');
630		subMenu.style.display = 'none';
631	}
632
633	btnOpenMenu.addEventListener('click', function(e) {
634		e.preventDefault();
635
636		if(mainMenu.classList.contains('On')) {
637			closeMenu();
638		} else {
639			openMenu();
640		}
641	});
642
643	document.addEventListener('click', function(e) {
644		if(!btnOpenMenu.contains(e.target) && !mainMenu.contains(e.target) && !subMenu.contains(e.target)) {
645			closeMenu();
646		}
647	});
648	// 메인 검색 하위 메뉴 END
649
650	//메인 우측영역 스크롤 START
651	const sticky = new Sticky('.StickyBox-B1GV3TJO');
652	//메인 우측영역 스크롤 END
653});

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.