spree_api_v2 0.2.0

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 (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.rb +4 -0
  101. data/lib/spree_api_v2/engine.rb +21 -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,4 @@
1
+ //= require ./lib/_energize
2
+ //= require ./app/_lang
3
+ //= require ./app/_search
4
+ //= require ./app/_toc
@@ -0,0 +1,3 @@
1
+ //= require ./lib/_energize
2
+ //= require ./app/_lang
3
+ //= require ./app/_toc
@@ -0,0 +1,162 @@
1
+ /*
2
+ Copyright 2008-2013 Concur Technologies, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+ not use this file except in compliance with the License. You may obtain
6
+ a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ License for the specific language governing permissions and limitations
14
+ under the License.
15
+ */
16
+ (function (global) {
17
+ 'use strict';
18
+
19
+ var languages = [];
20
+
21
+ global.setupLanguages = setupLanguages;
22
+ global.activateLanguage = activateLanguage;
23
+
24
+ function activateLanguage(language) {
25
+ if (!language) return;
26
+ if (language === "") return;
27
+
28
+ $(".lang-selector a").removeClass('active');
29
+ $(".lang-selector a[data-language-name='" + language + "']").addClass('active');
30
+ for (var i=0; i < languages.length; i++) {
31
+ $(".highlight." + languages[i]).hide();
32
+ }
33
+ $(".highlight." + language).show();
34
+
35
+ global.toc.calculateHeights();
36
+
37
+ // scroll to the new location of the position
38
+ if ($(window.location.hash).get(0)) {
39
+ $(window.location.hash).get(0).scrollIntoView(true);
40
+ }
41
+ }
42
+
43
+ // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string
44
+ // MIT licensed
45
+ // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license
46
+ function parseURL(str) {
47
+ if (typeof str !== 'string') {
48
+ return {};
49
+ }
50
+
51
+ str = str.trim().replace(/^(\?|#|&)/, '');
52
+
53
+ if (!str) {
54
+ return {};
55
+ }
56
+
57
+ return str.split('&').reduce(function (ret, param) {
58
+ var parts = param.replace(/\+/g, ' ').split('=');
59
+ var key = parts[0];
60
+ var val = parts[1];
61
+
62
+ key = decodeURIComponent(key);
63
+ // missing `=` should be `null`:
64
+ // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
65
+ val = val === undefined ? null : decodeURIComponent(val);
66
+
67
+ if (!ret.hasOwnProperty(key)) {
68
+ ret[key] = val;
69
+ } else if (Array.isArray(ret[key])) {
70
+ ret[key].push(val);
71
+ } else {
72
+ ret[key] = [ret[key], val];
73
+ }
74
+
75
+ return ret;
76
+ }, {});
77
+ };
78
+
79
+ function stringifyURL(obj) {
80
+ return obj ? Object.keys(obj).sort().map(function (key) {
81
+ var val = obj[key];
82
+
83
+ if (Array.isArray(val)) {
84
+ return val.sort().map(function (val2) {
85
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
86
+ }).join('&');
87
+ }
88
+
89
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val);
90
+ }).join('&') : '';
91
+ };
92
+
93
+ // gets the language set in the query string
94
+ function getLanguageFromQueryString() {
95
+ if (location.search.length >= 1) {
96
+ var language = parseURL(location.search).language
97
+ if (language) {
98
+ return language;
99
+ } else if (jQuery.inArray(location.search.substr(1), languages) != -1) {
100
+ return location.search.substr(1);
101
+ }
102
+ }
103
+
104
+ return false;
105
+ }
106
+
107
+ // returns a new query string with the new language in it
108
+ function generateNewQueryString(language) {
109
+ var url = parseURL(location.search);
110
+ if (url.language) {
111
+ url.language = language;
112
+ return stringifyURL(url);
113
+ }
114
+ return language;
115
+ }
116
+
117
+ // if a button is clicked, add the state to the history
118
+ function pushURL(language) {
119
+ if (!history) { return; }
120
+ var hash = window.location.hash;
121
+ if (hash) {
122
+ hash = hash.replace(/^#+/, '');
123
+ }
124
+ history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash);
125
+
126
+ // save language as next default
127
+ localStorage.setItem("language", language);
128
+ }
129
+
130
+ function setupLanguages(l) {
131
+ var defaultLanguage = localStorage.getItem("language");
132
+
133
+ languages = l;
134
+
135
+ var presetLanguage = getLanguageFromQueryString();
136
+ if (presetLanguage) {
137
+ // the language is in the URL, so use that language!
138
+ activateLanguage(presetLanguage);
139
+
140
+ localStorage.setItem("language", presetLanguage);
141
+ } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) {
142
+ // the language was the last selected one saved in localstorage, so use that language!
143
+ activateLanguage(defaultLanguage);
144
+ } else {
145
+ // no language selected, so use the default
146
+ activateLanguage(languages[0]);
147
+ }
148
+ }
149
+
150
+ // if we click on a language tab, activate that language
151
+ $(function() {
152
+ $(".lang-selector a").on("click", function() {
153
+ var language = $(this).data("language-name");
154
+ pushURL(language);
155
+ activateLanguage(language);
156
+ return false;
157
+ });
158
+ window.onpopstate = function() {
159
+ activateLanguage(getLanguageFromQueryString());
160
+ };
161
+ });
162
+ })(window);
@@ -0,0 +1,74 @@
1
+ //= require ../lib/_lunr
2
+ //= require ../lib/_jquery.highlight
3
+ (function () {
4
+ 'use strict';
5
+
6
+ var content, searchResults;
7
+ var highlightOpts = { element: 'span', className: 'search-highlight' };
8
+
9
+ var index = new lunr.Index();
10
+
11
+ index.ref('id');
12
+ index.field('title', { boost: 10 });
13
+ index.field('body');
14
+ index.pipeline.add(lunr.trimmer, lunr.stopWordFilter);
15
+
16
+ $(populate);
17
+ $(bind);
18
+
19
+ function populate() {
20
+ $('h1, h2').each(function() {
21
+ var title = $(this);
22
+ var body = title.nextUntil('h1, h2');
23
+ index.add({
24
+ id: title.prop('id'),
25
+ title: title.text(),
26
+ body: body.text()
27
+ });
28
+ });
29
+ }
30
+
31
+ function bind() {
32
+ content = $('.content');
33
+ searchResults = $('.search-results');
34
+
35
+ $('#input-search').on('keyup', search);
36
+ }
37
+
38
+ function search(event) {
39
+ unhighlight();
40
+ searchResults.addClass('visible');
41
+
42
+ // ESC clears the field
43
+ if (event.keyCode === 27) this.value = '';
44
+
45
+ if (this.value) {
46
+ var results = index.search(this.value).filter(function(r) {
47
+ return r.score > 0.0001;
48
+ });
49
+
50
+ if (results.length) {
51
+ searchResults.empty();
52
+ $.each(results, function (index, result) {
53
+ var elem = document.getElementById(result.ref);
54
+ searchResults.append("<li><a href='#" + result.ref + "'>" + $(elem).text() + "</a></li>");
55
+ });
56
+ highlight.call(this);
57
+ } else {
58
+ searchResults.html('<li></li>');
59
+ $('.search-results li').text('No Results Found for "' + this.value + '"');
60
+ }
61
+ } else {
62
+ unhighlight();
63
+ searchResults.removeClass('visible');
64
+ }
65
+ }
66
+
67
+ function highlight() {
68
+ if (this.value) content.highlight(this.value, highlightOpts);
69
+ }
70
+
71
+ function unhighlight() {
72
+ content.unhighlight(highlightOpts);
73
+ }
74
+ })();
@@ -0,0 +1,55 @@
1
+ //= require ../lib/_jquery_ui
2
+ //= require ../lib/_jquery.tocify
3
+ //= require ../lib/_imagesloaded.min
4
+ (function (global) {
5
+ 'use strict';
6
+
7
+ var closeToc = function() {
8
+ $(".tocify-wrapper").removeClass('open');
9
+ $("#nav-button").removeClass('open');
10
+ };
11
+
12
+ var makeToc = function() {
13
+ global.toc = $("#toc").tocify({
14
+ selectors: 'h1, h2',
15
+ extendPage: false,
16
+ theme: 'none',
17
+ smoothScroll: false,
18
+ showEffectSpeed: 0,
19
+ hideEffectSpeed: 180,
20
+ ignoreSelector: '.toc-ignore',
21
+ highlightOffset: 60,
22
+ scrollTo: -1,
23
+ scrollHistory: true,
24
+ hashGenerator: function (text, element) {
25
+ return element.prop('id');
26
+ }
27
+ }).data('toc-tocify');
28
+
29
+ $("#nav-button").click(function() {
30
+ $(".tocify-wrapper").toggleClass('open');
31
+ $("#nav-button").toggleClass('open');
32
+ return false;
33
+ });
34
+
35
+ $(".page-wrapper").click(closeToc);
36
+ $(".tocify-item").click(closeToc);
37
+ };
38
+
39
+ // Hack to make already open sections to start opened,
40
+ // instead of displaying an ugly animation
41
+ function animate() {
42
+ setTimeout(function() {
43
+ toc.setOption('showEffectSpeed', 180);
44
+ }, 50);
45
+ }
46
+
47
+ $(function() {
48
+ makeToc();
49
+ animate();
50
+ $('.content').imagesLoaded( function() {
51
+ global.toc.calculateHeights();
52
+ });
53
+ });
54
+ })(window);
55
+
@@ -0,0 +1,169 @@
1
+ /**
2
+ * energize.js v0.1.0
3
+ *
4
+ * Speeds up click events on mobile devices.
5
+ * https://github.com/davidcalhoun/energize.js
6
+ */
7
+
8
+ (function() { // Sandbox
9
+ /**
10
+ * Don't add to non-touch devices, which don't need to be sped up
11
+ */
12
+ if(!('ontouchstart' in window)) return;
13
+
14
+ var lastClick = {},
15
+ isThresholdReached, touchstart, touchmove, touchend,
16
+ click, closest;
17
+
18
+ /**
19
+ * isThresholdReached
20
+ *
21
+ * Compare touchstart with touchend xy coordinates,
22
+ * and only fire simulated click event if the coordinates
23
+ * are nearby. (don't want clicking to be confused with a swipe)
24
+ */
25
+ isThresholdReached = function(startXY, xy) {
26
+ return Math.abs(startXY[0] - xy[0]) > 5 || Math.abs(startXY[1] - xy[1]) > 5;
27
+ };
28
+
29
+ /**
30
+ * touchstart
31
+ *
32
+ * Save xy coordinates when the user starts touching the screen
33
+ */
34
+ touchstart = function(e) {
35
+ this.startXY = [e.touches[0].clientX, e.touches[0].clientY];
36
+ this.threshold = false;
37
+ };
38
+
39
+ /**
40
+ * touchmove
41
+ *
42
+ * Check if the user is scrolling past the threshold.
43
+ * Have to check here because touchend will not always fire
44
+ * on some tested devices (Kindle Fire?)
45
+ */
46
+ touchmove = function(e) {
47
+ // NOOP if the threshold has already been reached
48
+ if(this.threshold) return false;
49
+
50
+ this.threshold = isThresholdReached(this.startXY, [e.touches[0].clientX, e.touches[0].clientY]);
51
+ };
52
+
53
+ /**
54
+ * touchend
55
+ *
56
+ * If the user didn't scroll past the threshold between
57
+ * touchstart and touchend, fire a simulated click.
58
+ *
59
+ * (This will fire before a native click)
60
+ */
61
+ touchend = function(e) {
62
+ // Don't fire a click if the user scrolled past the threshold
63
+ if(this.threshold || isThresholdReached(this.startXY, [e.changedTouches[0].clientX, e.changedTouches[0].clientY])) {
64
+ return;
65
+ }
66
+
67
+ /**
68
+ * Create and fire a click event on the target element
69
+ * https://developer.mozilla.org/en/DOM/event.initMouseEvent
70
+ */
71
+ var touch = e.changedTouches[0],
72
+ evt = document.createEvent('MouseEvents');
73
+ evt.initMouseEvent('click', true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
74
+ evt.simulated = true; // distinguish from a normal (nonsimulated) click
75
+ e.target.dispatchEvent(evt);
76
+ };
77
+
78
+ /**
79
+ * click
80
+ *
81
+ * Because we've already fired a click event in touchend,
82
+ * we need to listed for all native click events here
83
+ * and suppress them as necessary.
84
+ */
85
+ click = function(e) {
86
+ /**
87
+ * Prevent ghost clicks by only allowing clicks we created
88
+ * in the click event we fired (look for e.simulated)
89
+ */
90
+ var time = Date.now(),
91
+ timeDiff = time - lastClick.time,
92
+ x = e.clientX,
93
+ y = e.clientY,
94
+ xyDiff = [Math.abs(lastClick.x - x), Math.abs(lastClick.y - y)],
95
+ target = closest(e.target, 'A') || e.target, // needed for standalone apps
96
+ nodeName = target.nodeName,
97
+ isLink = nodeName === 'A',
98
+ standAlone = window.navigator.standalone && isLink && e.target.getAttribute("href");
99
+
100
+ lastClick.time = time;
101
+ lastClick.x = x;
102
+ lastClick.y = y;
103
+
104
+ /**
105
+ * Unfortunately Android sometimes fires click events without touch events (seen on Kindle Fire),
106
+ * so we have to add more logic to determine the time of the last click. Not perfect...
107
+ *
108
+ * Older, simpler check: if((!e.simulated) || standAlone)
109
+ */
110
+ if((!e.simulated && (timeDiff < 500 || (timeDiff < 1500 && xyDiff[0] < 50 && xyDiff[1] < 50))) || standAlone) {
111
+ e.preventDefault();
112
+ e.stopPropagation();
113
+ if(!standAlone) return false;
114
+ }
115
+
116
+ /**
117
+ * Special logic for standalone web apps
118
+ * See http://stackoverflow.com/questions/2898740/iphone-safari-web-app-opens-links-in-new-window
119
+ */
120
+ if(standAlone) {
121
+ window.location = target.getAttribute("href");
122
+ }
123
+
124
+ /**
125
+ * Add an energize-focus class to the targeted link (mimics :focus behavior)
126
+ * TODO: test and/or remove? Does this work?
127
+ */
128
+ if(!target || !target.classList) return;
129
+ target.classList.add("energize-focus");
130
+ window.setTimeout(function(){
131
+ target.classList.remove("energize-focus");
132
+ }, 150);
133
+ };
134
+
135
+ /**
136
+ * closest
137
+ * @param {HTMLElement} node current node to start searching from.
138
+ * @param {string} tagName the (uppercase) name of the tag you're looking for.
139
+ *
140
+ * Find the closest ancestor tag of a given node.
141
+ *
142
+ * Starts at node and goes up the DOM tree looking for a
143
+ * matching nodeName, continuing until hitting document.body
144
+ */
145
+ closest = function(node, tagName){
146
+ var curNode = node;
147
+
148
+ while(curNode !== document.body) { // go up the dom until we find the tag we're after
149
+ if(!curNode || curNode.nodeName === tagName) { return curNode; } // found
150
+ curNode = curNode.parentNode; // not found, so keep going up
151
+ }
152
+
153
+ return null; // not found
154
+ };
155
+
156
+ /**
157
+ * Add all delegated event listeners
158
+ *
159
+ * All the events we care about bubble up to document,
160
+ * so we can take advantage of event delegation.
161
+ *
162
+ * Note: no need to wait for DOMContentLoaded here
163
+ */
164
+ document.addEventListener('touchstart', touchstart, false);
165
+ document.addEventListener('touchmove', touchmove, false);
166
+ document.addEventListener('touchend', touchend, false);
167
+ document.addEventListener('click', click, true); // TODO: why does this use capture?
168
+
169
+ })();