├── assets ├── fonts │ └── bootstrap │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.svg ├── js │ ├── bootstrap-sprockets.js │ ├── script.min.js │ ├── bootstrap │ │ ├── transition.js │ │ ├── alert.js │ │ ├── button.js │ │ ├── tab.js │ │ ├── popover.js │ │ ├── affix.js │ │ ├── dropdown.js │ │ ├── scrollspy.js │ │ ├── collapse.js │ │ ├── carousel.js │ │ ├── modal.js │ │ └── tooltip.js │ ├── script.js │ └── bootstrap.min.js └── _sass │ ├── style.scss │ └── _bootstrap-variables.scss ├── .gitignore ├── config.rb ├── README.md └── index.html /assets/fonts/bootstrap/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ixkaito/kakekomi-in-wakayama/master/assets/fonts/bootstrap/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /assets/fonts/bootstrap/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ixkaito/kakekomi-in-wakayama/master/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /assets/fonts/bootstrap/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ixkaito/kakekomi-in-wakayama/master/assets/fonts/bootstrap/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore .htpasswd 2 | .htpasswd 3 | 4 | # Ignore sublime setting files. 5 | sftp-config.json 6 | *.sublime-project 7 | *.sublime-workspace 8 | 9 | # Ignore all logfiles and tempfiles. 10 | /log/*.log 11 | /tmp 12 | 13 | # Ignore other unneeded files. 14 | doc/ 15 | *.swp 16 | *~ 17 | .project 18 | .DS_Store 19 | .idea 20 | .secret 21 | 22 | # Ignore Sass cache files. 23 | *.scssc 24 | -------------------------------------------------------------------------------- /assets/js/bootstrap-sprockets.js: -------------------------------------------------------------------------------- 1 | //= require ./bootstrap/affix 2 | //= require ./bootstrap/alert 3 | //= require ./bootstrap/button 4 | //= require ./bootstrap/carousel 5 | //= require ./bootstrap/collapse 6 | //= require ./bootstrap/dropdown 7 | //= require ./bootstrap/tab 8 | //= require ./bootstrap/transition 9 | //= require ./bootstrap/scrollspy 10 | //= require ./bootstrap/modal 11 | //= require ./bootstrap/tooltip 12 | //= require ./bootstrap/popover 13 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # run `$ compass compile -e production --force` to force compile for production 2 | 3 | require 'bootstrap-sass' 4 | 5 | http_path = "/" 6 | preferred_syntax = :scss 7 | css_dir = "assets/css" 8 | sass_dir = "assets/_sass" 9 | images_dir = "assets/images" 10 | javascripts_dir = "assets/js" 11 | fonts_dir = "assets/fonts" 12 | relative_assets = true 13 | # sass_options = { :debug_info => true } 14 | output_style = ( environment == :production ) ? :compressed : :expanded 15 | line_comments = ( environment == :production ) ? false : true 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KAKEKOMI in Wakayama 2 | 3 | 4 | 5 | ## The heatmap of public facilities in Wakayama Prefecture differentiated by time. 6 | 7 | __The web application URL (available for smartphone)__ 8 | http://ixkaito.github.io/kakekomi-in-wakayama 9 | 10 | __Use following open data of Wakayama Prefecture__ 11 | https://github.com/wakayama-pref-org/list-of-public-facilities 12 | 13 | __Feel free to fork__ 14 | Make KAKEKOMI in your prefecture! 15 | 16 | 17 | 18 | ## 時間別の和歌山県内の公共施設のヒートマップ 19 | 20 | __ウェブアプリ URL (スマートフォン対応)__ 21 | http://ixkaito.github.io/kakekomi-in-wakayama 22 | 23 | __下記和歌山県のオープンデータを使用__ 24 | https://github.com/wakayama-pref-org/list-of-public-facilities 25 | 26 | __フォーク歓迎__ 27 | あなたの都道府県の KAKEKOMI を作ってみてください! 28 | -------------------------------------------------------------------------------- /assets/js/script.min.js: -------------------------------------------------------------------------------- 1 | var data="data.csv";var now=new Date();var hour=("0"+now.getHours()).slice(-2);var minute=("0"+now.getMinutes()).slice(-2);var map=new google.maps.Map(document.getElementById("map"),{center:{lat:34.2321,lng:135.1911},zoom:11}); 2 | kakekomiMap(data,hour,minute);function time2minute(a){a=a.split(":");a=parseInt(a[0],10)*60+parseInt(a[1],10);return a;}var selectHour=document.getElementById("hour"); 3 | var selectMinute=document.getElementById("minute");var submitSetting=document.getElementById("submit-setting");selectHour.value=now.getHours();selectMinute.value=Math.floor(now.getMinutes()/10)*10; 4 | submitSetting.onclick=function(){var a=selectHour.value;var b=selectMinute.value;kakekomiMap(data,a,b);return false;};function kakekomiMap(b,a,d){var c=parseInt(a,10)*60+parseInt(d,10); 5 | d3.csv(b,function(e,g){map=new google.maps.Map(document.getElementById("map"),{center:{lat:map.getCenter().lat(),lng:map.getCenter().lng()},zoom:map.getZoom()}); 6 | var k,j=[];for(var f=0;f 2 | 3 | 4 | 5 | KAKEKOMI in Wakayama 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

14 | KAKEKOMI in Wakayama 15 |

16 |
17 |
18 | 19 |
20 |
21 | 47 | : 48 | 56 | OK 57 |
58 |
59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /assets/js/bootstrap/alert.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: alert.js v3.2.0 3 | * http://getbootstrap.com/javascript/#alerts 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // ALERT CLASS DEFINITION 14 | // ====================== 15 | 16 | var dismiss = '[data-dismiss="alert"]' 17 | var Alert = function (el) { 18 | $(el).on('click', dismiss, this.close) 19 | } 20 | 21 | Alert.VERSION = '3.2.0' 22 | 23 | Alert.prototype.close = function (e) { 24 | var $this = $(this) 25 | var selector = $this.attr('data-target') 26 | 27 | if (!selector) { 28 | selector = $this.attr('href') 29 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 30 | } 31 | 32 | var $parent = $(selector) 33 | 34 | if (e) e.preventDefault() 35 | 36 | if (!$parent.length) { 37 | $parent = $this.hasClass('alert') ? $this : $this.parent() 38 | } 39 | 40 | $parent.trigger(e = $.Event('close.bs.alert')) 41 | 42 | if (e.isDefaultPrevented()) return 43 | 44 | $parent.removeClass('in') 45 | 46 | function removeElement() { 47 | // detach from parent, fire event then clean up data 48 | $parent.detach().trigger('closed.bs.alert').remove() 49 | } 50 | 51 | $.support.transition && $parent.hasClass('fade') ? 52 | $parent 53 | .one('bsTransitionEnd', removeElement) 54 | .emulateTransitionEnd(150) : 55 | removeElement() 56 | } 57 | 58 | 59 | // ALERT PLUGIN DEFINITION 60 | // ======================= 61 | 62 | function Plugin(option) { 63 | return this.each(function () { 64 | var $this = $(this) 65 | var data = $this.data('bs.alert') 66 | 67 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 68 | if (typeof option == 'string') data[option].call($this) 69 | }) 70 | } 71 | 72 | var old = $.fn.alert 73 | 74 | $.fn.alert = Plugin 75 | $.fn.alert.Constructor = Alert 76 | 77 | 78 | // ALERT NO CONFLICT 79 | // ================= 80 | 81 | $.fn.alert.noConflict = function () { 82 | $.fn.alert = old 83 | return this 84 | } 85 | 86 | 87 | // ALERT DATA-API 88 | // ============== 89 | 90 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 91 | 92 | }(jQuery); 93 | -------------------------------------------------------------------------------- /assets/js/script.js: -------------------------------------------------------------------------------- 1 | var data = 'data.csv'; 2 | 3 | /* 4 | ================================================================================ 5 | Current Time 6 | ================================================================================ 7 | */ 8 | var now = new Date(); 9 | var hour = ('0' + now.getHours()).slice(-2); 10 | var minute = ('0' + now.getMinutes()).slice(-2); 11 | 12 | // var viewTime = document.getElementById('time'); 13 | // viewTime.innerHTML = hour + ':' + minute; 14 | 15 | // Initialize google map 16 | var map = new google.maps.Map(document.getElementById('map'), { 17 | center: { lat: 34.2321, lng: 135.1911 }, 18 | zoom: 11 19 | }); 20 | 21 | // Visualize the heatmap of current time 22 | kakekomiMap(data, hour, minute); 23 | 24 | 25 | /* 26 | ================================================================================ 27 | Convert time format to minutes 28 | ================================================================================ 29 | */ 30 | function time2minute(time) { 31 | time = time.split(':'); 32 | time = parseInt(time[0], 10) * 60 + parseInt(time[1], 10); 33 | return time; 34 | } 35 | 36 | 37 | /* 38 | ================================================================================ 39 | Select time 40 | ================================================================================ 41 | */ 42 | var selectHour = document.getElementById('hour'); 43 | var selectMinute = document.getElementById('minute'); 44 | var submitSetting = document.getElementById('submit-setting'); 45 | 46 | selectHour.value = now.getHours(); 47 | selectMinute.value = Math.floor(now.getMinutes()/10)*10; 48 | 49 | submitSetting.onclick = function() { 50 | var hour = selectHour.value; 51 | var minute = selectMinute.value; 52 | kakekomiMap(data, hour, minute); 53 | return false; 54 | }; 55 | 56 | 57 | /* 58 | ================================================================================ 59 | Visualize the heatmap 60 | ================================================================================ 61 | */ 62 | function kakekomiMap(data, hour, minute) { 63 | var time = parseInt(hour, 10) * 60 + parseInt(minute, 10); 64 | 65 | d3.csv(data, function(error, data){ 66 | 67 | // Renew google map 68 | map = new google.maps.Map(document.getElementById('map'), { 69 | center: { lat: map.getCenter().lat(), lng: map.getCenter().lng() }, 70 | zoom: map.getZoom() 71 | }); 72 | 73 | // Initialize heatmap data 74 | var pos, heatmapData = []; 75 | for (var i = 0; i < data.length; i++) { 76 | if (time2minute(data[i].open) <= time && time <= time2minute(data[i].close)) { 77 | heatmapData.push({ 78 | location : new google.maps.LatLng(data[i].lat, data[i].lng), 79 | weight : 10 80 | }); 81 | } 82 | } 83 | 84 | // Initialize heatmap layer 85 | var heatmap = new google.maps.visualization.HeatmapLayer({ 86 | radius: 100, 87 | opacity: 0.75 88 | }); 89 | 90 | // Set the heatmap data to the heatmap layer 91 | heatmap.setData(heatmapData); 92 | 93 | // Overlay the heatmap 94 | heatmap.setMap(map); 95 | 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /assets/js/bootstrap/button.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: button.js v3.2.0 3 | * http://getbootstrap.com/javascript/#buttons 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // BUTTON PUBLIC CLASS DEFINITION 14 | // ============================== 15 | 16 | var Button = function (element, options) { 17 | this.$element = $(element) 18 | this.options = $.extend({}, Button.DEFAULTS, options) 19 | this.isLoading = false 20 | } 21 | 22 | Button.VERSION = '3.2.0' 23 | 24 | Button.DEFAULTS = { 25 | loadingText: 'loading...' 26 | } 27 | 28 | Button.prototype.setState = function (state) { 29 | var d = 'disabled' 30 | var $el = this.$element 31 | var val = $el.is('input') ? 'val' : 'html' 32 | var data = $el.data() 33 | 34 | state = state + 'Text' 35 | 36 | if (data.resetText == null) $el.data('resetText', $el[val]()) 37 | 38 | $el[val](data[state] == null ? this.options[state] : data[state]) 39 | 40 | // push to event loop to allow forms to submit 41 | setTimeout($.proxy(function () { 42 | if (state == 'loadingText') { 43 | this.isLoading = true 44 | $el.addClass(d).attr(d, d) 45 | } else if (this.isLoading) { 46 | this.isLoading = false 47 | $el.removeClass(d).removeAttr(d) 48 | } 49 | }, this), 0) 50 | } 51 | 52 | Button.prototype.toggle = function () { 53 | var changed = true 54 | var $parent = this.$element.closest('[data-toggle="buttons"]') 55 | 56 | if ($parent.length) { 57 | var $input = this.$element.find('input') 58 | if ($input.prop('type') == 'radio') { 59 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 60 | else $parent.find('.active').removeClass('active') 61 | } 62 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 63 | } 64 | 65 | if (changed) this.$element.toggleClass('active') 66 | } 67 | 68 | 69 | // BUTTON PLUGIN DEFINITION 70 | // ======================== 71 | 72 | function Plugin(option) { 73 | return this.each(function () { 74 | var $this = $(this) 75 | var data = $this.data('bs.button') 76 | var options = typeof option == 'object' && option 77 | 78 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 79 | 80 | if (option == 'toggle') data.toggle() 81 | else if (option) data.setState(option) 82 | }) 83 | } 84 | 85 | var old = $.fn.button 86 | 87 | $.fn.button = Plugin 88 | $.fn.button.Constructor = Button 89 | 90 | 91 | // BUTTON NO CONFLICT 92 | // ================== 93 | 94 | $.fn.button.noConflict = function () { 95 | $.fn.button = old 96 | return this 97 | } 98 | 99 | 100 | // BUTTON DATA-API 101 | // =============== 102 | 103 | $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 104 | var $btn = $(e.target) 105 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 106 | Plugin.call($btn, 'toggle') 107 | e.preventDefault() 108 | }) 109 | 110 | }(jQuery); 111 | -------------------------------------------------------------------------------- /assets/js/bootstrap/tab.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: tab.js v3.2.0 3 | * http://getbootstrap.com/javascript/#tabs 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // TAB CLASS DEFINITION 14 | // ==================== 15 | 16 | var Tab = function (element) { 17 | this.element = $(element) 18 | } 19 | 20 | Tab.VERSION = '3.2.0' 21 | 22 | Tab.prototype.show = function () { 23 | var $this = this.element 24 | var $ul = $this.closest('ul:not(.dropdown-menu)') 25 | var selector = $this.data('target') 26 | 27 | if (!selector) { 28 | selector = $this.attr('href') 29 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 30 | } 31 | 32 | if ($this.parent('li').hasClass('active')) return 33 | 34 | var previous = $ul.find('.active:last a')[0] 35 | var e = $.Event('show.bs.tab', { 36 | relatedTarget: previous 37 | }) 38 | 39 | $this.trigger(e) 40 | 41 | if (e.isDefaultPrevented()) return 42 | 43 | var $target = $(selector) 44 | 45 | this.activate($this.closest('li'), $ul) 46 | this.activate($target, $target.parent(), function () { 47 | $this.trigger({ 48 | type: 'shown.bs.tab', 49 | relatedTarget: previous 50 | }) 51 | }) 52 | } 53 | 54 | Tab.prototype.activate = function (element, container, callback) { 55 | var $active = container.find('> .active') 56 | var transition = callback 57 | && $.support.transition 58 | && $active.hasClass('fade') 59 | 60 | function next() { 61 | $active 62 | .removeClass('active') 63 | .find('> .dropdown-menu > .active') 64 | .removeClass('active') 65 | 66 | element.addClass('active') 67 | 68 | if (transition) { 69 | element[0].offsetWidth // reflow for transition 70 | element.addClass('in') 71 | } else { 72 | element.removeClass('fade') 73 | } 74 | 75 | if (element.parent('.dropdown-menu')) { 76 | element.closest('li.dropdown').addClass('active') 77 | } 78 | 79 | callback && callback() 80 | } 81 | 82 | transition ? 83 | $active 84 | .one('bsTransitionEnd', next) 85 | .emulateTransitionEnd(150) : 86 | next() 87 | 88 | $active.removeClass('in') 89 | } 90 | 91 | 92 | // TAB PLUGIN DEFINITION 93 | // ===================== 94 | 95 | function Plugin(option) { 96 | return this.each(function () { 97 | var $this = $(this) 98 | var data = $this.data('bs.tab') 99 | 100 | if (!data) $this.data('bs.tab', (data = new Tab(this))) 101 | if (typeof option == 'string') data[option]() 102 | }) 103 | } 104 | 105 | var old = $.fn.tab 106 | 107 | $.fn.tab = Plugin 108 | $.fn.tab.Constructor = Tab 109 | 110 | 111 | // TAB NO CONFLICT 112 | // =============== 113 | 114 | $.fn.tab.noConflict = function () { 115 | $.fn.tab = old 116 | return this 117 | } 118 | 119 | 120 | // TAB DATA-API 121 | // ============ 122 | 123 | $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 124 | e.preventDefault() 125 | Plugin.call($(this), 'show') 126 | }) 127 | 128 | }(jQuery); 129 | -------------------------------------------------------------------------------- /assets/js/bootstrap/popover.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: popover.js v3.2.0 3 | * http://getbootstrap.com/javascript/#popovers 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // POPOVER PUBLIC CLASS DEFINITION 14 | // =============================== 15 | 16 | var Popover = function (element, options) { 17 | this.init('popover', element, options) 18 | } 19 | 20 | if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 21 | 22 | Popover.VERSION = '3.2.0' 23 | 24 | Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 25 | placement: 'right', 26 | trigger: 'click', 27 | content: '', 28 | template: '' 29 | }) 30 | 31 | 32 | // NOTE: POPOVER EXTENDS tooltip.js 33 | // ================================ 34 | 35 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 36 | 37 | Popover.prototype.constructor = Popover 38 | 39 | Popover.prototype.getDefaults = function () { 40 | return Popover.DEFAULTS 41 | } 42 | 43 | Popover.prototype.setContent = function () { 44 | var $tip = this.tip() 45 | var title = this.getTitle() 46 | var content = this.getContent() 47 | 48 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 49 | $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events 50 | this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 51 | ](content) 52 | 53 | $tip.removeClass('fade top bottom left right in') 54 | 55 | // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 56 | // this manually by checking the contents. 57 | if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 58 | } 59 | 60 | Popover.prototype.hasContent = function () { 61 | return this.getTitle() || this.getContent() 62 | } 63 | 64 | Popover.prototype.getContent = function () { 65 | var $e = this.$element 66 | var o = this.options 67 | 68 | return $e.attr('data-content') 69 | || (typeof o.content == 'function' ? 70 | o.content.call($e[0]) : 71 | o.content) 72 | } 73 | 74 | Popover.prototype.arrow = function () { 75 | return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 76 | } 77 | 78 | Popover.prototype.tip = function () { 79 | if (!this.$tip) this.$tip = $(this.options.template) 80 | return this.$tip 81 | } 82 | 83 | 84 | // POPOVER PLUGIN DEFINITION 85 | // ========================= 86 | 87 | function Plugin(option) { 88 | return this.each(function () { 89 | var $this = $(this) 90 | var data = $this.data('bs.popover') 91 | var options = typeof option == 'object' && option 92 | 93 | if (!data && option == 'destroy') return 94 | if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 95 | if (typeof option == 'string') data[option]() 96 | }) 97 | } 98 | 99 | var old = $.fn.popover 100 | 101 | $.fn.popover = Plugin 102 | $.fn.popover.Constructor = Popover 103 | 104 | 105 | // POPOVER NO CONFLICT 106 | // =================== 107 | 108 | $.fn.popover.noConflict = function () { 109 | $.fn.popover = old 110 | return this 111 | } 112 | 113 | }(jQuery); 114 | -------------------------------------------------------------------------------- /assets/js/bootstrap/affix.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: affix.js v3.2.0 3 | * http://getbootstrap.com/javascript/#affix 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // AFFIX CLASS DEFINITION 14 | // ====================== 15 | 16 | var Affix = function (element, options) { 17 | this.options = $.extend({}, Affix.DEFAULTS, options) 18 | 19 | this.$target = $(this.options.target) 20 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 21 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 22 | 23 | this.$element = $(element) 24 | this.affixed = 25 | this.unpin = 26 | this.pinnedOffset = null 27 | 28 | this.checkPosition() 29 | } 30 | 31 | Affix.VERSION = '3.2.0' 32 | 33 | Affix.RESET = 'affix affix-top affix-bottom' 34 | 35 | Affix.DEFAULTS = { 36 | offset: 0, 37 | target: window 38 | } 39 | 40 | Affix.prototype.getPinnedOffset = function () { 41 | if (this.pinnedOffset) return this.pinnedOffset 42 | this.$element.removeClass(Affix.RESET).addClass('affix') 43 | var scrollTop = this.$target.scrollTop() 44 | var position = this.$element.offset() 45 | return (this.pinnedOffset = position.top - scrollTop) 46 | } 47 | 48 | Affix.prototype.checkPositionWithEventLoop = function () { 49 | setTimeout($.proxy(this.checkPosition, this), 1) 50 | } 51 | 52 | Affix.prototype.checkPosition = function () { 53 | if (!this.$element.is(':visible')) return 54 | 55 | var scrollHeight = $(document).height() 56 | var scrollTop = this.$target.scrollTop() 57 | var position = this.$element.offset() 58 | var offset = this.options.offset 59 | var offsetTop = offset.top 60 | var offsetBottom = offset.bottom 61 | 62 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 63 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 64 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 65 | 66 | var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : 67 | offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : 68 | offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false 69 | 70 | if (this.affixed === affix) return 71 | if (this.unpin != null) this.$element.css('top', '') 72 | 73 | var affixType = 'affix' + (affix ? '-' + affix : '') 74 | var e = $.Event(affixType + '.bs.affix') 75 | 76 | this.$element.trigger(e) 77 | 78 | if (e.isDefaultPrevented()) return 79 | 80 | this.affixed = affix 81 | this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 82 | 83 | this.$element 84 | .removeClass(Affix.RESET) 85 | .addClass(affixType) 86 | .trigger($.Event(affixType.replace('affix', 'affixed'))) 87 | 88 | if (affix == 'bottom') { 89 | this.$element.offset({ 90 | top: scrollHeight - this.$element.height() - offsetBottom 91 | }) 92 | } 93 | } 94 | 95 | 96 | // AFFIX PLUGIN DEFINITION 97 | // ======================= 98 | 99 | function Plugin(option) { 100 | return this.each(function () { 101 | var $this = $(this) 102 | var data = $this.data('bs.affix') 103 | var options = typeof option == 'object' && option 104 | 105 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 106 | if (typeof option == 'string') data[option]() 107 | }) 108 | } 109 | 110 | var old = $.fn.affix 111 | 112 | $.fn.affix = Plugin 113 | $.fn.affix.Constructor = Affix 114 | 115 | 116 | // AFFIX NO CONFLICT 117 | // ================= 118 | 119 | $.fn.affix.noConflict = function () { 120 | $.fn.affix = old 121 | return this 122 | } 123 | 124 | 125 | // AFFIX DATA-API 126 | // ============== 127 | 128 | $(window).on('load', function () { 129 | $('[data-spy="affix"]').each(function () { 130 | var $spy = $(this) 131 | var data = $spy.data() 132 | 133 | data.offset = data.offset || {} 134 | 135 | if (data.offsetBottom) data.offset.bottom = data.offsetBottom 136 | if (data.offsetTop) data.offset.top = data.offsetTop 137 | 138 | Plugin.call($spy, data) 139 | }) 140 | }) 141 | 142 | }(jQuery); 143 | -------------------------------------------------------------------------------- /assets/js/bootstrap/dropdown.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: dropdown.js v3.2.0 3 | * http://getbootstrap.com/javascript/#dropdowns 4 | * ======================================================================== 5 | * Copyright 2011-2014 Twitter, Inc. 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // DROPDOWN CLASS DEFINITION 14 | // ========================= 15 | 16 | var backdrop = '.dropdown-backdrop' 17 | var toggle = '[data-toggle="dropdown"]' 18 | var Dropdown = function (element) { 19 | $(element).on('click.bs.dropdown', this.toggle) 20 | } 21 | 22 | Dropdown.VERSION = '3.2.0' 23 | 24 | Dropdown.prototype.toggle = function (e) { 25 | var $this = $(this) 26 | 27 | if ($this.is('.disabled, :disabled')) return 28 | 29 | var $parent = getParent($this) 30 | var isActive = $parent.hasClass('open') 31 | 32 | clearMenus() 33 | 34 | if (!isActive) { 35 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 36 | // if mobile we use a backdrop because click events don't delegate 37 | $('