solidus_api_v2 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +38 -0
  5. data/Gemfile +13 -0
  6. data/LICENSE +26 -0
  7. data/README.md +98 -0
  8. data/Rakefile +37 -0
  9. data/app/controllers/concerns/spree/api/v2/renderable.rb +51 -0
  10. data/app/controllers/spree/api/v2/base_controller.rb +31 -0
  11. data/app/controllers/spree/api/v2/children_controller.rb +29 -0
  12. data/app/controllers/spree/api/v2/countries_controller.rb +21 -0
  13. data/app/controllers/spree/api/v2/images_controller.rb +29 -0
  14. data/app/controllers/spree/api/v2/line_items_controller.rb +36 -0
  15. data/app/controllers/spree/api/v2/option_types_controller.rb +31 -0
  16. data/app/controllers/spree/api/v2/option_values_controller.rb +29 -0
  17. data/app/controllers/spree/api/v2/orders_controller.rb +11 -0
  18. data/app/controllers/spree/api/v2/prices_controller.rb +27 -0
  19. data/app/controllers/spree/api/v2/products_controller.rb +37 -0
  20. data/app/controllers/spree/api/v2/states_controller.rb +29 -0
  21. data/app/controllers/spree/api/v2/taxonomies_controller.rb +21 -0
  22. data/app/controllers/spree/api/v2/taxons_controller.rb +40 -0
  23. data/app/controllers/spree/api/v2/variants_controller.rb +35 -0
  24. data/app/models/spree/base_decorator.rb +5 -0
  25. data/app/models/spree/image_decorator.rb +3 -0
  26. data/app/models/spree/price_decorator.rb +3 -0
  27. data/app/models/spree/state_decorator.rb +3 -0
  28. data/app/serializers/spree/address_serializer.rb +9 -0
  29. data/app/serializers/spree/base_serializer.rb +13 -0
  30. data/app/serializers/spree/country_serializer.rb +7 -0
  31. data/app/serializers/spree/error_serializer.rb +52 -0
  32. data/app/serializers/spree/image_serializer.rb +13 -0
  33. data/app/serializers/spree/line_item_serializer.rb +13 -0
  34. data/app/serializers/spree/option_type_serializer.rb +8 -0
  35. data/app/serializers/spree/option_value_serializer.rb +8 -0
  36. data/app/serializers/spree/order_serializer.rb +21 -0
  37. data/app/serializers/spree/price_serializer.rb +7 -0
  38. data/app/serializers/spree/product_serializer.rb +12 -0
  39. data/app/serializers/spree/role_serializer.rb +5 -0
  40. data/app/serializers/spree/state_serializer.rb +7 -0
  41. data/app/serializers/spree/store_serializer.rb +6 -0
  42. data/app/serializers/spree/taxon_serializer.rb +16 -0
  43. data/app/serializers/spree/taxonomy_serializer.rb +7 -0
  44. data/app/serializers/spree/user_serializer.rb +5 -0
  45. data/app/serializers/spree/variant_serializer.rb +12 -0
  46. data/bin/rails +7 -0
  47. data/circle.yml +13 -0
  48. data/config/locales/en.yml +25 -0
  49. data/config/routes.rb +53 -0
  50. data/docs/.nojekyll +0 -0
  51. data/docs/Dockerfile +12 -0
  52. data/docs/Gemfile +13 -0
  53. data/docs/README.md +12 -0
  54. data/docs/Rakefile +9 -0
  55. data/docs/config.rb +39 -0
  56. data/docs/font-selection.json +148 -0
  57. data/docs/source/fonts/slate.eot +0 -0
  58. data/docs/source/fonts/slate.svg +14 -0
  59. data/docs/source/fonts/slate.ttf +0 -0
  60. data/docs/source/fonts/slate.woff +0 -0
  61. data/docs/source/fonts/slate.woff2 +0 -0
  62. data/docs/source/images/logo.png +0 -0
  63. data/docs/source/images/navbar.png +0 -0
  64. data/docs/source/includes/_authentication.md +61 -0
  65. data/docs/source/includes/_countries.md +133 -0
  66. data/docs/source/includes/_errors.md +17 -0
  67. data/docs/source/includes/_filtering.md +11 -0
  68. data/docs/source/includes/_images.md +201 -0
  69. data/docs/source/includes/_line_items.md +137 -0
  70. data/docs/source/includes/_option_types.md +267 -0
  71. data/docs/source/includes/_option_values.md +227 -0
  72. data/docs/source/includes/_orders.md +75 -0
  73. data/docs/source/includes/_pagination.md +10 -0
  74. data/docs/source/includes/_prices.md +188 -0
  75. data/docs/source/includes/_products.md +403 -0
  76. data/docs/source/includes/_states.md +96 -0
  77. data/docs/source/includes/_taxonomies.md +325 -0
  78. data/docs/source/includes/_taxons.md +414 -0
  79. data/docs/source/includes/_variants.md +430 -0
  80. data/docs/source/index.md +53 -0
  81. data/docs/source/javascripts/all.js +4 -0
  82. data/docs/source/javascripts/all_nosearch.js +3 -0
  83. data/docs/source/javascripts/app/_lang.js +162 -0
  84. data/docs/source/javascripts/app/_search.js +74 -0
  85. data/docs/source/javascripts/app/_toc.js +55 -0
  86. data/docs/source/javascripts/lib/_energize.js +169 -0
  87. data/docs/source/javascripts/lib/_imagesloaded.min.js +7 -0
  88. data/docs/source/javascripts/lib/_jquery.highlight.js +108 -0
  89. data/docs/source/javascripts/lib/_jquery.tocify.js +1042 -0
  90. data/docs/source/javascripts/lib/_jquery_ui.js +566 -0
  91. data/docs/source/javascripts/lib/_lunr.js +1910 -0
  92. data/docs/source/layouts/layout.erb +102 -0
  93. data/docs/source/stylesheets/_icon-font.scss +38 -0
  94. data/docs/source/stylesheets/_normalize.css +427 -0
  95. data/docs/source/stylesheets/_syntax.scss.erb +27 -0
  96. data/docs/source/stylesheets/_variables.scss +109 -0
  97. data/docs/source/stylesheets/print.css.scss +142 -0
  98. data/docs/source/stylesheets/screen.css.scss +622 -0
  99. data/lib/solidus_api_v2.rb +5 -0
  100. data/lib/spree_api_v2/engine.rb +21 -0
  101. data/lib/spree_api_v2.rb +4 -0
  102. data/solidus_api_v2.gemspec +36 -0
  103. data/spec/controllers/spree/api/v2/children_controller_spec.rb +28 -0
  104. data/spec/controllers/spree/api/v2/countries_controller_spec.rb +25 -0
  105. data/spec/controllers/spree/api/v2/images_controller_spec.rb +93 -0
  106. data/spec/controllers/spree/api/v2/line_items_controller_spec.rb +86 -0
  107. data/spec/controllers/spree/api/v2/option_types_controller_spec.rb +73 -0
  108. data/spec/controllers/spree/api/v2/option_values_controller_spec.rb +88 -0
  109. data/spec/controllers/spree/api/v2/orders_controller_spec.rb +15 -0
  110. data/spec/controllers/spree/api/v2/prices_controller_spec.rb +55 -0
  111. data/spec/controllers/spree/api/v2/products_controller_spec.rb +95 -0
  112. data/spec/controllers/spree/api/v2/states_controller_spec.rb +42 -0
  113. data/spec/controllers/spree/api/v2/taxonomies_controller_spec.rb +31 -0
  114. data/spec/controllers/spree/api/v2/taxons_controller_spec.rb +54 -0
  115. data/spec/controllers/spree/api/v2/variants_controller_spec.rb +108 -0
  116. data/spec/models/spree/base_decorator_spec.rb +9 -0
  117. data/spec/models/spree/price_decorator_spec.rb +3 -0
  118. data/spec/serializers/spree/address_serializer_spec.rb +35 -0
  119. data/spec/serializers/spree/country_serializer_spec.rb +27 -0
  120. data/spec/serializers/spree/error_serializer_spec.rb +116 -0
  121. data/spec/serializers/spree/image_serializer_spec.rb +30 -0
  122. data/spec/serializers/spree/line_item_serializer_spec.rb +40 -0
  123. data/spec/serializers/spree/option_type_serializer_spec.rb +27 -0
  124. data/spec/serializers/spree/option_value_serializer_spec.rb +29 -0
  125. data/spec/serializers/spree/order_serializer_spec.rb +69 -0
  126. data/spec/serializers/spree/price_serializer_spec.rb +28 -0
  127. data/spec/serializers/spree/product_serializer_spec.rb +47 -0
  128. data/spec/serializers/spree/role_serializer_spec.rb +17 -0
  129. data/spec/serializers/spree/state_serializer_spec.rb +25 -0
  130. data/spec/serializers/spree/store_serializer_spec.rb +25 -0
  131. data/spec/serializers/spree/taxon_serializer_spec.rb +44 -0
  132. data/spec/serializers/spree/taxonomy_serializer_spec.rb +27 -0
  133. data/spec/serializers/spree/user_serializer_spec.rb +17 -0
  134. data/spec/serializers/spree/variant_serializer_spec.rb +55 -0
  135. data/spec/spec_helper.rb +51 -0
  136. data/spec/support/shoulda_matchers.rb +6 -0
  137. data/spree_api_v2.gemspec +36 -0
  138. metadata +437 -0
@@ -0,0 +1,1042 @@
1
+ /* jquery Tocify - v1.8.0 - 2013-09-16
2
+ * http://www.gregfranko.com/jquery.tocify.js/
3
+ * Copyright (c) 2013 Greg Franko; Licensed MIT
4
+ * Modified lightly by Robert Lord to fix a bug I found,
5
+ * and also so it adds ids to headers
6
+ * also because I want height caching, since the
7
+ * height lookup for h1s and h2s was causing serious
8
+ * lag spikes below 30 fps */
9
+
10
+ // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE.
11
+ (function(tocify) {
12
+
13
+ // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
14
+ "use strict";
15
+
16
+ // Calls the second IIFE and locally passes in the global jQuery, window, and document objects
17
+ tocify(window.jQuery, window, document);
18
+
19
+ }
20
+
21
+ // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript.
22
+ (function($, window, document, undefined) {
23
+
24
+ // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
25
+ "use strict";
26
+
27
+ var tocClassName = "tocify",
28
+ tocClass = "." + tocClassName,
29
+ tocFocusClassName = "tocify-focus",
30
+ tocHoverClassName = "tocify-hover",
31
+ hideTocClassName = "tocify-hide",
32
+ hideTocClass = "." + hideTocClassName,
33
+ headerClassName = "tocify-header",
34
+ headerClass = "." + headerClassName,
35
+ subheaderClassName = "tocify-subheader",
36
+ subheaderClass = "." + subheaderClassName,
37
+ itemClassName = "tocify-item",
38
+ itemClass = "." + itemClassName,
39
+ extendPageClassName = "tocify-extend-page",
40
+ extendPageClass = "." + extendPageClassName;
41
+
42
+ // Calling the jQueryUI Widget Factory Method
43
+ $.widget("toc.tocify", {
44
+
45
+ //Plugin version
46
+ version: "1.8.0",
47
+
48
+ // These options will be used as defaults
49
+ options: {
50
+
51
+ // **context**: Accepts String: Any jQuery selector
52
+ // The container element that holds all of the elements used to generate the table of contents
53
+ context: "body",
54
+
55
+ // **ignoreSelector**: Accepts String: Any jQuery selector
56
+ // A selector to any element that would be matched by selectors that you wish to be ignored
57
+ ignoreSelector: null,
58
+
59
+ // **selectors**: Accepts an Array of Strings: Any jQuery selectors
60
+ // The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure
61
+ selectors: "h1, h2, h3",
62
+
63
+ // **showAndHide**: Accepts a boolean: true or false
64
+ // Used to determine if elements should be shown and hidden
65
+ showAndHide: true,
66
+
67
+ // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown"
68
+ // Used to display any of the table of contents nested items
69
+ showEffect: "slideDown",
70
+
71
+ // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
72
+ // The time duration of the show animation
73
+ showEffectSpeed: "medium",
74
+
75
+ // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp"
76
+ // Used to hide any of the table of contents nested items
77
+ hideEffect: "slideUp",
78
+
79
+ // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
80
+ // The time duration of the hide animation
81
+ hideEffectSpeed: "medium",
82
+
83
+ // **smoothScroll**: Accepts a boolean: true or false
84
+ // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page
85
+ smoothScroll: true,
86
+
87
+ // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
88
+ // The time duration of the smoothScroll animation
89
+ smoothScrollSpeed: "medium",
90
+
91
+ // **scrollTo**: Accepts Number (pixels)
92
+ // The amount of space between the top of page and the selected table of contents item after the page has been scrolled
93
+ scrollTo: 0,
94
+
95
+ // **showAndHideOnScroll**: Accepts a boolean: true or false
96
+ // Determines if table of contents nested items should be shown and hidden while scrolling
97
+ showAndHideOnScroll: true,
98
+
99
+ // **highlightOnScroll**: Accepts a boolean: true or false
100
+ // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling
101
+ highlightOnScroll: true,
102
+
103
+ // **highlightOffset**: Accepts a number
104
+ // The offset distance in pixels to trigger the next active table of contents item
105
+ highlightOffset: 40,
106
+
107
+ // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none"
108
+ // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents
109
+ theme: "bootstrap",
110
+
111
+ // **extendPage**: Accepts a boolean: true or false
112
+ // If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased
113
+ extendPage: true,
114
+
115
+ // **extendPageOffset**: Accepts a number: pixels
116
+ // How close to the bottom of the page a user must scroll before the page is extended
117
+ extendPageOffset: 100,
118
+
119
+ // **history**: Accepts a boolean: true or false
120
+ // Adds a hash to the page url to maintain history
121
+ history: true,
122
+
123
+ // **scrollHistory**: Accepts a boolean: true or false
124
+ // Adds a hash to the page url, to maintain history, when scrolling to a TOC item
125
+ scrollHistory: false,
126
+
127
+ // **hashGenerator**: How the hash value (the anchor segment of the URL, following the
128
+ // # character) will be generated.
129
+ //
130
+ // "compact" (default) - #CompressesEverythingTogether
131
+ // "pretty" - #looks-like-a-nice-url-and-is-easily-readable
132
+ // function(text, element){} - Your own hash generation function that accepts the text as an
133
+ // argument, and returns the hash value.
134
+ hashGenerator: "compact",
135
+
136
+ // **highlightDefault**: Accepts a boolean: true or false
137
+ // Set's the first TOC item as active if no other TOC item is active.
138
+ highlightDefault: true
139
+
140
+ },
141
+
142
+ // _Create
143
+ // -------
144
+ // Constructs the plugin. Only called once.
145
+ _create: function() {
146
+
147
+ var self = this;
148
+
149
+ self.tocifyWrapper = $('.tocify-wrapper');
150
+ self.extendPageScroll = true;
151
+
152
+ // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings)
153
+ self.items = [];
154
+
155
+ // Generates the HTML for the dynamic table of contents
156
+ self._generateToc();
157
+
158
+ // Caches heights and anchors
159
+ self.cachedHeights = [],
160
+ self.cachedAnchors = [];
161
+
162
+ // Adds CSS classes to the newly generated table of contents HTML
163
+ self._addCSSClasses();
164
+
165
+ self.webkit = (function() {
166
+
167
+ for(var prop in window) {
168
+
169
+ if(prop) {
170
+
171
+ if(prop.toLowerCase().indexOf("webkit") !== -1) {
172
+
173
+ return true;
174
+
175
+ }
176
+
177
+ }
178
+
179
+ }
180
+
181
+ return false;
182
+
183
+ }());
184
+
185
+ // Adds jQuery event handlers to the newly generated table of contents
186
+ self._setEventHandlers();
187
+
188
+ // Binding to the Window load event to make sure the correct scrollTop is calculated
189
+ $(window).load(function() {
190
+
191
+ // Sets the active TOC item
192
+ self._setActiveElement(true);
193
+
194
+ // Once all animations on the page are complete, this callback function will be called
195
+ $("html, body").promise().done(function() {
196
+
197
+ setTimeout(function() {
198
+
199
+ self.extendPageScroll = false;
200
+
201
+ },0);
202
+
203
+ });
204
+
205
+ });
206
+
207
+ },
208
+
209
+ // _generateToc
210
+ // ------------
211
+ // Generates the HTML for the dynamic table of contents
212
+ _generateToc: function() {
213
+
214
+ // _Local variables_
215
+
216
+ // Stores the plugin context in the self variable
217
+ var self = this,
218
+
219
+ // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above
220
+ firstElem,
221
+
222
+ // Instantiated variable that will store the top level newly created unordered list DOM element
223
+ ul,
224
+ ignoreSelector = self.options.ignoreSelector;
225
+
226
+ // If the selectors option has a comma within the string
227
+ if(this.options.selectors.indexOf(",") !== -1) {
228
+
229
+ // Grabs the first selector from the string
230
+ firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(",")));
231
+
232
+ }
233
+
234
+ // If the selectors option does not have a comman within the string
235
+ else {
236
+
237
+ // Grabs the first selector from the string and makes sure there are no spaces
238
+ firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,""));
239
+
240
+ }
241
+
242
+ if(!firstElem.length) {
243
+
244
+ self.element.addClass(hideTocClassName);
245
+
246
+ return;
247
+
248
+ }
249
+
250
+ self.element.addClass(tocClassName);
251
+
252
+ // Loops through each top level selector
253
+ firstElem.each(function(index) {
254
+
255
+ //If the element matches the ignoreSelector then we skip it
256
+ if($(this).is(ignoreSelector)) {
257
+ return;
258
+ }
259
+
260
+ // Creates an unordered list HTML element and adds a dynamic ID and standard class name
261
+ ul = $("<ul/>", {
262
+ "id": headerClassName + index,
263
+ "class": headerClassName
264
+ }).
265
+
266
+ // Appends a top level list item HTML element to the previously created HTML header
267
+ append(self._nestElements($(this), index));
268
+
269
+ // Add the created unordered list element to the HTML element calling the plugin
270
+ self.element.append(ul);
271
+
272
+ // Finds all of the HTML tags between the header and subheader elements
273
+ $(this).nextUntil(this.nodeName.toLowerCase()).each(function() {
274
+
275
+ // If there are no nested subheader elemements
276
+ if($(this).find(self.options.selectors).length === 0) {
277
+
278
+ // Loops through all of the subheader elements
279
+ $(this).filter(self.options.selectors).each(function() {
280
+
281
+ //If the element matches the ignoreSelector then we skip it
282
+ if($(this).is(ignoreSelector)) {
283
+ return;
284
+ }
285
+
286
+ self._appendSubheaders.call(this, self, ul);
287
+
288
+ });
289
+
290
+ }
291
+
292
+ // If there are nested subheader elements
293
+ else {
294
+
295
+ // Loops through all of the subheader elements
296
+ $(this).find(self.options.selectors).each(function() {
297
+
298
+ //If the element matches the ignoreSelector then we skip it
299
+ if($(this).is(ignoreSelector)) {
300
+ return;
301
+ }
302
+
303
+ self._appendSubheaders.call(this, self, ul);
304
+
305
+ });
306
+
307
+ }
308
+
309
+ });
310
+
311
+ });
312
+
313
+ },
314
+
315
+ _setActiveElement: function(pageload) {
316
+
317
+ var self = this,
318
+
319
+ hash = window.location.hash.substring(1),
320
+
321
+ elem = self.element.find("li[data-unique='" + hash + "']");
322
+
323
+ if(hash.length) {
324
+
325
+ // Removes highlighting from all of the list item's
326
+ self.element.find("." + self.focusClass).removeClass(self.focusClass);
327
+
328
+ // Highlights the current list item that was clicked
329
+ elem.addClass(self.focusClass);
330
+
331
+ // If the showAndHide option is true
332
+ if(self.options.showAndHide) {
333
+
334
+ // Triggers the click event on the currently focused TOC item
335
+ elem.click();
336
+
337
+ }
338
+
339
+ }
340
+
341
+ else {
342
+
343
+ // Removes highlighting from all of the list item's
344
+ self.element.find("." + self.focusClass).removeClass(self.focusClass);
345
+
346
+ if(!hash.length && pageload && self.options.highlightDefault) {
347
+
348
+ // Highlights the first TOC item if no other items are highlighted
349
+ self.element.find(itemClass).first().addClass(self.focusClass);
350
+
351
+ }
352
+
353
+ }
354
+
355
+ return self;
356
+
357
+ },
358
+
359
+ // _nestElements
360
+ // -------------
361
+ // Helps create the table of contents list by appending nested list items
362
+ _nestElements: function(self, index) {
363
+
364
+ var arr, item, hashValue;
365
+
366
+ arr = $.grep(this.items, function (item) {
367
+
368
+ return item === self.text();
369
+
370
+ });
371
+
372
+ // If there is already a duplicate TOC item
373
+ if(arr.length) {
374
+
375
+ // Adds the current TOC item text and index (for slight randomization) to the internal array
376
+ this.items.push(self.text() + index);
377
+
378
+ }
379
+
380
+ // If there not a duplicate TOC item
381
+ else {
382
+
383
+ // Adds the current TOC item text to the internal array
384
+ this.items.push(self.text());
385
+
386
+ }
387
+
388
+ hashValue = this._generateHashValue(arr, self, index);
389
+
390
+ // ADDED BY ROBERT
391
+ // actually add the hash value to the element's id
392
+ // self.attr("id", "link-" + hashValue);
393
+
394
+ // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
395
+ item = $("<li/>", {
396
+
397
+ // Sets a common class name to the list item
398
+ "class": itemClassName,
399
+
400
+ "data-unique": hashValue
401
+
402
+ }).append($("<a/>", {
403
+
404
+ "text": self.text()
405
+
406
+ }));
407
+
408
+ // Adds an HTML anchor tag before the currently traversed HTML element
409
+ self.before($("<div/>", {
410
+
411
+ // Sets a name attribute on the anchor tag to the text of the currently traversed HTML element (also making sure that all whitespace is replaced with an underscore)
412
+ "name": hashValue,
413
+
414
+ "data-unique": hashValue
415
+
416
+ }));
417
+
418
+ return item;
419
+
420
+ },
421
+
422
+ // _generateHashValue
423
+ // ------------------
424
+ // Generates the hash value that will be used to refer to each item.
425
+ _generateHashValue: function(arr, self, index) {
426
+
427
+ var hashValue = "",
428
+ hashGeneratorOption = this.options.hashGenerator;
429
+
430
+ if (hashGeneratorOption === "pretty") {
431
+ // remove weird characters
432
+
433
+
434
+ // prettify the text
435
+ hashValue = self.text().toLowerCase().replace(/\s/g, "-");
436
+
437
+ // ADDED BY ROBERT
438
+ // remove weird characters
439
+ hashValue = hashValue.replace(/[^\x00-\x7F]/g, "");
440
+
441
+ // fix double hyphens
442
+ while (hashValue.indexOf("--") > -1) {
443
+ hashValue = hashValue.replace(/--/g, "-");
444
+ }
445
+
446
+ // fix colon-space instances
447
+ while (hashValue.indexOf(":-") > -1) {
448
+ hashValue = hashValue.replace(/:-/g, "-");
449
+ }
450
+
451
+ } else if (typeof hashGeneratorOption === "function") {
452
+
453
+ // call the function
454
+ hashValue = hashGeneratorOption(self.text(), self);
455
+
456
+ } else {
457
+
458
+ // compact - the default
459
+ hashValue = self.text().replace(/\s/g, "");
460
+
461
+ }
462
+
463
+ // add the index if we need to
464
+ if (arr.length) { hashValue += ""+index; }
465
+
466
+ // return the value
467
+ return hashValue;
468
+
469
+ },
470
+
471
+ // _appendElements
472
+ // ---------------
473
+ // Helps create the table of contents list by appending subheader elements
474
+
475
+ _appendSubheaders: function(self, ul) {
476
+
477
+ // The current element index
478
+ var index = $(this).index(self.options.selectors),
479
+
480
+ // Finds the previous header DOM element
481
+ previousHeader = $(self.options.selectors).eq(index - 1),
482
+
483
+ currentTagName = +$(this).prop("tagName").charAt(1),
484
+
485
+ previousTagName = +previousHeader.prop("tagName").charAt(1),
486
+
487
+ lastSubheader;
488
+
489
+ // If the current header DOM element is smaller than the previous header DOM element or the first subheader
490
+ if(currentTagName < previousTagName) {
491
+
492
+ // Selects the last unordered list HTML found within the HTML element calling the plugin
493
+ self.element.find(subheaderClass + "[data-tag=" + currentTagName + "]").last().append(self._nestElements($(this), index));
494
+
495
+ }
496
+
497
+ // If the current header DOM element is the same type of header(eg. h4) as the previous header DOM element
498
+ else if(currentTagName === previousTagName) {
499
+
500
+ ul.find(itemClass).last().after(self._nestElements($(this), index));
501
+
502
+ }
503
+
504
+ else {
505
+
506
+ // Selects the last unordered list HTML found within the HTML element calling the plugin
507
+ ul.find(itemClass).last().
508
+
509
+ // Appends an unorderedList HTML element to the dynamic `unorderedList` variable and sets a common class name
510
+ after($("<ul/>", {
511
+
512
+ "class": subheaderClassName,
513
+
514
+ "data-tag": currentTagName
515
+
516
+ })).next(subheaderClass).
517
+
518
+ // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
519
+ append(self._nestElements($(this), index));
520
+ }
521
+
522
+ },
523
+
524
+ // _setEventHandlers
525
+ // ----------------
526
+ // Adds jQuery event handlers to the newly generated table of contents
527
+ _setEventHandlers: function() {
528
+
529
+ // _Local variables_
530
+
531
+ // Stores the plugin context in the self variable
532
+ var self = this,
533
+
534
+ // Instantiates a new variable that will be used to hold a specific element's context
535
+ $self,
536
+
537
+ // Instantiates a new variable that will be used to determine the smoothScroll animation time duration
538
+ duration;
539
+
540
+ // Event delegation that looks for any clicks on list item elements inside of the HTML element calling the plugin
541
+ this.element.on("click.tocify", "li", function(event) {
542
+
543
+ if(self.options.history) {
544
+
545
+ window.location.hash = $(this).attr("data-unique");
546
+
547
+ }
548
+
549
+ // Removes highlighting from all of the list item's
550
+ self.element.find("." + self.focusClass).removeClass(self.focusClass);
551
+
552
+ // Highlights the current list item that was clicked
553
+ $(this).addClass(self.focusClass);
554
+
555
+ // If the showAndHide option is true
556
+ if(self.options.showAndHide) {
557
+
558
+ var elem = $('li[data-unique="' + $(this).attr("data-unique") + '"]');
559
+
560
+ self._triggerShow(elem);
561
+
562
+ }
563
+
564
+ self._scrollTo($(this));
565
+
566
+ });
567
+
568
+ // Mouseenter and Mouseleave event handlers for the list item's within the HTML element calling the plugin
569
+ this.element.find("li").on({
570
+
571
+ // Mouseenter event handler
572
+ "mouseenter.tocify": function() {
573
+
574
+ // Adds a hover CSS class to the current list item
575
+ $(this).addClass(self.hoverClass);
576
+
577
+ // Makes sure the cursor is set to the pointer icon
578
+ $(this).css("cursor", "pointer");
579
+
580
+ },
581
+
582
+ // Mouseleave event handler
583
+ "mouseleave.tocify": function() {
584
+
585
+ if(self.options.theme !== "bootstrap") {
586
+
587
+ // Removes the hover CSS class from the current list item
588
+ $(this).removeClass(self.hoverClass);
589
+
590
+ }
591
+
592
+ }
593
+ });
594
+
595
+ // Reset height cache on scroll
596
+
597
+ $(window).on('resize', function() {
598
+ self.calculateHeights();
599
+ });
600
+
601
+ // Window scroll event handler
602
+ $(window).on("scroll.tocify", function() {
603
+
604
+ // Once all animations on the page are complete, this callback function will be called
605
+ $("html, body").promise().done(function() {
606
+
607
+ // Local variables
608
+
609
+ // Stores how far the user has scrolled
610
+ var winScrollTop = $(window).scrollTop(),
611
+
612
+ // Stores the height of the window
613
+ winHeight = $(window).height(),
614
+
615
+ // Stores the height of the document
616
+ docHeight = $(document).height(),
617
+
618
+ scrollHeight = $("body")[0].scrollHeight,
619
+
620
+ // Instantiates a variable that will be used to hold a selected HTML element
621
+ elem,
622
+
623
+ lastElem,
624
+
625
+ lastElemOffset,
626
+
627
+ currentElem;
628
+
629
+ if(self.options.extendPage) {
630
+
631
+ // If the user has scrolled to the bottom of the page and the last toc item is not focused
632
+ if((self.webkit && winScrollTop >= scrollHeight - winHeight - self.options.extendPageOffset) || (!self.webkit && winHeight + winScrollTop > docHeight - self.options.extendPageOffset)) {
633
+
634
+ if(!$(extendPageClass).length) {
635
+
636
+ lastElem = $('div[data-unique="' + $(itemClass).last().attr("data-unique") + '"]');
637
+
638
+ if(!lastElem.length) return;
639
+
640
+ // Gets the top offset of the page header that is linked to the last toc item
641
+ lastElemOffset = lastElem.offset().top;
642
+
643
+ // Appends a div to the bottom of the page and sets the height to the difference of the window scrollTop and the last element's position top offset
644
+ $(self.options.context).append($("<div />", {
645
+
646
+ "class": extendPageClassName,
647
+
648
+ "height": Math.abs(lastElemOffset - winScrollTop) + "px",
649
+
650
+ "data-unique": extendPageClassName
651
+
652
+ }));
653
+
654
+ if(self.extendPageScroll) {
655
+
656
+ currentElem = self.element.find('li.active');
657
+
658
+ self._scrollTo($("div[data-unique=" + currentElem.attr("data-unique") + "]"));
659
+
660
+ }
661
+
662
+ }
663
+
664
+ }
665
+
666
+ }
667
+
668
+ // The zero timeout ensures the following code is run after the scroll events
669
+ setTimeout(function() {
670
+
671
+ // _Local variables_
672
+
673
+ // Stores the distance to the closest anchor
674
+ var // Stores the index of the closest anchor
675
+ closestAnchorIdx = null,
676
+ anchorText;
677
+
678
+ // if never calculated before, calculate and cache the heights
679
+ if (self.cachedHeights.length == 0) {
680
+ self.calculateHeights();
681
+ }
682
+
683
+ var scrollTop = $(window).scrollTop();
684
+
685
+ // Determines the index of the closest anchor
686
+ self.cachedAnchors.each(function(idx) {
687
+ if (self.cachedHeights[idx] - scrollTop < 0) {
688
+ closestAnchorIdx = idx;
689
+ } else {
690
+ return false;
691
+ }
692
+ });
693
+
694
+ anchorText = $(self.cachedAnchors[closestAnchorIdx]).attr("data-unique");
695
+
696
+ // Stores the list item HTML element that corresponds to the currently traversed anchor tag
697
+ elem = $('li[data-unique="' + anchorText + '"]');
698
+
699
+ // If the `highlightOnScroll` option is true and a next element is found
700
+ if(self.options.highlightOnScroll && elem.length && !elem.hasClass(self.focusClass)) {
701
+
702
+ // Removes highlighting from all of the list item's
703
+ self.element.find("." + self.focusClass).removeClass(self.focusClass);
704
+
705
+ // Highlights the corresponding list item
706
+ elem.addClass(self.focusClass);
707
+
708
+ // Scroll to highlighted element's header
709
+ var tocifyWrapper = self.tocifyWrapper;
710
+ var scrollToElem = $(elem).closest('.tocify-header');
711
+
712
+ var elementOffset = scrollToElem.offset().top,
713
+ wrapperOffset = tocifyWrapper.offset().top;
714
+ var offset = elementOffset - wrapperOffset;
715
+
716
+ if (offset >= $(window).height()) {
717
+ var scrollPosition = offset + tocifyWrapper.scrollTop();
718
+ tocifyWrapper.scrollTop(scrollPosition);
719
+ } else if (offset < 0) {
720
+ tocifyWrapper.scrollTop(0);
721
+ }
722
+ }
723
+
724
+ if(self.options.scrollHistory) {
725
+
726
+ // IF STATEMENT ADDED BY ROBERT
727
+
728
+ if(window.location.hash !== "#" + anchorText && anchorText !== undefined) {
729
+
730
+ if(history.replaceState) {
731
+ history.replaceState({}, "", "#" + anchorText);
732
+ // provide a fallback
733
+ } else {
734
+ scrollV = document.body.scrollTop;
735
+ scrollH = document.body.scrollLeft;
736
+ location.hash = "#" + anchorText;
737
+ document.body.scrollTop = scrollV;
738
+ document.body.scrollLeft = scrollH;
739
+ }
740
+
741
+ }
742
+
743
+ }
744
+
745
+ // If the `showAndHideOnScroll` option is true
746
+ if(self.options.showAndHideOnScroll && self.options.showAndHide) {
747
+
748
+ self._triggerShow(elem, true);
749
+
750
+ }
751
+
752
+ }, 0);
753
+
754
+ });
755
+
756
+ });
757
+
758
+ },
759
+
760
+ // calculateHeights
761
+ // ----
762
+ // ADDED BY ROBERT
763
+ calculateHeights: function() {
764
+ var self = this;
765
+ self.cachedHeights = [];
766
+ self.cachedAnchors = [];
767
+ var anchors = $(self.options.context).find("div[data-unique]");
768
+ anchors.each(function(idx) {
769
+ var distance = (($(this).next().length ? $(this).next() : $(this)).offset().top - self.options.highlightOffset);
770
+ self.cachedHeights[idx] = distance;
771
+ });
772
+ self.cachedAnchors = anchors;
773
+ },
774
+
775
+ // Show
776
+ // ----
777
+ // Opens the current sub-header
778
+ show: function(elem, scroll) {
779
+
780
+ // Stores the plugin context in the `self` variable
781
+ var self = this,
782
+ element = elem;
783
+
784
+ // If the sub-header is not already visible
785
+ if (!elem.is(":visible")) {
786
+
787
+ // If the current element does not have any nested subheaders, is not a header, and its parent is not visible
788
+ if(!elem.find(subheaderClass).length && !elem.parent().is(headerClass) && !elem.parent().is(":visible")) {
789
+
790
+ // Sets the current element to all of the subheaders within the current header
791
+ elem = elem.parents(subheaderClass).add(elem);
792
+
793
+ }
794
+
795
+ // If the current element does not have any nested subheaders and is not a header
796
+ else if(!elem.children(subheaderClass).length && !elem.parent().is(headerClass)) {
797
+
798
+ // Sets the current element to the closest subheader
799
+ elem = elem.closest(subheaderClass);
800
+
801
+ }
802
+
803
+ //Determines what jQuery effect to use
804
+ switch (self.options.showEffect) {
805
+
806
+ //Uses `no effect`
807
+ case "none":
808
+
809
+ elem.show();
810
+
811
+ break;
812
+
813
+ //Uses the jQuery `show` special effect
814
+ case "show":
815
+
816
+ elem.show(self.options.showEffectSpeed);
817
+
818
+ break;
819
+
820
+ //Uses the jQuery `slideDown` special effect
821
+ case "slideDown":
822
+
823
+ elem.slideDown(self.options.showEffectSpeed);
824
+
825
+ break;
826
+
827
+ //Uses the jQuery `fadeIn` special effect
828
+ case "fadeIn":
829
+
830
+ elem.fadeIn(self.options.showEffectSpeed);
831
+
832
+ break;
833
+
834
+ //If none of the above options were passed, then a `jQueryUI show effect` is expected
835
+ default:
836
+
837
+ elem.show();
838
+
839
+ break;
840
+
841
+ }
842
+
843
+ }
844
+
845
+ // If the current subheader parent element is a header
846
+ if(elem.parent().is(headerClass)) {
847
+
848
+ // Hides all non-active sub-headers
849
+ self.hide($(subheaderClass).not(elem));
850
+
851
+ }
852
+
853
+ // If the current subheader parent element is not a header
854
+ else {
855
+
856
+ // Hides all non-active sub-headers
857
+ self.hide($(subheaderClass).not(elem.closest(headerClass).find(subheaderClass).not(elem.siblings())));
858
+
859
+ }
860
+
861
+ // Maintains chainablity
862
+ return self;
863
+
864
+ },
865
+
866
+ // Hide
867
+ // ----
868
+ // Closes the current sub-header
869
+ hide: function(elem) {
870
+
871
+ // Stores the plugin context in the `self` variable
872
+ var self = this;
873
+
874
+ //Determines what jQuery effect to use
875
+ switch (self.options.hideEffect) {
876
+
877
+ // Uses `no effect`
878
+ case "none":
879
+
880
+ elem.hide();
881
+
882
+ break;
883
+
884
+ // Uses the jQuery `hide` special effect
885
+ case "hide":
886
+
887
+ elem.hide(self.options.hideEffectSpeed);
888
+
889
+ break;
890
+
891
+ // Uses the jQuery `slideUp` special effect
892
+ case "slideUp":
893
+
894
+ elem.slideUp(self.options.hideEffectSpeed);
895
+
896
+ break;
897
+
898
+ // Uses the jQuery `fadeOut` special effect
899
+ case "fadeOut":
900
+
901
+ elem.fadeOut(self.options.hideEffectSpeed);
902
+
903
+ break;
904
+
905
+ // If none of the above options were passed, then a `jqueryUI hide effect` is expected
906
+ default:
907
+
908
+ elem.hide();
909
+
910
+ break;
911
+
912
+ }
913
+
914
+ // Maintains chainablity
915
+ return self;
916
+ },
917
+
918
+ // _triggerShow
919
+ // ------------
920
+ // Determines what elements get shown on scroll and click
921
+ _triggerShow: function(elem, scroll) {
922
+
923
+ var self = this;
924
+
925
+ // If the current element's parent is a header element or the next element is a nested subheader element
926
+ if(elem.parent().is(headerClass) || elem.next().is(subheaderClass)) {
927
+
928
+ // Shows the next sub-header element
929
+ self.show(elem.next(subheaderClass), scroll);
930
+
931
+ }
932
+
933
+ // If the current element's parent is a subheader element
934
+ else if(elem.parent().is(subheaderClass)) {
935
+
936
+ // Shows the parent sub-header element
937
+ self.show(elem.parent(), scroll);
938
+
939
+ }
940
+
941
+ // Maintains chainability
942
+ return self;
943
+
944
+ },
945
+
946
+ // _addCSSClasses
947
+ // --------------
948
+ // Adds CSS classes to the newly generated table of contents HTML
949
+ _addCSSClasses: function() {
950
+
951
+ // If the user wants a jqueryUI theme
952
+ if(this.options.theme === "jqueryui") {
953
+
954
+ this.focusClass = "ui-state-default";
955
+
956
+ this.hoverClass = "ui-state-hover";
957
+
958
+ //Adds the default styling to the dropdown list
959
+ this.element.addClass("ui-widget").find(".toc-title").addClass("ui-widget-header").end().find("li").addClass("ui-widget-content");
960
+
961
+ }
962
+
963
+ // If the user wants a twitterBootstrap theme
964
+ else if(this.options.theme === "bootstrap") {
965
+
966
+ this.element.find(headerClass + "," + subheaderClass).addClass("nav nav-list");
967
+
968
+ this.focusClass = "active";
969
+
970
+ }
971
+
972
+ // If a user does not want a prebuilt theme
973
+ else {
974
+
975
+ // Adds more neutral classes (instead of jqueryui)
976
+
977
+ this.focusClass = tocFocusClassName;
978
+
979
+ this.hoverClass = tocHoverClassName;
980
+
981
+ }
982
+
983
+ //Maintains chainability
984
+ return this;
985
+
986
+ },
987
+
988
+ // setOption
989
+ // ---------
990
+ // Sets a single Tocify option after the plugin is invoked
991
+ setOption: function() {
992
+
993
+ // Calls the jQueryUI Widget Factory setOption method
994
+ $.Widget.prototype._setOption.apply(this, arguments);
995
+
996
+ },
997
+
998
+ // setOptions
999
+ // ----------
1000
+ // Sets a single or multiple Tocify options after the plugin is invoked
1001
+ setOptions: function() {
1002
+
1003
+ // Calls the jQueryUI Widget Factory setOptions method
1004
+ $.Widget.prototype._setOptions.apply(this, arguments);
1005
+
1006
+ },
1007
+
1008
+ // _scrollTo
1009
+ // ---------
1010
+ // Scrolls to a specific element
1011
+ _scrollTo: function(elem) {
1012
+
1013
+ var self = this,
1014
+ duration = self.options.smoothScroll || 0,
1015
+ scrollTo = self.options.scrollTo;
1016
+
1017
+ // Once all animations on the page are complete, this callback function will be called
1018
+ $("html, body").promise().done(function() {
1019
+
1020
+ // Animates the html and body element scrolltops
1021
+ $("html, body").animate({
1022
+
1023
+ // Sets the jQuery `scrollTop` to the top offset of the HTML div tag that matches the current list item's `data-unique` tag
1024
+ "scrollTop": $('div[data-unique="' + elem.attr("data-unique") + '"]').next().offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + "px"
1025
+
1026
+ }, {
1027
+
1028
+ // Sets the smoothScroll animation time duration to the smoothScrollSpeed option
1029
+ "duration": duration
1030
+
1031
+ });
1032
+
1033
+ });
1034
+
1035
+ // Maintains chainability
1036
+ return self;
1037
+
1038
+ }
1039
+
1040
+ });
1041
+
1042
+ })); //end of plugin