sql-jarvis 2.0.1 → 2.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +153 -52
  5. data/app/assets/fonts/blazer/glyphicons-halflings-regular.eot +0 -0
  6. data/app/assets/fonts/blazer/glyphicons-halflings-regular.svg +0 -0
  7. data/app/assets/fonts/blazer/glyphicons-halflings-regular.ttf +0 -0
  8. data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff +0 -0
  9. data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff2 +0 -0
  10. data/app/assets/images/blazer/favicon.png +0 -0
  11. data/app/assets/javascripts/blazer/Chart.js +4195 -3884
  12. data/app/assets/javascripts/blazer/Sortable.js +1493 -1097
  13. data/app/assets/javascripts/blazer/ace/ace.js +21294 -4
  14. data/app/assets/javascripts/blazer/ace/ext-language_tools.js +1991 -3
  15. data/app/assets/javascripts/blazer/ace/mode-sql.js +110 -1
  16. data/app/assets/javascripts/blazer/ace/snippets/sql.js +40 -1
  17. data/app/assets/javascripts/blazer/ace/snippets/text.js +14 -1
  18. data/app/assets/javascripts/blazer/ace/theme-twilight.js +116 -1
  19. data/app/assets/javascripts/blazer/application.js +4 -3
  20. data/app/assets/javascripts/blazer/bootstrap.js +623 -612
  21. data/app/assets/javascripts/blazer/chartkick.js +1769 -1248
  22. data/app/assets/javascripts/blazer/daterangepicker.js +263 -115
  23. data/app/assets/javascripts/blazer/highlight.min.js +3 -0
  24. data/app/assets/javascripts/blazer/{jquery_ujs.js → jquery-ujs.js} +161 -75
  25. data/app/assets/javascripts/blazer/jquery.js +9506 -9450
  26. data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +321 -259
  27. data/app/assets/javascripts/blazer/moment-timezone-with-data.js +1212 -0
  28. data/app/assets/javascripts/blazer/queries.js +1 -1
  29. data/app/assets/javascripts/blazer/routes.js +3 -0
  30. data/app/assets/javascripts/blazer/selectize.js +3828 -3604
  31. data/app/assets/javascripts/blazer/stupidtable.js +255 -88
  32. data/app/assets/javascripts/blazer/vue.js +8015 -4583
  33. data/app/assets/stylesheets/blazer/application.css +41 -5
  34. data/app/assets/stylesheets/blazer/bootstrap.css.erb +879 -325
  35. data/app/assets/stylesheets/blazer/daterangepicker.css +269 -0
  36. data/app/assets/stylesheets/blazer/selectize.default.css +26 -10
  37. data/app/controllers/blazer/base_controller.rb +7 -0
  38. data/app/controllers/blazer/checks_controller.rb +1 -1
  39. data/app/controllers/blazer/dashboards_controller.rb +0 -4
  40. data/app/controllers/blazer/queries_controller.rb +20 -12
  41. data/app/helpers/blazer/base_helper.rb +1 -1
  42. data/app/mailers/blazer/slack_notifier.rb +76 -0
  43. data/app/models/blazer/check.rb +9 -0
  44. data/app/views/blazer/_nav.html.erb +0 -1
  45. data/app/views/blazer/_variables.html.erb +41 -19
  46. data/app/views/blazer/checks/_form.html.erb +16 -8
  47. data/app/views/blazer/checks/edit.html.erb +2 -0
  48. data/app/views/blazer/checks/index.html.erb +33 -4
  49. data/app/views/blazer/checks/new.html.erb +2 -0
  50. data/app/views/blazer/dashboards/_form.html.erb +4 -4
  51. data/app/views/blazer/dashboards/edit.html.erb +2 -0
  52. data/app/views/blazer/dashboards/new.html.erb +2 -0
  53. data/app/views/blazer/dashboards/show.html.erb +7 -3
  54. data/app/views/blazer/queries/_form.html.erb +11 -6
  55. data/app/views/blazer/queries/docs.html.erb +131 -0
  56. data/app/views/blazer/queries/home.html.erb +12 -3
  57. data/app/views/blazer/queries/run.html.erb +36 -6
  58. data/app/views/blazer/queries/schema.html.erb +46 -8
  59. data/app/views/blazer/queries/show.html.erb +4 -4
  60. data/app/views/layouts/blazer/application.html.erb +3 -3
  61. data/config/routes.rb +5 -1
  62. data/lib/blazer.rb +32 -13
  63. data/lib/blazer/adapters/athena_adapter.rb +1 -1
  64. data/lib/blazer/adapters/elasticsearch_adapter.rb +14 -17
  65. data/lib/blazer/adapters/mongodb_adapter.rb +1 -1
  66. data/lib/blazer/adapters/sql_adapter.rb +7 -1
  67. data/lib/blazer/engine.rb +4 -0
  68. data/lib/blazer/result.rb +62 -29
  69. data/lib/blazer/run_statement_job.rb +6 -9
  70. data/lib/blazer/version.rb +1 -1
  71. data/lib/generators/blazer/templates/config.yml.tt +13 -2
  72. data/lib/generators/blazer/templates/install.rb.tt +1 -0
  73. data/lib/tasks/blazer.rake +1 -0
  74. metadata +33 -37
  75. data/.gitattributes +0 -1
  76. data/.github/ISSUE_TEMPLATE.md +0 -7
  77. data/.gitignore +0 -14
  78. data/Gemfile +0 -7
  79. data/Rakefile +0 -1
  80. data/app/assets/javascripts/blazer/highlight.pack.js +0 -1
  81. data/app/assets/javascripts/blazer/moment-timezone.js +0 -1007
  82. data/app/assets/stylesheets/blazer/daterangepicker-bs3.css +0 -375
  83. data/blazer.gemspec +0 -30
@@ -1,263 +1,325 @@
1
- /*! Copyright (c) 2011 by Jonas Mosbech - https://github.com/jmosbech/StickyTableHeaders
2
- MIT license info: https://github.com/jmosbech/StickyTableHeaders/blob/master/license.txt */
1
+ /*! Copyright (c) Jonas Mosbech - https://github.com/jmosbech/StickyTableHeaders
2
+ MIT license info: https://github.com/jmosbech/StickyTableHeaders/blob/master/license.txt */
3
3
 
4
4
  ;(function ($, window, undefined) {
5
- 'use strict';
6
-
7
- var name = 'stickyTableHeaders',
8
- id = 0,
9
- defaults = {
10
- fixedOffset: 0,
11
- leftOffset: 0,
12
- scrollableArea: window
13
- };
14
-
15
- function Plugin (el, options) {
16
- // To avoid scope issues, use 'base' instead of 'this'
17
- // to reference this class from internal events and functions.
18
- var base = this;
19
-
20
- // Access to jQuery and DOM versions of element
21
- base.$el = $(el);
22
- base.el = el;
23
- base.id = id++;
24
-
25
- // Listen for destroyed, call teardown
26
- base.$el.bind('destroyed',
27
- $.proxy(base.teardown, base));
28
-
29
- // Cache DOM refs for performance reasons
30
- base.$clonedHeader = null;
31
- base.$originalHeader = null;
32
-
33
- // Keep track of state
34
- base.isSticky = false;
35
- base.hasBeenSticky = false;
36
- base.leftOffset = null;
37
- base.topOffset = null;
38
-
39
- base.init = function () {
40
- base.options = $.extend({}, defaults, options);
41
-
42
- base.$el.each(function () {
43
- var $this = $(this);
44
-
45
- // remove padding on <table> to fix issue #7
46
- $this.css('padding', 0);
47
-
48
- base.$scrollableArea = $(base.options.scrollableArea);
49
-
50
- base.$originalHeader = $('thead:first', this);
51
- base.$clonedHeader = base.$originalHeader.clone();
52
- $this.trigger('clonedHeader.' + name, [base.$clonedHeader]);
53
-
54
- base.$clonedHeader.addClass('tableFloatingHeader');
55
- base.$clonedHeader.css('display', 'none');
56
-
57
- base.$originalHeader.addClass('tableFloatingHeaderOriginal');
58
-
59
- base.$originalHeader.after(base.$clonedHeader);
60
-
61
- base.$printStyle = $('<style type="text/css" media="print">' +
62
- '.tableFloatingHeader{display:none !important;}' +
63
- '.tableFloatingHeaderOriginal{position:static !important;}' +
64
- '</style>');
65
- $('head').append(base.$printStyle);
66
- });
67
-
68
- base.updateWidth();
69
- base.toggleHeaders();
70
-
71
- base.bind();
72
- };
73
-
74
- base.destroy = function (){
75
- base.$el.unbind('destroyed', base.teardown);
76
- base.teardown();
77
- };
78
-
79
- base.teardown = function(){
80
- if (base.isSticky) {
81
- base.$originalHeader.css('position', 'static');
82
- }
83
- $.removeData(base.el, 'plugin_' + name);
84
- base.unbind();
85
-
86
- base.$clonedHeader.remove();
87
- base.$originalHeader.removeClass('tableFloatingHeaderOriginal');
88
- base.$originalHeader.css('visibility', 'visible');
89
- base.$printStyle.remove();
90
-
91
- base.el = null;
92
- base.$el = null;
93
- };
94
-
95
- base.bind = function(){
96
- base.$scrollableArea.on('scroll.' + name, base.toggleHeaders);
97
- if (!base.isWindowScrolling()) {
98
- $(window).on('scroll.' + name + base.id, base.setPositionValues);
99
- $(window).on('resize.' + name + base.id, base.toggleHeaders);
100
- }
101
- base.$scrollableArea.on('resize.' + name, base.toggleHeaders);
102
- base.$scrollableArea.on('resize.' + name, base.updateWidth);
103
- };
104
-
105
- base.unbind = function(){
106
- // unbind window events by specifying handle so we don't remove too much
107
- base.$scrollableArea.off('.' + name, base.toggleHeaders);
108
- if (!base.isWindowScrolling()) {
109
- $(window).off('.' + name + base.id, base.setPositionValues);
110
- $(window).off('.' + name + base.id, base.toggleHeaders);
111
- }
112
- base.$scrollableArea.off('.' + name, base.updateWidth);
113
- base.$el.off('.' + name);
114
- base.$el.find('*').off('.' + name);
115
- };
116
-
117
- base.toggleHeaders = function () {
118
- if (base.$el) {
119
- base.$el.each(function () {
120
- var $this = $(this),
121
- newLeft,
122
- newTopOffset = base.isWindowScrolling() ? (
123
- isNaN(base.options.fixedOffset) ?
124
- base.options.fixedOffset.outerHeight() :
125
- base.options.fixedOffset
126
- ) :
127
- base.$scrollableArea.offset().top + (!isNaN(base.options.fixedOffset) ? base.options.fixedOffset : 0),
128
- offset = $this.offset(),
129
-
130
- scrollTop = base.$scrollableArea.scrollTop() + newTopOffset,
131
- scrollLeft = base.$scrollableArea.scrollLeft(),
132
-
133
- scrolledPastTop = base.isWindowScrolling() ?
134
- scrollTop > offset.top :
135
- newTopOffset > offset.top,
136
- notScrolledPastBottom = (base.isWindowScrolling() ? scrollTop : 0) <
137
- (offset.top + $this.height() - base.$clonedHeader.height() - (base.isWindowScrolling() ? 0 : newTopOffset));
138
-
139
- if (scrolledPastTop && notScrolledPastBottom) {
140
- newLeft = offset.left - scrollLeft + base.options.leftOffset;
141
- base.$originalHeader.css({
142
- 'position': 'fixed',
143
- 'margin-top': 0,
144
- 'left': newLeft,
145
- 'z-index': 1 // #18: opacity bug
146
- });
147
- base.isSticky = true;
148
- base.leftOffset = newLeft;
149
- base.topOffset = newTopOffset;
150
- base.$clonedHeader.css('display', '');
151
- base.setPositionValues();
152
- // make sure the width is correct: the user might have resized the browser while in static mode
153
- base.updateWidth();
154
- } else if (base.isSticky) {
155
- base.$originalHeader.css('position', 'static');
156
- base.$clonedHeader.css('display', 'none');
157
- base.isSticky = false;
158
- base.resetWidth($("td,th", base.$clonedHeader), $("td,th", base.$originalHeader));
159
- }
160
- });
161
- }
162
- };
163
-
164
- base.isWindowScrolling = function() {
165
- return base.$scrollableArea[0] === window;
166
- };
167
-
168
- base.setPositionValues = function () {
169
- var winScrollTop = $(window).scrollTop(),
170
- winScrollLeft = $(window).scrollLeft();
171
- if (!base.isSticky ||
172
- winScrollTop < 0 || winScrollTop + $(window).height() > $(document).height() ||
173
- winScrollLeft < 0 || winScrollLeft + $(window).width() > $(document).width()) {
174
- return;
175
- }
176
- base.$originalHeader.css({
177
- 'top': base.topOffset - (base.isWindowScrolling() ? 0 : winScrollTop),
178
- 'left': base.leftOffset - (base.isWindowScrolling() ? 0 : winScrollLeft)
179
- });
180
- };
181
-
182
- base.updateWidth = function () {
183
- if (!base.isSticky) {
184
- return;
185
- }
186
- // Copy cell widths from clone
187
- if (!base.$originalHeaderCells) {
188
- base.$originalHeaderCells = $('th,td', base.$originalHeader);
189
- }
190
- if (!base.$clonedHeaderCells) {
191
- base.$clonedHeaderCells = $('th,td', base.$clonedHeader);
192
- }
193
- var cellWidths = base.getWidth(base.$clonedHeaderCells);
194
- base.setWidth(cellWidths, base.$clonedHeaderCells, base.$originalHeaderCells);
195
-
196
- // Copy row width from whole table
197
- base.$originalHeader.css('width', base.$clonedHeader.width());
198
- };
199
-
200
- base.getWidth = function ($clonedHeaders) {
201
- var widths = [];
202
- $clonedHeaders.each(function (index) {
203
- var width, $this = $(this);
204
-
205
- if ($this.css('box-sizing') === 'border-box') {
206
- width = $this.outerWidth(); // #39: border-box bug
207
- } else {
208
- width = $this.width();
209
- }
210
-
211
- widths[index] = width;
212
- });
213
- return widths;
214
- };
215
-
216
- base.setWidth = function (widths, $clonedHeaders, $origHeaders) {
217
- $clonedHeaders.each(function (index) {
218
- var width = widths[index];
219
- $origHeaders.eq(index).css({
220
- 'min-width': width,
221
- 'max-width': width
222
- });
223
- });
224
- };
225
-
226
- base.resetWidth = function ($clonedHeaders, $origHeaders) {
227
- $clonedHeaders.each(function (index) {
228
- var $this = $(this);
229
- $origHeaders.eq(index).css({
230
- 'min-width': $this.css("min-width"),
231
- 'max-width': $this.css("max-width")
232
- });
233
- });
234
- };
235
-
236
- base.updateOptions = function(options) {
237
- base.options = $.extend({}, defaults, options);
238
- base.updateWidth();
239
- base.toggleHeaders();
240
- };
241
-
242
- // Run initializer
243
- base.init();
244
- }
245
-
246
- // A plugin wrapper around the constructor,
247
- // preventing against multiple instantiations
248
- $.fn[name] = function ( options ) {
249
- return this.each(function () {
250
- var instance = $.data(this, 'plugin_' + name);
251
- if (instance) {
252
- if (typeof options === "string") {
253
- instance[options].apply(instance);
254
- } else {
255
- instance.updateOptions(options);
256
- }
257
- } else if(options !== 'destroy') {
258
- $.data(this, 'plugin_' + name, new Plugin( this, options ));
259
- }
260
- });
261
- };
5
+ 'use strict';
6
+
7
+ var name = 'stickyTableHeaders',
8
+ id = 0,
9
+ defaults = {
10
+ fixedOffset: 0,
11
+ leftOffset: 0,
12
+ marginTop: 0,
13
+ objDocument: document,
14
+ objHead: 'head',
15
+ objWindow: window,
16
+ scrollableArea: window,
17
+ cacheHeaderHeight: false,
18
+ zIndex: 3
19
+ };
20
+
21
+ function Plugin (el, options) {
22
+ // To avoid scope issues, use 'base' instead of 'this'
23
+ // to reference this class from internal events and functions.
24
+ var base = this;
25
+
26
+ // Access to jQuery and DOM versions of element
27
+ base.$el = $(el);
28
+ base.el = el;
29
+ base.id = id++;
30
+
31
+ // Listen for destroyed, call teardown
32
+ base.$el.bind('destroyed',
33
+ $.proxy(base.teardown, base));
34
+
35
+ // Cache DOM refs for performance reasons
36
+ base.$clonedHeader = null;
37
+ base.$originalHeader = null;
38
+
39
+ // Cache header height for performance reasons
40
+ base.cachedHeaderHeight = null;
41
+
42
+ // Keep track of state
43
+ base.isSticky = false;
44
+ base.hasBeenSticky = false;
45
+ base.leftOffset = null;
46
+ base.topOffset = null;
47
+
48
+ base.init = function () {
49
+ base.setOptions(options);
50
+
51
+ base.$el.each(function () {
52
+ var $this = $(this);
53
+
54
+ // remove padding on <table> to fix issue #7
55
+ $this.css('padding', 0);
56
+
57
+ base.$originalHeader = $('thead:first', this);
58
+ base.$clonedHeader = base.$originalHeader.clone();
59
+ $this.trigger('clonedHeader.' + name, [base.$clonedHeader]);
60
+
61
+ base.$clonedHeader.addClass('tableFloatingHeader');
62
+ base.$clonedHeader.css({display: 'none', opacity: 0.0});
63
+
64
+ base.$originalHeader.addClass('tableFloatingHeaderOriginal');
65
+
66
+ base.$originalHeader.after(base.$clonedHeader);
67
+
68
+ base.$printStyle = $('<style type="text/css" media="print">' +
69
+ '.tableFloatingHeader{display:none !important;}' +
70
+ '.tableFloatingHeaderOriginal{position:static !important;}' +
71
+ '</style>');
72
+ base.$head.append(base.$printStyle);
73
+ });
74
+
75
+ base.$clonedHeader.find("input, select").attr("disabled", true);
76
+
77
+ base.updateWidth();
78
+ base.toggleHeaders();
79
+ base.bind();
80
+ };
81
+
82
+ base.destroy = function (){
83
+ base.$el.unbind('destroyed', base.teardown);
84
+ base.teardown();
85
+ };
86
+
87
+ base.teardown = function(){
88
+ if (base.isSticky) {
89
+ base.$originalHeader.css('position', 'static');
90
+ }
91
+ $.removeData(base.el, 'plugin_' + name);
92
+ base.unbind();
93
+
94
+ base.$clonedHeader.remove();
95
+ base.$originalHeader.removeClass('tableFloatingHeaderOriginal');
96
+ base.$originalHeader.css('visibility', 'visible');
97
+ base.$printStyle.remove();
98
+
99
+ base.el = null;
100
+ base.$el = null;
101
+ };
102
+
103
+ base.bind = function(){
104
+ base.$scrollableArea.on('scroll.' + name, base.toggleHeaders);
105
+ if (!base.isWindowScrolling) {
106
+ base.$window.on('scroll.' + name + base.id, base.setPositionValues);
107
+ base.$window.on('resize.' + name + base.id, base.toggleHeaders);
108
+ }
109
+ base.$scrollableArea.on('resize.' + name, base.toggleHeaders);
110
+ base.$scrollableArea.on('resize.' + name, base.updateWidth);
111
+ };
112
+
113
+ base.unbind = function(){
114
+ // unbind window events by specifying handle so we don't remove too much
115
+ base.$scrollableArea.off('.' + name, base.toggleHeaders);
116
+ if (!base.isWindowScrolling) {
117
+ base.$window.off('.' + name + base.id, base.setPositionValues);
118
+ base.$window.off('.' + name + base.id, base.toggleHeaders);
119
+ }
120
+ base.$scrollableArea.off('.' + name, base.updateWidth);
121
+ };
122
+
123
+ // We debounce the functions bound to the scroll and resize events
124
+ base.debounce = function (fn, delay) {
125
+ var timer = null;
126
+ return function () {
127
+ var context = this, args = arguments;
128
+ clearTimeout(timer);
129
+ timer = setTimeout(function () {
130
+ fn.apply(context, args);
131
+ }, delay);
132
+ };
133
+ };
134
+
135
+ base.toggleHeaders = base.debounce(function () {
136
+ if (base.$el) {
137
+ base.$el.each(function () {
138
+ var $this = $(this),
139
+ newLeft,
140
+ newTopOffset = base.isWindowScrolling ? (
141
+ isNaN(base.options.fixedOffset) ?
142
+ base.options.fixedOffset.outerHeight() :
143
+ base.options.fixedOffset
144
+ ) :
145
+ base.$scrollableArea.offset().top + (!isNaN(base.options.fixedOffset) ? base.options.fixedOffset : 0),
146
+ offset = $this.offset(),
147
+
148
+ scrollTop = base.$scrollableArea.scrollTop() + newTopOffset,
149
+ scrollLeft = base.$scrollableArea.scrollLeft(),
150
+
151
+ headerHeight,
152
+
153
+ scrolledPastTop = base.isWindowScrolling ?
154
+ scrollTop > offset.top :
155
+ newTopOffset > offset.top,
156
+ notScrolledPastBottom;
157
+
158
+ if (scrolledPastTop) {
159
+ headerHeight = base.options.cacheHeaderHeight ? base.cachedHeaderHeight : base.$clonedHeader.height();
160
+ notScrolledPastBottom = (base.isWindowScrolling ? scrollTop : 0) <
161
+ (offset.top + $this.height() - headerHeight - (base.isWindowScrolling ? 0 : newTopOffset));
162
+ }
163
+
164
+ if (scrolledPastTop && notScrolledPastBottom) {
165
+ newLeft = offset.left - scrollLeft + base.options.leftOffset;
166
+ base.$originalHeader.css({
167
+ 'position': 'fixed',
168
+ 'margin-top': base.options.marginTop,
169
+ 'top': 0,
170
+ 'left': newLeft,
171
+ 'z-index': base.options.zIndex
172
+ });
173
+ base.leftOffset = newLeft;
174
+ base.topOffset = newTopOffset;
175
+ base.$clonedHeader.css('display', '');
176
+ if (!base.isSticky) {
177
+ base.isSticky = true;
178
+ // make sure the width is correct: the user might have resized the browser while in static mode
179
+ base.updateWidth();
180
+ $this.trigger('enabledStickiness.' + name);
181
+ }
182
+ base.setPositionValues();
183
+ } else if (base.isSticky) {
184
+ base.$originalHeader.css('position', 'static');
185
+ base.$clonedHeader.css('display', 'none');
186
+ base.isSticky = false;
187
+ base.resetWidth($('td,th', base.$clonedHeader), $('td,th', base.$originalHeader));
188
+ $this.trigger('disabledStickiness.' + name);
189
+ }
190
+ });
191
+ }
192
+ }, 0);
193
+
194
+ base.setPositionValues = base.debounce(function () {
195
+ var winScrollTop = base.$window.scrollTop(),
196
+ winScrollLeft = base.$window.scrollLeft();
197
+ if (!base.isSticky ||
198
+ winScrollTop < 0 || winScrollTop + base.$window.height() > base.$document.height() ||
199
+ winScrollLeft < 0 || winScrollLeft + base.$window.width() > base.$document.width()) {
200
+ return;
201
+ }
202
+ base.$originalHeader.css({
203
+ 'top': base.topOffset - (base.isWindowScrolling ? 0 : winScrollTop),
204
+ 'left': base.leftOffset - (base.isWindowScrolling ? 0 : winScrollLeft)
205
+ });
206
+ }, 0);
207
+
208
+ base.updateWidth = base.debounce(function () {
209
+ if (!base.isSticky) {
210
+ return;
211
+ }
212
+ // Copy cell widths from clone
213
+ if (!base.$originalHeaderCells) {
214
+ base.$originalHeaderCells = $('th,td', base.$originalHeader);
215
+ }
216
+ if (!base.$clonedHeaderCells) {
217
+ base.$clonedHeaderCells = $('th,td', base.$clonedHeader);
218
+ }
219
+ var cellWidths = base.getWidth(base.$clonedHeaderCells);
220
+ base.setWidth(cellWidths, base.$clonedHeaderCells, base.$originalHeaderCells);
221
+
222
+ // Copy row width from whole table
223
+ base.$originalHeader.css('width', base.$clonedHeader.width());
224
+
225
+ // If we're caching the height, we need to update the cached value when the width changes
226
+ if (base.options.cacheHeaderHeight) {
227
+ base.cachedHeaderHeight = base.$clonedHeader.height();
228
+ }
229
+ }, 0);
230
+
231
+ base.getWidth = function ($clonedHeaders) {
232
+ var widths = [];
233
+ $clonedHeaders.each(function (index) {
234
+ var width, $this = $(this);
235
+
236
+ if ($this.css('box-sizing') === 'border-box') {
237
+ var boundingClientRect = $this[0].getBoundingClientRect();
238
+ if(boundingClientRect.width) {
239
+ width = boundingClientRect.width; // #39: border-box bug
240
+ } else {
241
+ width = boundingClientRect.right - boundingClientRect.left; // ie8 bug: getBoundingClientRect() does not have a width property
242
+ }
243
+ } else {
244
+ var $origTh = $('th', base.$originalHeader);
245
+ if ($origTh.css('border-collapse') === 'collapse') {
246
+ if (window.getComputedStyle) {
247
+ width = parseFloat(window.getComputedStyle(this, null).width);
248
+ } else {
249
+ // ie8 only
250
+ var leftPadding = parseFloat($this.css('padding-left'));
251
+ var rightPadding = parseFloat($this.css('padding-right'));
252
+ // Needs more investigation - this is assuming constant border around this cell and it's neighbours.
253
+ var border = parseFloat($this.css('border-width'));
254
+ width = $this.outerWidth() - leftPadding - rightPadding - border;
255
+ }
256
+ } else {
257
+ width = $this.width();
258
+ }
259
+ }
260
+
261
+ widths[index] = width;
262
+ });
263
+ return widths;
264
+ };
265
+
266
+ base.setWidth = function (widths, $clonedHeaders, $origHeaders) {
267
+ $clonedHeaders.each(function (index) {
268
+ var width = widths[index];
269
+ $origHeaders.eq(index).css({
270
+ 'min-width': width,
271
+ 'max-width': width
272
+ });
273
+ });
274
+ };
275
+
276
+ base.resetWidth = function ($clonedHeaders, $origHeaders) {
277
+ $clonedHeaders.each(function (index) {
278
+ var $this = $(this);
279
+ $origHeaders.eq(index).css({
280
+ 'min-width': $this.css('min-width'),
281
+ 'max-width': $this.css('max-width')
282
+ });
283
+ });
284
+ };
285
+
286
+ base.setOptions = function (options) {
287
+ base.options = $.extend({}, defaults, options);
288
+ base.$window = $(base.options.objWindow);
289
+ base.$head = $(base.options.objHead);
290
+ base.$document = $(base.options.objDocument);
291
+ base.$scrollableArea = $(base.options.scrollableArea);
292
+ base.isWindowScrolling = base.$scrollableArea[0] === base.$window[0];
293
+ };
294
+
295
+ base.updateOptions = function (options) {
296
+ base.setOptions(options);
297
+ // scrollableArea might have changed
298
+ base.unbind();
299
+ base.bind();
300
+ base.updateWidth();
301
+ base.toggleHeaders();
302
+ };
303
+
304
+ // Run initializer
305
+ base.init();
306
+ }
307
+
308
+ // A plugin wrapper around the constructor,
309
+ // preventing against multiple instantiations
310
+ $.fn[name] = function ( options ) {
311
+ return this.each(function () {
312
+ var instance = $.data(this, 'plugin_' + name);
313
+ if (instance) {
314
+ if (typeof options === 'string') {
315
+ instance[options].apply(instance);
316
+ } else {
317
+ instance.updateOptions(options);
318
+ }
319
+ } else if(options !== 'destroy') {
320
+ $.data(this, 'plugin_' + name, new Plugin( this, options ));
321
+ }
322
+ });
323
+ };
262
324
 
263
325
  })(jQuery, window);