jumbo-jekyll-theme 3.0.42 → 3.0.43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +21 -0
  3. data/README.md +26 -0
  4. data/_config.yml +190 -0
  5. data/_data/authors.yml +7 -0
  6. data/_data/footer.yml +57 -0
  7. data/_data/nav.yml +75 -0
  8. data/_data/news.yaml +230 -0
  9. data/_data/settings.yml +93 -0
  10. data/_data/sidebar-nav.yml +23 -0
  11. data/_data/sticky-tab-bar.yml +29 -0
  12. data/_includes/author-pagination.html +36 -0
  13. data/_includes/authors-posts.html +49 -0
  14. data/_includes/breadcrumb.html +95 -0
  15. data/_includes/carousel-header.html +15 -0
  16. data/_includes/css.html +11 -0
  17. data/_includes/custom.html +1 -0
  18. data/_includes/display-blog-posts.html +67 -0
  19. data/_includes/disqus-comments.html +8 -0
  20. data/_includes/footer.html +68 -0
  21. data/_includes/github-edit.html +60 -0
  22. data/_includes/google-analytics-script.html +9 -0
  23. data/_includes/gtm-noscript.html +5 -0
  24. data/_includes/gtm-script.html +7 -0
  25. data/_includes/head.html +44 -0
  26. data/_includes/hero-banner.html +21 -0
  27. data/_includes/image.html +6 -0
  28. data/_includes/javascript.html +9 -0
  29. data/_includes/jumbotron.html +71 -0
  30. data/_includes/linaro-404.html +10 -0
  31. data/_includes/linaro-svg.html +1 -0
  32. data/_includes/media.html +11 -0
  33. data/_includes/members.html +63 -0
  34. data/_includes/nav.html +132 -0
  35. data/_includes/newsletter-script.html +30 -0
  36. data/_includes/owl-carousel-homepage.html +103 -0
  37. data/_includes/pagination-authors.html +36 -0
  38. data/_includes/pagination-news.html +36 -0
  39. data/_includes/pagination.html +36 -0
  40. data/_includes/post-sidebar.html +90 -0
  41. data/_includes/post-tags.html +9 -0
  42. data/_includes/read_time.html +2 -0
  43. data/_includes/responsive-image.html +6 -0
  44. data/_includes/schema.html +50 -0
  45. data/_includes/sidebar.html +55 -0
  46. data/_includes/sticky-tab-bar.html +61 -0
  47. data/_includes/thumb.html +2 -0
  48. data/_includes/thumbnail_image.html +10 -0
  49. data/_includes/universal-nav.html +28 -0
  50. data/_includes/youtube.html +7 -0
  51. data/_layouts/author-layout.html +13 -0
  52. data/_layouts/author.html +7 -0
  53. data/_layouts/container-breadcrumb-tabs.html +10 -0
  54. data/_layouts/container-breadcrumb.html +19 -0
  55. data/_layouts/container.html +8 -0
  56. data/_layouts/default.html +27 -0
  57. data/_layouts/error.html +23 -0
  58. data/_layouts/jumbotron-container.html +19 -0
  59. data/_layouts/jumbotron.html +12 -0
  60. data/_layouts/post-index.html +18 -0
  61. data/_layouts/post-old.html +70 -0
  62. data/_layouts/post.html +145 -0
  63. data/_layouts/redirect.html +11 -0
  64. data/_sass/_bootstrap-compass.scss +9 -0
  65. data/_sass/_bootstrap-mincer.scss +19 -0
  66. data/_sass/_bootstrap-sprockets.scss +9 -0
  67. data/_sass/_bootstrap.scss +56 -0
  68. data/_sass/app/blog.scss +59 -0
  69. data/_sass/app/contact.scss +3 -0
  70. data/_sass/app/custom.scss +1 -0
  71. data/_sass/app/overrides.scss +37 -0
  72. data/_sass/app/search.scss +1 -0
  73. data/_sass/blog.scss +9 -0
  74. data/_sass/bootstrap/_alerts.scss +73 -0
  75. data/_sass/bootstrap/_badges.scss +68 -0
  76. data/_sass/bootstrap/_breadcrumbs.scss +28 -0
  77. data/_sass/bootstrap/_button-groups.scss +244 -0
  78. data/_sass/bootstrap/_buttons.scss +168 -0
  79. data/_sass/bootstrap/_carousel.scss +270 -0
  80. data/_sass/bootstrap/_close.scss +36 -0
  81. data/_sass/bootstrap/_code.scss +69 -0
  82. data/_sass/bootstrap/_component-animations.scss +37 -0
  83. data/_sass/bootstrap/_dropdowns.scss +216 -0
  84. data/_sass/bootstrap/_forms.scss +617 -0
  85. data/_sass/bootstrap/_glyphicons.scss +307 -0
  86. data/_sass/bootstrap/_grid.scss +84 -0
  87. data/_sass/bootstrap/_input-groups.scss +171 -0
  88. data/_sass/bootstrap/_jumbotron.scss +54 -0
  89. data/_sass/bootstrap/_labels.scss +66 -0
  90. data/_sass/bootstrap/_list-group.scss +130 -0
  91. data/_sass/bootstrap/_media.scss +66 -0
  92. data/_sass/bootstrap/_mixins.scss +40 -0
  93. data/_sass/bootstrap/_modals.scss +150 -0
  94. data/_sass/bootstrap/_navbar.scss +662 -0
  95. data/_sass/bootstrap/_navs.scss +242 -0
  96. data/_sass/bootstrap/_normalize.scss +424 -0
  97. data/_sass/bootstrap/_pager.scss +54 -0
  98. data/_sass/bootstrap/_pagination.scss +89 -0
  99. data/_sass/bootstrap/_panels.scss +271 -0
  100. data/_sass/bootstrap/_popovers.scss +131 -0
  101. data/_sass/bootstrap/_print.scss +101 -0
  102. data/_sass/bootstrap/_progress-bars.scss +87 -0
  103. data/_sass/bootstrap/_responsive-embed.scss +35 -0
  104. data/_sass/bootstrap/_responsive-utilities.scss +179 -0
  105. data/_sass/bootstrap/_scaffolding.scss +161 -0
  106. data/_sass/bootstrap/_tables.scss +234 -0
  107. data/_sass/bootstrap/_theme.scss +291 -0
  108. data/_sass/bootstrap/_thumbnails.scss +38 -0
  109. data/_sass/bootstrap/_tooltip.scss +101 -0
  110. data/_sass/bootstrap/_type.scss +298 -0
  111. data/_sass/bootstrap/_utilities.scss +55 -0
  112. data/_sass/bootstrap/_variables.scss +932 -0
  113. data/_sass/bootstrap/_wells.scss +29 -0
  114. data/_sass/bootstrap/mixins/_alerts.scss +14 -0
  115. data/_sass/bootstrap/mixins/_background-variant.scss +12 -0
  116. data/_sass/bootstrap/mixins/_border-radius.scss +18 -0
  117. data/_sass/bootstrap/mixins/_buttons.scss +65 -0
  118. data/_sass/bootstrap/mixins/_center-block.scss +7 -0
  119. data/_sass/bootstrap/mixins/_clearfix.scss +22 -0
  120. data/_sass/bootstrap/mixins/_forms.scss +88 -0
  121. data/_sass/bootstrap/mixins/_gradients.scss +58 -0
  122. data/_sass/bootstrap/mixins/_grid-framework.scss +81 -0
  123. data/_sass/bootstrap/mixins/_grid.scss +122 -0
  124. data/_sass/bootstrap/mixins/_hide-text.scss +21 -0
  125. data/_sass/bootstrap/mixins/_image.scss +33 -0
  126. data/_sass/bootstrap/mixins/_labels.scss +12 -0
  127. data/_sass/bootstrap/mixins/_list-group.scss +32 -0
  128. data/_sass/bootstrap/mixins/_nav-divider.scss +10 -0
  129. data/_sass/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  130. data/_sass/bootstrap/mixins/_opacity.scss +8 -0
  131. data/_sass/bootstrap/mixins/_pagination.scss +24 -0
  132. data/_sass/bootstrap/mixins/_panels.scss +24 -0
  133. data/_sass/bootstrap/mixins/_progress-bar.scss +10 -0
  134. data/_sass/bootstrap/mixins/_reset-filter.scss +8 -0
  135. data/_sass/bootstrap/mixins/_reset-text.scss +18 -0
  136. data/_sass/bootstrap/mixins/_resize.scss +6 -0
  137. data/_sass/bootstrap/mixins/_responsive-visibility.scss +21 -0
  138. data/_sass/bootstrap/mixins/_size.scss +10 -0
  139. data/_sass/bootstrap/mixins/_tab-focus.scss +9 -0
  140. data/_sass/bootstrap/mixins/_table-row.scss +28 -0
  141. data/_sass/bootstrap/mixins/_text-emphasis.scss +12 -0
  142. data/_sass/bootstrap/mixins/_text-overflow.scss +8 -0
  143. data/_sass/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  144. data/_sass/core.scss +18 -0
  145. data/_sass/core/animations.scss +125 -0
  146. data/_sass/core/blog.scss +438 -0
  147. data/_sass/core/breadcrumb.scss +98 -0
  148. data/_sass/core/carousel-header.scss +91 -0
  149. data/_sass/core/carousel-styles.scss +4 -0
  150. data/_sass/core/carousel.scss +312 -0
  151. data/_sass/core/cookieconsent.scss +39 -0
  152. data/_sass/core/critical.scss +0 -0
  153. data/_sass/core/custom.scss +3 -0
  154. data/_sass/core/error.scss +186 -0
  155. data/_sass/core/fa.scss +2336 -0
  156. data/_sass/core/featherlight.scss +158 -0
  157. data/_sass/core/flipclock.scss +434 -0
  158. data/_sass/core/fly.scss +10 -0
  159. data/_sass/core/font-awesome.min.scss +4 -0
  160. data/_sass/core/fonts.scss +3 -0
  161. data/_sass/core/footer.scss +146 -0
  162. data/_sass/core/forms.scss +3 -0
  163. data/_sass/core/homepage.scss +19 -0
  164. data/_sass/core/jumbotron.scss +116 -0
  165. data/_sass/core/lightbox.scss +212 -0
  166. data/_sass/core/nav.scss +958 -0
  167. data/_sass/core/owl.carousel.min.scss +6 -0
  168. data/_sass/core/owl.theme.default.min.scss +6 -0
  169. data/_sass/core/social-media-icons.scss +67 -0
  170. data/_sass/core/syntax.scss +65 -0
  171. data/_sass/core/tables.scss +145 -0
  172. data/_sass/core/theme.scss +714 -0
  173. data/_sass/core/universal-nav.scss +161 -0
  174. data/_sass/core/youtube-lazy.scss +51 -0
  175. data/_sass/core/youtube.scss +65 -0
  176. data/_sass/home.scss +2 -0
  177. data/assets/css/main-blog.scss +19 -0
  178. data/assets/css/main-error.scss +14 -0
  179. data/assets/css/main-search.scss +13 -0
  180. data/assets/css/main.scss +12 -0
  181. data/assets/fonts/fontawesome-webfont.eot +0 -0
  182. data/assets/fonts/fontawesome-webfont.svg +2671 -0
  183. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  184. data/assets/fonts/fontawesome-webfont.woff +0 -0
  185. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  186. data/assets/fonts/fontello.eot +0 -0
  187. data/assets/fonts/fontello.svg +44 -0
  188. data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  189. data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  190. data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  191. data/assets/fonts/lato-regular/LICENSE.txt +93 -0
  192. data/assets/fonts/lato-regular/Lato-regular.eot +0 -0
  193. data/assets/fonts/lato-regular/Lato-regular.svg +435 -0
  194. data/assets/fonts/lato-regular/Lato-regular.ttf +0 -0
  195. data/assets/fonts/lato-regular/Lato-regular.woff +0 -0
  196. data/assets/fonts/lato-regular/Lato-regular.woff2 +0 -0
  197. data/assets/images/Linaro-Logo.svg +1 -0
  198. data/assets/images/Linaro-Logo_light.png +0 -0
  199. data/assets/images/Linaro-Logo_standard.svg +1 -0
  200. data/assets/images/Linaro-Sprinkle.png +0 -0
  201. data/assets/images/avatar-placeholder.png +0 -0
  202. data/assets/images/breadcrumb-image.jpg +0 -0
  203. data/assets/images/close.png +0 -0
  204. data/assets/images/content/background-image1.jpg +0 -0
  205. data/assets/images/content/background-image2.png +0 -0
  206. data/assets/images/content/background-image3.jpg +0 -0
  207. data/assets/images/favicon.ico +0 -0
  208. data/assets/images/favicon.png +0 -0
  209. data/assets/images/loading.gif +0 -0
  210. data/assets/images/next.png +0 -0
  211. data/assets/images/owl.video.play.png +0 -0
  212. data/assets/images/placeholder.png +0 -0
  213. data/assets/images/prev.png +0 -0
  214. data/assets/images/social-media-image.png +0 -0
  215. data/assets/js/app/blog-comments.js +50 -0
  216. data/assets/js/app/custom.js +0 -0
  217. data/assets/js/app/facebook.js +8 -0
  218. data/assets/js/app/fly.js +45 -0
  219. data/assets/js/app/home.js +46 -0
  220. data/assets/js/app/main.js +163 -0
  221. data/assets/js/app/scroll-to-anchors.js +10 -0
  222. data/assets/js/app/search.js +29 -0
  223. data/assets/js/app/sticky-tab-bar.js +71 -0
  224. data/assets/js/app/tables.js +35 -0
  225. data/assets/js/app/youtube-lazy.js +25 -0
  226. data/assets/js/package-blog.js +13 -0
  227. data/assets/js/package-extended.js +14 -0
  228. data/assets/js/package-home.js +12 -0
  229. data/assets/js/package-main.js +13 -0
  230. data/assets/js/package-search.js +8 -0
  231. data/assets/js/vendor/bootstrap.js +2377 -0
  232. data/assets/js/vendor/cognito.js +11 -0
  233. data/assets/js/vendor/cookieconsent.js +1495 -0
  234. data/assets/js/vendor/disqus-loader.js +87 -0
  235. data/assets/js/vendor/featherlight.js +641 -0
  236. data/assets/js/vendor/jquery.js +10364 -0
  237. data/assets/js/vendor/jquery.rss.js +333 -0
  238. data/assets/js/vendor/jquery.validate.js +1601 -0
  239. data/assets/js/vendor/lazysizes.js +698 -0
  240. data/assets/js/vendor/loadCSS.js +35 -0
  241. data/assets/js/vendor/ls.unveilhooks.js +145 -0
  242. data/assets/js/vendor/owl.carousel.js +3475 -0
  243. data/assets/js/vendor/picturefill.js +1471 -0
  244. data/assets/js/vendor/shuffle.js +2004 -0
  245. data/robots.txt +9 -0
  246. metadata +246 -2
@@ -0,0 +1,333 @@
1
+ (function ($) {
2
+ 'use strict';
3
+
4
+ var RSS = function (target, url, options, callback) {
5
+ this.target = target;
6
+
7
+ this.url = url;
8
+ this.html = [];
9
+ this.effectQueue = [];
10
+
11
+ this.options = $.extend({
12
+ ssl: true,
13
+ host: 'www.feedrapp.info',
14
+ limit: null,
15
+ key: null,
16
+ layoutTemplate: '<ul>{entries}</ul>',
17
+ entryTemplate: '<li><a href="{url}">[{author}@{date}] {title}</a><br/>{shortBodyPlain}</li>',
18
+ tokens: {},
19
+ outputMode: 'json',
20
+ dateFormat: 'dddd MMM Do',
21
+ dateLocale: 'en',
22
+ effect: 'show',
23
+ offsetStart: false,
24
+ offsetEnd: false,
25
+ error: function () {
26
+ console.log('jQuery RSS: url doesn\'t link to RSS-Feed');
27
+ },
28
+ onData: function () {},
29
+ success: function () {}
30
+ }, options || {});
31
+
32
+ this.callback = callback || this.options.success;
33
+ };
34
+
35
+ RSS.htmlTags = [
36
+ 'doctype', 'html', 'head', 'title', 'base', 'link', 'meta', 'style', 'script', 'noscript',
37
+ 'body', 'article', 'nav', 'aside', 'section', 'header', 'footer', 'h1-h6', 'hgroup', 'address',
38
+ 'p', 'hr', 'pre', 'blockquote', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'figure', 'figcaption',
39
+ 'div', 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'col', 'colgroup',
40
+ 'form', 'fieldset', 'legend', 'label', 'input', 'button', 'select', 'datalist', 'optgroup',
41
+ 'option', 'textarea', 'keygen', 'output', 'progress', 'meter', 'details', 'summary', 'command',
42
+ 'menu', 'del', 'ins', 'img', 'iframe', 'embed', 'object', 'param', 'video', 'audio', 'source',
43
+ 'canvas', 'track', 'map', 'area', 'a', 'em', 'strong', 'i', 'b', 'u', 's', 'small', 'abbr', 'q',
44
+ 'cite', 'dfn', 'sub', 'sup', 'time', 'code', 'kbd', 'samp', 'var', 'mark', 'bdi', 'bdo', 'ruby',
45
+ 'rt', 'rp', 'span', 'br', 'wbr'
46
+ ];
47
+
48
+ RSS.prototype.load = function (callback) {
49
+ var apiProtocol = 'https';
50
+ var apiHost = apiProtocol + '://' + this.options.host;
51
+ var apiUrl = apiHost + '?callback=?&q=' + encodeURIComponent(this.url);
52
+
53
+ // set limit to offsetEnd if offset has been set
54
+ if (this.options.offsetStart && this.options.offsetEnd) {
55
+ this.options.limit = this.options.offsetEnd;
56
+ }
57
+
58
+ if (this.options.limit !== null) {
59
+ apiUrl += '&num=' + this.options.limit;
60
+ }
61
+
62
+ if (this.options.key !== null) {
63
+ apiUrl += '&key=' + this.options.key;
64
+ }
65
+
66
+ $.getJSON(apiUrl, callback);
67
+ };
68
+
69
+ RSS.prototype.render = function () {
70
+ var self = this;
71
+
72
+ this.load(function (data) {
73
+ try {
74
+ self.feed = data.responseData.feed;
75
+ self.entries = data.responseData.feed.entries;
76
+ } catch (e) {
77
+ self.entries = [];
78
+ self.feed = null;
79
+ return self.options.error.call(self);
80
+ }
81
+
82
+ var html = self.generateHTMLForEntries();
83
+
84
+ self.target.append(html.layout);
85
+
86
+ if (html.entries.length !== 0) {
87
+ if ($.isFunction(self.options.onData)) {
88
+ self.options.onData.call(self);
89
+ }
90
+
91
+ var container = $(html.layout).is('entries') ? html.layout : $('entries', html.layout);
92
+
93
+ self.appendEntriesAndApplyEffects(container, html.entries);
94
+ }
95
+
96
+ if (self.effectQueue.length > 0) {
97
+ self.executeEffectQueue(self.callback);
98
+ } else if ($.isFunction(self.callback)) {
99
+ self.callback.call(self);
100
+ }
101
+ });
102
+ };
103
+
104
+ RSS.prototype.appendEntriesAndApplyEffects = function (target, entries) {
105
+ var self = this;
106
+
107
+ $.each(entries, function (idx, entry) {
108
+ var $html = self.wrapContent(entry);
109
+
110
+ if (self.options.effect === 'show') {
111
+ target.before($html);
112
+ } else {
113
+ $html.css({ display: 'none' });
114
+ target.before($html);
115
+ self.applyEffect($html, self.options.effect);
116
+ }
117
+ });
118
+
119
+ target.remove();
120
+ };
121
+
122
+ RSS.prototype.generateHTMLForEntries = function () {
123
+ var self = this;
124
+ var result = { entries: [], layout: null };
125
+
126
+ $(this.entries).each(function () {
127
+ var entry = this;
128
+ var offsetStart = self.options.offsetStart;
129
+ var offsetEnd = self.options.offsetEnd;
130
+ var evaluatedString;
131
+
132
+ // offset required
133
+ if (offsetStart && offsetEnd) {
134
+ if (index >= offsetStart && index <= offsetEnd) {
135
+ if (self.isRelevant(entry, result.entries)) {
136
+ evaluatedString = self.evaluateStringForEntry(
137
+ self.options.entryTemplate, entry
138
+ );
139
+
140
+ result.entries.push(evaluatedString);
141
+ }
142
+ }
143
+ } else {
144
+ // no offset
145
+ if (self.isRelevant(entry, result.entries)) {
146
+ evaluatedString = self.evaluateStringForEntry(
147
+ self.options.entryTemplate, entry
148
+ );
149
+
150
+ result.entries.push(evaluatedString);
151
+ }
152
+ }
153
+ });
154
+
155
+ if (!!this.options.entryTemplate) {
156
+ // we have an entryTemplate
157
+ result.layout = this.wrapContent(
158
+ this.options.layoutTemplate.replace('{entries}', '<entries></entries>')
159
+ );
160
+ } else {
161
+ // no entryTemplate available
162
+ result.layout = this.wrapContent('<div><entries></entries></div>');
163
+ }
164
+
165
+ return result;
166
+ };
167
+
168
+ RSS.prototype.wrapContent = function (content) {
169
+ if (($.trim(content).indexOf('<') !== 0)) {
170
+ // the content has no html => create a surrounding div
171
+ return $('<div>' + content + '</div>');
172
+ } else {
173
+ // the content has html => don't touch it
174
+ return $(content);
175
+ }
176
+ };
177
+
178
+ RSS.prototype.applyEffect = function ($element, effect, callback) {
179
+ var self = this;
180
+
181
+ switch (effect) {
182
+ case 'slide':
183
+ $element.slideDown('slow', callback);
184
+ break;
185
+ case 'slideFast':
186
+ $element.slideDown(callback);
187
+ break;
188
+ case 'slideSynced':
189
+ self.effectQueue.push({ element: $element, effect: 'slide' });
190
+ break;
191
+ case 'slideFastSynced':
192
+ self.effectQueue.push({ element: $element, effect: 'slideFast' });
193
+ break;
194
+ }
195
+ };
196
+
197
+ RSS.prototype.executeEffectQueue = function (callback) {
198
+ var self = this;
199
+
200
+ this.effectQueue.reverse();
201
+
202
+ var executeEffectQueueItem = function () {
203
+ var item = self.effectQueue.pop();
204
+
205
+ if (item) {
206
+ self.applyEffect(item.element, item.effect, executeEffectQueueItem);
207
+ } else if (callback) {
208
+ callback();
209
+ }
210
+ };
211
+
212
+ executeEffectQueueItem();
213
+ };
214
+
215
+ RSS.prototype.evaluateStringForEntry = function (string, entry) {
216
+ var result = string;
217
+ var self = this;
218
+
219
+ $(string.match(/(\{.*?\})/g)).each(function () {
220
+ var token = this.toString();
221
+
222
+ result = result.replace(token, self.getValueForToken(token, entry));
223
+ });
224
+
225
+ return result;
226
+ };
227
+
228
+ RSS.prototype.isRelevant = function (entry, entries) {
229
+ var tokenMap = this.getTokenMap(entry);
230
+
231
+ if (this.options.filter) {
232
+ if (this.options.filterLimit && (this.options.filterLimit === entries.length)) {
233
+ return false;
234
+ } else {
235
+ return this.options.filter(entry, tokenMap);
236
+ }
237
+ } else {
238
+ return true;
239
+ }
240
+ };
241
+
242
+ RSS.prototype.getFormattedDate = function (dateString) {
243
+ // If a custom formatting function is provided, use that.
244
+ if (this.options.dateFormatFunction) {
245
+ return this.options.dateFormatFunction(dateString);
246
+ } else if (typeof moment !== 'undefined') {
247
+ // If moment.js is available and dateFormatFunction is not overriding it,
248
+ // use it to format the date.
249
+ var date = moment(new Date(dateString));
250
+
251
+ if (date.locale) {
252
+ date = date.locale(this.options.dateLocale);
253
+ } else {
254
+ date = date.lang(this.options.dateLocale);
255
+ }
256
+
257
+ return date.format(this.options.dateFormat);
258
+ } else {
259
+ // If all else fails, just use the date as-is.
260
+ return dateString;
261
+ }
262
+ };
263
+
264
+ RSS.prototype.getTokenMap = function (entry) {
265
+ if (!this.feedTokens) {
266
+ var feed = JSON.parse(JSON.stringify(this.feed));
267
+
268
+ delete feed.entries;
269
+ this.feedTokens = feed;
270
+ }
271
+
272
+ return $.extend({
273
+ feed: this.feedTokens,
274
+ url: entry.link,
275
+ author: entry.author,
276
+ date: this.getFormattedDate(entry.publishedDate),
277
+ title: entry.title,
278
+ body: entry.content,
279
+ shortBody: entry.contentSnippet,
280
+
281
+ bodyPlain: (function (entry) {
282
+ var result = entry.content
283
+ .replace(/<script[\\r\\\s\S]*<\/script>/mgi, '')
284
+ .replace(/<\/?[^>]+>/gi, '');
285
+
286
+ for (var i = 0; i < RSS.htmlTags.length; i++) {
287
+ result = result.replace(new RegExp('<' + RSS.htmlTags[i], 'gi'), '');
288
+ }
289
+
290
+ return result;
291
+ })(entry),
292
+
293
+ shortBodyPlain: entry.contentSnippet.replace(/<\/?[^>]+>/gi, ''),
294
+ index: $.inArray(entry, this.entries),
295
+ totalEntries: this.entries.length,
296
+
297
+ teaserImage: (function (entry) {
298
+ try {
299
+ return entry.content.match(/(<img.*?>)/gi)[0];
300
+ }
301
+ catch (e) {
302
+ return '';
303
+ }
304
+ })(entry),
305
+
306
+ teaserImageUrl: (function (entry) {
307
+ try {
308
+ return entry.content.match(/(<img.*?>)/gi)[0].match(/src="(.*?)"/)[1];
309
+ }
310
+ catch (e) {
311
+ return '';
312
+ }
313
+ })(entry)
314
+ }, this.options.tokens);
315
+ };
316
+
317
+ RSS.prototype.getValueForToken = function (_token, entry) {
318
+ var tokenMap = this.getTokenMap(entry);
319
+ var token = _token.replace(/[\{\}]/g, '');
320
+ var result = tokenMap[token];
321
+
322
+ if (typeof result !== 'undefined') {
323
+ return ((typeof result === 'function') ? result(entry, tokenMap) : result);
324
+ } else {
325
+ throw new Error('Unknown token: ' + _token + ', url:' + this.url);
326
+ }
327
+ };
328
+
329
+ $.fn.rss = function (url, options, callback) {
330
+ new RSS(this, url, options, callback).render();
331
+ return this; // Implement chaining
332
+ };
333
+ })(jQuery);
@@ -0,0 +1,1601 @@
1
+ /*!
2
+ * jQuery Validation Plugin v1.17.0
3
+ *
4
+ * https://jqueryvalidation.org/
5
+ *
6
+ * Copyright (c) 2017 Jörn Zaefferer
7
+ * Released under the MIT license
8
+ */
9
+ (function( factory ) {
10
+ if ( typeof define === "function" && define.amd ) {
11
+ define( ["jquery"], factory );
12
+ } else if (typeof module === "object" && module.exports) {
13
+ module.exports = factory( require( "jquery" ) );
14
+ } else {
15
+ factory( jQuery );
16
+ }
17
+ }(function( $ ) {
18
+
19
+ $.extend( $.fn, {
20
+
21
+ // https://jqueryvalidation.org/validate/
22
+ validate: function( options ) {
23
+
24
+ // If nothing is selected, return nothing; can't chain anyway
25
+ if ( !this.length ) {
26
+ if ( options && options.debug && window.console ) {
27
+ console.warn( "Nothing selected, can't validate, returning nothing." );
28
+ }
29
+ return;
30
+ }
31
+
32
+ // Check if a validator for this form was already created
33
+ var validator = $.data( this[ 0 ], "validator" );
34
+ if ( validator ) {
35
+ return validator;
36
+ }
37
+
38
+ // Add novalidate tag if HTML5.
39
+ this.attr( "novalidate", "novalidate" );
40
+
41
+ validator = new $.validator( options, this[ 0 ] );
42
+ $.data( this[ 0 ], "validator", validator );
43
+
44
+ if ( validator.settings.onsubmit ) {
45
+
46
+ this.on( "click.validate", ":submit", function( event ) {
47
+
48
+ // Track the used submit button to properly handle scripted
49
+ // submits later.
50
+ validator.submitButton = event.currentTarget;
51
+
52
+ // Allow suppressing validation by adding a cancel class to the submit button
53
+ if ( $( this ).hasClass( "cancel" ) ) {
54
+ validator.cancelSubmit = true;
55
+ }
56
+
57
+ // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
58
+ if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
59
+ validator.cancelSubmit = true;
60
+ }
61
+ } );
62
+
63
+ // Validate the form on submit
64
+ this.on( "submit.validate", function( event ) {
65
+ if ( validator.settings.debug ) {
66
+
67
+ // Prevent form submit to be able to see console output
68
+ event.preventDefault();
69
+ }
70
+ function handle() {
71
+ var hidden, result;
72
+
73
+ // Insert a hidden input as a replacement for the missing submit button
74
+ // The hidden input is inserted in two cases:
75
+ // - A user defined a `submitHandler`
76
+ // - There was a pending request due to `remote` method and `stopRequest()`
77
+ // was called to submit the form in case it's valid
78
+ if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
79
+ hidden = $( "<input type='hidden'/>" )
80
+ .attr( "name", validator.submitButton.name )
81
+ .val( $( validator.submitButton ).val() )
82
+ .appendTo( validator.currentForm );
83
+ }
84
+
85
+ if ( validator.settings.submitHandler ) {
86
+ result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
87
+ if ( hidden ) {
88
+
89
+ // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
90
+ hidden.remove();
91
+ }
92
+ if ( result !== undefined ) {
93
+ return result;
94
+ }
95
+ return false;
96
+ }
97
+ return true;
98
+ }
99
+
100
+ // Prevent submit for invalid forms or custom submit handlers
101
+ if ( validator.cancelSubmit ) {
102
+ validator.cancelSubmit = false;
103
+ return handle();
104
+ }
105
+ if ( validator.form() ) {
106
+ if ( validator.pendingRequest ) {
107
+ validator.formSubmitted = true;
108
+ return false;
109
+ }
110
+ return handle();
111
+ } else {
112
+ validator.focusInvalid();
113
+ return false;
114
+ }
115
+ } );
116
+ }
117
+
118
+ return validator;
119
+ },
120
+
121
+ // https://jqueryvalidation.org/valid/
122
+ valid: function() {
123
+ var valid, validator, errorList;
124
+
125
+ if ( $( this[ 0 ] ).is( "form" ) ) {
126
+ valid = this.validate().form();
127
+ } else {
128
+ errorList = [];
129
+ valid = true;
130
+ validator = $( this[ 0 ].form ).validate();
131
+ this.each( function() {
132
+ valid = validator.element( this ) && valid;
133
+ if ( !valid ) {
134
+ errorList = errorList.concat( validator.errorList );
135
+ }
136
+ } );
137
+ validator.errorList = errorList;
138
+ }
139
+ return valid;
140
+ },
141
+
142
+ // https://jqueryvalidation.org/rules/
143
+ rules: function( command, argument ) {
144
+ var element = this[ 0 ],
145
+ settings, staticRules, existingRules, data, param, filtered;
146
+
147
+ // If nothing is selected, return empty object; can't chain anyway
148
+ if ( element == null ) {
149
+ return;
150
+ }
151
+
152
+ if ( !element.form && element.hasAttribute( "contenteditable" ) ) {
153
+ element.form = this.closest( "form" )[ 0 ];
154
+ element.name = this.attr( "name" );
155
+ }
156
+
157
+ if ( element.form == null ) {
158
+ return;
159
+ }
160
+
161
+ if ( command ) {
162
+ settings = $.data( element.form, "validator" ).settings;
163
+ staticRules = settings.rules;
164
+ existingRules = $.validator.staticRules( element );
165
+ switch ( command ) {
166
+ case "add":
167
+ $.extend( existingRules, $.validator.normalizeRule( argument ) );
168
+
169
+ // Remove messages from rules, but allow them to be set separately
170
+ delete existingRules.messages;
171
+ staticRules[ element.name ] = existingRules;
172
+ if ( argument.messages ) {
173
+ settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
174
+ }
175
+ break;
176
+ case "remove":
177
+ if ( !argument ) {
178
+ delete staticRules[ element.name ];
179
+ return existingRules;
180
+ }
181
+ filtered = {};
182
+ $.each( argument.split( /\s/ ), function( index, method ) {
183
+ filtered[ method ] = existingRules[ method ];
184
+ delete existingRules[ method ];
185
+ } );
186
+ return filtered;
187
+ }
188
+ }
189
+
190
+ data = $.validator.normalizeRules(
191
+ $.extend(
192
+ {},
193
+ $.validator.classRules( element ),
194
+ $.validator.attributeRules( element ),
195
+ $.validator.dataRules( element ),
196
+ $.validator.staticRules( element )
197
+ ), element );
198
+
199
+ // Make sure required is at front
200
+ if ( data.required ) {
201
+ param = data.required;
202
+ delete data.required;
203
+ data = $.extend( { required: param }, data );
204
+ }
205
+
206
+ // Make sure remote is at back
207
+ if ( data.remote ) {
208
+ param = data.remote;
209
+ delete data.remote;
210
+ data = $.extend( data, { remote: param } );
211
+ }
212
+
213
+ return data;
214
+ }
215
+ } );
216
+
217
+ // Custom selectors
218
+ $.extend( $.expr.pseudos || $.expr[ ":" ], { // '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
219
+
220
+ // https://jqueryvalidation.org/blank-selector/
221
+ blank: function( a ) {
222
+ return !$.trim( "" + $( a ).val() );
223
+ },
224
+
225
+ // https://jqueryvalidation.org/filled-selector/
226
+ filled: function( a ) {
227
+ var val = $( a ).val();
228
+ return val !== null && !!$.trim( "" + val );
229
+ },
230
+
231
+ // https://jqueryvalidation.org/unchecked-selector/
232
+ unchecked: function( a ) {
233
+ return !$( a ).prop( "checked" );
234
+ }
235
+ } );
236
+
237
+ // Constructor for validator
238
+ $.validator = function( options, form ) {
239
+ this.settings = $.extend( true, {}, $.validator.defaults, options );
240
+ this.currentForm = form;
241
+ this.init();
242
+ };
243
+
244
+ // https://jqueryvalidation.org/jQuery.validator.format/
245
+ $.validator.format = function( source, params ) {
246
+ if ( arguments.length === 1 ) {
247
+ return function() {
248
+ var args = $.makeArray( arguments );
249
+ args.unshift( source );
250
+ return $.validator.format.apply( this, args );
251
+ };
252
+ }
253
+ if ( params === undefined ) {
254
+ return source;
255
+ }
256
+ if ( arguments.length > 2 && params.constructor !== Array ) {
257
+ params = $.makeArray( arguments ).slice( 1 );
258
+ }
259
+ if ( params.constructor !== Array ) {
260
+ params = [ params ];
261
+ }
262
+ $.each( params, function( i, n ) {
263
+ source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
264
+ return n;
265
+ } );
266
+ } );
267
+ return source;
268
+ };
269
+
270
+ $.extend( $.validator, {
271
+
272
+ defaults: {
273
+ messages: {},
274
+ groups: {},
275
+ rules: {},
276
+ errorClass: "error",
277
+ pendingClass: "pending",
278
+ validClass: "valid",
279
+ errorElement: "label",
280
+ focusCleanup: false,
281
+ focusInvalid: true,
282
+ errorContainer: $( [] ),
283
+ errorLabelContainer: $( [] ),
284
+ onsubmit: true,
285
+ ignore: ":hidden",
286
+ ignoreTitle: false,
287
+ onfocusin: function( element ) {
288
+ this.lastActive = element;
289
+
290
+ // Hide error label and remove error class on focus if enabled
291
+ if ( this.settings.focusCleanup ) {
292
+ if ( this.settings.unhighlight ) {
293
+ this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
294
+ }
295
+ this.hideThese( this.errorsFor( element ) );
296
+ }
297
+ },
298
+ onfocusout: function( element ) {
299
+ if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
300
+ this.element( element );
301
+ }
302
+ },
303
+ onkeyup: function( element, event ) {
304
+
305
+ // Avoid revalidate the field when pressing one of the following keys
306
+ // Shift => 16
307
+ // Ctrl => 17
308
+ // Alt => 18
309
+ // Caps lock => 20
310
+ // End => 35
311
+ // Home => 36
312
+ // Left arrow => 37
313
+ // Up arrow => 38
314
+ // Right arrow => 39
315
+ // Down arrow => 40
316
+ // Insert => 45
317
+ // Num lock => 144
318
+ // AltGr key => 225
319
+ var excludedKeys = [
320
+ 16, 17, 18, 20, 35, 36, 37,
321
+ 38, 39, 40, 45, 144, 225
322
+ ];
323
+
324
+ if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
325
+ return;
326
+ } else if ( element.name in this.submitted || element.name in this.invalid ) {
327
+ this.element( element );
328
+ }
329
+ },
330
+ onclick: function( element ) {
331
+
332
+ // Click on selects, radiobuttons and checkboxes
333
+ if ( element.name in this.submitted ) {
334
+ this.element( element );
335
+
336
+ // Or option elements, check parent select in that case
337
+ } else if ( element.parentNode.name in this.submitted ) {
338
+ this.element( element.parentNode );
339
+ }
340
+ },
341
+ highlight: function( element, errorClass, validClass ) {
342
+ if ( element.type === "radio" ) {
343
+ this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
344
+ } else {
345
+ $( element ).addClass( errorClass ).removeClass( validClass );
346
+ }
347
+ },
348
+ unhighlight: function( element, errorClass, validClass ) {
349
+ if ( element.type === "radio" ) {
350
+ this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
351
+ } else {
352
+ $( element ).removeClass( errorClass ).addClass( validClass );
353
+ }
354
+ }
355
+ },
356
+
357
+ // https://jqueryvalidation.org/jQuery.validator.setDefaults/
358
+ setDefaults: function( settings ) {
359
+ $.extend( $.validator.defaults, settings );
360
+ },
361
+
362
+ messages: {
363
+ required: "This field is required.",
364
+ remote: "Please fix this field.",
365
+ email: "Please enter a valid email address.",
366
+ url: "Please enter a valid URL.",
367
+ date: "Please enter a valid date.",
368
+ dateISO: "Please enter a valid date (ISO).",
369
+ number: "Please enter a valid number.",
370
+ digits: "Please enter only digits.",
371
+ equalTo: "Please enter the same value again.",
372
+ maxlength: $.validator.format( "Please enter no more than {0} characters." ),
373
+ minlength: $.validator.format( "Please enter at least {0} characters." ),
374
+ rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
375
+ range: $.validator.format( "Please enter a value between {0} and {1}." ),
376
+ max: $.validator.format( "Please enter a value less than or equal to {0}." ),
377
+ min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
378
+ step: $.validator.format( "Please enter a multiple of {0}." )
379
+ },
380
+
381
+ autoCreateRanges: false,
382
+
383
+ prototype: {
384
+
385
+ init: function() {
386
+ this.labelContainer = $( this.settings.errorLabelContainer );
387
+ this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
388
+ this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
389
+ this.submitted = {};
390
+ this.valueCache = {};
391
+ this.pendingRequest = 0;
392
+ this.pending = {};
393
+ this.invalid = {};
394
+ this.reset();
395
+
396
+ var groups = ( this.groups = {} ),
397
+ rules;
398
+ $.each( this.settings.groups, function( key, value ) {
399
+ if ( typeof value === "string" ) {
400
+ value = value.split( /\s/ );
401
+ }
402
+ $.each( value, function( index, name ) {
403
+ groups[ name ] = key;
404
+ } );
405
+ } );
406
+ rules = this.settings.rules;
407
+ $.each( rules, function( key, value ) {
408
+ rules[ key ] = $.validator.normalizeRule( value );
409
+ } );
410
+
411
+ function delegate( event ) {
412
+
413
+ // Set form expando on contenteditable
414
+ if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
415
+ this.form = $( this ).closest( "form" )[ 0 ];
416
+ this.name = $( this ).attr( "name" );
417
+ }
418
+
419
+ var validator = $.data( this.form, "validator" ),
420
+ eventType = "on" + event.type.replace( /^validate/, "" ),
421
+ settings = validator.settings;
422
+ if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
423
+ settings[ eventType ].call( validator, this, event );
424
+ }
425
+ }
426
+
427
+ $( this.currentForm )
428
+ .on( "focusin.validate focusout.validate keyup.validate",
429
+ ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
430
+ "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
431
+ "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
432
+ "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )
433
+
434
+ // Support: Chrome, oldIE
435
+ // "select" is provided as event.target when clicking a option
436
+ .on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
437
+
438
+ if ( this.settings.invalidHandler ) {
439
+ $( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
440
+ }
441
+ },
442
+
443
+ // https://jqueryvalidation.org/Validator.form/
444
+ form: function() {
445
+ this.checkForm();
446
+ $.extend( this.submitted, this.errorMap );
447
+ this.invalid = $.extend( {}, this.errorMap );
448
+ if ( !this.valid() ) {
449
+ $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
450
+ }
451
+ this.showErrors();
452
+ return this.valid();
453
+ },
454
+
455
+ checkForm: function() {
456
+ this.prepareForm();
457
+ for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
458
+ this.check( elements[ i ] );
459
+ }
460
+ return this.valid();
461
+ },
462
+
463
+ // https://jqueryvalidation.org/Validator.element/
464
+ element: function( element ) {
465
+ var cleanElement = this.clean( element ),
466
+ checkElement = this.validationTargetFor( cleanElement ),
467
+ v = this,
468
+ result = true,
469
+ rs, group;
470
+
471
+ if ( checkElement === undefined ) {
472
+ delete this.invalid[ cleanElement.name ];
473
+ } else {
474
+ this.prepareElement( checkElement );
475
+ this.currentElements = $( checkElement );
476
+
477
+ // If this element is grouped, then validate all group elements already
478
+ // containing a value
479
+ group = this.groups[ checkElement.name ];
480
+ if ( group ) {
481
+ $.each( this.groups, function( name, testgroup ) {
482
+ if ( testgroup === group && name !== checkElement.name ) {
483
+ cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
484
+ if ( cleanElement && cleanElement.name in v.invalid ) {
485
+ v.currentElements.push( cleanElement );
486
+ result = v.check( cleanElement ) && result;
487
+ }
488
+ }
489
+ } );
490
+ }
491
+
492
+ rs = this.check( checkElement ) !== false;
493
+ result = result && rs;
494
+ if ( rs ) {
495
+ this.invalid[ checkElement.name ] = false;
496
+ } else {
497
+ this.invalid[ checkElement.name ] = true;
498
+ }
499
+
500
+ if ( !this.numberOfInvalids() ) {
501
+
502
+ // Hide error containers on last error
503
+ this.toHide = this.toHide.add( this.containers );
504
+ }
505
+ this.showErrors();
506
+
507
+ // Add aria-invalid status for screen readers
508
+ $( element ).attr( "aria-invalid", !rs );
509
+ }
510
+
511
+ return result;
512
+ },
513
+
514
+ // https://jqueryvalidation.org/Validator.showErrors/
515
+ showErrors: function( errors ) {
516
+ if ( errors ) {
517
+ var validator = this;
518
+
519
+ // Add items to error list and map
520
+ $.extend( this.errorMap, errors );
521
+ this.errorList = $.map( this.errorMap, function( message, name ) {
522
+ return {
523
+ message: message,
524
+ element: validator.findByName( name )[ 0 ]
525
+ };
526
+ } );
527
+
528
+ // Remove items from success list
529
+ this.successList = $.grep( this.successList, function( element ) {
530
+ return !( element.name in errors );
531
+ } );
532
+ }
533
+ if ( this.settings.showErrors ) {
534
+ this.settings.showErrors.call( this, this.errorMap, this.errorList );
535
+ } else {
536
+ this.defaultShowErrors();
537
+ }
538
+ },
539
+
540
+ // https://jqueryvalidation.org/Validator.resetForm/
541
+ resetForm: function() {
542
+ if ( $.fn.resetForm ) {
543
+ $( this.currentForm ).resetForm();
544
+ }
545
+ this.invalid = {};
546
+ this.submitted = {};
547
+ this.prepareForm();
548
+ this.hideErrors();
549
+ var elements = this.elements()
550
+ .removeData( "previousValue" )
551
+ .removeAttr( "aria-invalid" );
552
+
553
+ this.resetElements( elements );
554
+ },
555
+
556
+ resetElements: function( elements ) {
557
+ var i;
558
+
559
+ if ( this.settings.unhighlight ) {
560
+ for ( i = 0; elements[ i ]; i++ ) {
561
+ this.settings.unhighlight.call( this, elements[ i ],
562
+ this.settings.errorClass, "" );
563
+ this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
564
+ }
565
+ } else {
566
+ elements
567
+ .removeClass( this.settings.errorClass )
568
+ .removeClass( this.settings.validClass );
569
+ }
570
+ },
571
+
572
+ numberOfInvalids: function() {
573
+ return this.objectLength( this.invalid );
574
+ },
575
+
576
+ objectLength: function( obj ) {
577
+ /* jshint unused: false */
578
+ var count = 0,
579
+ i;
580
+ for ( i in obj ) {
581
+
582
+ // This check allows counting elements with empty error
583
+ // message as invalid elements
584
+ if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
585
+ count++;
586
+ }
587
+ }
588
+ return count;
589
+ },
590
+
591
+ hideErrors: function() {
592
+ this.hideThese( this.toHide );
593
+ },
594
+
595
+ hideThese: function( errors ) {
596
+ errors.not( this.containers ).text( "" );
597
+ this.addWrapper( errors ).hide();
598
+ },
599
+
600
+ valid: function() {
601
+ return this.size() === 0;
602
+ },
603
+
604
+ size: function() {
605
+ return this.errorList.length;
606
+ },
607
+
608
+ focusInvalid: function() {
609
+ if ( this.settings.focusInvalid ) {
610
+ try {
611
+ $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
612
+ .filter( ":visible" )
613
+ .focus()
614
+
615
+ // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
616
+ .trigger( "focusin" );
617
+ } catch ( e ) {
618
+
619
+ // Ignore IE throwing errors when focusing hidden elements
620
+ }
621
+ }
622
+ },
623
+
624
+ findLastActive: function() {
625
+ var lastActive = this.lastActive;
626
+ return lastActive && $.grep( this.errorList, function( n ) {
627
+ return n.element.name === lastActive.name;
628
+ } ).length === 1 && lastActive;
629
+ },
630
+
631
+ elements: function() {
632
+ var validator = this,
633
+ rulesCache = {};
634
+
635
+ // Select all valid inputs inside the form (no submit or reset buttons)
636
+ return $( this.currentForm )
637
+ .find( "input, select, textarea, [contenteditable]" )
638
+ .not( ":submit, :reset, :image, :disabled" )
639
+ .not( this.settings.ignore )
640
+ .filter( function() {
641
+ var name = this.name || $( this ).attr( "name" ); // For contenteditable
642
+ if ( !name && validator.settings.debug && window.console ) {
643
+ console.error( "%o has no name assigned", this );
644
+ }
645
+
646
+ // Set form expando on contenteditable
647
+ if ( this.hasAttribute( "contenteditable" ) ) {
648
+ this.form = $( this ).closest( "form" )[ 0 ];
649
+ this.name = name;
650
+ }
651
+
652
+ // Select only the first element for each name, and only those with rules specified
653
+ if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
654
+ return false;
655
+ }
656
+
657
+ rulesCache[ name ] = true;
658
+ return true;
659
+ } );
660
+ },
661
+
662
+ clean: function( selector ) {
663
+ return $( selector )[ 0 ];
664
+ },
665
+
666
+ errors: function() {
667
+ var errorClass = this.settings.errorClass.split( " " ).join( "." );
668
+ return $( this.settings.errorElement + "." + errorClass, this.errorContext );
669
+ },
670
+
671
+ resetInternals: function() {
672
+ this.successList = [];
673
+ this.errorList = [];
674
+ this.errorMap = {};
675
+ this.toShow = $( [] );
676
+ this.toHide = $( [] );
677
+ },
678
+
679
+ reset: function() {
680
+ this.resetInternals();
681
+ this.currentElements = $( [] );
682
+ },
683
+
684
+ prepareForm: function() {
685
+ this.reset();
686
+ this.toHide = this.errors().add( this.containers );
687
+ },
688
+
689
+ prepareElement: function( element ) {
690
+ this.reset();
691
+ this.toHide = this.errorsFor( element );
692
+ },
693
+
694
+ elementValue: function( element ) {
695
+ var $element = $( element ),
696
+ type = element.type,
697
+ val, idx;
698
+
699
+ if ( type === "radio" || type === "checkbox" ) {
700
+ return this.findByName( element.name ).filter( ":checked" ).val();
701
+ } else if ( type === "number" && typeof element.validity !== "undefined" ) {
702
+ return element.validity.badInput ? "NaN" : $element.val();
703
+ }
704
+
705
+ if ( element.hasAttribute( "contenteditable" ) ) {
706
+ val = $element.text();
707
+ } else {
708
+ val = $element.val();
709
+ }
710
+
711
+ if ( type === "file" ) {
712
+
713
+ // Modern browser (chrome & safari)
714
+ if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
715
+ return val.substr( 12 );
716
+ }
717
+
718
+ // Legacy browsers
719
+ // Unix-based path
720
+ idx = val.lastIndexOf( "/" );
721
+ if ( idx >= 0 ) {
722
+ return val.substr( idx + 1 );
723
+ }
724
+
725
+ // Windows-based path
726
+ idx = val.lastIndexOf( "\\" );
727
+ if ( idx >= 0 ) {
728
+ return val.substr( idx + 1 );
729
+ }
730
+
731
+ // Just the file name
732
+ return val;
733
+ }
734
+
735
+ if ( typeof val === "string" ) {
736
+ return val.replace( /\r/g, "" );
737
+ }
738
+ return val;
739
+ },
740
+
741
+ check: function( element ) {
742
+ element = this.validationTargetFor( this.clean( element ) );
743
+
744
+ var rules = $( element ).rules(),
745
+ rulesCount = $.map( rules, function( n, i ) {
746
+ return i;
747
+ } ).length,
748
+ dependencyMismatch = false,
749
+ val = this.elementValue( element ),
750
+ result, method, rule, normalizer;
751
+
752
+ // Prioritize the local normalizer defined for this element over the global one
753
+ // if the former exists, otherwise user the global one in case it exists.
754
+ if ( typeof rules.normalizer === "function" ) {
755
+ normalizer = rules.normalizer;
756
+ } else if ( typeof this.settings.normalizer === "function" ) {
757
+ normalizer = this.settings.normalizer;
758
+ }
759
+
760
+ // If normalizer is defined, then call it to retreive the changed value instead
761
+ // of using the real one.
762
+ // Note that `this` in the normalizer is `element`.
763
+ if ( normalizer ) {
764
+ val = normalizer.call( element, val );
765
+
766
+ if ( typeof val !== "string" ) {
767
+ throw new TypeError( "The normalizer should return a string value." );
768
+ }
769
+
770
+ // Delete the normalizer from rules to avoid treating it as a pre-defined method.
771
+ delete rules.normalizer;
772
+ }
773
+
774
+ for ( method in rules ) {
775
+ rule = { method: method, parameters: rules[ method ] };
776
+ try {
777
+ result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
778
+
779
+ // If a method indicates that the field is optional and therefore valid,
780
+ // don't mark it as valid when there are no other rules
781
+ if ( result === "dependency-mismatch" && rulesCount === 1 ) {
782
+ dependencyMismatch = true;
783
+ continue;
784
+ }
785
+ dependencyMismatch = false;
786
+
787
+ if ( result === "pending" ) {
788
+ this.toHide = this.toHide.not( this.errorsFor( element ) );
789
+ return;
790
+ }
791
+
792
+ if ( !result ) {
793
+ this.formatAndAdd( element, rule );
794
+ return false;
795
+ }
796
+ } catch ( e ) {
797
+ if ( this.settings.debug && window.console ) {
798
+ console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
799
+ }
800
+ if ( e instanceof TypeError ) {
801
+ e.message += ". Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
802
+ }
803
+
804
+ throw e;
805
+ }
806
+ }
807
+ if ( dependencyMismatch ) {
808
+ return;
809
+ }
810
+ if ( this.objectLength( rules ) ) {
811
+ this.successList.push( element );
812
+ }
813
+ return true;
814
+ },
815
+
816
+ // Return the custom message for the given element and validation method
817
+ // specified in the element's HTML5 data attribute
818
+ // return the generic message if present and no method specific message is present
819
+ customDataMessage: function( element, method ) {
820
+ return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
821
+ method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
822
+ },
823
+
824
+ // Return the custom message for the given element name and validation method
825
+ customMessage: function( name, method ) {
826
+ var m = this.settings.messages[ name ];
827
+ return m && ( m.constructor === String ? m : m[ method ] );
828
+ },
829
+
830
+ // Return the first defined argument, allowing empty strings
831
+ findDefined: function() {
832
+ for ( var i = 0; i < arguments.length; i++ ) {
833
+ if ( arguments[ i ] !== undefined ) {
834
+ return arguments[ i ];
835
+ }
836
+ }
837
+ return undefined;
838
+ },
839
+
840
+ // The second parameter 'rule' used to be a string, and extended to an object literal
841
+ // of the following form:
842
+ // rule = {
843
+ // method: "method name",
844
+ // parameters: "the given method parameters"
845
+ // }
846
+ //
847
+ // The old behavior still supported, kept to maintain backward compatibility with
848
+ // old code, and will be removed in the next major release.
849
+ defaultMessage: function( element, rule ) {
850
+ if ( typeof rule === "string" ) {
851
+ rule = { method: rule };
852
+ }
853
+
854
+ var message = this.findDefined(
855
+ this.customMessage( element.name, rule.method ),
856
+ this.customDataMessage( element, rule.method ),
857
+
858
+ // 'title' is never undefined, so handle empty string as undefined
859
+ !this.settings.ignoreTitle && element.title || undefined,
860
+ $.validator.messages[ rule.method ],
861
+ "<strong>Warning: No message defined for " + element.name + "</strong>"
862
+ ),
863
+ theregex = /\$?\{(\d+)\}/g;
864
+ if ( typeof message === "function" ) {
865
+ message = message.call( this, rule.parameters, element );
866
+ } else if ( theregex.test( message ) ) {
867
+ message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
868
+ }
869
+
870
+ return message;
871
+ },
872
+
873
+ formatAndAdd: function( element, rule ) {
874
+ var message = this.defaultMessage( element, rule );
875
+
876
+ this.errorList.push( {
877
+ message: message,
878
+ element: element,
879
+ method: rule.method
880
+ } );
881
+
882
+ this.errorMap[ element.name ] = message;
883
+ this.submitted[ element.name ] = message;
884
+ },
885
+
886
+ addWrapper: function( toToggle ) {
887
+ if ( this.settings.wrapper ) {
888
+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
889
+ }
890
+ return toToggle;
891
+ },
892
+
893
+ defaultShowErrors: function() {
894
+ var i, elements, error;
895
+ for ( i = 0; this.errorList[ i ]; i++ ) {
896
+ error = this.errorList[ i ];
897
+ if ( this.settings.highlight ) {
898
+ this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
899
+ }
900
+ this.showLabel( error.element, error.message );
901
+ }
902
+ if ( this.errorList.length ) {
903
+ this.toShow = this.toShow.add( this.containers );
904
+ }
905
+ if ( this.settings.success ) {
906
+ for ( i = 0; this.successList[ i ]; i++ ) {
907
+ this.showLabel( this.successList[ i ] );
908
+ }
909
+ }
910
+ if ( this.settings.unhighlight ) {
911
+ for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
912
+ this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
913
+ }
914
+ }
915
+ this.toHide = this.toHide.not( this.toShow );
916
+ this.hideErrors();
917
+ this.addWrapper( this.toShow ).show();
918
+ },
919
+
920
+ validElements: function() {
921
+ return this.currentElements.not( this.invalidElements() );
922
+ },
923
+
924
+ invalidElements: function() {
925
+ return $( this.errorList ).map( function() {
926
+ return this.element;
927
+ } );
928
+ },
929
+
930
+ showLabel: function( element, message ) {
931
+ var place, group, errorID, v,
932
+ error = this.errorsFor( element ),
933
+ elementID = this.idOrName( element ),
934
+ describedBy = $( element ).attr( "aria-describedby" );
935
+
936
+ if ( error.length ) {
937
+
938
+ // Refresh error/success class
939
+ error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
940
+
941
+ // Replace message on existing label
942
+ error.html( message );
943
+ } else {
944
+
945
+ // Create error element
946
+ error = $( "<" + this.settings.errorElement + ">" )
947
+ .attr( "id", elementID + "-error" )
948
+ .addClass( this.settings.errorClass )
949
+ .html( message || "" );
950
+
951
+ // Maintain reference to the element to be placed into the DOM
952
+ place = error;
953
+ if ( this.settings.wrapper ) {
954
+
955
+ // Make sure the element is visible, even in IE
956
+ // actually showing the wrapped element is handled elsewhere
957
+ place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
958
+ }
959
+ if ( this.labelContainer.length ) {
960
+ this.labelContainer.append( place );
961
+ } else if ( this.settings.errorPlacement ) {
962
+ this.settings.errorPlacement.call( this, place, $( element ) );
963
+ } else {
964
+ place.insertAfter( element );
965
+ }
966
+
967
+ // Link error back to the element
968
+ if ( error.is( "label" ) ) {
969
+
970
+ // If the error is a label, then associate using 'for'
971
+ error.attr( "for", elementID );
972
+
973
+ // If the element is not a child of an associated label, then it's necessary
974
+ // to explicitly apply aria-describedby
975
+ } else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
976
+ errorID = error.attr( "id" );
977
+
978
+ // Respect existing non-error aria-describedby
979
+ if ( !describedBy ) {
980
+ describedBy = errorID;
981
+ } else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
982
+
983
+ // Add to end of list if not already present
984
+ describedBy += " " + errorID;
985
+ }
986
+ $( element ).attr( "aria-describedby", describedBy );
987
+
988
+ // If this element is grouped, then assign to all elements in the same group
989
+ group = this.groups[ element.name ];
990
+ if ( group ) {
991
+ v = this;
992
+ $.each( v.groups, function( name, testgroup ) {
993
+ if ( testgroup === group ) {
994
+ $( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
995
+ .attr( "aria-describedby", error.attr( "id" ) );
996
+ }
997
+ } );
998
+ }
999
+ }
1000
+ }
1001
+ if ( !message && this.settings.success ) {
1002
+ error.text( "" );
1003
+ if ( typeof this.settings.success === "string" ) {
1004
+ error.addClass( this.settings.success );
1005
+ } else {
1006
+ this.settings.success( error, element );
1007
+ }
1008
+ }
1009
+ this.toShow = this.toShow.add( error );
1010
+ },
1011
+
1012
+ errorsFor: function( element ) {
1013
+ var name = this.escapeCssMeta( this.idOrName( element ) ),
1014
+ describer = $( element ).attr( "aria-describedby" ),
1015
+ selector = "label[for='" + name + "'], label[for='" + name + "'] *";
1016
+
1017
+ // 'aria-describedby' should directly reference the error element
1018
+ if ( describer ) {
1019
+ selector = selector + ", #" + this.escapeCssMeta( describer )
1020
+ .replace( /\s+/g, ", #" );
1021
+ }
1022
+
1023
+ return this
1024
+ .errors()
1025
+ .filter( selector );
1026
+ },
1027
+
1028
+ // See https://api.jquery.com/category/selectors/, for CSS
1029
+ // meta-characters that should be escaped in order to be used with JQuery
1030
+ // as a literal part of a name/id or any selector.
1031
+ escapeCssMeta: function( string ) {
1032
+ return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
1033
+ },
1034
+
1035
+ idOrName: function( element ) {
1036
+ return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
1037
+ },
1038
+
1039
+ validationTargetFor: function( element ) {
1040
+
1041
+ // If radio/checkbox, validate first element in group instead
1042
+ if ( this.checkable( element ) ) {
1043
+ element = this.findByName( element.name );
1044
+ }
1045
+
1046
+ // Always apply ignore filter
1047
+ return $( element ).not( this.settings.ignore )[ 0 ];
1048
+ },
1049
+
1050
+ checkable: function( element ) {
1051
+ return ( /radio|checkbox/i ).test( element.type );
1052
+ },
1053
+
1054
+ findByName: function( name ) {
1055
+ return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
1056
+ },
1057
+
1058
+ getLength: function( value, element ) {
1059
+ switch ( element.nodeName.toLowerCase() ) {
1060
+ case "select":
1061
+ return $( "option:selected", element ).length;
1062
+ case "input":
1063
+ if ( this.checkable( element ) ) {
1064
+ return this.findByName( element.name ).filter( ":checked" ).length;
1065
+ }
1066
+ }
1067
+ return value.length;
1068
+ },
1069
+
1070
+ depend: function( param, element ) {
1071
+ return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
1072
+ },
1073
+
1074
+ dependTypes: {
1075
+ "boolean": function( param ) {
1076
+ return param;
1077
+ },
1078
+ "string": function( param, element ) {
1079
+ return !!$( param, element.form ).length;
1080
+ },
1081
+ "function": function( param, element ) {
1082
+ return param( element );
1083
+ }
1084
+ },
1085
+
1086
+ optional: function( element ) {
1087
+ var val = this.elementValue( element );
1088
+ return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
1089
+ },
1090
+
1091
+ startRequest: function( element ) {
1092
+ if ( !this.pending[ element.name ] ) {
1093
+ this.pendingRequest++;
1094
+ $( element ).addClass( this.settings.pendingClass );
1095
+ this.pending[ element.name ] = true;
1096
+ }
1097
+ },
1098
+
1099
+ stopRequest: function( element, valid ) {
1100
+ this.pendingRequest--;
1101
+
1102
+ // Sometimes synchronization fails, make sure pendingRequest is never < 0
1103
+ if ( this.pendingRequest < 0 ) {
1104
+ this.pendingRequest = 0;
1105
+ }
1106
+ delete this.pending[ element.name ];
1107
+ $( element ).removeClass( this.settings.pendingClass );
1108
+ if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1109
+ $( this.currentForm ).submit();
1110
+
1111
+ // Remove the hidden input that was used as a replacement for the
1112
+ // missing submit button. The hidden input is added by `handle()`
1113
+ // to ensure that the value of the used submit button is passed on
1114
+ // for scripted submits triggered by this method
1115
+ if ( this.submitButton ) {
1116
+ $( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
1117
+ }
1118
+
1119
+ this.formSubmitted = false;
1120
+ } else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
1121
+ $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
1122
+ this.formSubmitted = false;
1123
+ }
1124
+ },
1125
+
1126
+ previousValue: function( element, method ) {
1127
+ method = typeof method === "string" && method || "remote";
1128
+
1129
+ return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
1130
+ old: null,
1131
+ valid: true,
1132
+ message: this.defaultMessage( element, { method: method } )
1133
+ } );
1134
+ },
1135
+
1136
+ // Cleans up all forms and elements, removes validator-specific events
1137
+ destroy: function() {
1138
+ this.resetForm();
1139
+
1140
+ $( this.currentForm )
1141
+ .off( ".validate" )
1142
+ .removeData( "validator" )
1143
+ .find( ".validate-equalTo-blur" )
1144
+ .off( ".validate-equalTo" )
1145
+ .removeClass( "validate-equalTo-blur" );
1146
+ }
1147
+
1148
+ },
1149
+
1150
+ classRuleSettings: {
1151
+ required: { required: true },
1152
+ email: { email: true },
1153
+ url: { url: true },
1154
+ date: { date: true },
1155
+ dateISO: { dateISO: true },
1156
+ number: { number: true },
1157
+ digits: { digits: true },
1158
+ creditcard: { creditcard: true }
1159
+ },
1160
+
1161
+ addClassRules: function( className, rules ) {
1162
+ if ( className.constructor === String ) {
1163
+ this.classRuleSettings[ className ] = rules;
1164
+ } else {
1165
+ $.extend( this.classRuleSettings, className );
1166
+ }
1167
+ },
1168
+
1169
+ classRules: function( element ) {
1170
+ var rules = {},
1171
+ classes = $( element ).attr( "class" );
1172
+
1173
+ if ( classes ) {
1174
+ $.each( classes.split( " " ), function() {
1175
+ if ( this in $.validator.classRuleSettings ) {
1176
+ $.extend( rules, $.validator.classRuleSettings[ this ] );
1177
+ }
1178
+ } );
1179
+ }
1180
+ return rules;
1181
+ },
1182
+
1183
+ normalizeAttributeRule: function( rules, type, method, value ) {
1184
+
1185
+ // Convert the value to a number for number inputs, and for text for backwards compability
1186
+ // allows type="date" and others to be compared as strings
1187
+ if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1188
+ value = Number( value );
1189
+
1190
+ // Support Opera Mini, which returns NaN for undefined minlength
1191
+ if ( isNaN( value ) ) {
1192
+ value = undefined;
1193
+ }
1194
+ }
1195
+
1196
+ if ( value || value === 0 ) {
1197
+ rules[ method ] = value;
1198
+ } else if ( type === method && type !== "range" ) {
1199
+
1200
+ // Exception: the jquery validate 'range' method
1201
+ // does not test for the html5 'range' type
1202
+ rules[ method ] = true;
1203
+ }
1204
+ },
1205
+
1206
+ attributeRules: function( element ) {
1207
+ var rules = {},
1208
+ $element = $( element ),
1209
+ type = element.getAttribute( "type" ),
1210
+ method, value;
1211
+
1212
+ for ( method in $.validator.methods ) {
1213
+
1214
+ // Support for <input required> in both html5 and older browsers
1215
+ if ( method === "required" ) {
1216
+ value = element.getAttribute( method );
1217
+
1218
+ // Some browsers return an empty string for the required attribute
1219
+ // and non-HTML5 browsers might have required="" markup
1220
+ if ( value === "" ) {
1221
+ value = true;
1222
+ }
1223
+
1224
+ // Force non-HTML5 browsers to return bool
1225
+ value = !!value;
1226
+ } else {
1227
+ value = $element.attr( method );
1228
+ }
1229
+
1230
+ this.normalizeAttributeRule( rules, type, method, value );
1231
+ }
1232
+
1233
+ // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
1234
+ if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
1235
+ delete rules.maxlength;
1236
+ }
1237
+
1238
+ return rules;
1239
+ },
1240
+
1241
+ dataRules: function( element ) {
1242
+ var rules = {},
1243
+ $element = $( element ),
1244
+ type = element.getAttribute( "type" ),
1245
+ method, value;
1246
+
1247
+ for ( method in $.validator.methods ) {
1248
+ value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
1249
+ this.normalizeAttributeRule( rules, type, method, value );
1250
+ }
1251
+ return rules;
1252
+ },
1253
+
1254
+ staticRules: function( element ) {
1255
+ var rules = {},
1256
+ validator = $.data( element.form, "validator" );
1257
+
1258
+ if ( validator.settings.rules ) {
1259
+ rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
1260
+ }
1261
+ return rules;
1262
+ },
1263
+
1264
+ normalizeRules: function( rules, element ) {
1265
+
1266
+ // Handle dependency check
1267
+ $.each( rules, function( prop, val ) {
1268
+
1269
+ // Ignore rule when param is explicitly false, eg. required:false
1270
+ if ( val === false ) {
1271
+ delete rules[ prop ];
1272
+ return;
1273
+ }
1274
+ if ( val.param || val.depends ) {
1275
+ var keepRule = true;
1276
+ switch ( typeof val.depends ) {
1277
+ case "string":
1278
+ keepRule = !!$( val.depends, element.form ).length;
1279
+ break;
1280
+ case "function":
1281
+ keepRule = val.depends.call( element, element );
1282
+ break;
1283
+ }
1284
+ if ( keepRule ) {
1285
+ rules[ prop ] = val.param !== undefined ? val.param : true;
1286
+ } else {
1287
+ $.data( element.form, "validator" ).resetElements( $( element ) );
1288
+ delete rules[ prop ];
1289
+ }
1290
+ }
1291
+ } );
1292
+
1293
+ // Evaluate parameters
1294
+ $.each( rules, function( rule, parameter ) {
1295
+ rules[ rule ] = $.isFunction( parameter ) && rule !== "normalizer" ? parameter( element ) : parameter;
1296
+ } );
1297
+
1298
+ // Clean number parameters
1299
+ $.each( [ "minlength", "maxlength" ], function() {
1300
+ if ( rules[ this ] ) {
1301
+ rules[ this ] = Number( rules[ this ] );
1302
+ }
1303
+ } );
1304
+ $.each( [ "rangelength", "range" ], function() {
1305
+ var parts;
1306
+ if ( rules[ this ] ) {
1307
+ if ( $.isArray( rules[ this ] ) ) {
1308
+ rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
1309
+ } else if ( typeof rules[ this ] === "string" ) {
1310
+ parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
1311
+ rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
1312
+ }
1313
+ }
1314
+ } );
1315
+
1316
+ if ( $.validator.autoCreateRanges ) {
1317
+
1318
+ // Auto-create ranges
1319
+ if ( rules.min != null && rules.max != null ) {
1320
+ rules.range = [ rules.min, rules.max ];
1321
+ delete rules.min;
1322
+ delete rules.max;
1323
+ }
1324
+ if ( rules.minlength != null && rules.maxlength != null ) {
1325
+ rules.rangelength = [ rules.minlength, rules.maxlength ];
1326
+ delete rules.minlength;
1327
+ delete rules.maxlength;
1328
+ }
1329
+ }
1330
+
1331
+ return rules;
1332
+ },
1333
+
1334
+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
1335
+ normalizeRule: function( data ) {
1336
+ if ( typeof data === "string" ) {
1337
+ var transformed = {};
1338
+ $.each( data.split( /\s/ ), function() {
1339
+ transformed[ this ] = true;
1340
+ } );
1341
+ data = transformed;
1342
+ }
1343
+ return data;
1344
+ },
1345
+
1346
+ // https://jqueryvalidation.org/jQuery.validator.addMethod/
1347
+ addMethod: function( name, method, message ) {
1348
+ $.validator.methods[ name ] = method;
1349
+ $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
1350
+ if ( method.length < 3 ) {
1351
+ $.validator.addClassRules( name, $.validator.normalizeRule( name ) );
1352
+ }
1353
+ },
1354
+
1355
+ // https://jqueryvalidation.org/jQuery.validator.methods/
1356
+ methods: {
1357
+
1358
+ // https://jqueryvalidation.org/required-method/
1359
+ required: function( value, element, param ) {
1360
+
1361
+ // Check if dependency is met
1362
+ if ( !this.depend( param, element ) ) {
1363
+ return "dependency-mismatch";
1364
+ }
1365
+ if ( element.nodeName.toLowerCase() === "select" ) {
1366
+
1367
+ // Could be an array for select-multiple or a string, both are fine this way
1368
+ var val = $( element ).val();
1369
+ return val && val.length > 0;
1370
+ }
1371
+ if ( this.checkable( element ) ) {
1372
+ return this.getLength( value, element ) > 0;
1373
+ }
1374
+ return value.length > 0;
1375
+ },
1376
+
1377
+ // https://jqueryvalidation.org/email-method/
1378
+ email: function( value, element ) {
1379
+
1380
+ // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
1381
+ // Retrieved 2014-01-14
1382
+ // If you have a problem with this implementation, report a bug against the above spec
1383
+ // Or use custom methods to implement your own email validation
1384
+ return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
1385
+ },
1386
+
1387
+ // https://jqueryvalidation.org/url-method/
1388
+ url: function( value, element ) {
1389
+
1390
+ // Copyright (c) 2010-2013 Diego Perini, MIT licensed
1391
+ // https://gist.github.com/dperini/729294
1392
+ // see also https://mathiasbynens.be/demo/url-regex
1393
+ // modified to allow protocol-relative URLs
1394
+ return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
1395
+ },
1396
+
1397
+ // https://jqueryvalidation.org/date-method/
1398
+ date: function( value, element ) {
1399
+ return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
1400
+ },
1401
+
1402
+ // https://jqueryvalidation.org/dateISO-method/
1403
+ dateISO: function( value, element ) {
1404
+ return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
1405
+ },
1406
+
1407
+ // https://jqueryvalidation.org/number-method/
1408
+ number: function( value, element ) {
1409
+ return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
1410
+ },
1411
+
1412
+ // https://jqueryvalidation.org/digits-method/
1413
+ digits: function( value, element ) {
1414
+ return this.optional( element ) || /^\d+$/.test( value );
1415
+ },
1416
+
1417
+ // https://jqueryvalidation.org/minlength-method/
1418
+ minlength: function( value, element, param ) {
1419
+ var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1420
+ return this.optional( element ) || length >= param;
1421
+ },
1422
+
1423
+ // https://jqueryvalidation.org/maxlength-method/
1424
+ maxlength: function( value, element, param ) {
1425
+ var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1426
+ return this.optional( element ) || length <= param;
1427
+ },
1428
+
1429
+ // https://jqueryvalidation.org/rangelength-method/
1430
+ rangelength: function( value, element, param ) {
1431
+ var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1432
+ return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
1433
+ },
1434
+
1435
+ // https://jqueryvalidation.org/min-method/
1436
+ min: function( value, element, param ) {
1437
+ return this.optional( element ) || value >= param;
1438
+ },
1439
+
1440
+ // https://jqueryvalidation.org/max-method/
1441
+ max: function( value, element, param ) {
1442
+ return this.optional( element ) || value <= param;
1443
+ },
1444
+
1445
+ // https://jqueryvalidation.org/range-method/
1446
+ range: function( value, element, param ) {
1447
+ return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
1448
+ },
1449
+
1450
+ // https://jqueryvalidation.org/step-method/
1451
+ step: function( value, element, param ) {
1452
+ var type = $( element ).attr( "type" ),
1453
+ errorMessage = "Step attribute on input type " + type + " is not supported.",
1454
+ supportedTypes = [ "text", "number", "range" ],
1455
+ re = new RegExp( "\\b" + type + "\\b" ),
1456
+ notSupported = type && !re.test( supportedTypes.join() ),
1457
+ decimalPlaces = function( num ) {
1458
+ var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
1459
+ if ( !match ) {
1460
+ return 0;
1461
+ }
1462
+
1463
+ // Number of digits right of decimal point.
1464
+ return match[ 1 ] ? match[ 1 ].length : 0;
1465
+ },
1466
+ toInt = function( num ) {
1467
+ return Math.round( num * Math.pow( 10, decimals ) );
1468
+ },
1469
+ valid = true,
1470
+ decimals;
1471
+
1472
+ // Works only for text, number and range input types
1473
+ // TODO find a way to support input types date, datetime, datetime-local, month, time and week
1474
+ if ( notSupported ) {
1475
+ throw new Error( errorMessage );
1476
+ }
1477
+
1478
+ decimals = decimalPlaces( param );
1479
+
1480
+ // Value can't have too many decimals
1481
+ if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
1482
+ valid = false;
1483
+ }
1484
+
1485
+ return this.optional( element ) || valid;
1486
+ },
1487
+
1488
+ // https://jqueryvalidation.org/equalTo-method/
1489
+ equalTo: function( value, element, param ) {
1490
+
1491
+ // Bind to the blur event of the target in order to revalidate whenever the target field is updated
1492
+ var target = $( param );
1493
+ if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
1494
+ target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
1495
+ $( element ).valid();
1496
+ } );
1497
+ }
1498
+ return value === target.val();
1499
+ },
1500
+
1501
+ // https://jqueryvalidation.org/remote-method/
1502
+ remote: function( value, element, param, method ) {
1503
+ if ( this.optional( element ) ) {
1504
+ return "dependency-mismatch";
1505
+ }
1506
+
1507
+ method = typeof method === "string" && method || "remote";
1508
+
1509
+ var previous = this.previousValue( element, method ),
1510
+ validator, data, optionDataString;
1511
+
1512
+ if ( !this.settings.messages[ element.name ] ) {
1513
+ this.settings.messages[ element.name ] = {};
1514
+ }
1515
+ previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
1516
+ this.settings.messages[ element.name ][ method ] = previous.message;
1517
+
1518
+ param = typeof param === "string" && { url: param } || param;
1519
+ optionDataString = $.param( $.extend( { data: value }, param.data ) );
1520
+ if ( previous.old === optionDataString ) {
1521
+ return previous.valid;
1522
+ }
1523
+
1524
+ previous.old = optionDataString;
1525
+ validator = this;
1526
+ this.startRequest( element );
1527
+ data = {};
1528
+ data[ element.name ] = value;
1529
+ $.ajax( $.extend( true, {
1530
+ mode: "abort",
1531
+ port: "validate" + element.name,
1532
+ dataType: "json",
1533
+ data: data,
1534
+ context: validator.currentForm,
1535
+ success: function( response ) {
1536
+ var valid = response === true || response === "true",
1537
+ errors, message, submitted;
1538
+
1539
+ validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
1540
+ if ( valid ) {
1541
+ submitted = validator.formSubmitted;
1542
+ validator.resetInternals();
1543
+ validator.toHide = validator.errorsFor( element );
1544
+ validator.formSubmitted = submitted;
1545
+ validator.successList.push( element );
1546
+ validator.invalid[ element.name ] = false;
1547
+ validator.showErrors();
1548
+ } else {
1549
+ errors = {};
1550
+ message = response || validator.defaultMessage( element, { method: method, parameters: value } );
1551
+ errors[ element.name ] = previous.message = message;
1552
+ validator.invalid[ element.name ] = true;
1553
+ validator.showErrors( errors );
1554
+ }
1555
+ previous.valid = valid;
1556
+ validator.stopRequest( element, valid );
1557
+ }
1558
+ }, param ) );
1559
+ return "pending";
1560
+ }
1561
+ }
1562
+
1563
+ } );
1564
+
1565
+ // Ajax mode: abort
1566
+ // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1567
+ // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1568
+
1569
+ var pendingRequests = {},
1570
+ ajax;
1571
+
1572
+ // Use a prefilter if available (1.5+)
1573
+ if ( $.ajaxPrefilter ) {
1574
+ $.ajaxPrefilter( function( settings, _, xhr ) {
1575
+ var port = settings.port;
1576
+ if ( settings.mode === "abort" ) {
1577
+ if ( pendingRequests[ port ] ) {
1578
+ pendingRequests[ port ].abort();
1579
+ }
1580
+ pendingRequests[ port ] = xhr;
1581
+ }
1582
+ } );
1583
+ } else {
1584
+
1585
+ // Proxy ajax
1586
+ ajax = $.ajax;
1587
+ $.ajax = function( settings ) {
1588
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1589
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1590
+ if ( mode === "abort" ) {
1591
+ if ( pendingRequests[ port ] ) {
1592
+ pendingRequests[ port ].abort();
1593
+ }
1594
+ pendingRequests[ port ] = ajax.apply( this, arguments );
1595
+ return pendingRequests[ port ];
1596
+ }
1597
+ return ajax.apply( this, arguments );
1598
+ };
1599
+ }
1600
+ return $;
1601
+ }));