PageSourceSearch

https://classycg.com/static/js/aten/email_mailcheck.js?1790861606

js classycg.com collected 2026-10-08 06:19:41 UTC 4,219 bytes, 141 lines download raw bytes

1// Email typo 即時糾正:使用者填完 email 欄位後,若網域疑似拼錯
2// 就在欄位下方提示「你是不是要打 [email protected]?」,點一下即可套用。
3// 純前端拼字距離 + 白名單,不查 DNS、非阻擋性。
4// KNOWN 清單須與後端 email_helper.php 的 email_common_domains() 一致。
5(function()
6{
7	if(!window.jQuery)					return;
8	var $								= window.jQuery;
9
10	var KNOWN = [
11		'gmail.com', 'yahoo.com', 'yahoo.com.tw', 'hotmail.com', 'outlook.com',
12		'live.com', 'msn.com', 'icloud.com', 'me.com', 'aol.com',
13		'pchome.com.tw', 'seed.net.tw', 'so-net.net.tw', 'url.com.tw',
14		'proton.me', 'protonmail.com', 'qq.com', '163.com', 'naver.com'
15	];
16	var TRUSTED_SUFFIX = ['hinet.net'];
17
18	// 合法的區域型網域(各國 Yahoo/Hotmail 等),絕不更正。
19	// 須與後端 email_helper.php 的 email_valid_regional_domains() 一致。
20	var TRUSTED_EXACT = [
21		'yahoo.com.hk', 'yahoo.com.my', 'yahoo.com.sg', 'yahoo.com.cn',
22		'yahoo.com.vn', 'yahoo.com.ph', 'yahoo.com.au', 'yahoo.com.br',
23		'yahoo.com.mx', 'yahoo.co.jp', 'yahoo.co.uk', 'yahoo.co.in',
24		'yahoo.co.id', 'yahoo.co.th', 'yahoo.co.kr', 'yahoo.co.nz',
25		'yahoo.fr', 'yahoo.de', 'yahoo.es', 'yahoo.it', 'yahoo.ca',
26		'ymail.com', 'rocketmail.com', 'kimo.com.tw', 'myyahoo.com',
27		'hotmail.co.uk', 'hotmail.fr', 'hotmail.de', 'hotmail.it',
28		'hotmail.es', 'hotmail.com.br', 'hotmail.com.au', 'hotmail.com.mx',
29		'outlook.com.au', 'outlook.jp', 'outlook.fr', 'outlook.de',
30		'live.com.au', 'live.co.uk', 'live.hk', 'live.jp', 'live.cn'
31	];
32
33	function lev(a, b)
34	{
35		var m = a.length, n = b.length;
36		if(!m) return n;
37		if(!n) return m;
38		var d = [], i, j;
39		for(i = 0; i <= m; i++)			d[i] = [i];
40		for(j = 0; j <= n; j++)			d[0][j] = j;
41		for(i = 1; i <= m; i++)
42		{
43			for(j = 1; j <= n; j++)
44			{
45				var c = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
46				d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + c);
47			}
48		}
49		return d[m][n];
50	}
51
52	function suggest(email)
53	{
54		email = $.trim(email || '');
55		var at = email.lastIndexOf('@');
56		if(at <= 0)						return null;
57
58		var local = email.slice(0, at);
59		var domain = email.slice(at + 1).toLowerCase();
60		if(!domain)						return null;
61
62		var i;
63		for(i = 0; i < TRUSTED_SUFFIX.length; i++)
64		{
65			var s = TRUSTED_SUFFIX[i];
66			if(domain === s || domain.slice(-(s.length + 1)) === '.' + s)
67				return null;
68		}
69		if($.inArray(domain, TRUSTED_EXACT) >= 0)	return null;
70		if($.inArray(domain, KNOWN) >= 0)	return null;
71
72		// 多打 .tw(gmail.com.tw → gmail.com)
73		if(domain.slice(-3) === '.tw')
74		{
75			var st = domain.slice(0, -3);
76			if($.inArray(st, KNOWN) >= 0)	return local + '@' + st;
77		}
78
79		var best = null, bd = 1e9;
80		for(i = 0; i < KNOWN.length; i++)
81		{
82			var dd = lev(domain, KNOWN[i]);
83			if(dd < bd) { bd = dd; best = KNOWN[i]; }
84		}
85
86		var thr = domain.length <= 5 ? 1 : 2;
87		if(best === null || bd === 0 || bd > thr)	return null;
88
89		return local + '@' + best;
90	}
91	window.suggestEmailCorrection = suggest;
92
93	function esc(str)
94	{
95		return $('<span>').text(str).html();
96	}
97
98	function render($input)
99	{
100		var sug = suggest($input.val());
101		var $box = $input.data('typoBox');
102		if(!sug)
103		{
104			if($box) $box.hide();
105			return;
106		}
107		if(!$box)
108		{
109			$box = $('<div class="email-typo-suggest" style="margin-top:6px;font-size:14px;color:#c0392b;"></div>');
110			$input.after($box);
111			$input.data('typoBox', $box);
112		}
113		$box.html(t('Did you mean %s?', '<a href="#" class="email-typo-apply" style="font-weight:bold;color:#2980b9;text-decoration:underline;">' + esc(sug) + '</a>')).show();
114		$box.data('sug', sug);
115	}
116
117	var SEL = 'input[type=email], input[name="email"]';
118
119	$(function()
120	{
121		$(document).on('blur change', SEL, function()
122		{
123			render($(this));
124		});
125		$(document).on('input', SEL, function()
126		{
127			var $b = $(this).data('typoBox');
128			if($b) $b.hide();
129		});
130		$(document).on('click', '.email-typo-apply', function(e)
131		{
132			e.preventDefault();
133			var $box = $(this).closest('.email-typo-suggest');
134			var sug = $box.data('sug');
135			var $input = $box.prev(SEL);
136			if(!$input.length) $input = $box.parent().find(SEL).first();
137			if(sug) $input.val(sug).trigger('change');
138			$box.hide();
139		});
140	});
141})();

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.