├── Demo.html ├── css ├── bootstrap.css ├── city-picker.css └── main.css ├── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 ├── images └── drop-arrow.png └── js ├── bootstrap.js ├── city-picker.data.js ├── city-picker.js ├── jquery.js └── main.js /Demo.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | :jQuery省市区三级联动插件city-picker 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /css/city-picker.css: -------------------------------------------------------------------------------- 1 | .city-picker-input { 2 | opacity: 0 !important; 3 | top: -9999px; 4 | left: -9999px; 5 | position: absolute; 6 | } 7 | 8 | .city-picker-span { 9 | position: relative; 10 | display: block; 11 | outline: 0; 12 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 13 | border-bottom: 1px solid #ccc; 14 | background-color: #fff; 15 | color: #ccc; 16 | cursor: pointer; 17 | } 18 | 19 | .city-picker-span > .placeholder { 20 | color: #aaa; 21 | } 22 | 23 | .city-picker-span > .arrow { 24 | position: absolute; 25 | top: 50%; 26 | right: 8px; 27 | width: 10px; 28 | margin-top: -3px; 29 | height: 5px; 30 | background: url(../images/drop-arrow.png) -10px -25px no-repeat; 31 | } 32 | 33 | .city-picker-span.focus, 34 | .city-picker-span.open { 35 | border-bottom-color: #46A4FF; 36 | } 37 | 38 | .city-picker-span.open > .arrow { 39 | background-position: -10px -10px; 40 | } 41 | 42 | .city-picker-span > .title > span { 43 | color: #333; 44 | padding: 5px; 45 | border-radius: 3px; 46 | } 47 | 48 | .city-picker-span > .title > span:hover { 49 | background-color: #f1f8ff; 50 | } 51 | 52 | .city-picker-dropdown { 53 | position: absolute; 54 | width: 315px; 55 | left: -9999px; 56 | top: -9999px; 57 | outline: 0; 58 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 59 | z-index: 999999; 60 | display: none; 61 | min-width: 330px; 62 | margin-bottom: 20px; 63 | } 64 | 65 | .city-select-wrap { 66 | box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5); 67 | } 68 | 69 | .city-select-tab { 70 | border-bottom: 1px solid #ccc; 71 | background: #f0f0f0; 72 | font-size: 13px; 73 | } 74 | 75 | .city-select-tab > a { 76 | display: inline-block; 77 | padding: 8px 22px; 78 | border-left: 1px solid #ccc; 79 | border-bottom: 1px solid transparent; 80 | color: #4D4D4D; 81 | text-align: center; 82 | outline: 0; 83 | text-decoration: none; 84 | cursor: pointer; 85 | font-size: 14px; 86 | margin-bottom: -1px; 87 | } 88 | 89 | .city-select-tab > a.active { 90 | background: #fff; 91 | border-bottom: 1px solid #fff; 92 | color: #46A4FF; 93 | } 94 | 95 | .city-select-tab > a:first-child { 96 | border-left: none; 97 | } 98 | 99 | .city-select-tab > a:last-child.active { 100 | border-right: 1px solid #ccc; 101 | } 102 | 103 | .city-select-content { 104 | width: 100%; 105 | min-height: 10px; 106 | background-color: #fff; 107 | padding: 10px 15px; 108 | } 109 | 110 | .city-select { 111 | font-size: 13px; 112 | } 113 | 114 | .city-select dl { 115 | line-height: 2; 116 | clear: both; 117 | padding: 3px 0; 118 | margin: 0; 119 | } 120 | 121 | .city-select dt { 122 | position: absolute; 123 | width: 2.5em; 124 | font-weight: 500; 125 | text-align: right; 126 | line-height: 2; 127 | } 128 | 129 | .city-select dd { 130 | margin-left: 0; 131 | line-height: 2; 132 | } 133 | 134 | .city-select.province dd { 135 | margin-left: 3em; 136 | } 137 | 138 | .city-select a { 139 | display: inline-block; 140 | padding: 0 10px; 141 | outline: 0; 142 | text-decoration: none; 143 | white-space: nowrap; 144 | margin-right: 2px; 145 | text-decoration: none; 146 | color: #333; 147 | cursor: pointer; 148 | } 149 | 150 | .city-select a:hover, 151 | .city-select a:focus { 152 | background-color: #f1f8ff; 153 | border-radius: 2px; 154 | color: #46A4FF; 155 | } 156 | 157 | .city-select a.active { 158 | background-color: #46A4FF; 159 | color: #fff; 160 | border-radius: 2px; 161 | } -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | input{ 2 | min-width: 360px; 3 | } -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemo0000/MyProject/dfa97ffca2d4c8c5fa89a6a34ec522b32840c0d6/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemo0000/MyProject/dfa97ffca2d4c8c5fa89a6a34ec522b32840c0d6/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemo0000/MyProject/dfa97ffca2d4c8c5fa89a6a34ec522b32840c0d6/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemo0000/MyProject/dfa97ffca2d4c8c5fa89a6a34ec522b32840c0d6/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /images/drop-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemo0000/MyProject/dfa97ffca2d4c8c5fa89a6a34ec522b32840c0d6/images/drop-arrow.png -------------------------------------------------------------------------------- /js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | 7 | if (typeof jQuery === 'undefined') { 8 | throw new Error('Bootstrap\'s JavaScript requires jQuery') 9 | } 10 | 11 | +function ($) { 12 | 'use strict'; 13 | var version = $.fn.jquery.split(' ')[0].split('.') 14 | if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) { 15 | throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3') 16 | } 17 | }(jQuery); 18 | 19 | /* ======================================================================== 20 | * Bootstrap: transition.js v3.3.6 21 | * http://getbootstrap.com/javascript/#transitions 22 | * ======================================================================== 23 | * Copyright 2011-2015 Twitter, Inc. 24 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 25 | * ======================================================================== */ 26 | 27 | 28 | +function ($) { 29 | 'use strict'; 30 | 31 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 32 | // ============================================================ 33 | 34 | function transitionEnd() { 35 | var el = document.createElement('bootstrap') 36 | 37 | var transEndEventNames = { 38 | WebkitTransition : 'webkitTransitionEnd', 39 | MozTransition : 'transitionend', 40 | OTransition : 'oTransitionEnd otransitionend', 41 | transition : 'transitionend' 42 | } 43 | 44 | for (var name in transEndEventNames) { 45 | if (el.style[name] !== undefined) { 46 | return { end: transEndEventNames[name] } 47 | } 48 | } 49 | 50 | return false // explicit for ie8 ( ._.) 51 | } 52 | 53 | // http://blog.alexmaccaw.com/css-transitions 54 | $.fn.emulateTransitionEnd = function (duration) { 55 | var called = false 56 | var $el = this 57 | $(this).one('bsTransitionEnd', function () { called = true }) 58 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 59 | setTimeout(callback, duration) 60 | return this 61 | } 62 | 63 | $(function () { 64 | $.support.transition = transitionEnd() 65 | 66 | if (!$.support.transition) return 67 | 68 | $.event.special.bsTransitionEnd = { 69 | bindType: $.support.transition.end, 70 | delegateType: $.support.transition.end, 71 | handle: function (e) { 72 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 73 | } 74 | } 75 | }) 76 | 77 | }(jQuery); 78 | 79 | /* ======================================================================== 80 | * Bootstrap: alert.js v3.3.6 81 | * http://getbootstrap.com/javascript/#alerts 82 | * ======================================================================== 83 | * Copyright 2011-2015 Twitter, Inc. 84 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 85 | * ======================================================================== */ 86 | 87 | 88 | +function ($) { 89 | 'use strict'; 90 | 91 | // ALERT CLASS DEFINITION 92 | // ====================== 93 | 94 | var dismiss = '[data-dismiss="alert"]' 95 | var Alert = function (el) { 96 | $(el).on('click', dismiss, this.close) 97 | } 98 | 99 | Alert.VERSION = '3.3.6' 100 | 101 | Alert.TRANSITION_DURATION = 150 102 | 103 | Alert.prototype.close = function (e) { 104 | var $this = $(this) 105 | var selector = $this.attr('data-target') 106 | 107 | if (!selector) { 108 | selector = $this.attr('href') 109 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 110 | } 111 | 112 | var $parent = $(selector) 113 | 114 | if (e) e.preventDefault() 115 | 116 | if (!$parent.length) { 117 | $parent = $this.closest('.alert') 118 | } 119 | 120 | $parent.trigger(e = $.Event('close.bs.alert')) 121 | 122 | if (e.isDefaultPrevented()) return 123 | 124 | $parent.removeClass('in') 125 | 126 | function removeElement() { 127 | // detach from parent, fire event then clean up data 128 | $parent.detach().trigger('closed.bs.alert').remove() 129 | } 130 | 131 | $.support.transition && $parent.hasClass('fade') ? 132 | $parent 133 | .one('bsTransitionEnd', removeElement) 134 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 135 | removeElement() 136 | } 137 | 138 | 139 | // ALERT PLUGIN DEFINITION 140 | // ======================= 141 | 142 | function Plugin(option) { 143 | return this.each(function () { 144 | var $this = $(this) 145 | var data = $this.data('bs.alert') 146 | 147 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 148 | if (typeof option == 'string') data[option].call($this) 149 | }) 150 | } 151 | 152 | var old = $.fn.alert 153 | 154 | $.fn.alert = Plugin 155 | $.fn.alert.Constructor = Alert 156 | 157 | 158 | // ALERT NO CONFLICT 159 | // ================= 160 | 161 | $.fn.alert.noConflict = function () { 162 | $.fn.alert = old 163 | return this 164 | } 165 | 166 | 167 | // ALERT DATA-API 168 | // ============== 169 | 170 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 171 | 172 | }(jQuery); 173 | 174 | /* ======================================================================== 175 | * Bootstrap: button.js v3.3.6 176 | * http://getbootstrap.com/javascript/#buttons 177 | * ======================================================================== 178 | * Copyright 2011-2015 Twitter, Inc. 179 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 180 | * ======================================================================== */ 181 | 182 | 183 | +function ($) { 184 | 'use strict'; 185 | 186 | // BUTTON PUBLIC CLASS DEFINITION 187 | // ============================== 188 | 189 | var Button = function (element, options) { 190 | this.$element = $(element) 191 | this.options = $.extend({}, Button.DEFAULTS, options) 192 | this.isLoading = false 193 | } 194 | 195 | Button.VERSION = '3.3.6' 196 | 197 | Button.DEFAULTS = { 198 | loadingText: 'loading...' 199 | } 200 | 201 | Button.prototype.setState = function (state) { 202 | var d = 'disabled' 203 | var $el = this.$element 204 | var val = $el.is('input') ? 'val' : 'html' 205 | var data = $el.data() 206 | 207 | state += 'Text' 208 | 209 | if (data.resetText == null) $el.data('resetText', $el[val]()) 210 | 211 | // push to event loop to allow forms to submit 212 | setTimeout($.proxy(function () { 213 | $el[val](data[state] == null ? this.options[state] : data[state]) 214 | 215 | if (state == 'loadingText') { 216 | this.isLoading = true 217 | $el.addClass(d).attr(d, d) 218 | } else if (this.isLoading) { 219 | this.isLoading = false 220 | $el.removeClass(d).removeAttr(d) 221 | } 222 | }, this), 0) 223 | } 224 | 225 | Button.prototype.toggle = function () { 226 | var changed = true 227 | var $parent = this.$element.closest('[data-toggle="buttons"]') 228 | 229 | if ($parent.length) { 230 | var $input = this.$element.find('input') 231 | if ($input.prop('type') == 'radio') { 232 | if ($input.prop('checked')) changed = false 233 | $parent.find('.active').removeClass('active') 234 | this.$element.addClass('active') 235 | } else if ($input.prop('type') == 'checkbox') { 236 | if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false 237 | this.$element.toggleClass('active') 238 | } 239 | $input.prop('checked', this.$element.hasClass('active')) 240 | if (changed) $input.trigger('change') 241 | } else { 242 | this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 243 | this.$element.toggleClass('active') 244 | } 245 | } 246 | 247 | 248 | // BUTTON PLUGIN DEFINITION 249 | // ======================== 250 | 251 | function Plugin(option) { 252 | return this.each(function () { 253 | var $this = $(this) 254 | var data = $this.data('bs.button') 255 | var options = typeof option == 'object' && option 256 | 257 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 258 | 259 | if (option == 'toggle') data.toggle() 260 | else if (option) data.setState(option) 261 | }) 262 | } 263 | 264 | var old = $.fn.button 265 | 266 | $.fn.button = Plugin 267 | $.fn.button.Constructor = Button 268 | 269 | 270 | // BUTTON NO CONFLICT 271 | // ================== 272 | 273 | $.fn.button.noConflict = function () { 274 | $.fn.button = old 275 | return this 276 | } 277 | 278 | 279 | // BUTTON DATA-API 280 | // =============== 281 | 282 | $(document) 283 | .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 284 | var $btn = $(e.target) 285 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 286 | Plugin.call($btn, 'toggle') 287 | if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() 288 | }) 289 | .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 290 | $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 291 | }) 292 | 293 | }(jQuery); 294 | 295 | /* ======================================================================== 296 | * Bootstrap: carousel.js v3.3.6 297 | * http://getbootstrap.com/javascript/#carousel 298 | * ======================================================================== 299 | * Copyright 2011-2015 Twitter, Inc. 300 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 301 | * ======================================================================== */ 302 | 303 | 304 | +function ($) { 305 | 'use strict'; 306 | 307 | // CAROUSEL CLASS DEFINITION 308 | // ========================= 309 | 310 | var Carousel = function (element, options) { 311 | this.$element = $(element) 312 | this.$indicators = this.$element.find('.carousel-indicators') 313 | this.options = options 314 | this.paused = null 315 | this.sliding = null 316 | this.interval = null 317 | this.$active = null 318 | this.$items = null 319 | 320 | this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) 321 | 322 | this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element 323 | .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 324 | .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 325 | } 326 | 327 | Carousel.VERSION = '3.3.6' 328 | 329 | Carousel.TRANSITION_DURATION = 600 330 | 331 | Carousel.DEFAULTS = { 332 | interval: 5000, 333 | pause: 'hover', 334 | wrap: true, 335 | keyboard: true 336 | } 337 | 338 | Carousel.prototype.keydown = function (e) { 339 | if (/input|textarea/i.test(e.target.tagName)) return 340 | switch (e.which) { 341 | case 37: this.prev(); break 342 | case 39: this.next(); break 343 | default: return 344 | } 345 | 346 | e.preventDefault() 347 | } 348 | 349 | Carousel.prototype.cycle = function (e) { 350 | e || (this.paused = false) 351 | 352 | this.interval && clearInterval(this.interval) 353 | 354 | this.options.interval 355 | && !this.paused 356 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 357 | 358 | return this 359 | } 360 | 361 | Carousel.prototype.getItemIndex = function (item) { 362 | this.$items = item.parent().children('.item') 363 | return this.$items.index(item || this.$active) 364 | } 365 | 366 | Carousel.prototype.getItemForDirection = function (direction, active) { 367 | var activeIndex = this.getItemIndex(active) 368 | var willWrap = (direction == 'prev' && activeIndex === 0) 369 | || (direction == 'next' && activeIndex == (this.$items.length - 1)) 370 | if (willWrap && !this.options.wrap) return active 371 | var delta = direction == 'prev' ? -1 : 1 372 | var itemIndex = (activeIndex + delta) % this.$items.length 373 | return this.$items.eq(itemIndex) 374 | } 375 | 376 | Carousel.prototype.to = function (pos) { 377 | var that = this 378 | var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 379 | 380 | if (pos > (this.$items.length - 1) || pos < 0) return 381 | 382 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 383 | if (activeIndex == pos) return this.pause().cycle() 384 | 385 | return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) 386 | } 387 | 388 | Carousel.prototype.pause = function (e) { 389 | e || (this.paused = true) 390 | 391 | if (this.$element.find('.next, .prev').length && $.support.transition) { 392 | this.$element.trigger($.support.transition.end) 393 | this.cycle(true) 394 | } 395 | 396 | this.interval = clearInterval(this.interval) 397 | 398 | return this 399 | } 400 | 401 | Carousel.prototype.next = function () { 402 | if (this.sliding) return 403 | return this.slide('next') 404 | } 405 | 406 | Carousel.prototype.prev = function () { 407 | if (this.sliding) return 408 | return this.slide('prev') 409 | } 410 | 411 | Carousel.prototype.slide = function (type, next) { 412 | var $active = this.$element.find('.item.active') 413 | var $next = next || this.getItemForDirection(type, $active) 414 | var isCycling = this.interval 415 | var direction = type == 'next' ? 'left' : 'right' 416 | var that = this 417 | 418 | if ($next.hasClass('active')) return (this.sliding = false) 419 | 420 | var relatedTarget = $next[0] 421 | var slideEvent = $.Event('slide.bs.carousel', { 422 | relatedTarget: relatedTarget, 423 | direction: direction 424 | }) 425 | this.$element.trigger(slideEvent) 426 | if (slideEvent.isDefaultPrevented()) return 427 | 428 | this.sliding = true 429 | 430 | isCycling && this.pause() 431 | 432 | if (this.$indicators.length) { 433 | this.$indicators.find('.active').removeClass('active') 434 | var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 435 | $nextIndicator && $nextIndicator.addClass('active') 436 | } 437 | 438 | var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 439 | if ($.support.transition && this.$element.hasClass('slide')) { 440 | $next.addClass(type) 441 | $next[0].offsetWidth // force reflow 442 | $active.addClass(direction) 443 | $next.addClass(direction) 444 | $active 445 | .one('bsTransitionEnd', function () { 446 | $next.removeClass([type, direction].join(' ')).addClass('active') 447 | $active.removeClass(['active', direction].join(' ')) 448 | that.sliding = false 449 | setTimeout(function () { 450 | that.$element.trigger(slidEvent) 451 | }, 0) 452 | }) 453 | .emulateTransitionEnd(Carousel.TRANSITION_DURATION) 454 | } else { 455 | $active.removeClass('active') 456 | $next.addClass('active') 457 | this.sliding = false 458 | this.$element.trigger(slidEvent) 459 | } 460 | 461 | isCycling && this.cycle() 462 | 463 | return this 464 | } 465 | 466 | 467 | // CAROUSEL PLUGIN DEFINITION 468 | // ========================== 469 | 470 | function Plugin(option) { 471 | return this.each(function () { 472 | var $this = $(this) 473 | var data = $this.data('bs.carousel') 474 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 475 | var action = typeof option == 'string' ? option : options.slide 476 | 477 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 478 | if (typeof option == 'number') data.to(option) 479 | else if (action) data[action]() 480 | else if (options.interval) data.pause().cycle() 481 | }) 482 | } 483 | 484 | var old = $.fn.carousel 485 | 486 | $.fn.carousel = Plugin 487 | $.fn.carousel.Constructor = Carousel 488 | 489 | 490 | // CAROUSEL NO CONFLICT 491 | // ==================== 492 | 493 | $.fn.carousel.noConflict = function () { 494 | $.fn.carousel = old 495 | return this 496 | } 497 | 498 | 499 | // CAROUSEL DATA-API 500 | // ================= 501 | 502 | var clickHandler = function (e) { 503 | var href 504 | var $this = $(this) 505 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 506 | if (!$target.hasClass('carousel')) return 507 | var options = $.extend({}, $target.data(), $this.data()) 508 | var slideIndex = $this.attr('data-slide-to') 509 | if (slideIndex) options.interval = false 510 | 511 | Plugin.call($target, options) 512 | 513 | if (slideIndex) { 514 | $target.data('bs.carousel').to(slideIndex) 515 | } 516 | 517 | e.preventDefault() 518 | } 519 | 520 | $(document) 521 | .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) 522 | .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) 523 | 524 | $(window).on('load', function () { 525 | $('[data-ride="carousel"]').each(function () { 526 | var $carousel = $(this) 527 | Plugin.call($carousel, $carousel.data()) 528 | }) 529 | }) 530 | 531 | }(jQuery); 532 | 533 | /* ======================================================================== 534 | * Bootstrap: collapse.js v3.3.6 535 | * http://getbootstrap.com/javascript/#collapse 536 | * ======================================================================== 537 | * Copyright 2011-2015 Twitter, Inc. 538 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 539 | * ======================================================================== */ 540 | 541 | 542 | +function ($) { 543 | 'use strict'; 544 | 545 | // COLLAPSE PUBLIC CLASS DEFINITION 546 | // ================================ 547 | 548 | var Collapse = function (element, options) { 549 | this.$element = $(element) 550 | this.options = $.extend({}, Collapse.DEFAULTS, options) 551 | this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + 552 | '[data-toggle="collapse"][data-target="#' + element.id + '"]') 553 | this.transitioning = null 554 | 555 | if (this.options.parent) { 556 | this.$parent = this.getParent() 557 | } else { 558 | this.addAriaAndCollapsedClass(this.$element, this.$trigger) 559 | } 560 | 561 | if (this.options.toggle) this.toggle() 562 | } 563 | 564 | Collapse.VERSION = '3.3.6' 565 | 566 | Collapse.TRANSITION_DURATION = 350 567 | 568 | Collapse.DEFAULTS = { 569 | toggle: true 570 | } 571 | 572 | Collapse.prototype.dimension = function () { 573 | var hasWidth = this.$element.hasClass('width') 574 | return hasWidth ? 'width' : 'height' 575 | } 576 | 577 | Collapse.prototype.show = function () { 578 | if (this.transitioning || this.$element.hasClass('in')) return 579 | 580 | var activesData 581 | var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') 582 | 583 | if (actives && actives.length) { 584 | activesData = actives.data('bs.collapse') 585 | if (activesData && activesData.transitioning) return 586 | } 587 | 588 | var startEvent = $.Event('show.bs.collapse') 589 | this.$element.trigger(startEvent) 590 | if (startEvent.isDefaultPrevented()) return 591 | 592 | if (actives && actives.length) { 593 | Plugin.call(actives, 'hide') 594 | activesData || actives.data('bs.collapse', null) 595 | } 596 | 597 | var dimension = this.dimension() 598 | 599 | this.$element 600 | .removeClass('collapse') 601 | .addClass('collapsing')[dimension](0) 602 | .attr('aria-expanded', true) 603 | 604 | this.$trigger 605 | .removeClass('collapsed') 606 | .attr('aria-expanded', true) 607 | 608 | this.transitioning = 1 609 | 610 | var complete = function () { 611 | this.$element 612 | .removeClass('collapsing') 613 | .addClass('collapse in')[dimension]('') 614 | this.transitioning = 0 615 | this.$element 616 | .trigger('shown.bs.collapse') 617 | } 618 | 619 | if (!$.support.transition) return complete.call(this) 620 | 621 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 622 | 623 | this.$element 624 | .one('bsTransitionEnd', $.proxy(complete, this)) 625 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 626 | } 627 | 628 | Collapse.prototype.hide = function () { 629 | if (this.transitioning || !this.$element.hasClass('in')) return 630 | 631 | var startEvent = $.Event('hide.bs.collapse') 632 | this.$element.trigger(startEvent) 633 | if (startEvent.isDefaultPrevented()) return 634 | 635 | var dimension = this.dimension() 636 | 637 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 638 | 639 | this.$element 640 | .addClass('collapsing') 641 | .removeClass('collapse in') 642 | .attr('aria-expanded', false) 643 | 644 | this.$trigger 645 | .addClass('collapsed') 646 | .attr('aria-expanded', false) 647 | 648 | this.transitioning = 1 649 | 650 | var complete = function () { 651 | this.transitioning = 0 652 | this.$element 653 | .removeClass('collapsing') 654 | .addClass('collapse') 655 | .trigger('hidden.bs.collapse') 656 | } 657 | 658 | if (!$.support.transition) return complete.call(this) 659 | 660 | this.$element 661 | [dimension](0) 662 | .one('bsTransitionEnd', $.proxy(complete, this)) 663 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 664 | } 665 | 666 | Collapse.prototype.toggle = function () { 667 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 668 | } 669 | 670 | Collapse.prototype.getParent = function () { 671 | return $(this.options.parent) 672 | .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 673 | .each($.proxy(function (i, element) { 674 | var $element = $(element) 675 | this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 676 | }, this)) 677 | .end() 678 | } 679 | 680 | Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 681 | var isOpen = $element.hasClass('in') 682 | 683 | $element.attr('aria-expanded', isOpen) 684 | $trigger 685 | .toggleClass('collapsed', !isOpen) 686 | .attr('aria-expanded', isOpen) 687 | } 688 | 689 | function getTargetFromTrigger($trigger) { 690 | var href 691 | var target = $trigger.attr('data-target') 692 | || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 693 | 694 | return $(target) 695 | } 696 | 697 | 698 | // COLLAPSE PLUGIN DEFINITION 699 | // ========================== 700 | 701 | function Plugin(option) { 702 | return this.each(function () { 703 | var $this = $(this) 704 | var data = $this.data('bs.collapse') 705 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 706 | 707 | if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false 708 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 709 | if (typeof option == 'string') data[option]() 710 | }) 711 | } 712 | 713 | var old = $.fn.collapse 714 | 715 | $.fn.collapse = Plugin 716 | $.fn.collapse.Constructor = Collapse 717 | 718 | 719 | // COLLAPSE NO CONFLICT 720 | // ==================== 721 | 722 | $.fn.collapse.noConflict = function () { 723 | $.fn.collapse = old 724 | return this 725 | } 726 | 727 | 728 | // COLLAPSE DATA-API 729 | // ================= 730 | 731 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 732 | var $this = $(this) 733 | 734 | if (!$this.attr('data-target')) e.preventDefault() 735 | 736 | var $target = getTargetFromTrigger($this) 737 | var data = $target.data('bs.collapse') 738 | var option = data ? 'toggle' : $this.data() 739 | 740 | Plugin.call($target, option) 741 | }) 742 | 743 | }(jQuery); 744 | 745 | /* ======================================================================== 746 | * Bootstrap: dropdown.js v3.3.6 747 | * http://getbootstrap.com/javascript/#dropdowns 748 | * ======================================================================== 749 | * Copyright 2011-2015 Twitter, Inc. 750 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 751 | * ======================================================================== */ 752 | 753 | 754 | +function ($) { 755 | 'use strict'; 756 | 757 | // DROPDOWN CLASS DEFINITION 758 | // ========================= 759 | 760 | var backdrop = '.dropdown-backdrop' 761 | var toggle = '[data-toggle="dropdown"]' 762 | var Dropdown = function (element) { 763 | $(element).on('click.bs.dropdown', this.toggle) 764 | } 765 | 766 | Dropdown.VERSION = '3.3.6' 767 | 768 | function getParent($this) { 769 | var selector = $this.attr('data-target') 770 | 771 | if (!selector) { 772 | selector = $this.attr('href') 773 | selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 774 | } 775 | 776 | var $parent = selector && $(selector) 777 | 778 | return $parent && $parent.length ? $parent : $this.parent() 779 | } 780 | 781 | function clearMenus(e) { 782 | if (e && e.which === 3) return 783 | $(backdrop).remove() 784 | $(toggle).each(function () { 785 | var $this = $(this) 786 | var $parent = getParent($this) 787 | var relatedTarget = { relatedTarget: this } 788 | 789 | if (!$parent.hasClass('open')) return 790 | 791 | if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return 792 | 793 | $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) 794 | 795 | if (e.isDefaultPrevented()) return 796 | 797 | $this.attr('aria-expanded', 'false') 798 | $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) 799 | }) 800 | } 801 | 802 | Dropdown.prototype.toggle = function (e) { 803 | var $this = $(this) 804 | 805 | if ($this.is('.disabled, :disabled')) return 806 | 807 | var $parent = getParent($this) 808 | var isActive = $parent.hasClass('open') 809 | 810 | clearMenus() 811 | 812 | if (!isActive) { 813 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 814 | // if mobile we use a backdrop because click events don't delegate 815 | $(document.createElement('div')) 816 | .addClass('dropdown-backdrop') 817 | .insertAfter($(this)) 818 | .on('click', clearMenus) 819 | } 820 | 821 | var relatedTarget = { relatedTarget: this } 822 | $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) 823 | 824 | if (e.isDefaultPrevented()) return 825 | 826 | $this 827 | .trigger('focus') 828 | .attr('aria-expanded', 'true') 829 | 830 | $parent 831 | .toggleClass('open') 832 | .trigger($.Event('shown.bs.dropdown', relatedTarget)) 833 | } 834 | 835 | return false 836 | } 837 | 838 | Dropdown.prototype.keydown = function (e) { 839 | if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return 840 | 841 | var $this = $(this) 842 | 843 | e.preventDefault() 844 | e.stopPropagation() 845 | 846 | if ($this.is('.disabled, :disabled')) return 847 | 848 | var $parent = getParent($this) 849 | var isActive = $parent.hasClass('open') 850 | 851 | if (!isActive && e.which != 27 || isActive && e.which == 27) { 852 | if (e.which == 27) $parent.find(toggle).trigger('focus') 853 | return $this.trigger('click') 854 | } 855 | 856 | var desc = ' li:not(.disabled):visible a' 857 | var $items = $parent.find('.dropdown-menu' + desc) 858 | 859 | if (!$items.length) return 860 | 861 | var index = $items.index(e.target) 862 | 863 | if (e.which == 38 && index > 0) index-- // up 864 | if (e.which == 40 && index < $items.length - 1) index++ // down 865 | if (!~index) index = 0 866 | 867 | $items.eq(index).trigger('focus') 868 | } 869 | 870 | 871 | // DROPDOWN PLUGIN DEFINITION 872 | // ========================== 873 | 874 | function Plugin(option) { 875 | return this.each(function () { 876 | var $this = $(this) 877 | var data = $this.data('bs.dropdown') 878 | 879 | if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) 880 | if (typeof option == 'string') data[option].call($this) 881 | }) 882 | } 883 | 884 | var old = $.fn.dropdown 885 | 886 | $.fn.dropdown = Plugin 887 | $.fn.dropdown.Constructor = Dropdown 888 | 889 | 890 | // DROPDOWN NO CONFLICT 891 | // ==================== 892 | 893 | $.fn.dropdown.noConflict = function () { 894 | $.fn.dropdown = old 895 | return this 896 | } 897 | 898 | 899 | // APPLY TO STANDARD DROPDOWN ELEMENTS 900 | // =================================== 901 | 902 | $(document) 903 | .on('click.bs.dropdown.data-api', clearMenus) 904 | .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) 905 | .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) 906 | .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) 907 | .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) 908 | 909 | }(jQuery); 910 | 911 | /* ======================================================================== 912 | * Bootstrap: modal.js v3.3.6 913 | * http://getbootstrap.com/javascript/#modals 914 | * ======================================================================== 915 | * Copyright 2011-2015 Twitter, Inc. 916 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 917 | * ======================================================================== */ 918 | 919 | 920 | +function ($) { 921 | 'use strict'; 922 | 923 | // MODAL CLASS DEFINITION 924 | // ====================== 925 | 926 | var Modal = function (element, options) { 927 | this.options = options 928 | this.$body = $(document.body) 929 | this.$element = $(element) 930 | this.$dialog = this.$element.find('.modal-dialog') 931 | this.$backdrop = null 932 | this.isShown = null 933 | this.originalBodyPad = null 934 | this.scrollbarWidth = 0 935 | this.ignoreBackdropClick = false 936 | 937 | if (this.options.remote) { 938 | this.$element 939 | .find('.modal-content') 940 | .load(this.options.remote, $.proxy(function () { 941 | this.$element.trigger('loaded.bs.modal') 942 | }, this)) 943 | } 944 | } 945 | 946 | Modal.VERSION = '3.3.6' 947 | 948 | Modal.TRANSITION_DURATION = 300 949 | Modal.BACKDROP_TRANSITION_DURATION = 150 950 | 951 | Modal.DEFAULTS = { 952 | backdrop: true, 953 | keyboard: true, 954 | show: true 955 | } 956 | 957 | Modal.prototype.toggle = function (_relatedTarget) { 958 | return this.isShown ? this.hide() : this.show(_relatedTarget) 959 | } 960 | 961 | Modal.prototype.show = function (_relatedTarget) { 962 | var that = this 963 | var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 964 | 965 | this.$element.trigger(e) 966 | 967 | if (this.isShown || e.isDefaultPrevented()) return 968 | 969 | this.isShown = true 970 | 971 | this.checkScrollbar() 972 | this.setScrollbar() 973 | this.$body.addClass('modal-open') 974 | 975 | this.escape() 976 | this.resize() 977 | 978 | this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 979 | 980 | this.$dialog.on('mousedown.dismiss.bs.modal', function () { 981 | that.$element.one('mouseup.dismiss.bs.modal', function (e) { 982 | if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true 983 | }) 984 | }) 985 | 986 | this.backdrop(function () { 987 | var transition = $.support.transition && that.$element.hasClass('fade') 988 | 989 | if (!that.$element.parent().length) { 990 | that.$element.appendTo(that.$body) // don't move modals dom position 991 | } 992 | 993 | that.$element 994 | .show() 995 | .scrollTop(0) 996 | 997 | that.adjustDialog() 998 | 999 | if (transition) { 1000 | that.$element[0].offsetWidth // force reflow 1001 | } 1002 | 1003 | that.$element.addClass('in') 1004 | 1005 | that.enforceFocus() 1006 | 1007 | var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 1008 | 1009 | transition ? 1010 | that.$dialog // wait for modal to slide in 1011 | .one('bsTransitionEnd', function () { 1012 | that.$element.trigger('focus').trigger(e) 1013 | }) 1014 | .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 1015 | that.$element.trigger('focus').trigger(e) 1016 | }) 1017 | } 1018 | 1019 | Modal.prototype.hide = function (e) { 1020 | if (e) e.preventDefault() 1021 | 1022 | e = $.Event('hide.bs.modal') 1023 | 1024 | this.$element.trigger(e) 1025 | 1026 | if (!this.isShown || e.isDefaultPrevented()) return 1027 | 1028 | this.isShown = false 1029 | 1030 | this.escape() 1031 | this.resize() 1032 | 1033 | $(document).off('focusin.bs.modal') 1034 | 1035 | this.$element 1036 | .removeClass('in') 1037 | .off('click.dismiss.bs.modal') 1038 | .off('mouseup.dismiss.bs.modal') 1039 | 1040 | this.$dialog.off('mousedown.dismiss.bs.modal') 1041 | 1042 | $.support.transition && this.$element.hasClass('fade') ? 1043 | this.$element 1044 | .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 1045 | .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 1046 | this.hideModal() 1047 | } 1048 | 1049 | Modal.prototype.enforceFocus = function () { 1050 | $(document) 1051 | .off('focusin.bs.modal') // guard against infinite focus loop 1052 | .on('focusin.bs.modal', $.proxy(function (e) { 1053 | if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 1054 | this.$element.trigger('focus') 1055 | } 1056 | }, this)) 1057 | } 1058 | 1059 | Modal.prototype.escape = function () { 1060 | if (this.isShown && this.options.keyboard) { 1061 | this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { 1062 | e.which == 27 && this.hide() 1063 | }, this)) 1064 | } else if (!this.isShown) { 1065 | this.$element.off('keydown.dismiss.bs.modal') 1066 | } 1067 | } 1068 | 1069 | Modal.prototype.resize = function () { 1070 | if (this.isShown) { 1071 | $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) 1072 | } else { 1073 | $(window).off('resize.bs.modal') 1074 | } 1075 | } 1076 | 1077 | Modal.prototype.hideModal = function () { 1078 | var that = this 1079 | this.$element.hide() 1080 | this.backdrop(function () { 1081 | that.$body.removeClass('modal-open') 1082 | that.resetAdjustments() 1083 | that.resetScrollbar() 1084 | that.$element.trigger('hidden.bs.modal') 1085 | }) 1086 | } 1087 | 1088 | Modal.prototype.removeBackdrop = function () { 1089 | this.$backdrop && this.$backdrop.remove() 1090 | this.$backdrop = null 1091 | } 1092 | 1093 | Modal.prototype.backdrop = function (callback) { 1094 | var that = this 1095 | var animate = this.$element.hasClass('fade') ? 'fade' : '' 1096 | 1097 | if (this.isShown && this.options.backdrop) { 1098 | var doAnimate = $.support.transition && animate 1099 | 1100 | this.$backdrop = $(document.createElement('div')) 1101 | .addClass('modal-backdrop ' + animate) 1102 | .appendTo(this.$body) 1103 | 1104 | this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 1105 | if (this.ignoreBackdropClick) { 1106 | this.ignoreBackdropClick = false 1107 | return 1108 | } 1109 | if (e.target !== e.currentTarget) return 1110 | this.options.backdrop == 'static' 1111 | ? this.$element[0].focus() 1112 | : this.hide() 1113 | }, this)) 1114 | 1115 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 1116 | 1117 | this.$backdrop.addClass('in') 1118 | 1119 | if (!callback) return 1120 | 1121 | doAnimate ? 1122 | this.$backdrop 1123 | .one('bsTransitionEnd', callback) 1124 | .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 1125 | callback() 1126 | 1127 | } else if (!this.isShown && this.$backdrop) { 1128 | this.$backdrop.removeClass('in') 1129 | 1130 | var callbackRemove = function () { 1131 | that.removeBackdrop() 1132 | callback && callback() 1133 | } 1134 | $.support.transition && this.$element.hasClass('fade') ? 1135 | this.$backdrop 1136 | .one('bsTransitionEnd', callbackRemove) 1137 | .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 1138 | callbackRemove() 1139 | 1140 | } else if (callback) { 1141 | callback() 1142 | } 1143 | } 1144 | 1145 | // these following methods are used to handle overflowing modals 1146 | 1147 | Modal.prototype.handleUpdate = function () { 1148 | this.adjustDialog() 1149 | } 1150 | 1151 | Modal.prototype.adjustDialog = function () { 1152 | var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight 1153 | 1154 | this.$element.css({ 1155 | paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', 1156 | paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' 1157 | }) 1158 | } 1159 | 1160 | Modal.prototype.resetAdjustments = function () { 1161 | this.$element.css({ 1162 | paddingLeft: '', 1163 | paddingRight: '' 1164 | }) 1165 | } 1166 | 1167 | Modal.prototype.checkScrollbar = function () { 1168 | var fullWindowWidth = window.innerWidth 1169 | if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 1170 | var documentElementRect = document.documentElement.getBoundingClientRect() 1171 | fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) 1172 | } 1173 | this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth 1174 | this.scrollbarWidth = this.measureScrollbar() 1175 | } 1176 | 1177 | Modal.prototype.setScrollbar = function () { 1178 | var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 1179 | this.originalBodyPad = document.body.style.paddingRight || '' 1180 | if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 1181 | } 1182 | 1183 | Modal.prototype.resetScrollbar = function () { 1184 | this.$body.css('padding-right', this.originalBodyPad) 1185 | } 1186 | 1187 | Modal.prototype.measureScrollbar = function () { // thx walsh 1188 | var scrollDiv = document.createElement('div') 1189 | scrollDiv.className = 'modal-scrollbar-measure' 1190 | this.$body.append(scrollDiv) 1191 | var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 1192 | this.$body[0].removeChild(scrollDiv) 1193 | return scrollbarWidth 1194 | } 1195 | 1196 | 1197 | // MODAL PLUGIN DEFINITION 1198 | // ======================= 1199 | 1200 | function Plugin(option, _relatedTarget) { 1201 | return this.each(function () { 1202 | var $this = $(this) 1203 | var data = $this.data('bs.modal') 1204 | var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 1205 | 1206 | if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 1207 | if (typeof option == 'string') data[option](_relatedTarget) 1208 | else if (options.show) data.show(_relatedTarget) 1209 | }) 1210 | } 1211 | 1212 | var old = $.fn.modal 1213 | 1214 | $.fn.modal = Plugin 1215 | $.fn.modal.Constructor = Modal 1216 | 1217 | 1218 | // MODAL NO CONFLICT 1219 | // ================= 1220 | 1221 | $.fn.modal.noConflict = function () { 1222 | $.fn.modal = old 1223 | return this 1224 | } 1225 | 1226 | 1227 | // MODAL DATA-API 1228 | // ============== 1229 | 1230 | $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 1231 | var $this = $(this) 1232 | var href = $this.attr('href') 1233 | var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 1234 | var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 1235 | 1236 | if ($this.is('a')) e.preventDefault() 1237 | 1238 | $target.one('show.bs.modal', function (showEvent) { 1239 | if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 1240 | $target.one('hidden.bs.modal', function () { 1241 | $this.is(':visible') && $this.trigger('focus') 1242 | }) 1243 | }) 1244 | Plugin.call($target, option, this) 1245 | }) 1246 | 1247 | }(jQuery); 1248 | 1249 | /* ======================================================================== 1250 | * Bootstrap: tooltip.js v3.3.6 1251 | * http://getbootstrap.com/javascript/#tooltip 1252 | * Inspired by the original jQuery.tipsy by Jason Frame 1253 | * ======================================================================== 1254 | * Copyright 2011-2015 Twitter, Inc. 1255 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1256 | * ======================================================================== */ 1257 | 1258 | 1259 | +function ($) { 1260 | 'use strict'; 1261 | 1262 | // TOOLTIP PUBLIC CLASS DEFINITION 1263 | // =============================== 1264 | 1265 | var Tooltip = function (element, options) { 1266 | this.type = null 1267 | this.options = null 1268 | this.enabled = null 1269 | this.timeout = null 1270 | this.hoverState = null 1271 | this.$element = null 1272 | this.inState = null 1273 | 1274 | this.init('tooltip', element, options) 1275 | } 1276 | 1277 | Tooltip.VERSION = '3.3.6' 1278 | 1279 | Tooltip.TRANSITION_DURATION = 150 1280 | 1281 | Tooltip.DEFAULTS = { 1282 | animation: true, 1283 | placement: 'top', 1284 | selector: false, 1285 | template: '', 1286 | trigger: 'hover focus', 1287 | title: '', 1288 | delay: 0, 1289 | html: false, 1290 | container: false, 1291 | viewport: { 1292 | selector: 'body', 1293 | padding: 0 1294 | } 1295 | } 1296 | 1297 | Tooltip.prototype.init = function (type, element, options) { 1298 | this.enabled = true 1299 | this.type = type 1300 | this.$element = $(element) 1301 | this.options = this.getOptions(options) 1302 | this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 1303 | this.inState = { click: false, hover: false, focus: false } 1304 | 1305 | if (this.$element[0] instanceof document.constructor && !this.options.selector) { 1306 | throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') 1307 | } 1308 | 1309 | var triggers = this.options.trigger.split(' ') 1310 | 1311 | for (var i = triggers.length; i--;) { 1312 | var trigger = triggers[i] 1313 | 1314 | if (trigger == 'click') { 1315 | this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 1316 | } else if (trigger != 'manual') { 1317 | var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 1318 | var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 1319 | 1320 | this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 1321 | this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 1322 | } 1323 | } 1324 | 1325 | this.options.selector ? 1326 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 1327 | this.fixTitle() 1328 | } 1329 | 1330 | Tooltip.prototype.getDefaults = function () { 1331 | return Tooltip.DEFAULTS 1332 | } 1333 | 1334 | Tooltip.prototype.getOptions = function (options) { 1335 | options = $.extend({}, this.getDefaults(), this.$element.data(), options) 1336 | 1337 | if (options.delay && typeof options.delay == 'number') { 1338 | options.delay = { 1339 | show: options.delay, 1340 | hide: options.delay 1341 | } 1342 | } 1343 | 1344 | return options 1345 | } 1346 | 1347 | Tooltip.prototype.getDelegateOptions = function () { 1348 | var options = {} 1349 | var defaults = this.getDefaults() 1350 | 1351 | this._options && $.each(this._options, function (key, value) { 1352 | if (defaults[key] != value) options[key] = value 1353 | }) 1354 | 1355 | return options 1356 | } 1357 | 1358 | Tooltip.prototype.enter = function (obj) { 1359 | var self = obj instanceof this.constructor ? 1360 | obj : $(obj.currentTarget).data('bs.' + this.type) 1361 | 1362 | if (!self) { 1363 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 1364 | $(obj.currentTarget).data('bs.' + this.type, self) 1365 | } 1366 | 1367 | if (obj instanceof $.Event) { 1368 | self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true 1369 | } 1370 | 1371 | if (self.tip().hasClass('in') || self.hoverState == 'in') { 1372 | self.hoverState = 'in' 1373 | return 1374 | } 1375 | 1376 | clearTimeout(self.timeout) 1377 | 1378 | self.hoverState = 'in' 1379 | 1380 | if (!self.options.delay || !self.options.delay.show) return self.show() 1381 | 1382 | self.timeout = setTimeout(function () { 1383 | if (self.hoverState == 'in') self.show() 1384 | }, self.options.delay.show) 1385 | } 1386 | 1387 | Tooltip.prototype.isInStateTrue = function () { 1388 | for (var key in this.inState) { 1389 | if (this.inState[key]) return true 1390 | } 1391 | 1392 | return false 1393 | } 1394 | 1395 | Tooltip.prototype.leave = function (obj) { 1396 | var self = obj instanceof this.constructor ? 1397 | obj : $(obj.currentTarget).data('bs.' + this.type) 1398 | 1399 | if (!self) { 1400 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 1401 | $(obj.currentTarget).data('bs.' + this.type, self) 1402 | } 1403 | 1404 | if (obj instanceof $.Event) { 1405 | self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false 1406 | } 1407 | 1408 | if (self.isInStateTrue()) return 1409 | 1410 | clearTimeout(self.timeout) 1411 | 1412 | self.hoverState = 'out' 1413 | 1414 | if (!self.options.delay || !self.options.delay.hide) return self.hide() 1415 | 1416 | self.timeout = setTimeout(function () { 1417 | if (self.hoverState == 'out') self.hide() 1418 | }, self.options.delay.hide) 1419 | } 1420 | 1421 | Tooltip.prototype.show = function () { 1422 | var e = $.Event('show.bs.' + this.type) 1423 | 1424 | if (this.hasContent() && this.enabled) { 1425 | this.$element.trigger(e) 1426 | 1427 | var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) 1428 | if (e.isDefaultPrevented() || !inDom) return 1429 | var that = this 1430 | 1431 | var $tip = this.tip() 1432 | 1433 | var tipId = this.getUID(this.type) 1434 | 1435 | this.setContent() 1436 | $tip.attr('id', tipId) 1437 | this.$element.attr('aria-describedby', tipId) 1438 | 1439 | if (this.options.animation) $tip.addClass('fade') 1440 | 1441 | var placement = typeof this.options.placement == 'function' ? 1442 | this.options.placement.call(this, $tip[0], this.$element[0]) : 1443 | this.options.placement 1444 | 1445 | var autoToken = /\s?auto?\s?/i 1446 | var autoPlace = autoToken.test(placement) 1447 | if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 1448 | 1449 | $tip 1450 | .detach() 1451 | .css({ top: 0, left: 0, display: 'block' }) 1452 | .addClass(placement) 1453 | .data('bs.' + this.type, this) 1454 | 1455 | this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 1456 | this.$element.trigger('inserted.bs.' + this.type) 1457 | 1458 | var pos = this.getPosition() 1459 | var actualWidth = $tip[0].offsetWidth 1460 | var actualHeight = $tip[0].offsetHeight 1461 | 1462 | if (autoPlace) { 1463 | var orgPlacement = placement 1464 | var viewportDim = this.getPosition(this.$viewport) 1465 | 1466 | placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : 1467 | placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : 1468 | placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : 1469 | placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : 1470 | placement 1471 | 1472 | $tip 1473 | .removeClass(orgPlacement) 1474 | .addClass(placement) 1475 | } 1476 | 1477 | var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 1478 | 1479 | this.applyPlacement(calculatedOffset, placement) 1480 | 1481 | var complete = function () { 1482 | var prevHoverState = that.hoverState 1483 | that.$element.trigger('shown.bs.' + that.type) 1484 | that.hoverState = null 1485 | 1486 | if (prevHoverState == 'out') that.leave(that) 1487 | } 1488 | 1489 | $.support.transition && this.$tip.hasClass('fade') ? 1490 | $tip 1491 | .one('bsTransitionEnd', complete) 1492 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 1493 | complete() 1494 | } 1495 | } 1496 | 1497 | Tooltip.prototype.applyPlacement = function (offset, placement) { 1498 | var $tip = this.tip() 1499 | var width = $tip[0].offsetWidth 1500 | var height = $tip[0].offsetHeight 1501 | 1502 | // manually read margins because getBoundingClientRect includes difference 1503 | var marginTop = parseInt($tip.css('margin-top'), 10) 1504 | var marginLeft = parseInt($tip.css('margin-left'), 10) 1505 | 1506 | // we must check for NaN for ie 8/9 1507 | if (isNaN(marginTop)) marginTop = 0 1508 | if (isNaN(marginLeft)) marginLeft = 0 1509 | 1510 | offset.top += marginTop 1511 | offset.left += marginLeft 1512 | 1513 | // $.fn.offset doesn't round pixel values 1514 | // so we use setOffset directly with our own function B-0 1515 | $.offset.setOffset($tip[0], $.extend({ 1516 | using: function (props) { 1517 | $tip.css({ 1518 | top: Math.round(props.top), 1519 | left: Math.round(props.left) 1520 | }) 1521 | } 1522 | }, offset), 0) 1523 | 1524 | $tip.addClass('in') 1525 | 1526 | // check to see if placing tip in new offset caused the tip to resize itself 1527 | var actualWidth = $tip[0].offsetWidth 1528 | var actualHeight = $tip[0].offsetHeight 1529 | 1530 | if (placement == 'top' && actualHeight != height) { 1531 | offset.top = offset.top + height - actualHeight 1532 | } 1533 | 1534 | var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 1535 | 1536 | if (delta.left) offset.left += delta.left 1537 | else offset.top += delta.top 1538 | 1539 | var isVertical = /top|bottom/.test(placement) 1540 | var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 1541 | var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' 1542 | 1543 | $tip.offset(offset) 1544 | this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) 1545 | } 1546 | 1547 | Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { 1548 | this.arrow() 1549 | .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') 1550 | .css(isVertical ? 'top' : 'left', '') 1551 | } 1552 | 1553 | Tooltip.prototype.setContent = function () { 1554 | var $tip = this.tip() 1555 | var title = this.getTitle() 1556 | 1557 | $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 1558 | $tip.removeClass('fade in top bottom left right') 1559 | } 1560 | 1561 | Tooltip.prototype.hide = function (callback) { 1562 | var that = this 1563 | var $tip = $(this.$tip) 1564 | var e = $.Event('hide.bs.' + this.type) 1565 | 1566 | function complete() { 1567 | if (that.hoverState != 'in') $tip.detach() 1568 | that.$element 1569 | .removeAttr('aria-describedby') 1570 | .trigger('hidden.bs.' + that.type) 1571 | callback && callback() 1572 | } 1573 | 1574 | this.$element.trigger(e) 1575 | 1576 | if (e.isDefaultPrevented()) return 1577 | 1578 | $tip.removeClass('in') 1579 | 1580 | $.support.transition && $tip.hasClass('fade') ? 1581 | $tip 1582 | .one('bsTransitionEnd', complete) 1583 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 1584 | complete() 1585 | 1586 | this.hoverState = null 1587 | 1588 | return this 1589 | } 1590 | 1591 | Tooltip.prototype.fixTitle = function () { 1592 | var $e = this.$element 1593 | if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { 1594 | $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 1595 | } 1596 | } 1597 | 1598 | Tooltip.prototype.hasContent = function () { 1599 | return this.getTitle() 1600 | } 1601 | 1602 | Tooltip.prototype.getPosition = function ($element) { 1603 | $element = $element || this.$element 1604 | 1605 | var el = $element[0] 1606 | var isBody = el.tagName == 'BODY' 1607 | 1608 | var elRect = el.getBoundingClientRect() 1609 | if (elRect.width == null) { 1610 | // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 1611 | elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 1612 | } 1613 | var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() 1614 | var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 1615 | var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 1616 | 1617 | return $.extend({}, elRect, scroll, outerDims, elOffset) 1618 | } 1619 | 1620 | Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 1621 | return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 1622 | placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 1623 | placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 1624 | /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 1625 | 1626 | } 1627 | 1628 | Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 1629 | var delta = { top: 0, left: 0 } 1630 | if (!this.$viewport) return delta 1631 | 1632 | var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 1633 | var viewportDimensions = this.getPosition(this.$viewport) 1634 | 1635 | if (/right|left/.test(placement)) { 1636 | var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 1637 | var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 1638 | if (topEdgeOffset < viewportDimensions.top) { // top overflow 1639 | delta.top = viewportDimensions.top - topEdgeOffset 1640 | } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 1641 | delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 1642 | } 1643 | } else { 1644 | var leftEdgeOffset = pos.left - viewportPadding 1645 | var rightEdgeOffset = pos.left + viewportPadding + actualWidth 1646 | if (leftEdgeOffset < viewportDimensions.left) { // left overflow 1647 | delta.left = viewportDimensions.left - leftEdgeOffset 1648 | } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow 1649 | delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 1650 | } 1651 | } 1652 | 1653 | return delta 1654 | } 1655 | 1656 | Tooltip.prototype.getTitle = function () { 1657 | var title 1658 | var $e = this.$element 1659 | var o = this.options 1660 | 1661 | title = $e.attr('data-original-title') 1662 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 1663 | 1664 | return title 1665 | } 1666 | 1667 | Tooltip.prototype.getUID = function (prefix) { 1668 | do prefix += ~~(Math.random() * 1000000) 1669 | while (document.getElementById(prefix)) 1670 | return prefix 1671 | } 1672 | 1673 | Tooltip.prototype.tip = function () { 1674 | if (!this.$tip) { 1675 | this.$tip = $(this.options.template) 1676 | if (this.$tip.length != 1) { 1677 | throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') 1678 | } 1679 | } 1680 | return this.$tip 1681 | } 1682 | 1683 | Tooltip.prototype.arrow = function () { 1684 | return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 1685 | } 1686 | 1687 | Tooltip.prototype.enable = function () { 1688 | this.enabled = true 1689 | } 1690 | 1691 | Tooltip.prototype.disable = function () { 1692 | this.enabled = false 1693 | } 1694 | 1695 | Tooltip.prototype.toggleEnabled = function () { 1696 | this.enabled = !this.enabled 1697 | } 1698 | 1699 | Tooltip.prototype.toggle = function (e) { 1700 | var self = this 1701 | if (e) { 1702 | self = $(e.currentTarget).data('bs.' + this.type) 1703 | if (!self) { 1704 | self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 1705 | $(e.currentTarget).data('bs.' + this.type, self) 1706 | } 1707 | } 1708 | 1709 | if (e) { 1710 | self.inState.click = !self.inState.click 1711 | if (self.isInStateTrue()) self.enter(self) 1712 | else self.leave(self) 1713 | } else { 1714 | self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 1715 | } 1716 | } 1717 | 1718 | Tooltip.prototype.destroy = function () { 1719 | var that = this 1720 | clearTimeout(this.timeout) 1721 | this.hide(function () { 1722 | that.$element.off('.' + that.type).removeData('bs.' + that.type) 1723 | if (that.$tip) { 1724 | that.$tip.detach() 1725 | } 1726 | that.$tip = null 1727 | that.$arrow = null 1728 | that.$viewport = null 1729 | }) 1730 | } 1731 | 1732 | 1733 | // TOOLTIP PLUGIN DEFINITION 1734 | // ========================= 1735 | 1736 | function Plugin(option) { 1737 | return this.each(function () { 1738 | var $this = $(this) 1739 | var data = $this.data('bs.tooltip') 1740 | var options = typeof option == 'object' && option 1741 | 1742 | if (!data && /destroy|hide/.test(option)) return 1743 | if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 1744 | if (typeof option == 'string') data[option]() 1745 | }) 1746 | } 1747 | 1748 | var old = $.fn.tooltip 1749 | 1750 | $.fn.tooltip = Plugin 1751 | $.fn.tooltip.Constructor = Tooltip 1752 | 1753 | 1754 | // TOOLTIP NO CONFLICT 1755 | // =================== 1756 | 1757 | $.fn.tooltip.noConflict = function () { 1758 | $.fn.tooltip = old 1759 | return this 1760 | } 1761 | 1762 | }(jQuery); 1763 | 1764 | /* ======================================================================== 1765 | * Bootstrap: popover.js v3.3.6 1766 | * http://getbootstrap.com/javascript/#popovers 1767 | * ======================================================================== 1768 | * Copyright 2011-2015 Twitter, Inc. 1769 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1770 | * ======================================================================== */ 1771 | 1772 | 1773 | +function ($) { 1774 | 'use strict'; 1775 | 1776 | // POPOVER PUBLIC CLASS DEFINITION 1777 | // =============================== 1778 | 1779 | var Popover = function (element, options) { 1780 | this.init('popover', element, options) 1781 | } 1782 | 1783 | if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 1784 | 1785 | Popover.VERSION = '3.3.6' 1786 | 1787 | Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 1788 | placement: 'right', 1789 | trigger: 'click', 1790 | content: '', 1791 | template: '' 1792 | }) 1793 | 1794 | 1795 | // NOTE: POPOVER EXTENDS tooltip.js 1796 | // ================================ 1797 | 1798 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 1799 | 1800 | Popover.prototype.constructor = Popover 1801 | 1802 | Popover.prototype.getDefaults = function () { 1803 | return Popover.DEFAULTS 1804 | } 1805 | 1806 | Popover.prototype.setContent = function () { 1807 | var $tip = this.tip() 1808 | var title = this.getTitle() 1809 | var content = this.getContent() 1810 | 1811 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 1812 | $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events 1813 | this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 1814 | ](content) 1815 | 1816 | $tip.removeClass('fade top bottom left right in') 1817 | 1818 | // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 1819 | // this manually by checking the contents. 1820 | if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 1821 | } 1822 | 1823 | Popover.prototype.hasContent = function () { 1824 | return this.getTitle() || this.getContent() 1825 | } 1826 | 1827 | Popover.prototype.getContent = function () { 1828 | var $e = this.$element 1829 | var o = this.options 1830 | 1831 | return $e.attr('data-content') 1832 | || (typeof o.content == 'function' ? 1833 | o.content.call($e[0]) : 1834 | o.content) 1835 | } 1836 | 1837 | Popover.prototype.arrow = function () { 1838 | return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 1839 | } 1840 | 1841 | 1842 | // POPOVER PLUGIN DEFINITION 1843 | // ========================= 1844 | 1845 | function Plugin(option) { 1846 | return this.each(function () { 1847 | var $this = $(this) 1848 | var data = $this.data('bs.popover') 1849 | var options = typeof option == 'object' && option 1850 | 1851 | if (!data && /destroy|hide/.test(option)) return 1852 | if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 1853 | if (typeof option == 'string') data[option]() 1854 | }) 1855 | } 1856 | 1857 | var old = $.fn.popover 1858 | 1859 | $.fn.popover = Plugin 1860 | $.fn.popover.Constructor = Popover 1861 | 1862 | 1863 | // POPOVER NO CONFLICT 1864 | // =================== 1865 | 1866 | $.fn.popover.noConflict = function () { 1867 | $.fn.popover = old 1868 | return this 1869 | } 1870 | 1871 | }(jQuery); 1872 | 1873 | /* ======================================================================== 1874 | * Bootstrap: scrollspy.js v3.3.6 1875 | * http://getbootstrap.com/javascript/#scrollspy 1876 | * ======================================================================== 1877 | * Copyright 2011-2015 Twitter, Inc. 1878 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1879 | * ======================================================================== */ 1880 | 1881 | 1882 | +function ($) { 1883 | 'use strict'; 1884 | 1885 | // SCROLLSPY CLASS DEFINITION 1886 | // ========================== 1887 | 1888 | function ScrollSpy(element, options) { 1889 | this.$body = $(document.body) 1890 | this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) 1891 | this.options = $.extend({}, ScrollSpy.DEFAULTS, options) 1892 | this.selector = (this.options.target || '') + ' .nav li > a' 1893 | this.offsets = [] 1894 | this.targets = [] 1895 | this.activeTarget = null 1896 | this.scrollHeight = 0 1897 | 1898 | this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) 1899 | this.refresh() 1900 | this.process() 1901 | } 1902 | 1903 | ScrollSpy.VERSION = '3.3.6' 1904 | 1905 | ScrollSpy.DEFAULTS = { 1906 | offset: 10 1907 | } 1908 | 1909 | ScrollSpy.prototype.getScrollHeight = function () { 1910 | return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) 1911 | } 1912 | 1913 | ScrollSpy.prototype.refresh = function () { 1914 | var that = this 1915 | var offsetMethod = 'offset' 1916 | var offsetBase = 0 1917 | 1918 | this.offsets = [] 1919 | this.targets = [] 1920 | this.scrollHeight = this.getScrollHeight() 1921 | 1922 | if (!$.isWindow(this.$scrollElement[0])) { 1923 | offsetMethod = 'position' 1924 | offsetBase = this.$scrollElement.scrollTop() 1925 | } 1926 | 1927 | this.$body 1928 | .find(this.selector) 1929 | .map(function () { 1930 | var $el = $(this) 1931 | var href = $el.data('target') || $el.attr('href') 1932 | var $href = /^#./.test(href) && $(href) 1933 | 1934 | return ($href 1935 | && $href.length 1936 | && $href.is(':visible') 1937 | && [[$href[offsetMethod]().top + offsetBase, href]]) || null 1938 | }) 1939 | .sort(function (a, b) { return a[0] - b[0] }) 1940 | .each(function () { 1941 | that.offsets.push(this[0]) 1942 | that.targets.push(this[1]) 1943 | }) 1944 | } 1945 | 1946 | ScrollSpy.prototype.process = function () { 1947 | var scrollTop = this.$scrollElement.scrollTop() + this.options.offset 1948 | var scrollHeight = this.getScrollHeight() 1949 | var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() 1950 | var offsets = this.offsets 1951 | var targets = this.targets 1952 | var activeTarget = this.activeTarget 1953 | var i 1954 | 1955 | if (this.scrollHeight != scrollHeight) { 1956 | this.refresh() 1957 | } 1958 | 1959 | if (scrollTop >= maxScroll) { 1960 | return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) 1961 | } 1962 | 1963 | if (activeTarget && scrollTop < offsets[0]) { 1964 | this.activeTarget = null 1965 | return this.clear() 1966 | } 1967 | 1968 | for (i = offsets.length; i--;) { 1969 | activeTarget != targets[i] 1970 | && scrollTop >= offsets[i] 1971 | && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) 1972 | && this.activate(targets[i]) 1973 | } 1974 | } 1975 | 1976 | ScrollSpy.prototype.activate = function (target) { 1977 | this.activeTarget = target 1978 | 1979 | this.clear() 1980 | 1981 | var selector = this.selector + 1982 | '[data-target="' + target + '"],' + 1983 | this.selector + '[href="' + target + '"]' 1984 | 1985 | var active = $(selector) 1986 | .parents('li') 1987 | .addClass('active') 1988 | 1989 | if (active.parent('.dropdown-menu').length) { 1990 | active = active 1991 | .closest('li.dropdown') 1992 | .addClass('active') 1993 | } 1994 | 1995 | active.trigger('activate.bs.scrollspy') 1996 | } 1997 | 1998 | ScrollSpy.prototype.clear = function () { 1999 | $(this.selector) 2000 | .parentsUntil(this.options.target, '.active') 2001 | .removeClass('active') 2002 | } 2003 | 2004 | 2005 | // SCROLLSPY PLUGIN DEFINITION 2006 | // =========================== 2007 | 2008 | function Plugin(option) { 2009 | return this.each(function () { 2010 | var $this = $(this) 2011 | var data = $this.data('bs.scrollspy') 2012 | var options = typeof option == 'object' && option 2013 | 2014 | if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) 2015 | if (typeof option == 'string') data[option]() 2016 | }) 2017 | } 2018 | 2019 | var old = $.fn.scrollspy 2020 | 2021 | $.fn.scrollspy = Plugin 2022 | $.fn.scrollspy.Constructor = ScrollSpy 2023 | 2024 | 2025 | // SCROLLSPY NO CONFLICT 2026 | // ===================== 2027 | 2028 | $.fn.scrollspy.noConflict = function () { 2029 | $.fn.scrollspy = old 2030 | return this 2031 | } 2032 | 2033 | 2034 | // SCROLLSPY DATA-API 2035 | // ================== 2036 | 2037 | $(window).on('load.bs.scrollspy.data-api', function () { 2038 | $('[data-spy="scroll"]').each(function () { 2039 | var $spy = $(this) 2040 | Plugin.call($spy, $spy.data()) 2041 | }) 2042 | }) 2043 | 2044 | }(jQuery); 2045 | 2046 | /* ======================================================================== 2047 | * Bootstrap: tab.js v3.3.6 2048 | * http://getbootstrap.com/javascript/#tabs 2049 | * ======================================================================== 2050 | * Copyright 2011-2015 Twitter, Inc. 2051 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2052 | * ======================================================================== */ 2053 | 2054 | 2055 | +function ($) { 2056 | 'use strict'; 2057 | 2058 | // TAB CLASS DEFINITION 2059 | // ==================== 2060 | 2061 | var Tab = function (element) { 2062 | // jscs:disable requireDollarBeforejQueryAssignment 2063 | this.element = $(element) 2064 | // jscs:enable requireDollarBeforejQueryAssignment 2065 | } 2066 | 2067 | Tab.VERSION = '3.3.6' 2068 | 2069 | Tab.TRANSITION_DURATION = 150 2070 | 2071 | Tab.prototype.show = function () { 2072 | var $this = this.element 2073 | var $ul = $this.closest('ul:not(.dropdown-menu)') 2074 | var selector = $this.data('target') 2075 | 2076 | if (!selector) { 2077 | selector = $this.attr('href') 2078 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 2079 | } 2080 | 2081 | if ($this.parent('li').hasClass('active')) return 2082 | 2083 | var $previous = $ul.find('.active:last a') 2084 | var hideEvent = $.Event('hide.bs.tab', { 2085 | relatedTarget: $this[0] 2086 | }) 2087 | var showEvent = $.Event('show.bs.tab', { 2088 | relatedTarget: $previous[0] 2089 | }) 2090 | 2091 | $previous.trigger(hideEvent) 2092 | $this.trigger(showEvent) 2093 | 2094 | if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return 2095 | 2096 | var $target = $(selector) 2097 | 2098 | this.activate($this.closest('li'), $ul) 2099 | this.activate($target, $target.parent(), function () { 2100 | $previous.trigger({ 2101 | type: 'hidden.bs.tab', 2102 | relatedTarget: $this[0] 2103 | }) 2104 | $this.trigger({ 2105 | type: 'shown.bs.tab', 2106 | relatedTarget: $previous[0] 2107 | }) 2108 | }) 2109 | } 2110 | 2111 | Tab.prototype.activate = function (element, container, callback) { 2112 | var $active = container.find('> .active') 2113 | var transition = callback 2114 | && $.support.transition 2115 | && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) 2116 | 2117 | function next() { 2118 | $active 2119 | .removeClass('active') 2120 | .find('> .dropdown-menu > .active') 2121 | .removeClass('active') 2122 | .end() 2123 | .find('[data-toggle="tab"]') 2124 | .attr('aria-expanded', false) 2125 | 2126 | element 2127 | .addClass('active') 2128 | .find('[data-toggle="tab"]') 2129 | .attr('aria-expanded', true) 2130 | 2131 | if (transition) { 2132 | element[0].offsetWidth // reflow for transition 2133 | element.addClass('in') 2134 | } else { 2135 | element.removeClass('fade') 2136 | } 2137 | 2138 | if (element.parent('.dropdown-menu').length) { 2139 | element 2140 | .closest('li.dropdown') 2141 | .addClass('active') 2142 | .end() 2143 | .find('[data-toggle="tab"]') 2144 | .attr('aria-expanded', true) 2145 | } 2146 | 2147 | callback && callback() 2148 | } 2149 | 2150 | $active.length && transition ? 2151 | $active 2152 | .one('bsTransitionEnd', next) 2153 | .emulateTransitionEnd(Tab.TRANSITION_DURATION) : 2154 | next() 2155 | 2156 | $active.removeClass('in') 2157 | } 2158 | 2159 | 2160 | // TAB PLUGIN DEFINITION 2161 | // ===================== 2162 | 2163 | function Plugin(option) { 2164 | return this.each(function () { 2165 | var $this = $(this) 2166 | var data = $this.data('bs.tab') 2167 | 2168 | if (!data) $this.data('bs.tab', (data = new Tab(this))) 2169 | if (typeof option == 'string') data[option]() 2170 | }) 2171 | } 2172 | 2173 | var old = $.fn.tab 2174 | 2175 | $.fn.tab = Plugin 2176 | $.fn.tab.Constructor = Tab 2177 | 2178 | 2179 | // TAB NO CONFLICT 2180 | // =============== 2181 | 2182 | $.fn.tab.noConflict = function () { 2183 | $.fn.tab = old 2184 | return this 2185 | } 2186 | 2187 | 2188 | // TAB DATA-API 2189 | // ============ 2190 | 2191 | var clickHandler = function (e) { 2192 | e.preventDefault() 2193 | Plugin.call($(this), 'show') 2194 | } 2195 | 2196 | $(document) 2197 | .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) 2198 | .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) 2199 | 2200 | }(jQuery); 2201 | 2202 | /* ======================================================================== 2203 | * Bootstrap: affix.js v3.3.6 2204 | * http://getbootstrap.com/javascript/#affix 2205 | * ======================================================================== 2206 | * Copyright 2011-2015 Twitter, Inc. 2207 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 2208 | * ======================================================================== */ 2209 | 2210 | 2211 | +function ($) { 2212 | 'use strict'; 2213 | 2214 | // AFFIX CLASS DEFINITION 2215 | // ====================== 2216 | 2217 | var Affix = function (element, options) { 2218 | this.options = $.extend({}, Affix.DEFAULTS, options) 2219 | 2220 | this.$target = $(this.options.target) 2221 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 2222 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 2223 | 2224 | this.$element = $(element) 2225 | this.affixed = null 2226 | this.unpin = null 2227 | this.pinnedOffset = null 2228 | 2229 | this.checkPosition() 2230 | } 2231 | 2232 | Affix.VERSION = '3.3.6' 2233 | 2234 | Affix.RESET = 'affix affix-top affix-bottom' 2235 | 2236 | Affix.DEFAULTS = { 2237 | offset: 0, 2238 | target: window 2239 | } 2240 | 2241 | Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { 2242 | var scrollTop = this.$target.scrollTop() 2243 | var position = this.$element.offset() 2244 | var targetHeight = this.$target.height() 2245 | 2246 | if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false 2247 | 2248 | if (this.affixed == 'bottom') { 2249 | if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' 2250 | return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' 2251 | } 2252 | 2253 | var initializing = this.affixed == null 2254 | var colliderTop = initializing ? scrollTop : position.top 2255 | var colliderHeight = initializing ? targetHeight : height 2256 | 2257 | if (offsetTop != null && scrollTop <= offsetTop) return 'top' 2258 | if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' 2259 | 2260 | return false 2261 | } 2262 | 2263 | Affix.prototype.getPinnedOffset = function () { 2264 | if (this.pinnedOffset) return this.pinnedOffset 2265 | this.$element.removeClass(Affix.RESET).addClass('affix') 2266 | var scrollTop = this.$target.scrollTop() 2267 | var position = this.$element.offset() 2268 | return (this.pinnedOffset = position.top - scrollTop) 2269 | } 2270 | 2271 | Affix.prototype.checkPositionWithEventLoop = function () { 2272 | setTimeout($.proxy(this.checkPosition, this), 1) 2273 | } 2274 | 2275 | Affix.prototype.checkPosition = function () { 2276 | if (!this.$element.is(':visible')) return 2277 | 2278 | var height = this.$element.height() 2279 | var offset = this.options.offset 2280 | var offsetTop = offset.top 2281 | var offsetBottom = offset.bottom 2282 | var scrollHeight = Math.max($(document).height(), $(document.body).height()) 2283 | 2284 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 2285 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 2286 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 2287 | 2288 | var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) 2289 | 2290 | if (this.affixed != affix) { 2291 | if (this.unpin != null) this.$element.css('top', '') 2292 | 2293 | var affixType = 'affix' + (affix ? '-' + affix : '') 2294 | var e = $.Event(affixType + '.bs.affix') 2295 | 2296 | this.$element.trigger(e) 2297 | 2298 | if (e.isDefaultPrevented()) return 2299 | 2300 | this.affixed = affix 2301 | this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 2302 | 2303 | this.$element 2304 | .removeClass(Affix.RESET) 2305 | .addClass(affixType) 2306 | .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') 2307 | } 2308 | 2309 | if (affix == 'bottom') { 2310 | this.$element.offset({ 2311 | top: scrollHeight - height - offsetBottom 2312 | }) 2313 | } 2314 | } 2315 | 2316 | 2317 | // AFFIX PLUGIN DEFINITION 2318 | // ======================= 2319 | 2320 | function Plugin(option) { 2321 | return this.each(function () { 2322 | var $this = $(this) 2323 | var data = $this.data('bs.affix') 2324 | var options = typeof option == 'object' && option 2325 | 2326 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 2327 | if (typeof option == 'string') data[option]() 2328 | }) 2329 | } 2330 | 2331 | var old = $.fn.affix 2332 | 2333 | $.fn.affix = Plugin 2334 | $.fn.affix.Constructor = Affix 2335 | 2336 | 2337 | // AFFIX NO CONFLICT 2338 | // ================= 2339 | 2340 | $.fn.affix.noConflict = function () { 2341 | $.fn.affix = old 2342 | return this 2343 | } 2344 | 2345 | 2346 | // AFFIX DATA-API 2347 | // ============== 2348 | 2349 | $(window).on('load', function () { 2350 | $('[data-spy="affix"]').each(function () { 2351 | var $spy = $(this) 2352 | var data = $spy.data() 2353 | 2354 | data.offset = data.offset || {} 2355 | 2356 | if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom 2357 | if (data.offsetTop != null) data.offset.top = data.offsetTop 2358 | 2359 | Plugin.call($spy, data) 2360 | }) 2361 | }) 2362 | 2363 | }(jQuery); 2364 | -------------------------------------------------------------------------------- /js/city-picker.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * CityPicker v1.0.2 3 | * https://github.com/tshi0912/citypicker 4 | * 5 | * Copyright (c) 2015-2016 Tao Shi 6 | * Released under the MIT license 7 | * 8 | * Date: 2016-02-29T12:11:36.477Z 9 | */ 10 | 11 | (function (factory) { 12 | if (typeof define === 'function' && define.amd) { 13 | // AMD. Register as anonymous module. 14 | define(['jquery', 'ChineseDistricts'], factory); 15 | } else if (typeof exports === 'object') { 16 | // Node / CommonJS 17 | factory(require('jquery'), require('ChineseDistricts')); 18 | } else { 19 | // Browser globals. 20 | factory(jQuery, ChineseDistricts); 21 | } 22 | })(function ($, ChineseDistricts) { 23 | 24 | 'use strict'; 25 | 26 | if (typeof ChineseDistricts === 'undefined') { 27 | throw new Error('The file "city-picker.data.js" must be included first!'); 28 | } 29 | 30 | var NAMESPACE = 'citypicker'; 31 | var EVENT_CHANGE = 'change.' + NAMESPACE; 32 | var PROVINCE = 'province'; 33 | var CITY = 'city'; 34 | var DISTRICT = 'district'; 35 | 36 | function CityPicker(element, options) { 37 | this.$element = $(element); 38 | this.$dropdown = null; 39 | this.options = $.extend({}, CityPicker.DEFAULTS, $.isPlainObject(options) && options); 40 | this.active = false; 41 | this.dems = []; 42 | this.needBlur = false; 43 | this.init(); 44 | } 45 | 46 | CityPicker.prototype = { 47 | constructor: CityPicker, 48 | 49 | init: function () { 50 | 51 | this.defineDems(); 52 | 53 | this.render(); 54 | 55 | this.bind(); 56 | 57 | this.active = true; 58 | }, 59 | 60 | render: function () { 61 | var p = this.getPosition(), 62 | placeholder = this.$element.attr('placeholder') || this.options.placeholder, 63 | textspan = '' + 66 | (placeholder ? '' + placeholder + '' : '') + 67 | '
' + '
', 68 | 69 | dropdown = '
' + 71 | '
' + 72 | '
' + 73 | '省份' + 74 | (this.includeDem('city') ? '城市' : '') + 75 | (this.includeDem('district') ? '区县' : '') + '
' + 76 | '
' + 77 | '
' + 78 | (this.includeDem('city') ? '
' : '') + 79 | (this.includeDem('district') ? '
' : '') + 80 | '
'; 81 | 82 | this.$element.addClass('city-picker-input'); 83 | this.$textspan = $(textspan).insertAfter(this.$element); 84 | this.$dropdown = $(dropdown).insertAfter(this.$textspan); 85 | var $select = this.$dropdown.find('.city-select'); 86 | 87 | // setup this.$province, this.$city and/or this.$district object 88 | $.each(this.dems, $.proxy(function (i, type) { 89 | this['$' + type] = $select.filter('.' + type + ''); 90 | }, this)); 91 | 92 | this.refresh(); 93 | }, 94 | 95 | refresh: function (force) { 96 | // clean the data-item for each $select 97 | var $select = this.$dropdown.find('.city-select'); 98 | $select.data('item', null); 99 | // parse value from value of the target $element 100 | var val = this.$element.val() || ''; 101 | val = val.split('/'); 102 | $.each(this.dems, $.proxy(function (i, type) { 103 | if (val[i] && i < val.length) { 104 | this.options[type] = val[i]; 105 | } else if (force) { 106 | this.options[type] = ''; 107 | } 108 | this.output(type); 109 | }, this)); 110 | this.tab(PROVINCE); 111 | this.feedText(); 112 | this.feedVal(); 113 | }, 114 | 115 | defineDems: function () { 116 | var stop = false; 117 | $.each([PROVINCE, CITY, DISTRICT], $.proxy(function (i, type) { 118 | if (!stop) { 119 | this.dems.push(type); 120 | } 121 | if (type === this.options.level) { 122 | stop = true; 123 | } 124 | }, this)); 125 | }, 126 | 127 | includeDem: function (type) { 128 | return $.inArray(type, this.dems) !== -1; 129 | }, 130 | 131 | getPosition: function () { 132 | var p, h, w, s, pw; 133 | p = this.$element.position(); 134 | s = this.getSize(this.$element); 135 | h = s.height; 136 | w = s.width; 137 | if (this.options.responsive) { 138 | pw = this.$element.offsetParent().width(); 139 | if (pw) { 140 | w = w / pw; 141 | if (w > 0.99) { 142 | w = 1; 143 | } 144 | w = w * 100 + '%'; 145 | } 146 | } 147 | 148 | return { 149 | top: p.top || 0, 150 | left: p.left || 0, 151 | height: h, 152 | width: w 153 | }; 154 | }, 155 | 156 | getSize: function ($dom) { 157 | var $wrap, $clone, sizes; 158 | if (!$dom.is(':visible')) { 159 | $wrap = $("
").appendTo($("body")); 160 | $wrap.css({ 161 | "position": "absolute !important", 162 | "visibility": "hidden !important", 163 | "display": "block !important" 164 | }); 165 | 166 | $clone = $dom.clone().appendTo($wrap); 167 | 168 | sizes = { 169 | width: $clone.outerWidth(), 170 | height: $clone.outerHeight() 171 | }; 172 | 173 | $wrap.remove(); 174 | } else { 175 | sizes = { 176 | width: $dom.outerWidth(), 177 | height: $dom.outerHeight() 178 | }; 179 | } 180 | 181 | return sizes; 182 | }, 183 | 184 | getWidthStyle: function (w, dropdown) { 185 | if (this.options.responsive && !$.isNumeric(w)) { 186 | return 'width:' + w + ';'; 187 | } else { 188 | return 'width:' + (dropdown ? Math.max(320, w) : w) + 'px;'; 189 | } 190 | }, 191 | 192 | bind: function () { 193 | var $this = this; 194 | 195 | $(document).on('click', (this._mouteclick = function (e) { 196 | var $target = $(e.target); 197 | var $dropdown, $span, $input; 198 | if ($target.is('.city-picker-span')) { 199 | $span = $target; 200 | } else if ($target.is('.city-picker-span *')) { 201 | $span = $target.parents('.city-picker-span'); 202 | } 203 | if ($target.is('.city-picker-input')) { 204 | $input = $target; 205 | } 206 | if ($target.is('.city-picker-dropdown')) { 207 | $dropdown = $target; 208 | } else if ($target.is('.city-picker-dropdown *')) { 209 | $dropdown = $target.parents('.city-picker-dropdown'); 210 | } 211 | if ((!$input && !$span && !$dropdown) || 212 | ($span && $span.get(0) !== $this.$textspan.get(0)) || 213 | ($input && $input.get(0) !== $this.$element.get(0)) || 214 | ($dropdown && $dropdown.get(0) !== $this.$dropdown.get(0))) { 215 | $this.close(true); 216 | } 217 | 218 | })); 219 | 220 | this.$element.on('change', (this._changeElement = $.proxy(function () { 221 | this.close(true); 222 | this.refresh(true); 223 | }, this))).on('focus', (this._focusElement = $.proxy(function () { 224 | this.needBlur = true; 225 | this.open(); 226 | }, this))).on('blur', (this._blurElement = $.proxy(function () { 227 | if (this.needBlur) { 228 | this.needBlur = false; 229 | this.close(true); 230 | } 231 | }, this))); 232 | 233 | this.$textspan.on('click', function (e) { 234 | var $target = $(e.target), type; 235 | $this.needBlur = false; 236 | if ($target.is('.select-item')) { 237 | type = $target.data('count'); 238 | $this.open(type); 239 | } else { 240 | if ($this.$dropdown.is(':visible')) { 241 | $this.close(); 242 | } else { 243 | $this.open(); 244 | } 245 | } 246 | }).on('mousedown', function () { 247 | $this.needBlur = false; 248 | }); 249 | 250 | this.$dropdown.on('click', '.city-select a', function () { 251 | var $select = $(this).parents('.city-select'); 252 | var $active = $select.find('a.active'); 253 | var last = $select.next().length === 0; 254 | $active.removeClass('active'); 255 | $(this).addClass('active'); 256 | if ($active.data('code') !== $(this).data('code')) { 257 | $select.data('item', { 258 | address: $(this).attr('title'), code: $(this).data('code') 259 | }); 260 | $(this).trigger(EVENT_CHANGE); 261 | $this.feedText(); 262 | $this.feedVal(); 263 | if (last) { 264 | $this.close(); 265 | } 266 | } 267 | }).on('click', '.city-select-tab a', function () { 268 | if (!$(this).hasClass('active')) { 269 | var type = $(this).data('count'); 270 | $this.tab(type); 271 | } 272 | }).on('mousedown', function () { 273 | $this.needBlur = false; 274 | }); 275 | 276 | if (this.$province) { 277 | this.$province.on(EVENT_CHANGE, (this._changeProvince = $.proxy(function () { 278 | this.output(CITY); 279 | this.output(DISTRICT); 280 | this.tab(CITY); 281 | }, this))); 282 | } 283 | 284 | if (this.$city) { 285 | this.$city.on(EVENT_CHANGE, (this._changeCity = $.proxy(function () { 286 | this.output(DISTRICT); 287 | this.tab(DISTRICT); 288 | }, this))); 289 | } 290 | }, 291 | 292 | open: function (type) { 293 | type = type || PROVINCE; 294 | this.$dropdown.show(); 295 | this.$textspan.addClass('open').addClass('focus'); 296 | this.tab(type); 297 | }, 298 | 299 | close: function (blur) { 300 | this.$dropdown.hide(); 301 | this.$textspan.removeClass('open'); 302 | if (blur) { 303 | this.$textspan.removeClass('focus'); 304 | } 305 | }, 306 | 307 | unbind: function () { 308 | 309 | $(document).off('click', this._mouteclick); 310 | 311 | this.$element.off('change', this._changeElement); 312 | this.$element.off('focus', this._focusElement); 313 | this.$element.off('blur', this._blurElement); 314 | 315 | this.$textspan.off('click'); 316 | this.$textspan.off('mousedown'); 317 | 318 | this.$dropdown.off('click'); 319 | this.$dropdown.off('mousedown'); 320 | 321 | if (this.$province) { 322 | this.$province.off(EVENT_CHANGE, this._changeProvince); 323 | } 324 | 325 | if (this.$city) { 326 | this.$city.off(EVENT_CHANGE, this._changeCity); 327 | } 328 | }, 329 | 330 | getText: function () { 331 | var text = ''; 332 | this.$dropdown.find('.city-select') 333 | .each(function () { 334 | var item = $(this).data('item'), 335 | type = $(this).data('count'); 336 | if (item) { 337 | text += ($(this).hasClass('province') ? '' : '/') + '' + item.address + ''; 339 | } 340 | }); 341 | return text; 342 | }, 343 | 344 | getPlaceHolder: function () { 345 | return this.$element.attr('placeholder') || this.options.placeholder; 346 | }, 347 | 348 | feedText: function () { 349 | var text = this.getText(); 350 | if (text) { 351 | this.$textspan.find('>.placeholder').hide(); 352 | this.$textspan.find('>.title').html(this.getText()).show(); 353 | } else { 354 | this.$textspan.find('>.placeholder').text(this.getPlaceHolder()).show(); 355 | this.$textspan.find('>.title').html('').hide(); 356 | } 357 | }, 358 | 359 | getVal: function () { 360 | var text = ''; 361 | this.$dropdown.find('.city-select') 362 | .each(function () { 363 | var item = $(this).data('item'); 364 | if (item) { 365 | text += ($(this).hasClass('province') ? '' : '/') + item.address; 366 | } 367 | }); 368 | return text; 369 | }, 370 | 371 | feedVal: function () { 372 | this.$element.val(this.getVal()); 373 | }, 374 | 375 | output: function (type) { 376 | var options = this.options; 377 | //var placeholders = this.placeholders; 378 | var $select = this['$' + type]; 379 | var data = type === PROVINCE ? {} : []; 380 | var item; 381 | var districts; 382 | var code; 383 | var matched = null; 384 | var value; 385 | 386 | if (!$select || !$select.length) { 387 | return; 388 | } 389 | 390 | item = $select.data('item'); 391 | 392 | value = (item ? item.address : null) || options[type]; 393 | 394 | code = ( 395 | type === PROVINCE ? 86 : 396 | type === CITY ? this.$province && this.$province.find('.active').data('code') : 397 | type === DISTRICT ? this.$city && this.$city.find('.active').data('code') : code 398 | ); 399 | 400 | districts = $.isNumeric(code) ? ChineseDistricts[code] : null; 401 | 402 | if ($.isPlainObject(districts)) { 403 | $.each(districts, function (code, address) { 404 | var provs; 405 | if (type === PROVINCE) { 406 | provs = []; 407 | for (var i = 0; i < address.length; i++) { 408 | if (address[i].address === value) { 409 | matched = { 410 | code: address[i].code, 411 | address: address[i].address 412 | }; 413 | } 414 | provs.push({ 415 | code: address[i].code, 416 | address: address[i].address, 417 | selected: address[i].address === value 418 | }); 419 | } 420 | data[code] = provs; 421 | } else { 422 | if (address === value) { 423 | matched = { 424 | code: code, 425 | address: address 426 | }; 427 | } 428 | data.push({ 429 | code: code, 430 | address: address, 431 | selected: address === value 432 | }); 433 | } 434 | }); 435 | } 436 | 437 | $select.html(type === PROVINCE ? this.getProvinceList(data) : 438 | this.getList(data, type)); 439 | $select.data('item', matched); 440 | }, 441 | 442 | getProvinceList: function (data) { 443 | var list = [], 444 | $this = this, 445 | simple = this.options.simple; 446 | 447 | $.each(data, function (i, n) { 448 | list.push('
'); 449 | list.push('
' + i + '
'); 450 | $.each(n, function (j, m) { 451 | list.push( 452 | '' + 458 | ( simple ? $this.simplize(m.address, PROVINCE) : m.address) + 459 | ''); 460 | }); 461 | list.push('
'); 462 | }); 463 | 464 | return list.join(''); 465 | }, 466 | 467 | getList: function (data, type) { 468 | var list = [], 469 | $this = this, 470 | simple = this.options.simple; 471 | list.push('
'); 472 | 473 | $.each(data, function (i, n) { 474 | list.push( 475 | '' + 481 | ( simple ? $this.simplize(n.address, type) : n.address) + 482 | ''); 483 | }); 484 | list.push('
'); 485 | 486 | return list.join(''); 487 | }, 488 | 489 | simplize: function (address, type) { 490 | address = address || ''; 491 | if (type === PROVINCE) { 492 | return address.replace(/[省,市,自治区,壮族,回族,维吾尔]/g, ''); 493 | } else if (type === CITY) { 494 | return address.replace(/[市,地区,回族,蒙古,苗族,白族,傣族,景颇族,藏族,彝族,壮族,傈僳族,布依族,侗族]/g, '') 495 | .replace('哈萨克', '').replace('自治州', '').replace(/自治县/, ''); 496 | } else if (type === DISTRICT) { 497 | return address.length > 2 ? address.replace(/[市,区,县,旗]/g, '') : address; 498 | } 499 | }, 500 | 501 | tab: function (type) { 502 | var $selects = this.$dropdown.find('.city-select'); 503 | var $tabs = this.$dropdown.find('.city-select-tab > a'); 504 | var $select = this['$' + type]; 505 | var $tab = this.$dropdown.find('.city-select-tab > a[data-count="' + type + '"]'); 506 | if ($select) { 507 | $selects.hide(); 508 | $select.show(); 509 | $tabs.removeClass('active'); 510 | $tab.addClass('active'); 511 | } 512 | }, 513 | 514 | reset: function () { 515 | this.$element.val(null).trigger('change'); 516 | }, 517 | 518 | destroy: function () { 519 | this.unbind(); 520 | this.$element.removeData(NAMESPACE).removeClass('city-picker-input'); 521 | this.$textspan.remove(); 522 | this.$dropdown.remove(); 523 | } 524 | }; 525 | 526 | CityPicker.DEFAULTS = { 527 | simple: false, 528 | responsive: false, 529 | placeholder: '请选择省/市/区', 530 | level: 'district', 531 | province: '', 532 | city: '', 533 | district: '' 534 | }; 535 | 536 | CityPicker.setDefaults = function (options) { 537 | $.extend(CityPicker.DEFAULTS, options); 538 | }; 539 | 540 | // Save the other citypicker 541 | CityPicker.other = $.fn.citypicker; 542 | 543 | // Register as jQuery plugin 544 | $.fn.citypicker = function (option) { 545 | var args = [].slice.call(arguments, 1); 546 | 547 | return this.each(function () { 548 | var $this = $(this); 549 | var data = $this.data(NAMESPACE); 550 | var options; 551 | var fn; 552 | 553 | if (!data) { 554 | if (/destroy/.test(option)) { 555 | return; 556 | } 557 | 558 | options = $.extend({}, $this.data(), $.isPlainObject(option) && option); 559 | $this.data(NAMESPACE, (data = new CityPicker(this, options))); 560 | } 561 | 562 | if (typeof option === 'string' && $.isFunction(fn = data[option])) { 563 | fn.apply(data, args); 564 | } 565 | }); 566 | }; 567 | 568 | $.fn.citypicker.Constructor = CityPicker; 569 | $.fn.citypicker.setDefaults = CityPicker.setDefaults; 570 | 571 | // No conflict 572 | $.fn.citypicker.noConflict = function () { 573 | $.fn.citypicker = CityPicker.other; 574 | return this; 575 | }; 576 | 577 | $(function () { 578 | $('[data-toggle="city-picker"]').citypicker(); 579 | }); 580 | }); -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | 3 | 'use strict'; 4 | 5 | 6 | var $citypicker1 = $('#city-picker1'); 7 | 8 | $citypicker1.citypicker(); 9 | 10 | var $citypicker2 = $('#city-picker2'); 11 | 12 | $citypicker2.citypicker({ 13 | province: '江苏省', 14 | city: '常州市', 15 | district: '溧阳市' 16 | }); 17 | 18 | var $citypicker3 = $('#city-picker3'); 19 | 20 | $('#reset').click(function () { 21 | $citypicker3.citypicker('reset'); 22 | }); 23 | 24 | $('#destroy').click(function () { 25 | $citypicker3.citypicker('destroy'); 26 | }); 27 | // 28 | //$('#distpicker1').distpicker(); 29 | // 30 | //$('#distpicker2').distpicker({ 31 | // province: '---- 所在省 ----', 32 | // city: '---- 所在市 ----', 33 | // district: '---- 所在区 ----' 34 | //}); 35 | // 36 | //$('#distpicker3').distpicker({ 37 | // province: '浙江省', 38 | // city: '杭州市', 39 | // district: '西湖区' 40 | //}); 41 | // 42 | //$('#distpicker4').distpicker({ 43 | // placeholder: false 44 | //}); 45 | // 46 | //$('#distpicker5').distpicker({ 47 | // autoSelect: false 48 | //}); 49 | 50 | }); 51 | --------------------------------------------------------------------------------