adhoq 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +80 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/adhoq/application.js +19 -0
  6. data/app/assets/javascripts/adhoq/bootstrap-sprockets.js +12 -0
  7. data/app/assets/javascripts/adhoq/bootstrap.js +2107 -0
  8. data/app/assets/javascripts/adhoq/bootstrap/affix.js +142 -0
  9. data/app/assets/javascripts/adhoq/bootstrap/alert.js +92 -0
  10. data/app/assets/javascripts/adhoq/bootstrap/button.js +110 -0
  11. data/app/assets/javascripts/adhoq/bootstrap/carousel.js +223 -0
  12. data/app/assets/javascripts/adhoq/bootstrap/collapse.js +170 -0
  13. data/app/assets/javascripts/adhoq/bootstrap/dropdown.js +151 -0
  14. data/app/assets/javascripts/adhoq/bootstrap/modal.js +280 -0
  15. data/app/assets/javascripts/adhoq/bootstrap/popover.js +113 -0
  16. data/app/assets/javascripts/adhoq/bootstrap/scrollspy.js +170 -0
  17. data/app/assets/javascripts/adhoq/bootstrap/tab.js +128 -0
  18. data/app/assets/javascripts/adhoq/bootstrap/tooltip.js +457 -0
  19. data/app/assets/javascripts/adhoq/bootstrap/transition.js +59 -0
  20. data/app/assets/javascripts/adhoq/previewer.js.coffee +25 -0
  21. data/app/assets/stylesheets/adhoq/_bootstrap-compass.scss +7 -0
  22. data/app/assets/stylesheets/adhoq/_bootstrap-mincer.scss +17 -0
  23. data/app/assets/stylesheets/adhoq/_bootstrap-sprockets.scss +7 -0
  24. data/app/assets/stylesheets/adhoq/adhoq.css.sass +57 -0
  25. data/app/assets/stylesheets/adhoq/application.css +16 -0
  26. data/app/assets/stylesheets/adhoq/bootstrap.scss +50 -0
  27. data/app/assets/stylesheets/adhoq/bootstrap/_alerts.scss +68 -0
  28. data/app/assets/stylesheets/adhoq/bootstrap/_badges.scss +57 -0
  29. data/app/assets/stylesheets/adhoq/bootstrap/_breadcrumbs.scss +26 -0
  30. data/app/assets/stylesheets/adhoq/bootstrap/_button-groups.scss +240 -0
  31. data/app/assets/stylesheets/adhoq/bootstrap/_buttons.scss +157 -0
  32. data/app/assets/stylesheets/adhoq/bootstrap/_carousel.scss +243 -0
  33. data/app/assets/stylesheets/adhoq/bootstrap/_close.scss +35 -0
  34. data/app/assets/stylesheets/adhoq/bootstrap/_code.scss +68 -0
  35. data/app/assets/stylesheets/adhoq/bootstrap/_component-animations.scss +35 -0
  36. data/app/assets/stylesheets/adhoq/bootstrap/_dropdowns.scss +215 -0
  37. data/app/assets/stylesheets/adhoq/bootstrap/_forms.scss +538 -0
  38. data/app/assets/stylesheets/adhoq/bootstrap/_glyphicons.scss +237 -0
  39. data/app/assets/stylesheets/adhoq/bootstrap/_grid.scss +84 -0
  40. data/app/assets/stylesheets/adhoq/bootstrap/_input-groups.scss +166 -0
  41. data/app/assets/stylesheets/adhoq/bootstrap/_jumbotron.scss +48 -0
  42. data/app/assets/stylesheets/adhoq/bootstrap/_labels.scss +66 -0
  43. data/app/assets/stylesheets/adhoq/bootstrap/_list-group.scss +131 -0
  44. data/app/assets/stylesheets/adhoq/bootstrap/_media.scss +56 -0
  45. data/app/assets/stylesheets/adhoq/bootstrap/_mixins.scss +39 -0
  46. data/app/assets/stylesheets/adhoq/bootstrap/_modals.scss +150 -0
  47. data/app/assets/stylesheets/adhoq/bootstrap/_navbar.scss +659 -0
  48. data/app/assets/stylesheets/adhoq/bootstrap/_navs.scss +242 -0
  49. data/app/assets/stylesheets/adhoq/bootstrap/_normalize.scss +425 -0
  50. data/app/assets/stylesheets/adhoq/bootstrap/_pager.scss +55 -0
  51. data/app/assets/stylesheets/adhoq/bootstrap/_pagination.scss +88 -0
  52. data/app/assets/stylesheets/adhoq/bootstrap/_panels.scss +243 -0
  53. data/app/assets/stylesheets/adhoq/bootstrap/_popovers.scss +133 -0
  54. data/app/assets/stylesheets/adhoq/bootstrap/_print.scss +101 -0
  55. data/app/assets/stylesheets/adhoq/bootstrap/_progress-bars.scss +105 -0
  56. data/app/assets/stylesheets/adhoq/bootstrap/_responsive-embed.scss +34 -0
  57. data/app/assets/stylesheets/adhoq/bootstrap/_responsive-utilities.scss +174 -0
  58. data/app/assets/stylesheets/adhoq/bootstrap/_scaffolding.scss +150 -0
  59. data/app/assets/stylesheets/adhoq/bootstrap/_tables.scss +233 -0
  60. data/app/assets/stylesheets/adhoq/bootstrap/_theme.scss +258 -0
  61. data/app/assets/stylesheets/adhoq/bootstrap/_thumbnails.scss +38 -0
  62. data/app/assets/stylesheets/adhoq/bootstrap/_tooltip.scss +95 -0
  63. data/app/assets/stylesheets/adhoq/bootstrap/_type.scss +304 -0
  64. data/app/assets/stylesheets/adhoq/bootstrap/_utilities.scss +57 -0
  65. data/app/assets/stylesheets/adhoq/bootstrap/_variables.scss +850 -0
  66. data/app/assets/stylesheets/adhoq/bootstrap/_wells.scss +29 -0
  67. data/app/assets/stylesheets/adhoq/bootstrap/bootstrap.scss +50 -0
  68. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_alerts.scss +14 -0
  69. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_background-variant.scss +11 -0
  70. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_border-radius.scss +18 -0
  71. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_buttons.scss +50 -0
  72. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_center-block.scss +7 -0
  73. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_clearfix.scss +22 -0
  74. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_forms.scss +84 -0
  75. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_gradients.scss +58 -0
  76. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_grid-framework.scss +81 -0
  77. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_grid.scss +122 -0
  78. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_hide-text.scss +21 -0
  79. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_image.scss +34 -0
  80. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_labels.scss +12 -0
  81. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_list-group.scss +31 -0
  82. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_nav-divider.scss +10 -0
  83. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  84. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_opacity.scss +8 -0
  85. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_pagination.scss +23 -0
  86. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_panels.scss +24 -0
  87. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_progress-bar.scss +10 -0
  88. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_reset-filter.scss +8 -0
  89. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_resize.scss +6 -0
  90. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_responsive-visibility.scss +21 -0
  91. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_size.scss +10 -0
  92. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_tab-focus.scss +9 -0
  93. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_table-row.scss +28 -0
  94. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_text-emphasis.scss +11 -0
  95. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_text-overflow.scss +8 -0
  96. data/app/assets/stylesheets/adhoq/bootstrap/mixins/_vendor-prefixes.scss +219 -0
  97. data/app/controllers/adhoq/application_controller.rb +5 -0
  98. data/app/controllers/adhoq/authorization_methods.rb +36 -0
  99. data/app/controllers/adhoq/executions_controller.rb +25 -0
  100. data/app/controllers/adhoq/previews_controller.rb +13 -0
  101. data/app/controllers/adhoq/queries_controller.rb +38 -0
  102. data/app/helpers/adhoq/application_helper.rb +11 -0
  103. data/app/models/adhoq/execution.rb +29 -0
  104. data/app/models/adhoq/query.rb +14 -0
  105. data/app/models/adhoq/report.rb +42 -0
  106. data/app/models/adhoq/time_based_orders.rb +9 -0
  107. data/app/views/adhoq/application/_global_nav.html.slim +11 -0
  108. data/app/views/adhoq/application/_sidebar_queries_index.html.slim +10 -0
  109. data/app/views/adhoq/previews/create.html.slim +12 -0
  110. data/app/views/adhoq/previews/statement_invalid.html.slim +5 -0
  111. data/app/views/adhoq/queries/_form.html.slim +38 -0
  112. data/app/views/adhoq/queries/_query.html.slim +43 -0
  113. data/app/views/adhoq/queries/edit.html.slim +2 -0
  114. data/app/views/adhoq/queries/index.html.slim +1 -0
  115. data/app/views/adhoq/queries/new.html.slim +2 -0
  116. data/app/views/adhoq/queries/show.html.slim +1 -0
  117. data/app/views/layouts/adhoq/application.html.slim +18 -0
  118. data/config/routes.rb +9 -0
  119. data/db/migrate/20141003095645_create_adhoq_queries.rb +11 -0
  120. data/db/migrate/20141006014750_create_adhoq_executions.rb +13 -0
  121. data/db/migrate/20141007052308_create_adhoq_reports.rb +12 -0
  122. data/lib/adhoq.rb +13 -0
  123. data/lib/adhoq/configuration.rb +21 -0
  124. data/lib/adhoq/engine.rb +15 -0
  125. data/lib/adhoq/error.rb +4 -0
  126. data/lib/adhoq/executor.rb +27 -0
  127. data/lib/adhoq/global_variable.rb +34 -0
  128. data/lib/adhoq/reporter.rb +5 -0
  129. data/lib/adhoq/reporter/xlsx.rb +32 -0
  130. data/lib/adhoq/result.rb +18 -0
  131. data/lib/adhoq/storage.rb +5 -0
  132. data/lib/adhoq/storage/local_file.rb +45 -0
  133. data/lib/adhoq/version.rb +3 -0
  134. data/lib/tasks/adhoq_tasks.rake +4 -0
  135. data/spec/adhoq/executor_spec.rb +11 -0
  136. data/spec/adhoq/storage_spec.rb +19 -0
  137. data/spec/factories/adhoq_queries.rb +29 -0
  138. data/spec/models/adhoq/execution_spec.rb +4 -0
  139. data/spec/models/adhoq/query_spec.rb +4 -0
  140. data/spec/models/adhoq/report_spec.rb +25 -0
  141. data/spec/spec_helper.rb +36 -0
  142. data/spec/support/have_values_in_xlsx_sheet_matcher.rb +20 -0
  143. metadata +375 -0
@@ -0,0 +1,170 @@
1
+ /* ========================================================================
2
+ * Bootstrap: collapse.js v3.2.0
3
+ * http://getbootstrap.com/javascript/#collapse
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
+ // COLLAPSE PUBLIC CLASS DEFINITION
14
+ // ================================
15
+
16
+ var Collapse = function (element, options) {
17
+ this.$element = $(element)
18
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
19
+ this.transitioning = null
20
+
21
+ if (this.options.parent) this.$parent = $(this.options.parent)
22
+ if (this.options.toggle) this.toggle()
23
+ }
24
+
25
+ Collapse.VERSION = '3.2.0'
26
+
27
+ Collapse.DEFAULTS = {
28
+ toggle: true
29
+ }
30
+
31
+ Collapse.prototype.dimension = function () {
32
+ var hasWidth = this.$element.hasClass('width')
33
+ return hasWidth ? 'width' : 'height'
34
+ }
35
+
36
+ Collapse.prototype.show = function () {
37
+ if (this.transitioning || this.$element.hasClass('in')) return
38
+
39
+ var startEvent = $.Event('show.bs.collapse')
40
+ this.$element.trigger(startEvent)
41
+ if (startEvent.isDefaultPrevented()) return
42
+
43
+ var actives = this.$parent && this.$parent.find('> .panel > .in')
44
+
45
+ if (actives && actives.length) {
46
+ var hasData = actives.data('bs.collapse')
47
+ if (hasData && hasData.transitioning) return
48
+ Plugin.call(actives, 'hide')
49
+ hasData || actives.data('bs.collapse', null)
50
+ }
51
+
52
+ var dimension = this.dimension()
53
+
54
+ this.$element
55
+ .removeClass('collapse')
56
+ .addClass('collapsing')[dimension](0)
57
+
58
+ this.transitioning = 1
59
+
60
+ var complete = function () {
61
+ this.$element
62
+ .removeClass('collapsing')
63
+ .addClass('collapse in')[dimension]('')
64
+ this.transitioning = 0
65
+ this.$element
66
+ .trigger('shown.bs.collapse')
67
+ }
68
+
69
+ if (!$.support.transition) return complete.call(this)
70
+
71
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
72
+
73
+ this.$element
74
+ .one('bsTransitionEnd', $.proxy(complete, this))
75
+ .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
76
+ }
77
+
78
+ Collapse.prototype.hide = function () {
79
+ if (this.transitioning || !this.$element.hasClass('in')) return
80
+
81
+ var startEvent = $.Event('hide.bs.collapse')
82
+ this.$element.trigger(startEvent)
83
+ if (startEvent.isDefaultPrevented()) return
84
+
85
+ var dimension = this.dimension()
86
+
87
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
88
+
89
+ this.$element
90
+ .addClass('collapsing')
91
+ .removeClass('collapse')
92
+ .removeClass('in')
93
+
94
+ this.transitioning = 1
95
+
96
+ var complete = function () {
97
+ this.transitioning = 0
98
+ this.$element
99
+ .trigger('hidden.bs.collapse')
100
+ .removeClass('collapsing')
101
+ .addClass('collapse')
102
+ }
103
+
104
+ if (!$.support.transition) return complete.call(this)
105
+
106
+ this.$element
107
+ [dimension](0)
108
+ .one('bsTransitionEnd', $.proxy(complete, this))
109
+ .emulateTransitionEnd(350)
110
+ }
111
+
112
+ Collapse.prototype.toggle = function () {
113
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
114
+ }
115
+
116
+
117
+ // COLLAPSE PLUGIN DEFINITION
118
+ // ==========================
119
+
120
+ function Plugin(option) {
121
+ return this.each(function () {
122
+ var $this = $(this)
123
+ var data = $this.data('bs.collapse')
124
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
125
+
126
+ if (!data && options.toggle && option == 'show') option = !option
127
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
128
+ if (typeof option == 'string') data[option]()
129
+ })
130
+ }
131
+
132
+ var old = $.fn.collapse
133
+
134
+ $.fn.collapse = Plugin
135
+ $.fn.collapse.Constructor = Collapse
136
+
137
+
138
+ // COLLAPSE NO CONFLICT
139
+ // ====================
140
+
141
+ $.fn.collapse.noConflict = function () {
142
+ $.fn.collapse = old
143
+ return this
144
+ }
145
+
146
+
147
+ // COLLAPSE DATA-API
148
+ // =================
149
+
150
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
151
+ var href
152
+ var $this = $(this)
153
+ var target = $this.attr('data-target')
154
+ || e.preventDefault()
155
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
156
+ var $target = $(target)
157
+ var data = $target.data('bs.collapse')
158
+ var option = data ? 'toggle' : $this.data()
159
+ var parent = $this.attr('data-parent')
160
+ var $parent = parent && $(parent)
161
+
162
+ if (!data || !data.transitioning) {
163
+ if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
164
+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
165
+ }
166
+
167
+ Plugin.call($target, option)
168
+ })
169
+
170
+ }(jQuery);
@@ -0,0 +1,151 @@
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
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
38
+ }
39
+
40
+ var relatedTarget = { relatedTarget: this }
41
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
42
+
43
+ if (e.isDefaultPrevented()) return
44
+
45
+ $this.trigger('focus')
46
+
47
+ $parent
48
+ .toggleClass('open')
49
+ .trigger('shown.bs.dropdown', relatedTarget)
50
+ }
51
+
52
+ return false
53
+ }
54
+
55
+ Dropdown.prototype.keydown = function (e) {
56
+ if (!/(38|40|27)/.test(e.keyCode)) return
57
+
58
+ var $this = $(this)
59
+
60
+ e.preventDefault()
61
+ e.stopPropagation()
62
+
63
+ if ($this.is('.disabled, :disabled')) return
64
+
65
+ var $parent = getParent($this)
66
+ var isActive = $parent.hasClass('open')
67
+
68
+ if (!isActive || (isActive && e.keyCode == 27)) {
69
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
70
+ return $this.trigger('click')
71
+ }
72
+
73
+ var desc = ' li:not(.divider):visible a'
74
+ var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
75
+
76
+ if (!$items.length) return
77
+
78
+ var index = $items.index($items.filter(':focus'))
79
+
80
+ if (e.keyCode == 38 && index > 0) index-- // up
81
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
82
+ if (!~index) index = 0
83
+
84
+ $items.eq(index).trigger('focus')
85
+ }
86
+
87
+ function clearMenus(e) {
88
+ if (e && e.which === 3) return
89
+ $(backdrop).remove()
90
+ $(toggle).each(function () {
91
+ var $parent = getParent($(this))
92
+ var relatedTarget = { relatedTarget: this }
93
+ if (!$parent.hasClass('open')) return
94
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
95
+ if (e.isDefaultPrevented()) return
96
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
97
+ })
98
+ }
99
+
100
+ function getParent($this) {
101
+ var selector = $this.attr('data-target')
102
+
103
+ if (!selector) {
104
+ selector = $this.attr('href')
105
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
106
+ }
107
+
108
+ var $parent = selector && $(selector)
109
+
110
+ return $parent && $parent.length ? $parent : $this.parent()
111
+ }
112
+
113
+
114
+ // DROPDOWN PLUGIN DEFINITION
115
+ // ==========================
116
+
117
+ function Plugin(option) {
118
+ return this.each(function () {
119
+ var $this = $(this)
120
+ var data = $this.data('bs.dropdown')
121
+
122
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
123
+ if (typeof option == 'string') data[option].call($this)
124
+ })
125
+ }
126
+
127
+ var old = $.fn.dropdown
128
+
129
+ $.fn.dropdown = Plugin
130
+ $.fn.dropdown.Constructor = Dropdown
131
+
132
+
133
+ // DROPDOWN NO CONFLICT
134
+ // ====================
135
+
136
+ $.fn.dropdown.noConflict = function () {
137
+ $.fn.dropdown = old
138
+ return this
139
+ }
140
+
141
+
142
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
143
+ // ===================================
144
+
145
+ $(document)
146
+ .on('click.bs.dropdown.data-api', clearMenus)
147
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
148
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
149
+ .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
150
+
151
+ }(jQuery);
@@ -0,0 +1,280 @@
1
+ /* ========================================================================
2
+ * Bootstrap: modal.js v3.2.0
3
+ * http://getbootstrap.com/javascript/#modals
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
+ // MODAL CLASS DEFINITION
14
+ // ======================
15
+
16
+ var Modal = function (element, options) {
17
+ this.options = options
18
+ this.$body = $(document.body)
19
+ this.$element = $(element)
20
+ this.$backdrop =
21
+ this.isShown = null
22
+ this.scrollbarWidth = 0
23
+
24
+ if (this.options.remote) {
25
+ this.$element
26
+ .find('.modal-content')
27
+ .load(this.options.remote, $.proxy(function () {
28
+ this.$element.trigger('loaded.bs.modal')
29
+ }, this))
30
+ }
31
+ }
32
+
33
+ Modal.VERSION = '3.2.0'
34
+
35
+ Modal.DEFAULTS = {
36
+ backdrop: true,
37
+ keyboard: true,
38
+ show: true
39
+ }
40
+
41
+ Modal.prototype.toggle = function (_relatedTarget) {
42
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
43
+ }
44
+
45
+ Modal.prototype.show = function (_relatedTarget) {
46
+ var that = this
47
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
48
+
49
+ this.$element.trigger(e)
50
+
51
+ if (this.isShown || e.isDefaultPrevented()) return
52
+
53
+ this.isShown = true
54
+
55
+ this.checkScrollbar()
56
+ this.$body.addClass('modal-open')
57
+
58
+ this.setScrollbar()
59
+ this.escape()
60
+
61
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
62
+
63
+ this.backdrop(function () {
64
+ var transition = $.support.transition && that.$element.hasClass('fade')
65
+
66
+ if (!that.$element.parent().length) {
67
+ that.$element.appendTo(that.$body) // don't move modals dom position
68
+ }
69
+
70
+ that.$element
71
+ .show()
72
+ .scrollTop(0)
73
+
74
+ if (transition) {
75
+ that.$element[0].offsetWidth // force reflow
76
+ }
77
+
78
+ that.$element
79
+ .addClass('in')
80
+ .attr('aria-hidden', false)
81
+
82
+ that.enforceFocus()
83
+
84
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
85
+
86
+ transition ?
87
+ that.$element.find('.modal-dialog') // wait for modal to slide in
88
+ .one('bsTransitionEnd', function () {
89
+ that.$element.trigger('focus').trigger(e)
90
+ })
91
+ .emulateTransitionEnd(300) :
92
+ that.$element.trigger('focus').trigger(e)
93
+ })
94
+ }
95
+
96
+ Modal.prototype.hide = function (e) {
97
+ if (e) e.preventDefault()
98
+
99
+ e = $.Event('hide.bs.modal')
100
+
101
+ this.$element.trigger(e)
102
+
103
+ if (!this.isShown || e.isDefaultPrevented()) return
104
+
105
+ this.isShown = false
106
+
107
+ this.$body.removeClass('modal-open')
108
+
109
+ this.resetScrollbar()
110
+ this.escape()
111
+
112
+ $(document).off('focusin.bs.modal')
113
+
114
+ this.$element
115
+ .removeClass('in')
116
+ .attr('aria-hidden', true)
117
+ .off('click.dismiss.bs.modal')
118
+
119
+ $.support.transition && this.$element.hasClass('fade') ?
120
+ this.$element
121
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
122
+ .emulateTransitionEnd(300) :
123
+ this.hideModal()
124
+ }
125
+
126
+ Modal.prototype.enforceFocus = function () {
127
+ $(document)
128
+ .off('focusin.bs.modal') // guard against infinite focus loop
129
+ .on('focusin.bs.modal', $.proxy(function (e) {
130
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
131
+ this.$element.trigger('focus')
132
+ }
133
+ }, this))
134
+ }
135
+
136
+ Modal.prototype.escape = function () {
137
+ if (this.isShown && this.options.keyboard) {
138
+ this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
139
+ e.which == 27 && this.hide()
140
+ }, this))
141
+ } else if (!this.isShown) {
142
+ this.$element.off('keyup.dismiss.bs.modal')
143
+ }
144
+ }
145
+
146
+ Modal.prototype.hideModal = function () {
147
+ var that = this
148
+ this.$element.hide()
149
+ this.backdrop(function () {
150
+ that.$element.trigger('hidden.bs.modal')
151
+ })
152
+ }
153
+
154
+ Modal.prototype.removeBackdrop = function () {
155
+ this.$backdrop && this.$backdrop.remove()
156
+ this.$backdrop = null
157
+ }
158
+
159
+ Modal.prototype.backdrop = function (callback) {
160
+ var that = this
161
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
162
+
163
+ if (this.isShown && this.options.backdrop) {
164
+ var doAnimate = $.support.transition && animate
165
+
166
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
167
+ .appendTo(this.$body)
168
+
169
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
170
+ if (e.target !== e.currentTarget) return
171
+ this.options.backdrop == 'static'
172
+ ? this.$element[0].focus.call(this.$element[0])
173
+ : this.hide.call(this)
174
+ }, this))
175
+
176
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
177
+
178
+ this.$backdrop.addClass('in')
179
+
180
+ if (!callback) return
181
+
182
+ doAnimate ?
183
+ this.$backdrop
184
+ .one('bsTransitionEnd', callback)
185
+ .emulateTransitionEnd(150) :
186
+ callback()
187
+
188
+ } else if (!this.isShown && this.$backdrop) {
189
+ this.$backdrop.removeClass('in')
190
+
191
+ var callbackRemove = function () {
192
+ that.removeBackdrop()
193
+ callback && callback()
194
+ }
195
+ $.support.transition && this.$element.hasClass('fade') ?
196
+ this.$backdrop
197
+ .one('bsTransitionEnd', callbackRemove)
198
+ .emulateTransitionEnd(150) :
199
+ callbackRemove()
200
+
201
+ } else if (callback) {
202
+ callback()
203
+ }
204
+ }
205
+
206
+ Modal.prototype.checkScrollbar = function () {
207
+ if (document.body.clientWidth >= window.innerWidth) return
208
+ this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
209
+ }
210
+
211
+ Modal.prototype.setScrollbar = function () {
212
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
213
+ if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
214
+ }
215
+
216
+ Modal.prototype.resetScrollbar = function () {
217
+ this.$body.css('padding-right', '')
218
+ }
219
+
220
+ Modal.prototype.measureScrollbar = function () { // thx walsh
221
+ var scrollDiv = document.createElement('div')
222
+ scrollDiv.className = 'modal-scrollbar-measure'
223
+ this.$body.append(scrollDiv)
224
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
225
+ this.$body[0].removeChild(scrollDiv)
226
+ return scrollbarWidth
227
+ }
228
+
229
+
230
+ // MODAL PLUGIN DEFINITION
231
+ // =======================
232
+
233
+ function Plugin(option, _relatedTarget) {
234
+ return this.each(function () {
235
+ var $this = $(this)
236
+ var data = $this.data('bs.modal')
237
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
238
+
239
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
240
+ if (typeof option == 'string') data[option](_relatedTarget)
241
+ else if (options.show) data.show(_relatedTarget)
242
+ })
243
+ }
244
+
245
+ var old = $.fn.modal
246
+
247
+ $.fn.modal = Plugin
248
+ $.fn.modal.Constructor = Modal
249
+
250
+
251
+ // MODAL NO CONFLICT
252
+ // =================
253
+
254
+ $.fn.modal.noConflict = function () {
255
+ $.fn.modal = old
256
+ return this
257
+ }
258
+
259
+
260
+ // MODAL DATA-API
261
+ // ==============
262
+
263
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
264
+ var $this = $(this)
265
+ var href = $this.attr('href')
266
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
267
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
268
+
269
+ if ($this.is('a')) e.preventDefault()
270
+
271
+ $target.one('show.bs.modal', function (showEvent) {
272
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
273
+ $target.one('hidden.bs.modal', function () {
274
+ $this.is(':visible') && $this.trigger('focus')
275
+ })
276
+ })
277
+ Plugin.call($target, option, this)
278
+ })
279
+
280
+ }(jQuery);