PageSourceSearch

https://www.joinnow.com.tw/js/jquery.twzipcode.js

js joinnow.com.tw collected 2026-10-06 13:28:12 UTC 25,242 bytes, 560 lines download raw bytes

1/**
2 * jQuery TWzipcode plugin
3 * https://app.essoduke.org/twzipcode/
4 * Copyright 2015 essoduke.org, Licensed MIT.
5 *
6 * Changelog
7 * -------------------------------
8 * 新增 get 方法,可取得元素 DOM。
9 * 取消 onCountySelect, onDistrictSelect, onZipcodeKeyUp 返回的參數,this 即為元素本身。
10 *
11 * @author essoduke.org
12 * @version 1.7.3
13 * @license MIT License
14 */
15;(function ($, window, document, undefined) {
16
17    'use strict';
18
19    // Zipcode JSON data
20    var data = {
21        '基隆市': {'仁愛區': '200', '信義區': '201', '中正區': '202', '中山區': '203', '安樂區': '204', '暖暖區': '205', '七堵區': '206'},
22        '台北市': {'中正區': '100', '大同區': '103', '中山區': '104', '松山區': '105', '大安區': '106', '萬華區': '108', '信義區': '110', '士林區': '111', '北投區': '112', '內湖區': '114', '南港區': '115', '文山區': '116'},
23        '新北市': {
24          '萬里區': '207', '金山區': '208', '板橋區': '220', '汐止區': '221', '深坑區': '222', '石碇區': '223',
25          '瑞芳區': '224', '平溪區': '226', '雙溪區': '227', '貢寮區': '228', '新店區': '231', '坪林區': '232',
26          '烏來區': '233', '永和區': '234', '中和區': '235', '土城區': '236', '三峽區': '237', '樹林區': '238',
27          '鶯歌區': '239', '三重區': '241', '新莊區': '242', '泰山區': '243', '林口區': '244', '蘆洲區': '247',
28          '五股區': '248', '八里區': '249', '淡水區': '251', '三芝區': '252', '石門區': '253'
29        },
30        '宜蘭縣': {
31          '宜蘭市': '260', '頭城鎮': '261', '礁溪鄉': '262', '壯圍鄉': '263', '員山鄉': '264', '羅東鎮': '265',
32          '三星鄉': '266', '大同鄉': '267', '五結鄉': '268', '冬山鄉': '269', '蘇澳鎮': '270', '南澳鄉': '272',
33          '釣魚台列嶼': '290'
34        },
35        '新竹市': {'東區': '300', '北區': '300', '香山區': '300'},
36        '新竹縣': {
37          '竹北市': '302', '湖口鄉': '303', '新豐鄉': '304', '新埔鎮': '305', '關西鎮': '306', '芎林鄉': '307',
38          '寶山鄉': '308', '竹東鎮': '310', '五峰鄉': '311', '橫山鄉': '312', '尖石鄉': '313', '北埔鄉': '314',
39          '峨嵋鄉': '315'
40        },
41        '桃園市': {
42          '中壢區': '320', '平鎮區': '324', '龍潭區': '325', '楊梅區': '326', '新屋區': '327', '觀音區': '328',
43          '桃園區': '330', '龜山區': '333', '八德區': '334', '大溪區': '335', '復興區': '336', '大園區': '337',
44          '蘆竹區': '338'
45        },
46        '苗栗縣': {
47          '竹南鎮': '350', '頭份市': '351', '三灣鄉': '352', '南庄鄉': '353', '獅潭鄉': '354', '後龍鎮': '356',
48          '通霄鎮': '357', '苑裡鎮': '358', '苗栗市': '360', '造橋鄉': '361', '頭屋鄉': '362', '公館鄉': '363',
49          '大湖鄉': '364', '泰安鄉': '365', '銅鑼鄉': '366', '三義鄉': '367', '西湖鄉': '368', '卓蘭鎮': '369'
50        },
51        '台中市': {
52          '中區': '400', '東區': '401', '南區': '402', '西區': '403', '北區': '404', '北屯區': '406', '西屯區': '407', '南屯區': '408',
53          '太平區': '411', '大里區': '412', '霧峰區': '413', '烏日區': '414', '豐原區': '420', '后里區': '421',
54          '石岡區': '422', '東勢區': '423', '和平區': '424', '新社區': '426', '潭子區': '427', '大雅區': '428',
55          '神岡區': '429', '大肚區': '432', '沙鹿區': '433', '龍井區': '434', '梧棲區': '435', '清水區': '436',
56          '大甲區': '437', '外埔區': '438', '大安區': '439'
57        },
58        '彰化縣': {
59          '彰化市': '500', '芬園鄉': '502', '花壇鄉': '503', '秀水鄉': '504', '鹿港鎮': '505', '福興鄉': '506',
60          '線西鄉': '507', '和美鎮': '508', '伸港鄉': '509', '員林市': '510', '社頭鄉': '511', '永靖鄉': '512',
61          '埔心鄉': '513', '溪湖鎮': '514', '大村鄉': '515', '埔鹽鄉': '516', '田中鎮': '520', '北斗鎮': '521',
62          '田尾鄉': '522', '埤頭鄉': '523', '溪州鄉': '524', '竹塘鄉': '525', '二林鎮': '526', '大城鄉': '527',
63          '芳苑鄉': '528', '二水鄉': '530'
64        },
65        '南投縣': {
66          '南投市': '540', '中寮鄉': '541', '草屯鎮': '542', '國姓鄉': '544', '埔里鎮': '545', '仁愛鄉': '546',
67          '名間鄉': '551', '集集鎮': '552', '水里鄉': '553', '魚池鄉': '555', '信義鄉': '556', '竹山鎮': '557',
68          '鹿谷鄉': '558'
69        },
70        '嘉義市': {'東區': '600', '西區': '600'},
71        '嘉義縣': {
72          '番路鄉': '602', '梅山鄉': '603', '竹崎鄉': '604', '阿里山': '605', '中埔鄉': '606', '大埔鄉': '607',
73          '水上鄉': '608', '鹿草鄉': '611', '太保市': '612', '朴子市': '613', '東石鄉': '614', '六腳鄉': '615',
74          '新港鄉': '616', '民雄鄉': '621', '大林鎮': '622', '溪口鄉': '623', '義竹鄉': '624', '布袋鎮': '625'
75        },
76        '雲林縣': {
77          '斗南鎮': '630', '大埤鄉': '631', '虎尾鎮': '632', '土庫鎮': '633', '褒忠鄉': '634', '東勢鄉': '635',
78          '臺西鄉': '636', '崙背鄉': '637', '麥寮鄉': '638', '斗六市': '640', '林內鄉': '643', '古坑鄉': '646',
79          '莿桐鄉': '647', '西螺鎮': '648', '二崙鄉': '649', '北港鎮': '651', '水林鄉': '652', '口湖鄉': '653',
80          '四湖鄉': '654', '元長鄉': '655'
81        },
82        '台南市': {
83          '中西區': '700', '東區': '701', '南區': '702', '北區': '704', '安å¹
vendor: 19,543 bytes, lines 83-560
83³å€': '708', '安南區': '709',
84          '永康區': '710', '歸仁區': '711', '新化區': '712', '左鎮區': '713', '玉井區': '714', '楠西區': '715',
85          '南化區': '716', '仁德區': '717', '關廟區': '718', '龍崎區': '719', '官田區': '720', '麻豆區': '721',
86          '佳里區': '722', '西港區': '723', '七股區': '724', '將軍區': '725', '學甲區': '726', '北門區': '727',
87          '新營區': '730', '後壁區': '731', '白河區': '732', '東山區': '733', '六甲區': '734', '下營區': '735',
88          '柳營區': '736', '鹽水區': '737', '善化區': '741', '大內區': '742', '山上區': '743', '新市區': '744',
89          '安定區': '745'
90        },
91        '高雄市': {
92          '新興區': '800', '前金區': '801', '苓雅區': '802', '鹽埕區': '803', '鼓山區': '804', '旗津區': '805',
93          '前鎮區': '806', '三民區': '807', '楠梓區': '811', '小港區': '812', '左營區': '813',
94          '仁武區': '814', '大社區': '815', '岡山區': '820', '路竹區': '821', '阿蓮區': '822', '田寮區': '823',
95          '燕巢區': '824', '橋頭區': '825', '梓官區': '826', '彌陀區': '827', '永安區': '828', '湖內區': '829',
96          '鳳山區': '830', '大寮區': '831', '林園區': '832', '鳥松區': '833', '大樹區': '840', '旗山區': '842',
97          '美濃區': '843', '六龜區': '844', '內門區': '845', '杉林區': '846', '甲仙區': '847', '桃源區': '848',
98          '那瑪夏區': '849', '茂林區': '851', '茄萣區': '852'
99        },
100        '屏東縣': {
101          '屏東市': '900', '三地門': '901', '霧臺鄉': '902', '瑪家鄉': '903', '九如鄉': '904', '里港鄉': '905',
102          '高樹鄉': '906', '鹽埔鄉': '907', '長治鄉': '908', '麟洛鄉': '909', '竹田鄉': '911', '內埔鄉': '912',
103          '萬丹鄉': '913', '潮州鎮': '920', '泰武鄉': '921', '來義鄉': '922', '萬巒鄉': '923', '崁頂鄉': '924',
104          '新埤鄉': '925', '南州鄉': '926', '林邊鄉': '927', '東港鎮': '928', '琉球鄉': '929', '佳冬鄉': '931',
105          '新園鄉': '932', '枋寮鄉': '940', '枋山鄉': '941', '春日鄉': '942', '獅子鄉': '943', '車城鄉': '944',
106          '牡丹鄉': '945', '恆春鎮': '946', '滿州鄉': '947'
107        },
108        '台東縣': {
109          '臺東市': '950', '綠島鄉': '951', '蘭嶼鄉': '952', '延平鄉': '953', '卑南鄉': '954', '鹿野鄉': '955',
110          '關山鎮': '956', '海端鄉': '957', '池上鄉': '958', '東河鄉': '959', '成功鎮': '961', '長濱鄉': '962',
111          '太麻里鄉': '963', '金峰鄉': '964', '大武鄉': '965', '達仁鄉': '966'
112        },
113        '花蓮縣': {
114          '花蓮市': '970', '新城鄉': '971', '秀林鄉': '972', '吉安鄉': '973', '壽豐鄉': '974', '鳳林鎮': '975',
115          '光復鄉': '976', '豐濱鄉': '977', '瑞穗鄉': '978', '萬榮鄉': '979', '玉里鎮': '981', '卓溪鄉': '982',
116          '富里鄉': '983'
117        },
118        '金門縣': {'金沙鎮': '890', '金湖鎮': '891', '金寧鄉': '892', '金城鎮': '893', '烈嶼鄉': '894', '烏坵鄉': '896'},
119        '連江縣': {'南竿鄉': '209', '北竿鄉': '210', '莒光鄉': '211', '東引鄉': '212'},
120        '澎湖縣': {'馬公市': '880', '西嶼鄉': '881', '望安鄉': '882', '七美鄉': '883', '白沙鄉': '884', '湖西鄉': '885'},
121        '南海諸島': {'東沙': '817', '南沙': '819'},
122        '其他': {}
123
124    };
125    /**
126     * twzipcode Constructor
127     * @param {Object} container HTML element
128     * @param {(Object|string)} options User settings
129     * @constructor
130     */
131    function TWzipcode (container, options) {
132        /**
133         * Default settings
134         * @type {Object}
135         */
136        var defaults = {
137            'countyName': 'county',
138            'countySel': '',
139            'css': [],
140            'detect': false,             // v1.6.7
141            'districtName': 'district',
142            'districtSel': '',
143            'onCountySelect': null,      // v1.5
144            'onDistrictSelect': null,    // v1.5
145            'onZipcodeKeyUp': null,      // v1.5
146            'readonly': false,
147            'zipcodeName': 'zipcode',
148            'zipcodeSel': '',
149            'zipcodeIntoDistrict': false, // v1.6.6
150            'googleMapsKey': '' // v1.6.9
151        };
152        /**
153         * DOM of selector
154         * @type {Object}
155         */
156        this.container = $(container);
157        /**
158         * Merge the options
159         * @type {Object}
160         */
161        this.options = $.extend({}, defaults, options);
162        // initialize
163        this.init();
164    }
165    /**
166     * TWzipcode prototype
167     */
168    TWzipcode.prototype = {
169
170        VERSION: '1.7.3',
171
172        /**
173         * Method: Get all post data
174         * @return {Object}
175         */
176        data: function () {
177            var wrap = this.wrap;
178            return 'undefined' !== typeof data[wrap.county.val()] ?
179                   data[wrap.county.val()] :
180                   data;
181        },
182        /**
183         * Method: Serialize the data
184         * @return {string}
185         */
186        serialize: function () {
187            var result = [],
188                obj = {},
189                ele = {},
190                s = {};
191            obj = this.container.find('select,input');
192            if (obj.length) {
193                obj.each(function () {
194                    ele = $(this);
195                    result.push(ele.attr('name') + '=' + ele.val());
196                });
197            } else {
198                $(this).children().each(function () {
199                    s = $(this);
200                    result.push(s.attr('name') + '=' + s.val());
201                });
202            }
203            return result.join('&');
204        },
205        /**
206         * Method: Destroy the container.
207         * @this {TWzipcode}
208         */
209        destroy: function () {
210            $.data(this.container.get(0), 'twzipcode', null);
211            if (this.container.length) {
212                return this.container.empty().off('change.twzipcode keyup.twzipcode blur.twzipcode');
213            }
214        },
215        /**
216         * Method: Get elements of instance
217         * @param {(string|Array)} opts Type name
218         * @param {Function} callback Function callback
219         */
220        get: function (callback) {
221            if ('function' === typeof callback) {
222                callback.call(this, this.wrap);
223            } else {
224                return this.wrap;
225            }
226        },
227        /**
228         * Method: Set value for elements.
229         * @param {(string|number|Object)} opts Input value
230         */
231        set: function (opts) {
232
233            var self = this,
234                def = {
235                    'county': '',
236                    'district': '',
237                    'zipcode': ''
238                },
239                opt = $.extend({}, def, opts);
240
241            try {
242                if ('string' === typeof opts || 'number' === typeof opts) {
243                    self.wrap.zipcode.val(opts).trigger('blur.twzipcode');
244                } else {
245                    if (opt.zipcode) {
246                        self.wrap.zipcode.val(opt.zipcode).trigger('blur.twzipcode');
247                    }
248                    if (opt.county) {
249                        self.wrap.county.val(opt.county).trigger('change.twzipcode');
250                    }
251                    if (opt.district) {
252                        self.wrap.district.val(opt.district).trigger('change.twzipcode');
253                    }
254                }
255            } catch (ignore) {
256                console.warn(ignore.message);
257            } finally {
258                return self.container;
259            }
260        },
261        /**
262         * Method: Reset the selected items to default.
263         * @this {TWzipcode}
264         */
265        reset: function (container, obj) {
266            var self = this,
267                wrap = self.wrap,
268                county = '',
269                list = {
270                    'county': '<option value="">縣市</option>',
271                    'district': '<option value="">鄉鎮市區</option>'
272                },
273                tpl = [];
274
275            switch (obj) {
276            case 'district':
277                wrap.district.html(list.district);
278                break;
279            default:
280                wrap.county.html(list.county);
281                wrap.district.html(list.district);
282                for (county in data) {
283                    if ('undefined' !== typeof data[county]) {
284                        tpl.push('<option value="' + county + '">' + county + '</option>');
285                    }
286                }
287                $(tpl.join('')).appendTo(wrap.county);
288                break;
289            }
290            wrap.zipcode.val('');
291        },
292        /**
293         * Binding the event of the elements
294         * @this {TWzipcode}
295         */
296        bindings: function () {
297
298            var self = this,
299                opts = self.options,
300                wrap = self.wrap,
301                dz   = '',
302                dc   = '',
303                dd   = '';
304
305            // county
306            wrap.county.on('change.twzipcode', function () {
307                var val = $(this).val(),
308                    district = '',
309                    tpl = [];
310
311                wrap.district.empty();
312
313                if (val) {
314                    if (true === opts.zipcodeIntoDistrict) {
315                        for (district in data[val]) {
316                            if ('undefined' !== typeof data[val][district]) {
317                                tpl.push('<option value="' + district + '">');
318                                tpl.push(data[val][district] + ' ' + district);
319                                tpl.push('</option>');
320                            }
321                        }
322                    } else {
323                        for (district in data[val]) {
324                            if ('undefined' !== typeof data[val][district]) {
325                                tpl.push('<option value="' + district + '">');
326                                tpl.push(district);
327                                tpl.push('</option>');
328                            }
329                        }
330                    }
331                    wrap.district.append(tpl.join('')).trigger('change.twzipcode');
332                } else {
333                    wrap.county.find('option:first').prop('selected', true);
334                    self.reset('district');
335                }
336                // County callback binding
337                if ('function' === typeof opts.onCountySelect) {
338                    opts.onCountySelect.call(this);
339                }
340            });
341            // District
342            wrap.district.on('change.twzipcode', function () {
343                var val = $(this).val();
344                if (wrap.county.val()) {
345                    wrap.zipcode.val(data[wrap.county.val()][val]);
346                }
347                // District callback binding
348                if ('function' === typeof opts.onDistrictSelect) {
349                    opts.onDistrictSelect.call(this);
350                }
351            });
352            // Zipcode
353            wrap.zipcode.on('keyup.twzipcode blur.twzipcode', function () {
354                var obj = $(this),
355                    val = '',
356                    i   = '',
357                    j   = '';
358                obj.val(obj.val().replace(/[^0-9]/g, ''));
359                val = obj.val().toString();
360
361                if (true !== opts.readonly) {
362                    if (3 === val.length) {
363                        for (i in data) {
364                            if ('undefined' !== typeof data[i]) {
365                                for (j in data[i]) {
366                                    if ('undefined' !== typeof data[i][j] &&
367                                        val === data[i][j]
368                                    ) {
369                                        wrap.county.val(i).trigger('change.twzipcode');
370                                        wrap.district.val(j).trigger('change.twzipcode');
371                                        break;
372                                    }
373                                }
374                            }
375                        }
376                    }
377                }
378                // Zipcode callback binding
379                if ('function' === typeof opts.onZipcodeKeyUp) {
380                    opts.onZipcodeKeyUp.call(this);
381                }
382            });
383
384            dz = 'undefined' !== typeof opts.zipcodeSel ?
385                 opts.zipcodeSel :
386                 (
387                    'undefined' !== typeof self.role.zipcode.data('value') ?
388                    self.role.zipcode.data('value') :
389                    opts.zipcodeSel
390                 );
391
392            dc = 'undefined' !== typeof opts.countySel ?
393                 opts.countySel :
394                 (
395                    'undefined' !== typeof self.role.county.data('value') ?
396                    self.role.county.data('value') :
397                    opts.countySel
398                 );
399
400            dd = 'undefined' !== typeof opts.districtSel ?
401                 opts.districtSel :
402                 (
403                    'undefined' !== typeof self.role.district.data('value') ?
404                    self.role.district.data('value') :
405                    opts.districtSel
406                 );
407
408            // Default value
409            if (dc) {
410                self.wrap.county.val(dc).trigger('change.twzipcode');
411                if ('undefined' !== typeof data[dc][dd]) {
412                    self.wrap.district.val(dd).trigger('change.twzipcode');
413                }
414            }
415            if (dz && 3 === dz.toString().length) {
416                self.wrap.zipcode.val(dz).trigger('blur.twzipcode');
417            }
418        },
419        /**
420         * Geolocation detect
421         * @this {TWzipcode}
422         */
423        geoLocation: function () {
424			var self = this,
425                geolocation = navigator.geolocation,
426                options = {
427                    'maximumAge': 600000,
428                    'timeout': 3000,
429                    'enableHighAccuracy': false
430                },
431                opts = self.options;
432
433            if (!geolocation) {
434                return;
435            }
436
437            geolocation.getCurrentPosition(
438                function (loc) {
439                    var latlng = {};
440                    if (('coords' in loc) &&
441                        ('latitude' in loc.coords) &&
442                        ('longitude' in loc.coords)
443                    ) {
444                        latlng = [loc.coords.latitude, loc.coords.longitude];
445                        $.getJSON(
446                            'https://maps.googleapis.com/maps/api/geocode/json',
447                            {
448                                'key': opts.googleMapsKey,
449                                'sensor': false,
450                                'latlng': latlng.join(',')
451                            },
452                            function (data) {
453                                var postal = '';
454                                if (data &&
455                                    'undefined' !== typeof data.results &&
456                                    'undefined' !== typeof data.results[0].address_components &&
457                                    'undefined' !== typeof data.results[0].address_components[0]
458                                ) {
459                                    postal = data.results[0]
460                                                 .address_components[data.results[0].address_components.length - 1]
461                                                 .long_name;
462                                    if (postal) {
463                                        self.wrap.zipcode.val(postal.toString()).trigger('blur.twzipcode');
464                                    }
465                                }
466                            });
467                    }
468                },
469                function (error) {
470                    console.error(error);
471                },
472                options
473            );
474        },
475        /**
476         * twzipcode Initialize
477         * @this {TWzipcode}
478         */
479        init: function () {
480
481            var self = this,
482                container = self.container,
483                opts = self.options,
484                role = {
485                    county: container.find('[data-role=county]:first'),
486                    district: container.find('[data-role=district]:first'),
487                    zipcode: container.find('[data-role=zipcode]:first')
488                },
489                countyName = role.county.data('name') || opts.countyName,
490                districtName = role.district.data('name') || opts.districtName,
491                zipcodeName = role.zipcode.data('name') || opts.zipcodeName,
492                readonly = role.zipcode.data('readonly') || opts.readonly;
493
494            // Elements create
495            $('<select/>')
496                .attr('name', countyName)
497                .addClass(role.county.data('style') || ('undefined' !== typeof opts.css[0] ? opts.css[0] : ''))
498                .appendTo(role.county.length ? role.county : container);
499
500            $('<select/>')
501                .attr('name', districtName)
502                .addClass(role.district.data('style') || ('undefined' !== typeof opts.css[1] ? opts.css[1] : ''))
503                .appendTo(role.district.length ? role.district : container);
504
505            $('<input/>')
506                .attr({'type': 'text', 'name': zipcodeName})
507                .prop('readonly', readonly)
508                .addClass(role.zipcode.data('style') || ('undefined' !== typeof opts.css[2] ? opts.css[2] : ''))
509                .appendTo(role.zipcode.length ? role.zipcode : container);
510
511            self.wrap = {
512                'county': container.find('select[name="' + countyName + '"]:first'),
513                'district': container.find('select[name="' + districtName + '"]:first'),
514                'zipcode': container.find('input[type=text][name="' + zipcodeName + '"]:first')
515            };
516
517            if (true === opts.zipcodeIntoDistrict) {
518                self.wrap.zipcode.hide();
519            }
520
521            self.role = role;
522            // Reset the elements
523            self.reset();
524            // Elements events binding
525            self.bindings();
526            // Geolocation
527            if (true === opts.detect) {
528                self.geoLocation();
529            }
530        }
531    };
532    /**
533     * jQuery twzipcode instance
534     * @param {Object} options Plugin settings
535     * @public
536     */
537    $.fn.twzipcode = function (options) {
538        var instance = {},
539            result = [],
540            args = arguments,
541            id  = 'twzipcode';
542        if ('string' === typeof options) {
543            this.each(function () {
544                instance = $.data(this, id);
545                if (instance instanceof TWzipcode && 'function' === typeof instance[options]) {
546                    result = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
547                }
548            });
549            return 'undefined' !== typeof result ? result : this;
550        } else {
551            return this.each(function () {
552                if (!$.data(this, id)) {
553                    $.data(this, id, new TWzipcode(this, options));
554                }
555            });
556        }
557    };
558
559})(window.jQuery || {}, window, document);
560//#EOF

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.