├── .gitignore ├── README.md ├── css ├── bootstrap.css └── main.css ├── img └── Blank_US_Map.svg ├── index.html └── js ├── angular.js ├── bootstrap.js ├── controllers.js ├── directives.js └── filters.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Tutorial: Dynamic data-driven SVG map with AngularJS# 2 | 3 | The tutorial that accompanies this example can be found [here](https://medium.com/@tweededbadger/tutorial-dynamic-data-driven-svg-map-with-angularjs-b112fdec421d). 4 | 5 | The example can be seen in action [here](http://tweededbadger.github.io/examples/svg_maps/). 6 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | svg .state { 2 | stroke-width: 2; 3 | stroke: #fff; 4 | 5 | -webkit-transition: stroke 0.5s, stroke-width 0.5s; 6 | -o-transition: stroke 0.5s, stroke-width 0.5s; 7 | transition: stroke 0.5s, stroke-width 0.5s; 8 | } 9 | svg .state:hover , .state.active { 10 | cursor: pointer; 11 | stroke-width: 4; 12 | stroke: #000; 13 | } 14 | 15 | .regionlist { 16 | -webkit-column-count: 5; /* Chrome, Safari, Opera */ 17 | -moz-column-count: 5; /* Firefox */ 18 | column-count: 5; 19 | } 20 | .regionlist > div { 21 | display: inline-block; 22 | width: 100%; 23 | border-bottom: 1px solid grey; 24 | } 25 | 26 | .regionlist > div.active { 27 | font-weight: bold; 28 | background-color: lightblue; 29 | } 30 | 31 | .regionlist > div > div { 32 | display: inline-block; 33 | width: 48%; 34 | } 35 | 36 | .scale { 37 | position: relative; 38 | } 39 | .scale div { 40 | width: 9.07%; 41 | display: inline-block; 42 | text-align: center; 43 | color: #fff; 44 | font-weight: bold; 45 | padding: 5px 0; 46 | } -------------------------------------------------------------------------------- /img/Blank_US_Map.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 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Data Responsive SVG Map 8 | 9 | 10 | 11 | 12 |
13 |

Angular JS Data Responsive SVG Map

14 |
15 |
16 |
17 |
18 |
19 |
20 |
{{n}} 22 |
23 |
24 |
25 |
26 |
27 |
28 |

29 | 30 |

31 |
32 |
33 |
34 |
37 |
{{key}}
38 |
{{region.value | number}}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } 8 | 9 | /* ======================================================================== 10 | * Bootstrap: transition.js v3.2.0 11 | * http://getbootstrap.com/javascript/#transitions 12 | * ======================================================================== 13 | * Copyright 2011-2014 Twitter, Inc. 14 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 15 | * ======================================================================== */ 16 | 17 | 18 | +function ($) { 19 | 'use strict'; 20 | 21 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 22 | // ============================================================ 23 | 24 | function transitionEnd() { 25 | var el = document.createElement('bootstrap') 26 | 27 | var transEndEventNames = { 28 | WebkitTransition : 'webkitTransitionEnd', 29 | MozTransition : 'transitionend', 30 | OTransition : 'oTransitionEnd otransitionend', 31 | transition : 'transitionend' 32 | } 33 | 34 | for (var name in transEndEventNames) { 35 | if (el.style[name] !== undefined) { 36 | return { end: transEndEventNames[name] } 37 | } 38 | } 39 | 40 | return false // explicit for ie8 ( ._.) 41 | } 42 | 43 | // http://blog.alexmaccaw.com/css-transitions 44 | $.fn.emulateTransitionEnd = function (duration) { 45 | var called = false 46 | var $el = this 47 | $(this).one('bsTransitionEnd', function () { called = true }) 48 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 49 | setTimeout(callback, duration) 50 | return this 51 | } 52 | 53 | $(function () { 54 | $.support.transition = transitionEnd() 55 | 56 | if (!$.support.transition) return 57 | 58 | $.event.special.bsTransitionEnd = { 59 | bindType: $.support.transition.end, 60 | delegateType: $.support.transition.end, 61 | handle: function (e) { 62 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 63 | } 64 | } 65 | }) 66 | 67 | }(jQuery); 68 | 69 | /* ======================================================================== 70 | * Bootstrap: alert.js v3.2.0 71 | * http://getbootstrap.com/javascript/#alerts 72 | * ======================================================================== 73 | * Copyright 2011-2014 Twitter, Inc. 74 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 75 | * ======================================================================== */ 76 | 77 | 78 | +function ($) { 79 | 'use strict'; 80 | 81 | // ALERT CLASS DEFINITION 82 | // ====================== 83 | 84 | var dismiss = '[data-dismiss="alert"]' 85 | var Alert = function (el) { 86 | $(el).on('click', dismiss, this.close) 87 | } 88 | 89 | Alert.VERSION = '3.2.0' 90 | 91 | Alert.prototype.close = function (e) { 92 | var $this = $(this) 93 | var selector = $this.attr('data-target') 94 | 95 | if (!selector) { 96 | selector = $this.attr('href') 97 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 98 | } 99 | 100 | var $parent = $(selector) 101 | 102 | if (e) e.preventDefault() 103 | 104 | if (!$parent.length) { 105 | $parent = $this.hasClass('alert') ? $this : $this.parent() 106 | } 107 | 108 | $parent.trigger(e = $.Event('close.bs.alert')) 109 | 110 | if (e.isDefaultPrevented()) return 111 | 112 | $parent.removeClass('in') 113 | 114 | function removeElement() { 115 | // detach from parent, fire event then clean up data 116 | $parent.detach().trigger('closed.bs.alert').remove() 117 | } 118 | 119 | $.support.transition && $parent.hasClass('fade') ? 120 | $parent 121 | .one('bsTransitionEnd', removeElement) 122 | .emulateTransitionEnd(150) : 123 | removeElement() 124 | } 125 | 126 | 127 | // ALERT PLUGIN DEFINITION 128 | // ======================= 129 | 130 | function Plugin(option) { 131 | return this.each(function () { 132 | var $this = $(this) 133 | var data = $this.data('bs.alert') 134 | 135 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 136 | if (typeof option == 'string') data[option].call($this) 137 | }) 138 | } 139 | 140 | var old = $.fn.alert 141 | 142 | $.fn.alert = Plugin 143 | $.fn.alert.Constructor = Alert 144 | 145 | 146 | // ALERT NO CONFLICT 147 | // ================= 148 | 149 | $.fn.alert.noConflict = function () { 150 | $.fn.alert = old 151 | return this 152 | } 153 | 154 | 155 | // ALERT DATA-API 156 | // ============== 157 | 158 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 159 | 160 | }(jQuery); 161 | 162 | /* ======================================================================== 163 | * Bootstrap: button.js v3.2.0 164 | * http://getbootstrap.com/javascript/#buttons 165 | * ======================================================================== 166 | * Copyright 2011-2014 Twitter, Inc. 167 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 168 | * ======================================================================== */ 169 | 170 | 171 | +function ($) { 172 | 'use strict'; 173 | 174 | // BUTTON PUBLIC CLASS DEFINITION 175 | // ============================== 176 | 177 | var Button = function (element, options) { 178 | this.$element = $(element) 179 | this.options = $.extend({}, Button.DEFAULTS, options) 180 | this.isLoading = false 181 | } 182 | 183 | Button.VERSION = '3.2.0' 184 | 185 | Button.DEFAULTS = { 186 | loadingText: 'loading...' 187 | } 188 | 189 | Button.prototype.setState = function (state) { 190 | var d = 'disabled' 191 | var $el = this.$element 192 | var val = $el.is('input') ? 'val' : 'html' 193 | var data = $el.data() 194 | 195 | state = state + 'Text' 196 | 197 | if (data.resetText == null) $el.data('resetText', $el[val]()) 198 | 199 | $el[val](data[state] == null ? this.options[state] : data[state]) 200 | 201 | // push to event loop to allow forms to submit 202 | setTimeout($.proxy(function () { 203 | if (state == 'loadingText') { 204 | this.isLoading = true 205 | $el.addClass(d).attr(d, d) 206 | } else if (this.isLoading) { 207 | this.isLoading = false 208 | $el.removeClass(d).removeAttr(d) 209 | } 210 | }, this), 0) 211 | } 212 | 213 | Button.prototype.toggle = function () { 214 | var changed = true 215 | var $parent = this.$element.closest('[data-toggle="buttons"]') 216 | 217 | if ($parent.length) { 218 | var $input = this.$element.find('input') 219 | if ($input.prop('type') == 'radio') { 220 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 221 | else $parent.find('.active').removeClass('active') 222 | } 223 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 224 | } 225 | 226 | if (changed) this.$element.toggleClass('active') 227 | } 228 | 229 | 230 | // BUTTON PLUGIN DEFINITION 231 | // ======================== 232 | 233 | function Plugin(option) { 234 | return this.each(function () { 235 | var $this = $(this) 236 | var data = $this.data('bs.button') 237 | var options = typeof option == 'object' && option 238 | 239 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 240 | 241 | if (option == 'toggle') data.toggle() 242 | else if (option) data.setState(option) 243 | }) 244 | } 245 | 246 | var old = $.fn.button 247 | 248 | $.fn.button = Plugin 249 | $.fn.button.Constructor = Button 250 | 251 | 252 | // BUTTON NO CONFLICT 253 | // ================== 254 | 255 | $.fn.button.noConflict = function () { 256 | $.fn.button = old 257 | return this 258 | } 259 | 260 | 261 | // BUTTON DATA-API 262 | // =============== 263 | 264 | $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 265 | var $btn = $(e.target) 266 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 267 | Plugin.call($btn, 'toggle') 268 | e.preventDefault() 269 | }) 270 | 271 | }(jQuery); 272 | 273 | /* ======================================================================== 274 | * Bootstrap: carousel.js v3.2.0 275 | * http://getbootstrap.com/javascript/#carousel 276 | * ======================================================================== 277 | * Copyright 2011-2014 Twitter, Inc. 278 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 279 | * ======================================================================== */ 280 | 281 | 282 | +function ($) { 283 | 'use strict'; 284 | 285 | // CAROUSEL CLASS DEFINITION 286 | // ========================= 287 | 288 | var Carousel = function (element, options) { 289 | this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this)) 290 | this.$indicators = this.$element.find('.carousel-indicators') 291 | this.options = options 292 | this.paused = 293 | this.sliding = 294 | this.interval = 295 | this.$active = 296 | this.$items = null 297 | 298 | this.options.pause == 'hover' && this.$element 299 | .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 300 | .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 301 | } 302 | 303 | Carousel.VERSION = '3.2.0' 304 | 305 | Carousel.DEFAULTS = { 306 | interval: 5000, 307 | pause: 'hover', 308 | wrap: true 309 | } 310 | 311 | Carousel.prototype.keydown = function (e) { 312 | switch (e.which) { 313 | case 37: this.prev(); break 314 | case 39: this.next(); break 315 | default: return 316 | } 317 | 318 | e.preventDefault() 319 | } 320 | 321 | Carousel.prototype.cycle = function (e) { 322 | e || (this.paused = false) 323 | 324 | this.interval && clearInterval(this.interval) 325 | 326 | this.options.interval 327 | && !this.paused 328 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 329 | 330 | return this 331 | } 332 | 333 | Carousel.prototype.getItemIndex = function (item) { 334 | this.$items = item.parent().children('.item') 335 | return this.$items.index(item || this.$active) 336 | } 337 | 338 | Carousel.prototype.to = function (pos) { 339 | var that = this 340 | var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 341 | 342 | if (pos > (this.$items.length - 1) || pos < 0) return 343 | 344 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 345 | if (activeIndex == pos) return this.pause().cycle() 346 | 347 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 348 | } 349 | 350 | Carousel.prototype.pause = function (e) { 351 | e || (this.paused = true) 352 | 353 | if (this.$element.find('.next, .prev').length && $.support.transition) { 354 | this.$element.trigger($.support.transition.end) 355 | this.cycle(true) 356 | } 357 | 358 | this.interval = clearInterval(this.interval) 359 | 360 | return this 361 | } 362 | 363 | Carousel.prototype.next = function () { 364 | if (this.sliding) return 365 | return this.slide('next') 366 | } 367 | 368 | Carousel.prototype.prev = function () { 369 | if (this.sliding) return 370 | return this.slide('prev') 371 | } 372 | 373 | Carousel.prototype.slide = function (type, next) { 374 | var $active = this.$element.find('.item.active') 375 | var $next = next || $active[type]() 376 | var isCycling = this.interval 377 | var direction = type == 'next' ? 'left' : 'right' 378 | var fallback = type == 'next' ? 'first' : 'last' 379 | var that = this 380 | 381 | if (!$next.length) { 382 | if (!this.options.wrap) return 383 | $next = this.$element.find('.item')[fallback]() 384 | } 385 | 386 | if ($next.hasClass('active')) return (this.sliding = false) 387 | 388 | var relatedTarget = $next[0] 389 | var slideEvent = $.Event('slide.bs.carousel', { 390 | relatedTarget: relatedTarget, 391 | direction: direction 392 | }) 393 | this.$element.trigger(slideEvent) 394 | if (slideEvent.isDefaultPrevented()) return 395 | 396 | this.sliding = true 397 | 398 | isCycling && this.pause() 399 | 400 | if (this.$indicators.length) { 401 | this.$indicators.find('.active').removeClass('active') 402 | var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 403 | $nextIndicator && $nextIndicator.addClass('active') 404 | } 405 | 406 | var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 407 | if ($.support.transition && this.$element.hasClass('slide')) { 408 | $next.addClass(type) 409 | $next[0].offsetWidth // force reflow 410 | $active.addClass(direction) 411 | $next.addClass(direction) 412 | $active 413 | .one('bsTransitionEnd', function () { 414 | $next.removeClass([type, direction].join(' ')).addClass('active') 415 | $active.removeClass(['active', direction].join(' ')) 416 | that.sliding = false 417 | setTimeout(function () { 418 | that.$element.trigger(slidEvent) 419 | }, 0) 420 | }) 421 | .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) 422 | } else { 423 | $active.removeClass('active') 424 | $next.addClass('active') 425 | this.sliding = false 426 | this.$element.trigger(slidEvent) 427 | } 428 | 429 | isCycling && this.cycle() 430 | 431 | return this 432 | } 433 | 434 | 435 | // CAROUSEL PLUGIN DEFINITION 436 | // ========================== 437 | 438 | function Plugin(option) { 439 | return this.each(function () { 440 | var $this = $(this) 441 | var data = $this.data('bs.carousel') 442 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 443 | var action = typeof option == 'string' ? option : options.slide 444 | 445 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 446 | if (typeof option == 'number') data.to(option) 447 | else if (action) data[action]() 448 | else if (options.interval) data.pause().cycle() 449 | }) 450 | } 451 | 452 | var old = $.fn.carousel 453 | 454 | $.fn.carousel = Plugin 455 | $.fn.carousel.Constructor = Carousel 456 | 457 | 458 | // CAROUSEL NO CONFLICT 459 | // ==================== 460 | 461 | $.fn.carousel.noConflict = function () { 462 | $.fn.carousel = old 463 | return this 464 | } 465 | 466 | 467 | // CAROUSEL DATA-API 468 | // ================= 469 | 470 | $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 471 | var href 472 | var $this = $(this) 473 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 474 | if (!$target.hasClass('carousel')) return 475 | var options = $.extend({}, $target.data(), $this.data()) 476 | var slideIndex = $this.attr('data-slide-to') 477 | if (slideIndex) options.interval = false 478 | 479 | Plugin.call($target, options) 480 | 481 | if (slideIndex) { 482 | $target.data('bs.carousel').to(slideIndex) 483 | } 484 | 485 | e.preventDefault() 486 | }) 487 | 488 | $(window).on('load', function () { 489 | $('[data-ride="carousel"]').each(function () { 490 | var $carousel = $(this) 491 | Plugin.call($carousel, $carousel.data()) 492 | }) 493 | }) 494 | 495 | }(jQuery); 496 | 497 | /* ======================================================================== 498 | * Bootstrap: collapse.js v3.2.0 499 | * http://getbootstrap.com/javascript/#collapse 500 | * ======================================================================== 501 | * Copyright 2011-2014 Twitter, Inc. 502 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 503 | * ======================================================================== */ 504 | 505 | 506 | +function ($) { 507 | 'use strict'; 508 | 509 | // COLLAPSE PUBLIC CLASS DEFINITION 510 | // ================================ 511 | 512 | var Collapse = function (element, options) { 513 | this.$element = $(element) 514 | this.options = $.extend({}, Collapse.DEFAULTS, options) 515 | this.transitioning = null 516 | 517 | if (this.options.parent) this.$parent = $(this.options.parent) 518 | if (this.options.toggle) this.toggle() 519 | } 520 | 521 | Collapse.VERSION = '3.2.0' 522 | 523 | Collapse.DEFAULTS = { 524 | toggle: true 525 | } 526 | 527 | Collapse.prototype.dimension = function () { 528 | var hasWidth = this.$element.hasClass('width') 529 | return hasWidth ? 'width' : 'height' 530 | } 531 | 532 | Collapse.prototype.show = function () { 533 | if (this.transitioning || this.$element.hasClass('in')) return 534 | 535 | var startEvent = $.Event('show.bs.collapse') 536 | this.$element.trigger(startEvent) 537 | if (startEvent.isDefaultPrevented()) return 538 | 539 | var actives = this.$parent && this.$parent.find('> .panel > .in') 540 | 541 | if (actives && actives.length) { 542 | var hasData = actives.data('bs.collapse') 543 | if (hasData && hasData.transitioning) return 544 | Plugin.call(actives, 'hide') 545 | hasData || actives.data('bs.collapse', null) 546 | } 547 | 548 | var dimension = this.dimension() 549 | 550 | this.$element 551 | .removeClass('collapse') 552 | .addClass('collapsing')[dimension](0) 553 | 554 | this.transitioning = 1 555 | 556 | var complete = function () { 557 | this.$element 558 | .removeClass('collapsing') 559 | .addClass('collapse in')[dimension]('') 560 | this.transitioning = 0 561 | this.$element 562 | .trigger('shown.bs.collapse') 563 | } 564 | 565 | if (!$.support.transition) return complete.call(this) 566 | 567 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 568 | 569 | this.$element 570 | .one('bsTransitionEnd', $.proxy(complete, this)) 571 | .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 572 | } 573 | 574 | Collapse.prototype.hide = function () { 575 | if (this.transitioning || !this.$element.hasClass('in')) return 576 | 577 | var startEvent = $.Event('hide.bs.collapse') 578 | this.$element.trigger(startEvent) 579 | if (startEvent.isDefaultPrevented()) return 580 | 581 | var dimension = this.dimension() 582 | 583 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 584 | 585 | this.$element 586 | .addClass('collapsing') 587 | .removeClass('collapse') 588 | .removeClass('in') 589 | 590 | this.transitioning = 1 591 | 592 | var complete = function () { 593 | this.transitioning = 0 594 | this.$element 595 | .trigger('hidden.bs.collapse') 596 | .removeClass('collapsing') 597 | .addClass('collapse') 598 | } 599 | 600 | if (!$.support.transition) return complete.call(this) 601 | 602 | this.$element 603 | [dimension](0) 604 | .one('bsTransitionEnd', $.proxy(complete, this)) 605 | .emulateTransitionEnd(350) 606 | } 607 | 608 | Collapse.prototype.toggle = function () { 609 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 610 | } 611 | 612 | 613 | // COLLAPSE PLUGIN DEFINITION 614 | // ========================== 615 | 616 | function Plugin(option) { 617 | return this.each(function () { 618 | var $this = $(this) 619 | var data = $this.data('bs.collapse') 620 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 621 | 622 | if (!data && options.toggle && option == 'show') option = !option 623 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 624 | if (typeof option == 'string') data[option]() 625 | }) 626 | } 627 | 628 | var old = $.fn.collapse 629 | 630 | $.fn.collapse = Plugin 631 | $.fn.collapse.Constructor = Collapse 632 | 633 | 634 | // COLLAPSE NO CONFLICT 635 | // ==================== 636 | 637 | $.fn.collapse.noConflict = function () { 638 | $.fn.collapse = old 639 | return this 640 | } 641 | 642 | 643 | // COLLAPSE DATA-API 644 | // ================= 645 | 646 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 647 | var href 648 | var $this = $(this) 649 | var target = $this.attr('data-target') 650 | || e.preventDefault() 651 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 652 | var $target = $(target) 653 | var data = $target.data('bs.collapse') 654 | var option = data ? 'toggle' : $this.data() 655 | var parent = $this.attr('data-parent') 656 | var $parent = parent && $(parent) 657 | 658 | if (!data || !data.transitioning) { 659 | if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 660 | $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 661 | } 662 | 663 | Plugin.call($target, option) 664 | }) 665 | 666 | }(jQuery); 667 | 668 | /* ======================================================================== 669 | * Bootstrap: dropdown.js v3.2.0 670 | * http://getbootstrap.com/javascript/#dropdowns 671 | * ======================================================================== 672 | * Copyright 2011-2014 Twitter, Inc. 673 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 674 | * ======================================================================== */ 675 | 676 | 677 | +function ($) { 678 | 'use strict'; 679 | 680 | // DROPDOWN CLASS DEFINITION 681 | // ========================= 682 | 683 | var backdrop = '.dropdown-backdrop' 684 | var toggle = '[data-toggle="dropdown"]' 685 | var Dropdown = function (element) { 686 | $(element).on('click.bs.dropdown', this.toggle) 687 | } 688 | 689 | Dropdown.VERSION = '3.2.0' 690 | 691 | Dropdown.prototype.toggle = function (e) { 692 | var $this = $(this) 693 | 694 | if ($this.is('.disabled, :disabled')) return 695 | 696 | var $parent = getParent($this) 697 | var isActive = $parent.hasClass('open') 698 | 699 | clearMenus() 700 | 701 | if (!isActive) { 702 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 703 | // if mobile we use a backdrop because click events don't delegate 704 | $('