city-picker.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*!
  2. * CityPicker v1.2.0
  3. * https://github.com/tshi0912/citypicker
  4. *
  5. * Copyright (c) 2015-2018 Tao Shi
  6. * Released under the MIT license
  7. *
  8. * Date: 2018-04-12T04:27:10.483Z
  9. */
  10. (function (factory) {
  11. if (typeof define === 'function' && define.amd) {
  12. // AMD. Register as anonymous module.
  13. define(['jquery', 'ChineseDistricts'], factory);
  14. } else if (typeof exports === 'object') {
  15. // Node / CommonJS
  16. factory(require('jquery'), require('ChineseDistricts'));
  17. } else {
  18. // Browser globals.
  19. factory(jQuery, ChineseDistricts);
  20. }
  21. })(function ($, ChineseDistricts) {
  22. 'use strict';
  23. if (typeof ChineseDistricts === 'undefined') {
  24. throw new Error('The file "city-picker.data.js" must be included first!');
  25. }
  26. var NAMESPACE = 'citypicker';
  27. var EVENT_CHANGE = 'change.' + NAMESPACE;
  28. var PROVINCE = 'province';
  29. var CITY = 'city';
  30. var DISTRICT = 'district';
  31. function CityPicker(element, options) {
  32. this.$element = $(element);
  33. this.$dropdown = null;
  34. this.options = $.extend({}, CityPicker.DEFAULTS, $.isPlainObject(options) && options);
  35. this.active = false;
  36. this.dems = [];
  37. this.needBlur = false;
  38. this.init();
  39. }
  40. CityPicker.prototype = {
  41. constructor: CityPicker,
  42. init: function () {
  43. this.codeRender();
  44. this.defineDems();
  45. this.render();
  46. this.bind();
  47. this.active = true;
  48. },
  49. codeRender: function(){
  50. var code = this.$element.attr('code');
  51. if(code!==undefined && code !== '' && !isNaN(Number(code))) this.$element.val($.fn.citypicker.getAddressbyCodeId(code));
  52. },
  53. render: function () {
  54. var p = this.getPosition(),
  55. placeholder = this.$element.attr('placeholder') || this.options.placeholder,
  56. textspan = '<span class="city-picker-span" style="' +
  57. this.getWidthStyle(p.width) + 'height:' +
  58. p.height + 'px;line-height:' + (p.height - 1) + 'px;">' +
  59. (placeholder ? '<span class="placeholder">' + placeholder + '</span>' : '') +
  60. '<span class="title"></span><div class="arrow"></div>' + '</span>',
  61. dropdown = '<div class="city-picker-dropdown" style="left:0px;top:100%;' +
  62. this.getWidthStyle(p.width, true) + '">' +
  63. '<div class="city-select-wrap">' +
  64. '<div class="city-select-tab">' +
  65. '<a class="active" data-count="province">省份</a>' +
  66. (this.includeDem('city') ? '<a data-count="city">城市</a>' : '') +
  67. (this.includeDem('district') ? '<a data-count="district">区县</a>' : '') + '</div>' +
  68. '<div class="city-select-content">' +
  69. '<div class="city-select province" data-count="province"></div>' +
  70. (this.includeDem('city') ? '<div class="city-select city" data-count="city"></div>' : '') +
  71. (this.includeDem('district') ? '<div class="city-select district" data-count="district"></div>' : '') +
  72. '</div></div>';
  73. this.$element.addClass('city-picker-input');
  74. this.$textspan = $(textspan).insertAfter(this.$element);
  75. this.$dropdown = $(dropdown).insertAfter(this.$textspan);
  76. var $select = this.$dropdown.find('.city-select');
  77. // setup this.$province, this.$city and/or this.$district object
  78. $.each(this.dems, $.proxy(function (i, type) {
  79. this['$' + type] = $select.filter('.' + type + '');
  80. }, this));
  81. this.refresh();
  82. },
  83. refresh: function (force) {
  84. // clean the data-item for each $select
  85. var $select = this.$dropdown.find('.city-select');
  86. $select.data('item', null);
  87. // parse value from value of the target $element
  88. var val = this.$element.val() || '';
  89. val = val.split('/');
  90. $.each(this.dems, $.proxy(function (i, type) {
  91. if (val[i] && i < val.length) {
  92. this.options[type] = val[i];
  93. } else if (force) {
  94. this.options[type] = '';
  95. }
  96. this.output(type);
  97. }, this));
  98. this.tab(PROVINCE);
  99. this.feedText();
  100. this.feedVal();
  101. },
  102. defineDems: function () {
  103. var stop = false;
  104. $.each([PROVINCE, CITY, DISTRICT], $.proxy(function (i, type) {
  105. if (!stop) {
  106. this.dems.push(type);
  107. }
  108. if (type === this.options.level) {
  109. stop = true;
  110. }
  111. }, this));
  112. },
  113. includeDem: function (type) {
  114. return $.inArray(type, this.dems) !== -1;
  115. },
  116. getPosition: function () {
  117. var p, h, w, s, pw;
  118. p = this.$element.position();
  119. s = this.getSize(this.$element);
  120. h = s.height;
  121. w = s.width;
  122. if (this.options.responsive) {
  123. pw = this.$element.offsetParent().width();
  124. if (pw) {
  125. w = w / pw;
  126. if (w > 0.99) {
  127. w = 1;
  128. }
  129. w = w * 100 + '%';
  130. }
  131. }
  132. return {
  133. top: p.top || 0,
  134. left: p.left || 0,
  135. height: h,
  136. width: w
  137. };
  138. },
  139. getSize: function ($dom) {
  140. var $wrap, $clone, sizes;
  141. if (!$dom.is(':visible')) {
  142. $wrap = $("<div />").appendTo($("body"));
  143. $wrap.css({
  144. "position": "absolute !important",
  145. "visibility": "hidden !important",
  146. "display": "block !important"
  147. });
  148. $clone = $dom.clone().appendTo($wrap);
  149. sizes = {
  150. width: $clone.outerWidth(),
  151. height: $clone.outerHeight()
  152. };
  153. $wrap.remove();
  154. } else {
  155. sizes = {
  156. width: $dom.outerWidth(),
  157. height: $dom.outerHeight()
  158. };
  159. }
  160. return sizes;
  161. },
  162. getWidthStyle: function (w, dropdown) {
  163. if (this.options.responsive && !$.isNumeric(w)) {
  164. return 'width:' + w + ';';
  165. } else {
  166. return 'width:' + (dropdown ? Math.max(320, w) : w) + 'px;';
  167. }
  168. },
  169. bind: function () {
  170. var that = this;
  171. $(document).on('click', (this._mouteclick = function (e) {
  172. var $target = $(e.target);
  173. var $dropdown, $span, $input;
  174. if ($target.is('.city-picker-span')) {
  175. $span = $target;
  176. } else if ($target.is('.city-picker-span *')) {
  177. $span = $target.parents('.city-picker-span');
  178. }
  179. if ($target.is('.city-picker-input')) {
  180. $input = $target;
  181. }
  182. if ($target.is('.city-picker-dropdown')) {
  183. $dropdown = $target;
  184. } else if ($target.is('.city-picker-dropdown *')) {
  185. $dropdown = $target.parents('.city-picker-dropdown');
  186. }
  187. if ((!$input && !$span && !$dropdown) ||
  188. ($span && $span.get(0) !== that.$textspan.get(0)) ||
  189. ($input && $input.get(0) !== that.$element.get(0)) ||
  190. ($dropdown && $dropdown.get(0) !== that.$dropdown.get(0))) {
  191. that.close(true);
  192. }
  193. }));
  194. this.$element.on('change', (this._changeElement = $.proxy(function () {
  195. this.close(true);
  196. this.refresh(true);
  197. }, this))).on('focus', (this._focusElement = $.proxy(function () {
  198. this.needBlur = true;
  199. this.open();
  200. }, this))).on('blur', (this._blurElement = $.proxy(function () {
  201. if (this.needBlur) {
  202. this.needBlur = false;
  203. this.close(true);
  204. }
  205. }, this)));
  206. this.$textspan.on('click', function (e) {
  207. var $target = $(e.target), type;
  208. that.needBlur = false;
  209. if ($target.is('.select-item')) {
  210. type = $target.data('count');
  211. that.open(type);
  212. } else {
  213. if (that.$dropdown.is(':visible')) {
  214. that.close();
  215. } else {
  216. that.open();
  217. }
  218. }
  219. }).on('mousedown', function () {
  220. that.needBlur = false;
  221. });
  222. this.$dropdown.on('click', '.city-select a', function () {
  223. var $select = $(this).parents('.city-select');
  224. var $active = $select.find('a.active');
  225. var last = $select.next().length === 0;
  226. $active.removeClass('active');
  227. $(this).addClass('active');
  228. if ($active.data('code') !== $(this).data('code')) {
  229. $select.data('item', {
  230. address: $(this).attr('title'), code: $(this).data('code')
  231. });
  232. $(this).trigger(EVENT_CHANGE);
  233. that.feedText();
  234. that.feedVal(true);
  235. if (last) {
  236. that.close();
  237. }
  238. }
  239. }).on('click', '.city-select-tab a', function () {
  240. if (!$(this).hasClass('active')) {
  241. var type = $(this).data('count');
  242. that.tab(type);
  243. }
  244. }).on('mousedown', function () {
  245. that.needBlur = false;
  246. });
  247. if (this.$province) {
  248. this.$province.on(EVENT_CHANGE, (this._changeProvince = $.proxy(function () {
  249. this.output(CITY);
  250. this.output(DISTRICT);
  251. this.tab(CITY);
  252. }, this)));
  253. }
  254. if (this.$city) {
  255. this.$city.on(EVENT_CHANGE, (this._changeCity = $.proxy(function () {
  256. this.output(DISTRICT);
  257. this.tab(DISTRICT);
  258. }, this)));
  259. }
  260. },
  261. open: function (type) {
  262. type = type || PROVINCE;
  263. this.$dropdown.show();
  264. this.$textspan.addClass('open').addClass('focus');
  265. this.tab(type);
  266. },
  267. close: function (blur) {
  268. this.$dropdown.hide();
  269. this.$textspan.removeClass('open');
  270. if (blur) {
  271. this.$textspan.removeClass('focus');
  272. }
  273. },
  274. unbind: function () {
  275. $(document).off('click', this._mouteclick);
  276. this.$element.off('change', this._changeElement);
  277. this.$element.off('focus', this._focusElement);
  278. this.$element.off('blur', this._blurElement);
  279. this.$textspan.off('click');
  280. this.$textspan.off('mousedown');
  281. this.$dropdown.off('click');
  282. this.$dropdown.off('mousedown');
  283. if (this.$province) {
  284. this.$province.off(EVENT_CHANGE, this._changeProvince);
  285. }
  286. if (this.$city) {
  287. this.$city.off(EVENT_CHANGE, this._changeCity);
  288. }
  289. },
  290. getText: function () {
  291. var text = '';
  292. this.$dropdown.find('.city-select')
  293. .each(function () {
  294. var item = $(this).data('item'),
  295. type = $(this).data('count');
  296. if (item) {
  297. text += ($(this).hasClass('province') ? '' : '/') + '<span class="select-item" data-count="' +
  298. type + '" data-code="' + item.code + '">' + item.address + '</span>';
  299. }
  300. });
  301. return text;
  302. },
  303. getPlaceHolder: function () {
  304. return this.$element.attr('placeholder') || this.options.placeholder;
  305. },
  306. feedText: function () {
  307. var text = this.getText();
  308. if (text) {
  309. this.$textspan.find('>.placeholder').hide();
  310. this.$textspan.find('>.title').html(this.getText()).show();
  311. } else {
  312. this.$textspan.find('>.placeholder').text(this.getPlaceHolder()).show();
  313. this.$textspan.find('>.title').html('').hide();
  314. }
  315. },
  316. // getCode: function (count) {
  317. // var obj = {}, arr = [];
  318. // this.$textspan.find('.select-item')
  319. // .each(function () {
  320. // var code = $(this).data('code');
  321. // var count = $(this).data('count');
  322. // obj[count] = code;
  323. // arr.push(code);
  324. // });
  325. // return count ? obj[count] : arr.join('/');
  326. // },
  327. getCode: function () {
  328. var obj = {}, arr = [];
  329. this.$textspan.find('.select-item')
  330. .each(function () {
  331. var code = $(this).data('code');
  332. var count = $(this).data('count');
  333. obj[count] = code;
  334. arr.push(code);
  335. });
  336. return arr[arr.length - 1];
  337. },
  338. getName: function () {
  339. var arr = [];
  340. this.$dropdown.find('.city-select')
  341. .each(function () {
  342. var item = $(this).data('item');
  343. if (item)
  344. arr.push(item.address);
  345. });
  346. return arr[arr.length - 1];
  347. },
  348. getVal: function () {
  349. var text = '';
  350. this.$dropdown.find('.city-select')
  351. .each(function () {
  352. var item = $(this).data('item');
  353. if (item) {
  354. text += ($(this).hasClass('province') ? '' : '/') + item.address;
  355. }
  356. });
  357. return text;
  358. },
  359. feedVal: function (trigger) {
  360. this.$element.val(this.getVal());
  361. if(trigger) {
  362. this.$element.trigger('cp:updated');
  363. }
  364. },
  365. output: function (type) {
  366. var options = this.options;
  367. //var placeholders = this.placeholders;
  368. var $select = this['$' + type];
  369. var data = type === PROVINCE ? {} : [];
  370. var item;
  371. var districts;
  372. var code;
  373. var matched = null;
  374. var value;
  375. if (!$select || !$select.length) {
  376. return;
  377. }
  378. item = $select.data('item');
  379. value = (item ? item.address : null) || options[type];
  380. code = (
  381. type === PROVINCE ? 86 :
  382. type === CITY ? this.$province && this.$province.find('.active').data('code') :
  383. type === DISTRICT ? this.$city && this.$city.find('.active').data('code') : code
  384. );
  385. districts = $.isNumeric(code) ? ChineseDistricts[code] : null;
  386. if ($.isPlainObject(districts)) {
  387. $.each(districts, function (code, address) {
  388. var provs;
  389. if (type === PROVINCE) {
  390. provs = [];
  391. for (var i = 0; i < address.length; i++) {
  392. if (address[i].address === value) {
  393. matched = {
  394. code: address[i].code,
  395. address: address[i].address
  396. };
  397. }
  398. provs.push({
  399. code: address[i].code,
  400. address: address[i].address,
  401. selected: address[i].address === value
  402. });
  403. }
  404. data[code] = provs;
  405. } else {
  406. if (address === value) {
  407. matched = {
  408. code: code,
  409. address: address
  410. };
  411. }
  412. data.push({
  413. code: code,
  414. address: address,
  415. selected: address === value
  416. });
  417. }
  418. });
  419. }
  420. $select.html(type === PROVINCE ? this.getProvinceList(data) :
  421. this.getList(data, type));
  422. $select.data('item', matched);
  423. },
  424. getProvinceList: function (data) {
  425. var list = [],
  426. that = this,
  427. simple = this.options.simple;
  428. $.each(data, function (i, n) {
  429. list.push('<dl class="clearfix">');
  430. list.push('<dt>' + i + '</dt><dd>');
  431. $.each(n, function (j, m) {
  432. list.push(
  433. '<a' +
  434. ' title="' + (m.address || '') + '"' +
  435. ' data-code="' + (m.code || '') + '"' +
  436. ' class="' +
  437. (m.selected ? ' active' : '') +
  438. '">' +
  439. ( simple ? that.simplize(m.address, PROVINCE) : m.address) +
  440. '</a>');
  441. });
  442. list.push('</dd></dl>');
  443. });
  444. return list.join('');
  445. },
  446. getList: function (data, type) {
  447. var list = [],
  448. that = this,
  449. simple = this.options.simple;
  450. list.push('<dl class="clearfix"><dd>');
  451. $.each(data, function (i, n) {
  452. list.push(
  453. '<a' +
  454. ' title="' + (n.address || '') + '"' +
  455. ' data-code="' + (n.code || '') + '"' +
  456. ' class="' +
  457. (n.selected ? ' active' : '') +
  458. '">' +
  459. ( simple ? that.simplize(n.address, type) : n.address) +
  460. '</a>');
  461. });
  462. list.push('</dd></dl>');
  463. return list.join('');
  464. },
  465. simplize: function (address, type) {
  466. address = address || '';
  467. if (type === PROVINCE) {
  468. return address.replace(/[省,市,自治区,壮族,回族,维吾尔]/g, '');
  469. } else if (type === CITY) {
  470. return address.replace(/[市,地区,回族,蒙古,苗族,白族,傣族,景颇族,藏族,彝族,壮族,傈僳族,布依族,侗族]/g, '')
  471. .replace('哈萨克', '').replace('自治州', '').replace(/自治县/, '');
  472. } else if (type === DISTRICT) {
  473. return address.length > 2 ? address.replace(/[市,区,县,旗]/g, '') : address;
  474. }
  475. },
  476. tab: function (type) {
  477. var $selects = this.$dropdown.find('.city-select');
  478. var $tabs = this.$dropdown.find('.city-select-tab > a');
  479. var $select = this['$' + type];
  480. var $tab = this.$dropdown.find('.city-select-tab > a[data-count="' + type + '"]');
  481. if ($select) {
  482. $selects.hide();
  483. $select.show();
  484. $tabs.removeClass('active');
  485. $tab.addClass('active');
  486. }
  487. },
  488. reset: function () {
  489. this.$element.val(null).trigger('change');
  490. },
  491. destroy: function () {
  492. this.unbind();
  493. this.$element.removeData(NAMESPACE).removeClass('city-picker-input');
  494. this.$textspan.remove();
  495. this.$dropdown.remove();
  496. }
  497. };
  498. CityPicker.DEFAULTS = {
  499. simple: false,
  500. responsive: false,
  501. placeholder: '请选择省/市/区',
  502. level: 'district',
  503. province: '',
  504. city: '',
  505. district: ''
  506. };
  507. CityPicker.setDefaults = function (options) {
  508. $.extend(CityPicker.DEFAULTS, options);
  509. };
  510. // Save the other citypicker
  511. CityPicker.other = $.fn.citypicker;
  512. // Register as jQuery plugin
  513. $.fn.citypicker = function (option) {
  514. var args = [].slice.call(arguments, 1);
  515. return this.each(function () {
  516. var that = $(this);
  517. var data = that.data(NAMESPACE);
  518. var options;
  519. var fn;
  520. if (!data) {
  521. if (/destroy/.test(option)) {
  522. return;
  523. }
  524. options = $.extend({}, that.data(), $.isPlainObject(option) && option);
  525. that.data(NAMESPACE, (data = new CityPicker(this, options)));
  526. }
  527. if (typeof option === 'string' && $.isFunction(fn = data[option])) {
  528. fn.apply(data, args);
  529. }
  530. });
  531. };
  532. $.fn.citypicker.Constructor = CityPicker;
  533. $.fn.citypicker.setDefaults = CityPicker.setDefaults;
  534. // No conflict
  535. $.fn.citypicker.noConflict = function () {
  536. $.fn.citypicker = CityPicker.other;
  537. return this;
  538. };
  539. // 根据code查询地址
  540. $.fn.citypicker.getAddressbyCodeId = function(code_id){
  541. var city = ChineseDistricts;
  542. var code = city[''+code_id];
  543. var addr = '';
  544. var province = '';
  545. var province_code = '';
  546. var city_str = '';
  547. var county = '';
  548. if(code_id.substring(0,2)==='44'){
  549. province = '广东省';
  550. province_code = '440000';
  551. }else{
  552. $.each(city['86'], function(i,item) {
  553. $.each(item, function(j,index) {
  554. if(index['code']===code_id.substring(0,2)+'0000'){
  555. province = index['address'];
  556. province_code = index['code'];
  557. return false;
  558. }
  559. });
  560. });
  561. }
  562. if(code_id.substring(2,4).indexOf('00')==-1){
  563. var city_code = code_id.substring(0,4)+'00';
  564. city_str = city[province_code][city_code];
  565. }
  566. if(code===undefined){
  567. //440103
  568. code = code_id.substring(0,4)+"00";
  569. if(city[code] == null) return;
  570. addr = city[code][code_id];
  571. return addr = province+'/'+city_str+'/'+addr;
  572. }else{
  573. if(code_id.substring(2,4).indexOf('00')!=-1){
  574. //440000
  575. return addr = province;
  576. }else{
  577. //440100
  578. var city_city = city[code_id.substring(0,2)+'0000'];
  579. return addr = province +'/'+city_city[code_id];
  580. }
  581. }
  582. }
  583. $(function () {
  584. $('[data-toggle="city-picker"]').citypicker();
  585. });
  586. });