mcmire-shoulda-matchers 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +7 -0
  5. data/Appraisals +45 -0
  6. data/CONTRIBUTING.md +41 -0
  7. data/Gemfile +31 -0
  8. data/Gemfile.lock +166 -0
  9. data/MIT-LICENSE +22 -0
  10. data/NEWS.md +299 -0
  11. data/README.md +163 -0
  12. data/Rakefile +116 -0
  13. data/doc_config/gh-pages/index.html.erb +9 -0
  14. data/doc_config/yard/setup.rb +22 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  27. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  28. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  29. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  30. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  31. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  32. data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
  33. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  34. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  35. data/features/rails_integration.feature +113 -0
  36. data/features/step_definitions/rails_steps.rb +162 -0
  37. data/features/support/env.rb +5 -0
  38. data/gemfiles/3.0.gemfile +24 -0
  39. data/gemfiles/3.0.gemfile.lock +150 -0
  40. data/gemfiles/3.1.gemfile +27 -0
  41. data/gemfiles/3.1.gemfile.lock +173 -0
  42. data/gemfiles/3.2.gemfile +27 -0
  43. data/gemfiles/3.2.gemfile.lock +171 -0
  44. data/gemfiles/4.0.0.gemfile +28 -0
  45. data/gemfiles/4.0.0.gemfile.lock +172 -0
  46. data/gemfiles/4.0.1.gemfile +28 -0
  47. data/gemfiles/4.0.1.gemfile.lock +172 -0
  48. data/lib/shoulda-matchers.rb +1 -0
  49. data/lib/shoulda/matchers.rb +11 -0
  50. data/lib/shoulda/matchers/action_controller.rb +17 -0
  51. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
  52. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
  53. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
  54. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
  55. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
  56. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
  57. data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
  58. data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
  59. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
  60. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
  61. data/lib/shoulda/matchers/active_model.rb +30 -0
  62. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
  63. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
  64. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
  65. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
  66. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
  67. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
  68. data/lib/shoulda/matchers/active_model/errors.rb +10 -0
  69. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
  70. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
  71. data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
  72. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  73. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
  74. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
  75. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
  76. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
  77. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
  78. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
  79. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
  80. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
  81. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
  82. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
  83. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
  84. data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
  85. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
  86. data/lib/shoulda/matchers/active_record.rb +22 -0
  87. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
  88. data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
  89. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  90. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
  91. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
  92. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
  93. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
  94. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
  95. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
  97. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
  98. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
  99. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
  100. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
  101. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
  102. data/lib/shoulda/matchers/assertion_error.rb +19 -0
  103. data/lib/shoulda/matchers/error.rb +6 -0
  104. data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
  105. data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
  106. data/lib/shoulda/matchers/rails_shim.rb +50 -0
  107. data/lib/shoulda/matchers/version.rb +6 -0
  108. data/lib/shoulda/matchers/warn.rb +8 -0
  109. data/shoulda-matchers.gemspec +23 -0
  110. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  111. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  112. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  113. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
  114. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
  115. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  116. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
  117. data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
  118. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  119. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  120. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  121. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
  122. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
  123. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
  124. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
  125. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
  126. data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
  127. data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
  128. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  129. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
  130. data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
  131. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
  132. data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
  133. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
  134. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  135. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
  136. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
  137. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
  138. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
  139. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
  140. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
  141. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
  142. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
  143. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  144. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  145. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  146. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  147. data/spec/spec_helper.rb +26 -0
  148. data/spec/support/active_model_versions.rb +13 -0
  149. data/spec/support/active_resource_builder.rb +29 -0
  150. data/spec/support/activemodel_helpers.rb +19 -0
  151. data/spec/support/capture_helpers.rb +19 -0
  152. data/spec/support/class_builder.rb +42 -0
  153. data/spec/support/controller_builder.rb +74 -0
  154. data/spec/support/fail_with_message_including_matcher.rb +33 -0
  155. data/spec/support/fail_with_message_matcher.rb +32 -0
  156. data/spec/support/i18n_faker.rb +10 -0
  157. data/spec/support/mailer_builder.rb +10 -0
  158. data/spec/support/model_builder.rb +81 -0
  159. data/spec/support/rails_versions.rb +18 -0
  160. data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
  161. data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
  162. data/spec/support/test_application.rb +120 -0
  163. data/yard.watchr +5 -0
  164. metadata +281 -0
@@ -0,0 +1,8 @@
1
+ <% n = 1 %>
2
+ <% @items.each do |item| %>
3
+ <li class="r<%= n %> <%= item.has_tag?(:deprecated) ? 'deprecated' : '' %>">
4
+ <%= linkify item, h(item.name(true)) %>
5
+ <small>(<%= item.namespace.title %>)</small>
6
+ </li>
7
+ <% n = n == 2 ? 1 : 2 %>
8
+ <% end %>
@@ -0,0 +1,300 @@
1
+ function createSourceLinks() {
2
+ $('.method_details_list .source_code').
3
+ before("<span class='showSource'>[<a href='#' class='toggleSource'>View source</a>]</span>");
4
+ $('.toggleSource').toggle(function() {
5
+ $(this).parent().nextAll('.source_code').show();
6
+ $(this).text("Hide source");
7
+ StickyHeaders.update();
8
+ },
9
+ function() {
10
+ $(this).parent().nextAll('.source_code').hide();
11
+ $(this).text("View source");
12
+ StickyHeaders.update();
13
+ });
14
+ }
15
+
16
+ function createDefineLinks() {
17
+ var tHeight = 0;
18
+ $('.defines').after(" <a href='#' class='toggleDefines'>more...</a>");
19
+ $('.toggleDefines').toggle(function() {
20
+ tHeight = $(this).parent().prev().height();
21
+ $(this).prev().show();
22
+ $(this).parent().prev().height($(this).parent().height());
23
+ $(this).text("(less)");
24
+ StickyHeaders.update();
25
+ },
26
+ function() {
27
+ $(this).prev().hide();
28
+ $(this).parent().prev().height(tHeight);
29
+ $(this).text("more...");
30
+ StickyHeaders.update();
31
+ });
32
+ }
33
+
34
+ function createFullTreeLinks() {
35
+ var tHeight = 0;
36
+ $('.inheritanceTree').toggle(function() {
37
+ tHeight = $(this).parent().prev().height();
38
+ $(this).parent().toggleClass('showAll');
39
+ $(this).text("(hide)");
40
+ $(this).parent().prev().height($(this).parent().height());
41
+ StickyHeaders.update();
42
+ },
43
+ function() {
44
+ $(this).parent().toggleClass('showAll');
45
+ $(this).parent().prev().height(tHeight);
46
+ $(this).text("show all");
47
+ StickyHeaders.update();
48
+ });
49
+ }
50
+
51
+ function hideSearchFrameOnBlur() {
52
+ $(document.body).on('click', hideSearchFrame);
53
+ }
54
+
55
+ function initSearchFrameLinks() {
56
+ var search = $('.js-search');
57
+ var items = search.find('li');
58
+ var links = search.find('a');
59
+ var frame = $('.js-search-frame');
60
+
61
+ function listen() {
62
+ links.on('click', function (event) {
63
+ event.preventDefault();
64
+ event.stopPropagation();
65
+ toggle(this, this.href);
66
+ });
67
+
68
+ $(document).on('keydown', function (event) {
69
+ if (event.which == 27) {
70
+ close();
71
+ }
72
+ })
73
+
74
+ $(document).on('click', function (event) {
75
+ close();
76
+ })
77
+ }
78
+
79
+ function toggle(link, frameSrc) {
80
+ if (isOpen() && clickedOnSameLink(frameSrc)) {
81
+ close();
82
+ } else {
83
+ open(link, frameSrc);
84
+ }
85
+ }
86
+
87
+ function isOpen() {
88
+ return frame.hasClass('open');
89
+ }
90
+
91
+ function clickedOnSameLink(location) {
92
+ return frame.attr('src') === location;
93
+ }
94
+
95
+ function reset() {
96
+ items.removeClass('active');
97
+ }
98
+
99
+ function open(link, location) {
100
+ reset();
101
+ $(link).parent().addClass('active');
102
+ frame.attr('src', location).one('load', function () {
103
+ frame.addClass('open');
104
+ })
105
+ }
106
+
107
+ function close() {
108
+ reset();
109
+ frame.removeClass('open');
110
+ }
111
+
112
+ listen();
113
+ }
114
+
115
+
116
+ function linkSummaries() {
117
+ $('.summary_signature').click(function() {
118
+ document.location = $(this).find('a').attr('href');
119
+ });
120
+ }
121
+
122
+ function framesInit() {
123
+ if (hasFrames) {
124
+ document.body.className = 'frames';
125
+ $('#menu .noframes a').attr('href', document.location);
126
+ try {
127
+ window.top.document.title = $('html head title').text();
128
+ } catch(error) {
129
+ // some browsers will not allow this when serving from file://
130
+ // but we don't want to stop the world.
131
+ }
132
+ }
133
+ else {
134
+ $('#menu .noframes a').text('frames').attr('href', framesUrl);
135
+ }
136
+ }
137
+
138
+ function keyboardShortcuts() {
139
+ if (window.top.frames.main) return;
140
+
141
+ $(document).keypress(function(evt) {
142
+ if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) return;
143
+
144
+ if (
145
+ typeof evt.target !== "undefined" &&
146
+ (evt.target.nodeName == "INPUT" || evt.target.nodeName == "TEXTAREA")
147
+ ) return;
148
+
149
+ switch (evt.charCode) {
150
+ case 67: case 99: $('#class_list_link').click(); break; // 'c'
151
+ case 77: case 109: $('#method_list_link').click(); break; // 'm'
152
+ case 70: case 102: $('#file_list_link').click(); break; // 'f'
153
+ default: break;
154
+ }
155
+ });
156
+ }
157
+
158
+ function summaryToggle() {
159
+ $('.summary_toggle').click(function() {
160
+ if (localStorage) {
161
+ localStorage.summaryCollapsed = $(this).text();
162
+ }
163
+ $('.summary_toggle').each(function() {
164
+ $(this).text($(this).text() == "collapse" ? "expand" : "collapse");
165
+ var next = $(this).parent().parent().nextAll('ul.summary').first();
166
+ if (next.hasClass('compact')) {
167
+ next.toggle();
168
+ next.nextAll('ul.summary').first().toggle();
169
+ }
170
+ else if (next.hasClass('summary')) {
171
+ var list = $('<ul class="summary compact" />');
172
+ list.html(next.html());
173
+ list.find('.summary_desc, .note').remove();
174
+ list.find('a').each(function() {
175
+ $(this).html($(this).find('strong').html());
176
+ $(this).parent().html($(this)[0].outerHTML);
177
+ });
178
+ next.before(list);
179
+ next.toggle();
180
+ }
181
+ });
182
+ StickyHeaders.update();
183
+ return false;
184
+ });
185
+ if (localStorage) {
186
+ if (localStorage.summaryCollapsed == "collapse") {
187
+ $('.summary_toggle').first().click();
188
+ }
189
+ else localStorage.summaryCollapsed = "expand";
190
+ }
191
+ }
192
+
193
+ function fixOutsideWorldLinks() {
194
+ $('a').each(function() {
195
+ if (window.location.host != this.host) this.target = '_parent';
196
+ });
197
+ }
198
+
199
+ function generateTOC() {
200
+ if ($('#filecontents').length === 0) return;
201
+ var _toc = $('<ol class="top"></ol>');
202
+ var show = false;
203
+ var toc = _toc;
204
+ var counter = 0;
205
+ var tags = ['h2', 'h3', 'h4', 'h5', 'h6'];
206
+ var i;
207
+ if ($('#filecontents h1').length > 1) tags.unshift('h1');
208
+ for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; }
209
+ var lastTag = parseInt(tags[0][1], 10);
210
+ $(tags.join(', ')).each(function() {
211
+ if ($(this).parents('.method_details .docstring').length != 0) return;
212
+ if (this.id == "filecontents") return;
213
+ show = true;
214
+ var thisTag = parseInt(this.tagName[1], 10);
215
+ if (this.id.length === 0) {
216
+ var proposedId = $(this).attr('toc-id');
217
+ if (typeof(proposedId) != "undefined") this.id = proposedId;
218
+ else {
219
+ var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_');
220
+ if ($('#' + proposedId).length > 0) { proposedId += counter; counter++; }
221
+ this.id = proposedId;
222
+ }
223
+ }
224
+ if (thisTag > lastTag) {
225
+ for (i = 0; i < thisTag - lastTag; i++) {
226
+ var tmp = $('<ol/>'); toc.append(tmp); toc = tmp;
227
+ }
228
+ }
229
+ if (thisTag < lastTag) {
230
+ for (i = 0; i < lastTag - thisTag; i++) toc = toc.parent();
231
+ }
232
+ var title = $(this).attr('toc-title');
233
+ if (typeof(title) == "undefined") title = $(this).text();
234
+ toc.append('<li><a href="#' + this.id + '">' + title + '</a></li>');
235
+ lastTag = thisTag;
236
+ });
237
+ if (!show) return;
238
+ html = '<div id="toc"><p class="title"><a class="hide_toc" href="#"><strong>Table of Contents</strong></a> <small>(<a href="#" class="float_toc">left</a>)</small></p></div>';
239
+ $('#content').prepend(html);
240
+ $('#toc').append(_toc);
241
+ $('#toc .hide_toc').toggle(function() {
242
+ $('#toc .top').slideUp('fast');
243
+ $('#toc').toggleClass('hidden');
244
+ $('#toc .title small').toggle();
245
+ }, function() {
246
+ $('#toc .top').slideDown('fast');
247
+ $('#toc').toggleClass('hidden');
248
+ $('#toc .title small').toggle();
249
+ });
250
+ $('#toc .float_toc').toggle(function() {
251
+ $(this).text('float');
252
+ $('#toc').toggleClass('nofloat');
253
+ }, function() {
254
+ $(this).text('left');
255
+ $('#toc').toggleClass('nofloat');
256
+ });
257
+ }
258
+
259
+ function removeDlBoxIfEmpty() {
260
+ var $box = $('dl.box')
261
+ if (!$box.text().trim()) {
262
+ $box.remove();
263
+ }
264
+ }
265
+
266
+ function makeHeadersSticky() {
267
+ StickyHeaders
268
+ .set({
269
+ contentContainer: '#main',
270
+ stickyHeaderContainer: '#header',
271
+ switchOnCollisionWith: 'top',
272
+ fillHeadersWith: function (node) {
273
+ var $elem = node.clone();
274
+ $elem.find('small').remove();
275
+ return $elem;
276
+ }
277
+ })
278
+ .add('.method_details > h3')
279
+ .activate();
280
+ }
281
+
282
+ function updateStickyHeaders() {
283
+ setTimeout(function () {
284
+ StickyHeaders.update()
285
+ }, 100)
286
+ }
287
+
288
+ $(makeHeadersSticky);
289
+ $(framesInit);
290
+ $(createSourceLinks);
291
+ $(createDefineLinks);
292
+ $(createFullTreeLinks);
293
+ $(initSearchFrameLinks);
294
+ $(linkSummaries);
295
+ $(keyboardShortcuts);
296
+ $(summaryToggle);
297
+ $(fixOutsideWorldLinks);
298
+ $(generateTOC);
299
+ $(removeDlBoxIfEmpty);
300
+ $(updateStickyHeaders);
@@ -0,0 +1 @@
1
+ // Override with nothing
@@ -0,0 +1,289 @@
1
+ window.StickyHeaders = (function ($) {
2
+ var me = {},
3
+ body, config, contentContainer, currentHeaderRangeIndex,
4
+ currentScrollOffset, elem, headerRanges, headers, isScrolling,
5
+ lastScrollOffset, selectors, stickyHeaderContainer;
6
+
7
+ function init() {
8
+ config = {
9
+ switchOnCollisionWith: 'top',
10
+ copy: 'element'
11
+ };
12
+ selectors = [];
13
+ headers = [];
14
+ headerRanges = [];
15
+
16
+ currentHeaderRangeIndex = -1;
17
+ currentScrollOffset = 0;
18
+ lastScrollOffset = 0;
19
+ isScrolling = false;
20
+
21
+ createStickyHeader();
22
+ }
23
+
24
+ function createStickyHeader() {
25
+ elem = $('<div>').attr('id', 'sticky-header');
26
+ }
27
+
28
+ function setHeaders() {
29
+ var elements = [],
30
+ stickyHeaderLineHeight = parseCssValue(elem.css('line-height')),
31
+ stickyHeaderTopPadding;
32
+
33
+ headers = [];
34
+ $.each(selectors, function (_, selector) {
35
+ contentContainer.find(selector).each(function (_, element) {
36
+ var $element = $(element),
37
+ fontSize = parseCssValue($element.css('font-size')),
38
+ topOffset = (
39
+ element.offsetTop +
40
+ parseFloat($element.css('padding-top'), 10) +
41
+ (- ((stickyHeaderLineHeight - fontSize) / 2))
42
+ ),
43
+ height = Math.round($element.height()),
44
+ outerHeight = Math.round($element.outerHeight(true)),
45
+ bottomOffset = topOffset + outerHeight;
46
+
47
+ headers.push({
48
+ element: element,
49
+ $element: $element,
50
+ topOffset: topOffset,
51
+ bottomOffset: bottomOffset
52
+ });
53
+ })
54
+ })
55
+ }
56
+
57
+ function setHeaderRanges() {
58
+ var offsetProp = config.switchOnCollisionWith + 'Offset',
59
+ start, end;
60
+
61
+ headerRanges = [];
62
+ for (var i = 0, len = headers.length; i < len; i++) {
63
+ start = headers[i][offsetProp];
64
+
65
+ if (headers[i+1]) {
66
+ end = headers[i+1][offsetProp];
67
+ } else {
68
+ end = null;
69
+ }
70
+
71
+ headerRanges.push({
72
+ start: start,
73
+ end: end,
74
+ element: headers[i].element
75
+ });
76
+ }
77
+
78
+ //debugHeaderRanges();
79
+ }
80
+
81
+ function debugHeaderRanges() {
82
+ contentContainer.find('.header-range-debug').remove();
83
+
84
+ $.each(headerRanges, function (i, range) {
85
+ var color = 'hsla('+(20*i)+', 100%, 50%, 0.15)',
86
+ debug = $('<div>')
87
+ .addClass('header-range-debug')
88
+ .css({
89
+ width: '100%',
90
+ position: 'absolute',
91
+ top: range.start + 'px',
92
+ height: (range.end === null ? '1px' : (range.end - range.start) + 'px'),
93
+ backgroundColor: color,
94
+ borderTop: '1px solid black'
95
+ })
96
+ .appendTo(contentContainer)
97
+
98
+ debug.append(
99
+ $('<div>')
100
+ .css({
101
+ position: 'absolute',
102
+ top: 0,
103
+ right: 0,
104
+ height: '2em',
105
+ lineHeight: '2em',
106
+ width: '40em',
107
+ fontSize: '13px',
108
+ backgroundColor: 'black',
109
+ color: 'white',
110
+ padding: '0 5px'
111
+ })
112
+ .text(headers[i].$element.text() + ' (#' + i + ')')
113
+ )
114
+ })
115
+ }
116
+
117
+ function setCurrentHeaderIndex() {
118
+ var scrollTop = contentContainer.scrollTop();
119
+
120
+ for (var i = 0, len = headers.length; i < len; i++) {
121
+ if (scrollTop < headers[i].bottomOffset) {
122
+ break;
123
+ }
124
+ currentHeaderIndex = i;
125
+ }
126
+ }
127
+
128
+ function render() {
129
+ var clonedHeader;
130
+
131
+ if (currentHeaderRangeIndex < 0 || currentHeaderRangeIndex > headerRanges.length-1) {
132
+ elem.removeClass('show');
133
+ body.removeClass('has-sticky-header');
134
+ }
135
+ else {
136
+ var realHeader = $(headerRanges[currentHeaderRangeIndex].element);
137
+
138
+ if (typeof config.fillHeadersWith === 'function') {
139
+ elem.html(config.fillHeadersWith(realHeader));
140
+ } else if (config.fillHeadersWith === 'content') {
141
+ elem.html(realHeader.clone().html());
142
+ } else {
143
+ elem.html(realHeader.clone());
144
+ }
145
+
146
+ elem.addClass('show');
147
+ body.addClass('has-sticky-header');
148
+ }
149
+
150
+ return me;
151
+ }
152
+
153
+ function determineCurrentHeaderRangeIndex(startIndex, direction) {
154
+ var index = startIndex;
155
+ while (true) {
156
+ currentHeaderRange = headerRanges[index];
157
+ if (!currentHeaderRange || isWithinRange(currentScrollOffset, currentHeaderRange)) {
158
+ break;
159
+ } else {
160
+ index += direction;
161
+ }
162
+ }
163
+ return index;
164
+ }
165
+
166
+ function onScroll() {
167
+ if (!headerRanges.length) {
168
+ return;
169
+ }
170
+
171
+ currentScrollOffset = contentContainer.scrollTop();
172
+
173
+ if (currentScrollOffset > headerRanges[0].start) {
174
+ var newCurrentHeaderRangeIndex = currentHeaderRangeIndex;
175
+ var currentHeaderRange = headerRanges[newCurrentHeaderRangeIndex];
176
+
177
+ if (newCurrentHeaderRangeIndex < 0) {
178
+ newCurrentHeaderRangeIndex = 0;
179
+ }
180
+
181
+ if (currentScrollOffset < lastScrollOffset) {
182
+ // scrolling up
183
+ newCurrentHeaderRangeIndex = determineCurrentHeaderRangeIndex(newCurrentHeaderRangeIndex, -1);
184
+ } else {
185
+ // scrolling down
186
+ newCurrentHeaderRangeIndex = determineCurrentHeaderRangeIndex(newCurrentHeaderRangeIndex, +1);
187
+ }
188
+ } else {
189
+ newCurrentHeaderRangeIndex = -1;
190
+ }
191
+
192
+ // only re-render when necessary
193
+ if (newCurrentHeaderRangeIndex !== undefined && currentHeaderRangeIndex !== newCurrentHeaderRangeIndex) {
194
+ currentHeaderRangeIndex = newCurrentHeaderRangeIndex;
195
+ render();
196
+ }
197
+
198
+ lastScrollOffset = currentScrollOffset;
199
+ }
200
+
201
+ function listenToScroll(element, callback, options) {
202
+ options = options || {};
203
+
204
+ if (options.every) {
205
+ element.on('scroll', function () {
206
+ isScrolling = true;
207
+ })
208
+
209
+ setInterval(function () {
210
+ if (isScrolling) {
211
+ callback();
212
+ isScrolling = false;
213
+ }
214
+ }, options.every);
215
+ }
216
+ else {
217
+ element.on('scroll', callback);
218
+ }
219
+ }
220
+
221
+ function isWithinRange(number, range) {
222
+ return (
223
+ number >= range.start &&
224
+ (
225
+ range.end === undefined ||
226
+ range.end === null ||
227
+ number <= range.end
228
+ )
229
+ );
230
+ }
231
+
232
+ function parseCssValue(value) {
233
+ if (value === null || value === undefined) {
234
+ return 0;
235
+ } else {
236
+ return parseInt(value, 10);
237
+ }
238
+ }
239
+
240
+ me.setHeaders = setHeaders;
241
+ me.setHeaderRanges = setHeaderRanges;
242
+
243
+ me.set = function (/* key, value | config */) {
244
+ if ($.isPlainObject(arguments[0])) {
245
+ $.extend(config, arguments[0]);
246
+ } else {
247
+ config[arguments[0]] = arguments[1];
248
+ }
249
+ return me;
250
+ }
251
+
252
+ me.add = function (/* selectors... */) {
253
+ selectors.push.apply(selectors, arguments);
254
+ return me;
255
+ }
256
+
257
+ me.activate = function () {
258
+ body = $('body');
259
+ contentContainer = config.contentContainer ? $(config.contentContainer) : body;
260
+ stickyHeaderContainer = config.stickyHeaderContainer ? $(config.stickyHeaderContainer) : contentContainer;
261
+
262
+ stickyHeaderContainer.append(elem);
263
+ setHeaders();
264
+ setHeaderRanges();
265
+ setCurrentHeaderIndex();
266
+
267
+ return me;
268
+ }
269
+
270
+ me.update = function () {
271
+ setHeaders();
272
+ setHeaderRanges();
273
+ render();
274
+
275
+ listenToScroll(contentContainer, onScroll);
276
+ }
277
+
278
+ me.getHeaders = function () {
279
+ return headers;
280
+ }
281
+
282
+ me.getHeaderRanges = function () {
283
+ return headerRanges;
284
+ }
285
+
286
+ init();
287
+
288
+ return me;
289
+ })(jQuery);