PageSourceSearch

https://www.kaken.or.jp/cms/lib/js/efo/validate.js

js kaken.or.jp collected 2026-10-02 06:20:53 UTC 46,163 bytes, 1,464 lines download raw bytes

1(function() {
2	document.addEventListener('DOMContentLoaded', initialize);
3
4	let EFOUtil;
5
6	const EVENT_START = [ 'focus' ];
7	const EVENT_CHANGE = [ 'input', 'select', 'change' ];
8	const EVENT_END = [ 'blur' ];
9
10	function initialize() {
11
12		// ルールキーが取得できなければEFO無効化
13		if (!EFOAPI) return;
14		const ruleKey = EFOAPI.GetRuleKey();
15		if (!ruleKey) return;
16
17		const isPreviewMode = document.querySelector('.smzpreview-is-preview-mode');
18		const efoForm = document.querySelector('[data-efo-form-id]');
19		if (!efoForm) return;
20
21		// EFO読み込み開始
22		EFOUtil = new _EFOUtil();
23		EFOUtil.Initializer
24		.done(function() {
25			if (!EFOUtil.Rule || !EFOAPI.AnalyticsSessionKey) {
26				if (isPreviewMode && efoForm && efoForm.noValidate != 'undefined') {
27					// プレビューモードならエラーを出さずにもどる
28					efoForm.noValidate = true;
29					return;
30				}
31				console.error('EFOルールが取得できませんでした。');
32				return;
33			}
34			
35			HTMLFormElement.prototype.checkValidityCustom = checkFormValidityCustom;
36			HTMLInputElement.prototype.checkValidityCustom = checkValidityCustom;
37			HTMLTextAreaElement.prototype.checkValidityCustom = checkValidityCustom;
38			HTMLSelectElement.prototype.checkValidityCustom = checkValidityCustom;
39			
40			EFOUtil.SetRule();
41			EFOUtil.SetAnalytics();
42			
43			const hasInputField = document.querySelector('[data-efo-item-id]');
44			if (hasInputField) {
45				EFOUtil.SetItem();
46				EFOUtil.SetConvert();
47				EFOUtil.SetAutoInput();
48			}
49		})
50		.fail(function() {
51			if (isPreviewMode && efoForm && efoForm.noValidate != 'undefined') {
52				// プレビューモードならエラーを出さずにもどる
53				efoForm.noValidate = true;
54				return;
55			}
56			console.error('EFOルールが取得できませんでした。');
57			return;
58		})
59		;
60
61		// エラー確認メソッド拡張(要素)
62		function checkValidityCustom() {
63
64			// ※先にエラーメッセージを消さないと、checkValidityが必ず false になる
65			if (this.validationMessage) this.setCustomValidity('');
66			
67			// 標準のエラーチェック
68			if (!this.checkValidity) return true;
69			const validity = this.checkValidity();
70			if (!validity) return false;
71			
72			// 拡張エラーチェック
73			const type = this.dataset["efoType"];
74			if (!type) return true;
75			
76			// タイプごとのエラーチェック
77			let validator;
78			switch(type) {
79				case 'text':
80					validator = EFOValidate.Text;
81					break;
82				case 'number':
83					validator = EFOValidate.Number;
84					break;
85				case 'checkbox':
86					validator = EFOValidate.Checkbox;
87					break;
88				case 'file':
89					validator = EFOValidate.File;
90					break;
91				case 'select':
92					validator = EFOValidate.Select;
93					break;
94			}
95			if (validator) {
96				for (method in validator) {
97					// エラーがあれば警告表示
98					if (validator[method].Validate(this)) continue;
99					return false;
100				}
101			}
102			
103			for (method in EFOValidate.Common) {
104				// エラーがあれば警告表示
105				if (EFOValidate.Common[method].Validate(this)) continue;
106				return false;
107			}
108			
109			return true;
110			
111		}
112
113		// エラー確認メソッド拡張(フォーム)
114		function checkFormValidityCustom() {
115			const targets = document.querySelectorAll('[data-efo-item-id]');
116			if (!targets || targets.length == 0) return true;
117			
118			let result = true;
119			
120			// 初回は全チェック
121			if (!this.dataset['efoCheckStart']) {
122				for (let i = 0; i < targets.length; i++) {
123					if (!targets[i].checkValidityCustom()) {
124						result = false;
125					}
126				}
127				this.dataset["efoCheckStart"] = true;
128				return result;
129			}
130			
131			// 2回目以降はエラーメッセージの有無のみをチェック
132			for (let i = 0; i < targets.length; i++) {
133				if (targets[i].validationMessage) {
134					result = false;
135					break;
136				}
137			}
138			return result;
139		}
140
141	}
142
143	_EFOUtil.prototype = {
144		
145		Rule : null,
146		AnalyticsSessingKey : null,
147		CookieSessionKey : 'efo_form_session_key',
148		Initializer : null,
149		LeaveAlertFired : false,
150
151		CheckTimeout : 200,
152		CheckTimer : undefined,
153		
154		Initialize : function() {
155			const util = this;
156			const defer = $cms.Deferred();
157			
158			const inputForm = document.querySelector('form[data-efo-path-root]');
159			const inputPostBack = document.querySelector('form[data-efo-postback]');
160			const inputError = document.querySelector('form[data-efo-error]');
161			const inputConfirm = document.querySelector('form[data-efo-confirm]');
162			const inputComplete = document.querySelector('form[data-efo-complete]');
163			
164			let sessionKey;
165			if (inputPostBack || inputError || inputConfirm || inputComplete) {
166				sessionKey = EFOCookie.GetItem(this.CookieSessionKey);
167			}
168			if (sessionKey) {
169				// セッションキー取得なし
170				EFOAPI.Rule()
171				.done(function (data) {
172					if (!data || data.result) {
173						defer.reject();
174						return;
175					}
176					util.Rule = new _EFORule(data);
177					EFOAPI.AnalyticsSessionKey = sessionKey;
178					defer.resolve();
179				})
180				.fail(function() {
181					defer.reject();
182				})
183				;
184			} else {
185				
186				EFOCookie.RemoveItem(this.CookieSessionKey, inputForm.dataset['efoPathRoot']);
187				
188				// セッションキー取得あり
189				$cms.when(
190					EFOAPI.Rule(), 
191					EFOAPI.Session()
192				)
193				.done(function ( rule, session ) {
194					if (!rule || !session) {
195						defer.reject();
196						return;
197					}
198					if (rule[0].result || rule[1] != 'success') {
199						defer.reject();
200						return;
201					}
202					if (session[0].result || session[1] != 'success') {
203						defer.reject();
204						return;
205					}
206					
207					util.Rule = new _EFORule(rule[0]);
208					
209					EFOAPI.AnalyticsSessionKey = session[0].efo_analytics_session_key;
210					EFOCookie.SetItem(_EFOUtil.prototype.CookieSessionKey, EFOAPI.AnalyticsSessionKey, null, inputForm.dataset['efoPathRoot'])
211					
212					defer.resolve();
213				})
214				.fail(function() {
215					defer.reject();
216				})
217				;
218			}
219			
220			return defer.promise();
221		},
222		
223		GetErrorMessage: function(key, argument) {
224			if (!this.Rule) return;
225			if (!this.Rule.ErrorMessage) return;
226			if (!this.Rule.ErrorMessage[key]) return;
227			
228			const message = this.Rule.ErrorMessage[key];
229			if (!argument) return message;
230			
231			return message.replace('{0}', argument);
232		},
233		
234		SetRule : function() {
235			if (!this.Rule) return;
236			
237			const form = document.querySelector('form[data-efo-form-id]');
238			const inputPostBack = document.querySelector('form[data-efo-postback]');
239			const inputConfirm = document.querySelector('form[data-efo-confirm]');
240			const inputComplete = document.querySelector('form[data-efo-complete]');
241			if (inputComplete) return;
242			
243			// 離脱防止
244			LeaveAlert : {
245				if (!this.Rule.LeaveAlert.Flag) break LeaveAlert;
246				if (!form) break LeaveAlert;
247				
248				const observer = new MutationObserver(function() {
249					if (!form.dataset['efoInputStart']) return;
250					window.addEventListener('beforeunload', leaveAlert);
251					observer.disconnect();
252				});
253				const observeOptions = {
254					attributes : true,
255					attributeFilter : [ 'data-efo-input-start' ]
256				};
257				observer.observe(form, observeOptions);
258				
259				form.addEventListener('submit', function(event) {
260					if (EFOUtil.LeaveAlertFired) {
261						EFOAPI.LeaveAlertSuccess();
262					}
263					window.removeEventListener('beforeunload', leaveAlert);
264					return true;
265				});
266				
267				const postBackButton = document.getElementById('postBackButton');
268				if (postBackButton) {
269					postBackButton.addEventListener('click', function() {
270						window.removeEventListener('beforeunload', leaveAlert);
271						return true;
272					});
273				}
274				
275				// 戻る画面・確認画面なら離脱防止を設定
276				if (inputPostBack || inputConfirm) {
277					form.dataset['efoInputStart'] = true.toString();
278				}
279				
280				function leaveAlert(event) {
281					EFOUtil.LeaveAlertFired = true;
282					EFOAPI.LeaveAlert();
283					event.returnValue = EFOUtil.Rule.LeaveAlert.Message;
284					return EFOUtil.Rule.LeaveAlert.Message;
285				}
286				
287			}
288			
289			if (inputConfirm) return;
290			
291			// エラー時の送信防止
292			SubmitBlock : {
293				if (!this.Rule.SubmitBlock.Flag) break SubmitBlock;
294				if (!form) break SubmitBlock;
295				
296				const ruleKey = EFOAPI.GetRuleKey();
297				if (!ruleKey) break SubmitBlock;
298				
299				form.addEventListener('submit', function(event) {
300					if (form.checkValidityCustom()) return true;
301					alert(EFOUtil.Rule.SubmitBlock.Message);
302					return false;
303				});
304				
305				switchSubmitButton();
306				form.addEventListener('efo_update', switchSubmitButton);
307				
308				// 送信ボタンの無効化
309				function switchSubmitButton() {
310					const submitButtons = document.querySelectorAll('[data-efo-form-id] [type="submit"]');
311					const submitImages = document.querySelectorAll('[data-efo-form-id] [type="image"]');
312					
313					if (
314						(!submitButtons || submitButtons.length == 0) && 
315						(!submitImages || submitImages.length == 0)
316					) return true;
317					
318					const isValid = form.checkValidityCustom();
319					submitButtons.forEach(function(element) {
320						// ツールチップ生成
321						if (!element.TooltipInstance) {
322							element.TooltipInstance = new Tooltip(element, {
323								title : EFOUtil.Rule.SubmitBlock.Message, 
324								trigger : 'manual',
325								placement : 'bottom'
326							});
327						}
328						
329						// ボタン有効化
330						if (isValid) {
331							element.removeAttribute('disabled');
332							if (EFOUtil.Rule.SubmitBlock.Message) {
333								element.TooltipInstance.hide();
334							}
335						}
336						// ボタン無効化
337						else {
338							element.setAttribute('disabled', '');
339							element.TooltipInstance.show();
340						}
341					});
342					
343					// 画像イメージ
344					submitImages.forEach(function(element) {
345						
346						// ツールチップ生成
347						if (!element.TooltipInstance) {
348							element.TooltipInstance = new Tooltip(element, {
349								title : EFOUtil.Rule.SubmitBlock.Message, 
350								trigger : 'manual',
351								placement : 'bottom'
352							});
353						}
354						
355						// ボタン有効化
356						if (isValid) {
357							element.removeAttribute('disabled');
358							if (element.dataset["efoSrcEnabled"]) {
359								element.src = element.dataset["efoSrcEnabled"];
360							}
361							if (EFOUtil.Rule.SubmitBlock.Message) {
362								element.TooltipInstance.hide();
363							}
364							return;
365						}
366						
367						// ボタン無効化
368						element.setAttribute('disabled', '');
369						if (element.dataset["efoSrcDisabled"]) {
370							element.src = element.dataset["efoSrcDisabled"];
371						}
372						element.TooltipInstance.show();
373					});
374				}
375				
376			}
377			
378			// 必須項目入力状態の表示
379			StatusIndication : {
380				if (!this.Rule.StatusIndication.Flag) break StatusIndication;
381				
382				if (!form) break StatusIndication;
383				
384				// 初期表示
385				form.checkValidityCustom();
386				UpdateStatusIndication();
387				
388				// 入力時更新
389				form.addEventListener('efo_update', UpdateStatusIndication);
390				
391				// 必須項目の残りの数を更新
392				function UpdateStatusIndication() {
393					const restRequiredCount = EFOUtil.GetRestRequiredCount();
394					const statusIndication = document.getElementById('status_indication');
395					const requiredCount = document.getElementById('required_count');
396					const statusIndicationComplete = document.getElementById('status_indication_complete');
397					if (restRequiredCount > 0) {
398						if (statusIndication) statusIndication.style.display = 'block';
399						if (requiredCount) requiredCount.textContent = restRequiredCount;
400						if (statusIndicationComplete) statusIndicationComplete.style.display = 'none';
401					} else {
402						if (statusIndication) statusIndication.style.display = 'none';
403						if (statusIndicationComplete) statusIndicationComplete.style.display = 'block';
404					}
405				}
406			}
407			
408		},
409		
410		SetItem : function() {
411			
412			const targets = document.querySelectorAll('[data-efo-type][data-efo-item-id]');
413			if (!targets || targets.length == 0) return;
414			targets.forEach(function(target) {
415				attachEvent(target);
416			});
417
418			function attachEvent(target) {
419
420				// 入力開始時
421				EVENT_START
422				.forEach(function(event) {
423					target.addEventListener(event, startItem, false);
424
425					// エラーメッセージ再表示
426					target.addEventListener(event, function() {
427						if (!target.validationMessage) return;
428						if (!target.dataset['efoInputEnd']) return;
429						EFOTooltip.Show(target, target.validationMessage);
430					});
431				});
432				
433				// 変更時
434				EVENT_CHANGE
435				.forEach(function(event) {
436					target.addEventListener(event, function() {
437						// 触った項目が変わったか
438						const lastInputItemId = target.form.dataset["efoLastInputItemId"];
439						if (lastInputItemId && lastInputItemId != target.dataset["efoItemId"]) {
440							const lastTarget = document.querySelector('[data-efo-item-id="' + lastInputItemId + '"]');
441							if (lastTarget.dataset['efoType'] == 'checkbox' || lastTarget.dataset['efoType'] == 'file') {
442								lastTarget.addEventListener(EVENT_END[0], endItem, false);
443								fireEvent(lastTarget, EVENT_END[0]);
444							}
445						}
446	
447						// 最後に触った項目を保存
448						target.form.dataset["efoLastInputItemId"] = target.dataset["efoItemId"];
449						target.form.dataset["efoLastInputType"] = target.dataset["efoType"];
450					});
451				});
452	
453				// 入力終了時
454				EVENT_END
455				.forEach(function(event) {
456					if (target.dataset['efoType'] == 'checkbox' || target.dataset['efoType'] == 'file') return;
457					target.addEventListener(event, endItem, false);
458				});
459	
460			}
461	
462			function startForm() {
463				const targets = document.querySelectorAll('[data-efo-item-id]');
464				const itemList = new Array();
465				targets.forEach(function(target) {
466					itemList.push({
467						item_id : target.dataset["efoItemId"],
468						item_title : target.dataset["efoItemTitle"],
469						item_required : 
470							(target.getAttribute('data-efo-required') ? 
471								target.dataset["efoRequired"] : target.required
472							).toString()
473					});
474				});
475				EFOAPI.InputStart({ item_list : JSON.stringify(itemList) });
476			}
477	
478			function startItem() {
479				const target = this;
480	
481				// フォームの送信
482				if (target.form.dataset["efoInputStart"] != true.toString()) {
483					startForm();
484					target.form.dataset["efoInputStart"] = true.toString();
485				}
486
487				// 初回のみ触った項目を保存
488				if (!target.form.dataset["efoLastInputItemId"] || !target.form.dataset["efoLastInputType"] ) {
489					target.form.dataset["efoLastInputItemId"] = target.dataset["efoItemId"];
490					target.form.dataset["efoLastInputType"] = target.dataset["efoType"];
491				}
492
493				// 同じEFO ITEM IDの項目
494				const siblings = document.querySelectorAll('[data-efo-item-id="' + target.dataset["efoItemId"] + '"]');
495				siblings.forEach(function(sibling) {
496					EFOAPI.InputItemStart({
497						item_id : sibling.dataset["efoItemId"],
498						item_title : sibling.dataset["efoItemTitle"],
499						item_required : 
500							(sibling.getAttribute('data-efo-required') ? 
501								sibling.dataset["efoRequired"] : sibling.required
502							).toString()
503					});
504					sibling.dataset["efoInputStart"] = true.toString();
505					EVENT_CHANGE.forEach(function(event) {
506						sibling.removeEventListener(event, startItem, false);
507					});
508				});
509	
510				// 連動項目
511				const autoinputSelectors = target.dataset["efoAutoinputTarget"] 
512					? target.dataset["efoAutoinputTarget"].split(',') : [];
513				autoinputSelectors.forEach(function(autoinputSelector) {
514					const autoinput = document.querySelector(autoinputSelector);
515					if (!autoinput) return;
516					EFOAPI.InputItemStart({
517						item_id : autoinput.dataset["efoItemId"],
518						item_title : autoinput.dataset["efoItemTitle"],
519						item_required : 
520							(autoinput.getAttribute('data-efo-required') ? 
521							autoinput.dataset["efoRequired"] : autoinput.required
522							).toString()
523					});
524					autoinput.dataset["efoInputStart"] = true.toString();
525					EVENT_CHANGE.forEach(function(event) {
526						autoinput.removeEventListener(event, startItem, false);
527					});
528				});
529
530				// 最後の項目なら即時
531				if (target.form.checkValidityCustom()) return;
532				const required = (target.required || target.dataset['efoRequired']);
533				if (!required) return;
534
535				// 違う要素を入力
536				const lastInputItemId = target.form.dataset["efoLastInputItemId"];
537				if (lastInputItemId && lastInputItemId != target.dataset["efoItemId"]) {
538					const lastTarget = document.querySelector('[data-efo-item-id="' + lastInputItemId + '"]');
539					if (lastTarget.dataset['efoType'] == 'checkbox' || lastTarget.dataset['efoType'] == 'file') {
540						lastTarget.addEventListener(EVENT_END[0], endItem, false);
541						fireEvent(lastTarget, EVENT_END[0]);
542					}
543				}
544
545				const restRequiredCount = EFOUtil.GetRestRequiredCount();
546				if (restRequiredCount > 1) return;
547				siblings.forEach(function(sibling) {
548					sibling.dataset["efoInputEnd"] = true.toString();
549					
550					EVENT_END
551					.forEach(function(event) {
552						sibling.removeEventListener(event, endItem, false);
553					});
554	
555					// 2回目以降
556					EVENT_CHANGE
557					.forEach(function(event) {
558						sibling.addEventListener(event, function() {
559							if (EFOUtil.CheckTimer) {
560								clearTimeout(EFOUtil.CheckTimer);
561							}
562							EFOUtil.CheckTimer = setTimeout(function() {
563								checkItem(sibling);
564							}, EFOUtil.CheckTimeout);
565						});
566					});
567				});
568				if (target.dataset["efoType"] == 'checkbox' || target.dataset["efoType"] == 'radio') {
569					fireEvent(target, EVENT_CHANGE[0]);
570				}
571			}
572	
573			function endItem() {
574				const target = this;
575
576				// 1回目のチェック
577				checkItem(target);
578				
579				// 同じEFO ITEM IDの項目
580				const siblings = document.querySelectorAll('[data-efo-item-id="' + target.dataset["efoItemId"] + '"]');
581				if (target.dataset['efoDateSet']) {
582					let inputed = true;
583					siblings.forEach(function(sibling) {
584						inputed = (inputed && sibling.value);
585					});
586					if (!inputed) return;
587				}
588				siblings.forEach(function(sibling) {
589					sibling.dataset["efoInputEnd"] = true.toString();
590					
591					EVENT_END
592					.forEach(function(event) {
593						sibling.removeEventListener(event, endItem, false);
594					});
595	
596					// 2回目以降
597					EVENT_CHANGE
598					.forEach(function(event) {
599						sibling.addEventListener(event, function() {
600							if (EFOUtil.CheckTimer) {
601								clearTimeout(EFOUtil.CheckTimer);
602							}
603							EFOUtil.CheckTimer = setTimeout(function() {
604								checkItem(sibling);
605							}, EFOUtil.CheckTimeout);
606						});
607					});
608				});
609	
610				// 連動項目
611				const autoinputSelectors = target.dataset["efoAutoinputTarget"] 
612					? target.dataset["efoAutoinputTarget"].split(',') : [];
613				autoinputSelectors.forEach(function(autoinputSelector) {
614					const autoinput = document.querySelector(autoinputSelector);
615					if (!autoinput) return;
616					autoinput.dataset["efoInputEnd"] = true.toString();
617					EVENT_END
618					.forEach(function(event) {
619						autoinput.removeEventListener(event, endItem, false);
620					});
621	
622					// 2回目以降のチェック
623					EVENT_CHANGE
624					.forEach(function(event) {
625						autoinput.addEventListener(event, function() {
626							checkItem(autoinput);
627						});
628					});
629				});
630	
631			}
632	
633			function checkItem(target) {
634				target.checkValidityCustom();
635				if (target.validationMessage) {
636					EFOAPI.InputItemError({
637						item_id : target.dataset["efoItemId"],
638						item_title : target.dataset["efoItemTitle"],
639						item_required : 
640							(target.getAttribute('data-efo-required') ? 
641								target.dataset["efoRequired"] : target.required
642							).toString()
643					});
644				}
645
646				let messageTarget = document.querySelector('[data-efo-item-id="' + target.dataset["efoItemId"] + '"]');
647				if (messageTarget && !isVisible(messageTarget) && messageTarget.id) {
648					messageTarget = document.querySelector('[for="' + messageTarget.id + '"]');
649				}
650				if (messageTarget) {
651					EFOTooltip.Show(messageTarget, target.validationMessage);
652				}
653				
654				// 送信ボタンを更新
655				fireEvent(target.form, 'efo_update');
656				if (target.validationMessage) return;
657
658				const equalFrom = document.querySelector('[data-efo-equal="' + target.dataset['efoItemId'] +'"]');
659				if (equalFrom && equalFrom.dataset['efoInputEnd']) {
660					if (EFOUtil.CheckTimer) {
661						clearTimeout(EFOUtil.CheckTimer);
662					}
663					EFOUtil.CheckTimer = setTimeout(function() {
664						checkItem(equalFrom);
665					}, EFOUtil);
666					if (!equalFrom.validationMessage && target.validationMessage) {
667						EFOTooltip.Show(messageTarget, target.validationMessage);
668					}
669				}
670
671			}
672	
673			function fireEvent(target, event) {
674				const e = document.createEvent('HTMLEvents');
675				e.initEvent(event, false, true);
676				target.dispatchEvent(e);
677			}
678	
679			function isVisible(target) {
680				const rect = target.getBoundingClientRect();
681				return (rect.height > 0 && rect.width > 0)
682			}
683			
684		},
685		
686		SetConvert: function() {
687			const targets = document.querySelectorAll('input[data-efo-convert]');
688			if (!targets || targets.length == 0) return;
689			
690			targets.forEach(function(target) {
691				target.addEventListener('blur', function() {
692					if (!target.value) return;
693					if (!target.dataset["efoConvert"]) return;
694					
695					const originalValue = target.value;
696					
697					for(let i = 0; i < 2; i++) {
698						if ( target.dataset["efoConvert"].indexOf('zenkaku') > -1 ) {
699							target.value = FHConvert.hkktofkk(target.value, {space: true} );
700							target.value = FHConvert.htof(target.value, {space: true} );
701						}
702						if ( target.dataset["efoConvert"].indexOf('hankaku') > -1 ) {
703							target.value = FHConvert.fkktohkk(target.value, {space: true} );
704							target.value = FHConvert.ftoh(target.value, {space: true} );
705							target.value = target.value.replace('ï½°', '-');
706							target.value = target.value.replace('−', '-');
707							target.value = target.value.replace('-', '-');
708							target.value = target.value.replace('ー', '-');
709						}
710						if ( target.dataset["efoConvert"].indexOf('hiragana') > -1 ) {
711							target.value = FHConvert.kktohg(target.value);
712						}
713						if ( target.dataset["efoConvert"].indexOf('katakana') > -1 ) {
714							target.value = FHConvert.hgtokk(target.value);
715						}
716					}
717					
718					if (originalValue != target.value) {
719						const changeEvent = document.createEvent('HTMLEvents');
720						changeEvent.initEvent('efo_convert', false, true);
721						target.dispatchEvent(changeEvent);
722					}
723					
724				});
725				
726			});
727			
728			
729		},
730		
731		SetAutoInput: function() {
732			const targets = document.querySelectorAll('input[data-efo-autoinput-type]');
733			if (!targets || targets.length == 0) return;
734			
735			targets.forEach(function(target) {
736				for (method in EFOAutoInput) {
737					EFOAutoInput[method].Set(target);
738				}
739			});
740		},
741		
742		SetAnalytics: function() {
743			
744			const inputForm = document.querySelector('form[data-efo-path-root]');
745			
746			const inputError = document.querySelector('form[data-efo-error]');
747			if (inputError && inputError.dataset["efoError"] == true.toString()) {
748				EFOAPI.InputError();
749			}
750			const inputConfirm = document.querySelector('form[data-efo-confirm]');
751			if (inputConfirm && inputConfirm.dataset["efoConfirm"] == true.toString()) {
752				EFOAPI.InputConfirm();
753			}
754			const inputComplete = document.querySelector('form[data-efo-complete]');
755			if (inputForm && inputComplete && inputComplete.dataset["efoComplete"] == true.toString()) {
756				EFOAPI.InputComplete();
757				EFOCookie.RemoveItem(this.CookieSessionKey, inputForm.dataset['efoPathRoot']);
758			}
759			
760		},
761
762		GetRestRequiredCount: function() {
763			let count = 0;
764			count += countInvalidFields('[data-efo-form-id] [required]');
765			count += countInvalidFields('[data-efo-form-id] [data-efo-required]');
766			if (count == 0) {
767				// 必須項目でエラーがゼロならすべてをチェック
768				count += countInvalidFields('[data-efo-form-id] [data-efo-item-id]');
769			}
770			return count;
771			
772			function countInvalidFields(selector) {
773				const fields = document.querySelectorAll(selector);
774				if (!fields) return 0;
775				if (fields.length == 0) return 0;
776				
777				let count = 0;
778				let name;
779				fields.forEach(function(field) {
780					if (!field.name) return;
781					if (name == field.name) return;
782					name = field.name
783					if (field.validationMessage) 
784						count += 1;
785				});
786				return count;
787			}			
788		}
789		
790
791	}
792	function _EFOUtil() {
793		// 初期化処理
794		this.Initializer = this.Initialize();
795	}
796
797	// EFOルール
798	function _EFORule(data) {
799		if (!data) return null;
800		
801		const rule = new Object();
802		
803		rule.SubmitBlock = {};
804		rule.SubmitBlock.Flag = data.submit_block_flag;
805		rule.SubmitBlock.Message = data.submit_block_message;
806		
807		rule.LeaveAlert = {};
808		rule.LeaveAlert.Flag = data.leave_alert_flag;
809		rule.LeaveAlert.Message = data.leave_alert_message;
810		
811		rule.StatusIndication = {};
812		rule.StatusIndication.Flag = data.status_indication_flag;
813		
814		rule.CSS = {};
815		rule.CSS.Normal = data.css_normal;
816		rule.CSS.Input = data.css_input;
817		rule.CSS.Error = data.css_error;
818		
819		rule.ErrorMessage = data.error_message;
820		
821		return rule;
822	}
823
824	const EFOValidate = {
825		// テキスト
826		Text: {
827			MaxLength: {
828				Key: "text-maxlength",
829				Validate: function(target) {
830					if (!target) return true;
831					if (!target.getAttribute('maxlength')) return true;
832					if (EFOBrowserSupport && EFOBrowserSupport.MaxLength) return true;
833					if (!target.value) {
834						target.setCustomValidity('');
835						return true;
836					}
837					
838					const argument = target.getAttribute('maxlength');
839					const value = parseInt(argument);
840					if (!value) {
841						console.error('制限値の取得に失敗。argument=' + argument);
842						return true;
843					}
844					
845					if (target.value.length <= value) return true;
846					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
847					return false;
848				},
849			},
850			MinLength: {
851				Key: "text-minlength",
852				Validate: function(target) {
853					if (!target.getAttribute('minlength')) return true;
854					if (EFOBrowserSupport && EFOBrowserSupport.MinLength) return true;
855					if (!target.value) {
856						target.setCustomValidity('');
857						return true;
858					}
859					
860					const argument = target.getAttribute('minlength');
861					const value = parseInt(argument);
862					if (!value) {
863						console.error('制限値の取得に失敗。argument=' + argument);
864						return true;
865					}
866					
867					if (target.value.length >= value) return true;
868					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
869					return false;
870				}
871			},
872			Pattern: {
873				Key: "text-pattern",
874				Validate: function(target) {
875					if (!target) return true;
876					if (!target.getAttribute('pattern')) return true;
877					if (EFOBrowserSupport && EFOBrowserSupport.Pattern) return true;
878					if (!target.value) {
879						target.setCustomValidity('');
880						return true;
881					}
882					
883					const key = this.Key;
884					const argument = EFOUtil.GetArgument(checkName);
885					
886					const pattern = new RegExp(argument, 'i');
887					const match = target.value.match(pattern);
888					if (match) return true;
889					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
890					return false;
891				}
892			}
893		},
894		// 数値
895		Number: {
896			Max: {
897				Key: 'number-max',
898				Validate: function(target) {
899					if (!target) return true;
900					if (!target.getAttribute('max')) return true;
901					if (EFOBrowserSupport && EFOBrowserSupport.Max) return true;
902					if (!target.value) {
903						target.setCustomValidity('');
904						return true;
905					}
906					
907					const argument = target.getAttribute('max');
908					const value = parseInt(argument);
909					if (!value) {
910						console.error('制限値の取得に失敗。argument=' + argument);
911						return true;
912					}
913					
914					let targetValue = parseInt(target.value);
915					if (!targetValue) targetValue = 0;
916					if (targetValue <= value) return true;
917					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
918					return false;
919				}
920			},
921			Min: {
922				Key: "number-min",
923				Validate: function(target) {
924					if (!target) return true;
925					if (!target.getAttribute('min')) return true;
926					if (EFOBrowserSupport && EFOBrowserSupport.Min) return true;
927					if (!target.value) {
928						target.setCustomValidity('');
929						return true;
930					}
931					
932					const argument = target.getAttribute('min');
933					const value = parseInt(argument);
934					if (!value) {
935						console.error('制限値の取得に失敗。argument=' + argument);
936						return true;
937					}
938					
939					let targetValue = parseInt(target.value);
940					if (!targetValue) targetValue = 0;
941					if (targetValue >= value) return true;
942					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
943					return false;
944				}
945			}
946		},
947		// チェックボックス
948		Checkbox: {
949			CheckboxRequired: {
950				Key: 'checkbox-required',
951				Validate: function(target) {
952					if (!target) return true;
953					if (!target.dataset['efoRequired']) return true;
954					
955					const checkboxes = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]');
956					if (!checkboxes || checkboxes.length == 0) return true;
957					
958					const checked = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]:checked');
959					if (checked.length > 0) {
960						checkboxes.forEach(function(checkbox) {
961							checkbox.setCustomValidity('');
962						});
963						return true;
964					}
965					
966					const message = EFOUtil.GetErrorMessage(this.Key);
967					const targetSiblings = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]');
968					targetSiblings.forEach(function(targetSibling) {
969						targetSibling.setCustomValidity(message);
970					});
971					return false;
972				}
973			},
974			CheckboxMax: {
975				Key: 'checkbox-max',
976				Validate: function(target) {
977					if (!target) return true;
978					if (!target.dataset['efoCheckboxMax']) return true;
979					if (!target.value) {
980						target.setCustomValidity('');
981						return true;
982					}
983					
984					const argument = target.dataset['efoCheckboxMax'];
985					const value = parseInt(argument);
986					if (!value) {
987						console.error('制限値の取得に失敗。argument=' + argument);
988						return true;
989					}
990					
991					const checked = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]:checked');
992					if (checked.length == 0) return true;
993					if (checked.length <= value) return true;
994					
995					const message = EFOUtil.GetErrorMessage(this.Key, argument);
996					const targetSiblings = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]');
997					targetSiblings.forEach(function(targetSibling) {
998						targetSibling.setCustomValidity(message);
999					});
1000					return false;
1001				}
1002			},
1003			CheckboxMin: {
1004				Key: "checkbox-min",
1005				Validate: function(target) {
1006					if (!target) return true;
1007					if (!target.dataset['efoCheckboxMin']) return true;
1008					if (!target.value) {
1009						target.setCustomValidity('');
1010						return true;
1011					}
1012					
1013					const argument = target.dataset['efoCheckboxMin'];
1014					const value = parseInt(argument);
1015					if (!value) {
1016						console.error('制限値の取得に失敗。argument=' + argument);
1017						return true;
1018					}
1019					
1020					const checked = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]:checked');
1021					if (checked.length == 0) return true;
1022					if (checked.length >= value) return true;
1023					
1024					const message = EFOUtil.GetErrorMessage(this.Key, argument);
1025					const targetSiblings = document.querySelectorAll('[type="checkbox"][name="' + target.name + '"]');
1026					targetSiblings.forEach(function(targetSibling) {
1027						targetSibling.setCustomValidity(message);
1028					});
1029					return false;
1030				}
1031			}
1032		},
1033		// ファイル
1034		File: {
1035			Accept: {
1036				Key: 'file-accept',
1037				Validate: function(target) {
1038					if (!target) return true;
1039					if (!target.getAttribute('accept')) return true;
1040					if (!target.files || target.files.length == 0) {
1041						target.setCustomValidity('');
1042						return true;
1043					}
1044					
1045					const argument = target.getAttribute('accept');
1046					const values = argument.split(',')
1047					if (!values || values.length == 0) {
1048						console.error('制限値の取得に失敗。argument=' + argument);
1049						return true;
1050					}
1051					
1052					const fileName = target.files[0].name.toLowerCase();
1053					const match = values.some(function(value) {
1054						const position = fileName.length;
1055						const extension = value.trim().toLowerCase();
1056						const lastIndex = fileName.lastIndexOf(extension, position);
1057						return lastIndex !== -1 && lastIndex + extension.length === position;
1058					});
1059					if (match) return true;
1060					
1061					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, argument) );
1062					return false;
1063				}
1064			},
1065			ByteMax: {
1066				Key: 'file-byte-max',
1067				Validate: function(target) {
1068					if (!target) return true;
1069					if (!target.dataset['efoByteMax']) return true;
1070					if (!target.files || target.files.length == 0) {
1071						target.setCustomValidity('');
1072						return true;
1073					}
1074					
1075					const argument = target.dataset['efoByteMax'];
1076					const value = parseInt(argument);
1077					if (!value) {
1078						console.error('制限値の取得に失敗。argument=' + argument);
1079						return true;
1080					}
1081					
1082					if (target.files[0].size <= value) return true;
1083					
1084					let fixedArgument = value.toString();
1085					if (value / Math.pow(1024, 2) > 1.0) {
1086						fixedArgument = (value / Math.pow(1024, 2)).toFixed(2).toString() + 'メガ';
1087					} 
1088					else if (value / Math.pow(1024, 1) > 1.0) {
1089						fixedArgument = (value / Math.pow(1024, 1)).toFixed(2).toString() + 'キロ';
1090					} 
1091					
1092					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, fixedArgument) );
1093					return false;
1094				}
1095			},
1096			ByteMin: {
1097				Key: "file-byte-min",
1098				Validate: function(target) {
1099					if (!target) return true;
1100					if (!target.dataset['efoByteMin']) return true;
1101					if (!target.files || target.files.length == 0) {
1102						target.setCustomValidity('');
1103						return true;
1104					}
1105					
1106					const argument = target.dataset['efoByteMin'];
1107					if (argument == '0') return true;
1108					const value = parseInt(argument);
1109					if (!value) {
1110						console.error('制限値の取得に失敗。argument=' + argument);
1111						return true;
1112					}
1113					
1114					if (target.files[0].size >= value) return true;
1115					
1116					let fixedArgument = value.toString();
1117					if (value / Math.pow(1024, 2) > 1.0) {
1118						fixedArgument = (value / Math.pow(1024, 2)).toFixed(2).toString() + 'メガ';
1119					} 
1120					else if (value / Math.pow(1024, 1) > 1.0) {
1121						fixedArgument = (value / Math.pow(1024, 1)).toFixed(2).toString() + 'キロ';
1122					} 
1123					
1124					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key, fixedArgument) );
1125					return false;
1126				}
1127			}
1128		},
1129		// セレクト
1130		Select: {
1131			DateSet: {
1132				Key: 'select-date-set',
1133				Validate: function(target) {
1134					if (!target) return true;
1135					if (!target.dataset['efoDateSet']) return true;
1136					if (!target.dataset['efoItemId']) return true;
1137					
1138					const dateSet = document.querySelectorAll('select[data-efo-item-id="' + target.dataset['efoItemId'] + '"]');
1139					if (!dateSet || dateSet.length != 3) return true;
1140					dateSet[0].setCustomValidity('');
1141					dateSet[1].setCustomValidity('');
1142					dateSet[2].setCustomValidity('');
1143					if (!dateSet[0].value && !dateSet[1].value && !dateSet[2].value) return true;
1144					
1145					const stringYear = dateSet[0].value;
1146					const stringMonth = dateSet[1].value;
1147					const stringDate = dateSet[2].value;
1148					if (!stringYear || !stringMonth || !stringDate) return true;
1149	
1150					const year = parseInt(dateSet[0].value);
1151					const month = parseInt(dateSet[1].value);
1152					const date = parseInt(dateSet[2].value);
1153					if (!year && !month && !date) return true;
1154					
1155					const d = new Date(year, month - 1, date);
1156					if (d.getFullYear() == year &&
1157						d.getMonth() == month - 1 &&
1158						d.getDate() == date
1159					) return true;
1160					
1161					const message = EFOUtil.GetErrorMessage(this.Key);
1162					dateSet[0].setCustomValidity(message);
1163					dateSet[1].setCustomValidity(message);
1164					dateSet[2].setCustomValidity(message);
1165					return false;
1166				}
1167			}
1168		},
1169		// 共通
1170		Common: {
1171			Equal: {
1172				Key: 'equal',
1173				Validate: function(target) {
1174					if (!target) return true;
1175					if (!target.dataset['efoEqual']) return true;
1176					if (!target.value) {
1177						target.setCustomValidity('');
1178						return true;
1179					}
1180					
1181					const argument = target.dataset['efoEqual'];
1182					const equalTo = document.querySelector('[data-efo-item-id="' + argument + '"]');
1183					if (!equalTo) {
1184						console.error('制限値の取得に失敗。argument=' + argument);
1185						return true;
1186					}
1187					
1188					if (target.value == equalTo.value) {
1189						if (equalTo.checkValidityCustom()) {
1190							equalTo.setCustomValidity('');
1191						}
1192						return true;
1193					}
1194					target.setCustomValidity( EFOUtil.GetErrorMessage(this.Key) );
1195					return false;
1196				}
1197			},
1198			DuplicateEmail: {
1199				Key: 'duplicate-email',
1200				Validate: function(target) {
1201					if (!target) return true;
1202					if (!target.dataset['efoValidate']) return true;
1203					if (target.dataset['efoValidate'] != this.Key) return true;
1204					if (!target.value) {
1205						target.setCustomValidity('');
1206						return true;
1207					}
1208					
1209					let result = true.toString();
1210					EFOAPI.ValidateDuplicateEmail(target.value)
1211					.done(function(data) {
1212						if (!data) return;
1213						result = data.result;
1214						if (data.message) {
1215							target.setCustomValidity( data.message );
1216						}
1217					})
1218					.fail(function() {
1219						result = true;
1220					})
1221					
1222					return (result == true.toString());
1223				}
1224			},
1225			
1226			Password: {
1227				Key: "password",
1228				Validate: function(target) {
1229					if (!target) return true;
1230					if (!target.dataset['efoValidate']) return true;
1231					if (target.dataset['efoValidate'] != this.Key) return true;
1232					if (!target.value) {
1233						target.setCustomValidity('');
1234						return true;
1235					}
1236					
1237					let result = true;
1238					EFOAPI.ValidatePassword(target.value)
1239					.done(function(data) {
1240						if (!data) return;
1241						result = data.result;
1242						if (data.message) {
1243							target.setCustomValidity( data.message );
1244						}
1245					})
1246					.fail(function() {
1247						result = true;
1248					})
1249					;
1250					
1251					return result;
1252				}
1253			}
1254		}
1255	};
1256	
1257	const EFOAutoInput = {
1258		Katakana: {
1259			Key: 'furigana-katakana',
1260			Set: function(target) {
1261				if (EFOBrowserSupport.IsMacintosh) return true;
1262				if (!target) return true;
1263				if (!target.dataset['efoAutoinputType']) return true;
1264				if (target.dataset['efoAutoinputType'] != this.Key) return true;
1265				
1266				if (!target.dataset['efoAutoinputTarget']) return true;
1267				const selector = target.dataset['efoAutoinputTarget'];
1268				const furigana = document.querySelector(selector);
1269				if (!furigana) {
1270					console.error('フリガナ入力先の取得に失敗。selector=' + selector);
1271					return true;
1272				}
1273				
1274				autoKana(target, furigana, { 'katakana' : true });
1275			}
1276		},
1277		Hiragana: {
1278			Key: 'furigana-hiragana',
1279			Set: function(target) {
1280				if (EFOBrowserSupport.IsMacintosh) return true;
1281				if (!target) return true;
1282				if (!target.dataset['efoAutoinputType']) return true;
1283				if (target.dataset['efoAutoinputType'] != this.Key) return true;
1284				
1285				if (!target.dataset['efoAutoinputTarget']) return true;
1286				const selector = target.dataset['efoAutoinputTarget'];
1287				const furigana = document.querySelector(selector);
1288				if (!furigana) {
1289					console.error('ふりがな入力先の取得に失敗。selector=' + selector);
1290					return true;
1291				}
1292				
1293				autoKana(target, furigana, { 'katakana' : false });
1294			}
1295		},
1296		Address: {
1297			Key: "address",
1298			Set: function(target) {
1299				if (!target) return true;
1300				if (!target.dataset['efoAutoinputType']) return true;
1301				if (target.dataset['efoAutoinputType'] != this.Key) return true;
1302				
1303				if (!target.dataset['efoAutoinputTarget']) return true;
1304				
1305				const addressTargets = new Array();
1306				const selectors = target.dataset['efoAutoinputTarget'];
1307				selectors.split(',').forEach(function(selector) {
1308					const addressTarget = document.querySelector(selector.trim());
1309					if (!addressTarget) {
1310						console.error('入力先の取得に失敗。selector=' + selector)
1311						return;
1312					}
1313					addressTargets.push( addressTarget );
1314				});
1315				
1316				let focusTarget = null;
1317				[ 'input', 'efo_convert' ].forEach(function(event) {
1318				
1319					target.addEventListener(event, function() {
1320						
1321						focusTarget = null;
1322						const zip = target.value.replace('-', '');
1323						if (zip.length != 7) return;
1324						
1325						EFOAPI.GetAddress(zip)
1326						.done(function(data) {
1327							if (!data) return;
1328							if (!data[zip]) return;
1329							
1330							// 値を設定
1331							if (addressTargets[0] && data[zip].pref)
1332								addressTargets[0].value = data[zip].pref;
1333							
1334							if (addressTargets[1] && data[zip].addr)
1335								addressTargets[1].value = data[zip].addr;
1336							
1337							if (addressTargets[2] && data[zip].addr2)
1338								addressTargets[2].value = data[zip].addr2;
1339							
1340							// 設定したフィールドにフォーカス
1341							if (addressTargets[2] && data[zip].addr2) {
1342								focusTarget = addressTargets[2];
1343								return;
1344							}
1345							if (addressTargets[1] && data[zip].addr) {
1346								focusTarget = addressTargets[1];
1347								return;
1348							}
1349							if (addressTargets[0] && data[zip].pref) {
1350								focusTarget = addressTargets[0];
1351								return;
1352							}
1353						});
1354						
1355					});
1356				});
1357				target.addEventListener('blur', function() {
1358					if (focusTarget) {
1359						focusTarget.focus();
1360						focusTarget = null;
1361					}
1362				});
1363			}
1364		}
1365	};
1366
1367})();
1368
1369const EFOTooltip = {
1370	_instance : null,
1371	_tap_count : 0,
1372	Show : function(target, message) {
1373		
1374		if (this._instance) {
1375			if (this._instance instanceof Tooltip)
1376				this._instance.dispose();
1377			else
1378				this._instance = null;
1379		}
1380		
1381		this._instance = new Tooltip(target, { title : message, trigger : 'manual' });
1382		this._instance.show();
1383		
1384		if (this._instance._tooltipNode) {
1385			// ダブルクリックで隠す
1386			this._instance._tooltipNode.addEventListener('dblclick', function() {
1387				if (EFOTooltip._instance._isOpen) {
1388					EFOTooltip._instance.hide();
1389				}
1390			});
1391			
1392			// ダブルタップで隠す
1393			this._instance._tooltipNode.addEventListener('touchstart', function() {
1394				
1395				if (!EFOTooltip._tap_count) {
1396					++EFOTooltip._tap_count;
1397					setTimeout(function() {
1398						EFOTooltip._tap_count = 0;
1399					}, 500);
1400				} else {
1401					if (EFOTooltip._instance._isOpen) {
1402						EFOTooltip._instance.hide();
1403						EFOTooltip._tap_count = 0;
1404					}
1405				}
1406				
1407			});
1408		}
1409	}
1410};
1411
1412
1413/*\
1414 |*|  based on
1415 |*|  :: cookies.js ::
1416 |*|
1417 |*|  A complete cookies reader/writer framework with full unicode support.
1418 |*|  https://developer.mozilla.org/en-US/docs/DOM/document.cookie
1419 |*|
1420 |*|  Syntaxes:
1421 |*|  * EFOCookie.SetItem(name, value[, end[, path[, domain[, secure]]]])
1422 |*|  * EFOCookie.GetItem(name)
1423 |*|  * EFOCookie.RemoveItem(name[, path])
1424 |*|  * EFOCookie.HasItem(name)
1425 |*|  * EFOCookie.Keys()
1426 |*|
1427 \*/
1428const EFOCookie = {
1429	GetItem: function (sKey) {
1430		if (!sKey || !this.HasItem(sKey)) { return null; }
1431		return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1"));
1432	},
1433	SetItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
1434		if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return; }
1435		var sExpires = "";
1436		if (vEnd) {
1437			switch (vEnd.constructor) {
1438				case Number:
1439					sExpires = vEnd === Infinity ? "; expires=Tue, 19 Jan 2038 03:14:07 GMT" : "; max-age=" + vEnd;
1440					break;
1441				case String:
1442					sExpires = "; expires=" + vEnd;
1443					break;
1444				case Date:
1445					sExpires = "; expires=" + vEnd.toGMTString();
1446					break;
1447			}
1448		}
1449		document.cookie = escape(sKey) + "=" + escape(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
1450	},
1451	RemoveItem: function (sKey, sPath) {
1452		if (!sKey || !this.HasItem(sKey)) { return; }
1453		document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sPath ? "; path=" + sPath : "");
1454	},
1455	HasItem: function (sKey) {
1456		return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
1457	},
1458	Keys: /* optional method: you can safely remove it! */ function () {
1459		var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
1460		for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = unescape(aKeys[nIdx]); }
1461		return aKeys;
1462	}
1463};
1464

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.