jumbo-jekyll-theme 2.2.1.1 → 2.2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/_data/authors.yml +7 -0
  3. data/_data/footer.yml +55 -0
  4. data/_data/nav.yml +77 -0
  5. data/_data/news.yaml +230 -0
  6. data/_data/settings.yml +148 -0
  7. data/_data/sidebar-nav.yml +23 -0
  8. data/_data/sticky-tab-bar.yml +29 -0
  9. data/_includes/author-pagination.html +36 -0
  10. data/_includes/authors-posts.html +49 -0
  11. data/_includes/breadcrumb.html +97 -0
  12. data/_includes/css.html +9 -0
  13. data/_includes/custom.html +1 -0
  14. data/_includes/display-blog-posts.html +67 -0
  15. data/_includes/disqus-comments.html +14 -0
  16. data/_includes/footer.html +70 -0
  17. data/_includes/github-edit.html +73 -0
  18. data/_includes/google-analytics-script.html +9 -0
  19. data/_includes/gtm-noscript.html +5 -0
  20. data/_includes/gtm-script.html +7 -0
  21. data/_includes/head.html +44 -0
  22. data/_includes/hero-banner.html +21 -0
  23. data/_includes/image.html +6 -0
  24. data/_includes/javascript.html +9 -0
  25. data/_includes/jumbotron.html +87 -0
  26. data/_includes/linaro-404.html +13 -0
  27. data/_includes/linaro-svg.html +1 -0
  28. data/_includes/media.html +11 -0
  29. data/_includes/members.html +63 -0
  30. data/_includes/nav.html +132 -0
  31. data/_includes/newsletter-script.html +30 -0
  32. data/_includes/owl-carousel-homepage.html +103 -0
  33. data/_includes/pagination-authors.html +36 -0
  34. data/_includes/pagination-news.html +36 -0
  35. data/_includes/pagination.html +36 -0
  36. data/_includes/post-comments.html +9 -0
  37. data/_includes/post-sidebar.html +74 -0
  38. data/_includes/post-tags.html +9 -0
  39. data/_includes/schema.html +50 -0
  40. data/_includes/shape-divider.html +12 -0
  41. data/_includes/shape.html +52 -0
  42. data/_includes/sidebar.html +55 -0
  43. data/_includes/sticky-tab-bar.html +63 -0
  44. data/_includes/thumbnail_image.html +10 -0
  45. data/_includes/universal-nav.html +28 -0
  46. data/_includes/youtube.html +7 -0
  47. data/_layouts/author-layout.html +13 -0
  48. data/_layouts/author.html +7 -0
  49. data/_layouts/container-breadcrumb-left-sidebar.html +10 -0
  50. data/_layouts/container-breadcrumb-right-sidebar.html +9 -0
  51. data/_layouts/container-breadcrumb-tabs.html +7 -0
  52. data/_layouts/container-breadcrumb.html +6 -0
  53. data/_layouts/container-left-sidebar.html +9 -0
  54. data/_layouts/container-right-sidebar.html +9 -0
  55. data/_layouts/container.html +9 -0
  56. data/_layouts/default.html +29 -0
  57. data/_layouts/full-width-breadcrumb.html +10 -0
  58. data/_layouts/full-width.html +9 -0
  59. data/_layouts/home.html +21 -0
  60. data/_layouts/post-index.html +19 -0
  61. data/_layouts/post-no-sidebar.html +0 -0
  62. data/_layouts/post-old.html +70 -0
  63. data/_layouts/post.html +240 -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 +58 -0
  69. data/_sass/app/contact.scss +3 -0
  70. data/_sass/app/custom.scss +1 -0
  71. data/_sass/app/fly.scss +10 -0
  72. data/_sass/app/home.scss +18 -0
  73. data/_sass/app/overrides.scss +36 -0
  74. data/_sass/app/search.scss +1 -0
  75. data/_sass/blog.scss +9 -0
  76. data/_sass/bootstrap/_alerts.scss +73 -0
  77. data/_sass/bootstrap/_badges.scss +68 -0
  78. data/_sass/bootstrap/_breadcrumbs.scss +28 -0
  79. data/_sass/bootstrap/_button-groups.scss +244 -0
  80. data/_sass/bootstrap/_buttons.scss +168 -0
  81. data/_sass/bootstrap/_carousel.scss +270 -0
  82. data/_sass/bootstrap/_close.scss +36 -0
  83. data/_sass/bootstrap/_code.scss +69 -0
  84. data/_sass/bootstrap/_component-animations.scss +37 -0
  85. data/_sass/bootstrap/_dropdowns.scss +216 -0
  86. data/_sass/bootstrap/_forms.scss +617 -0
  87. data/_sass/bootstrap/_glyphicons.scss +307 -0
  88. data/_sass/bootstrap/_grid.scss +84 -0
  89. data/_sass/bootstrap/_input-groups.scss +171 -0
  90. data/_sass/bootstrap/_jumbotron.scss +54 -0
  91. data/_sass/bootstrap/_labels.scss +66 -0
  92. data/_sass/bootstrap/_list-group.scss +130 -0
  93. data/_sass/bootstrap/_media.scss +66 -0
  94. data/_sass/bootstrap/_mixins.scss +40 -0
  95. data/_sass/bootstrap/_modals.scss +150 -0
  96. data/_sass/bootstrap/_navbar.scss +662 -0
  97. data/_sass/bootstrap/_navs.scss +242 -0
  98. data/_sass/bootstrap/_normalize.scss +424 -0
  99. data/_sass/bootstrap/_pager.scss +54 -0
  100. data/_sass/bootstrap/_pagination.scss +89 -0
  101. data/_sass/bootstrap/_panels.scss +271 -0
  102. data/_sass/bootstrap/_popovers.scss +131 -0
  103. data/_sass/bootstrap/_print.scss +101 -0
  104. data/_sass/bootstrap/_progress-bars.scss +87 -0
  105. data/_sass/bootstrap/_responsive-embed.scss +35 -0
  106. data/_sass/bootstrap/_responsive-utilities.scss +179 -0
  107. data/_sass/bootstrap/_scaffolding.scss +161 -0
  108. data/_sass/bootstrap/_tables.scss +234 -0
  109. data/_sass/bootstrap/_theme.scss +291 -0
  110. data/_sass/bootstrap/_thumbnails.scss +38 -0
  111. data/_sass/bootstrap/_tooltip.scss +101 -0
  112. data/_sass/bootstrap/_type.scss +298 -0
  113. data/_sass/bootstrap/_utilities.scss +55 -0
  114. data/_sass/bootstrap/_variables.scss +922 -0
  115. data/_sass/bootstrap/_wells.scss +29 -0
  116. data/_sass/bootstrap/mixins/_alerts.scss +14 -0
  117. data/_sass/bootstrap/mixins/_background-variant.scss +12 -0
  118. data/_sass/bootstrap/mixins/_border-radius.scss +18 -0
  119. data/_sass/bootstrap/mixins/_buttons.scss +65 -0
  120. data/_sass/bootstrap/mixins/_center-block.scss +7 -0
  121. data/_sass/bootstrap/mixins/_clearfix.scss +22 -0
  122. data/_sass/bootstrap/mixins/_forms.scss +88 -0
  123. data/_sass/bootstrap/mixins/_gradients.scss +58 -0
  124. data/_sass/bootstrap/mixins/_grid-framework.scss +81 -0
  125. data/_sass/bootstrap/mixins/_grid.scss +122 -0
  126. data/_sass/bootstrap/mixins/_hide-text.scss +21 -0
  127. data/_sass/bootstrap/mixins/_image.scss +33 -0
  128. data/_sass/bootstrap/mixins/_labels.scss +12 -0
  129. data/_sass/bootstrap/mixins/_list-group.scss +32 -0
  130. data/_sass/bootstrap/mixins/_nav-divider.scss +10 -0
  131. data/_sass/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  132. data/_sass/bootstrap/mixins/_opacity.scss +8 -0
  133. data/_sass/bootstrap/mixins/_pagination.scss +24 -0
  134. data/_sass/bootstrap/mixins/_panels.scss +24 -0
  135. data/_sass/bootstrap/mixins/_progress-bar.scss +10 -0
  136. data/_sass/bootstrap/mixins/_reset-filter.scss +8 -0
  137. data/_sass/bootstrap/mixins/_reset-text.scss +18 -0
  138. data/_sass/bootstrap/mixins/_resize.scss +6 -0
  139. data/_sass/bootstrap/mixins/_responsive-visibility.scss +21 -0
  140. data/_sass/bootstrap/mixins/_size.scss +10 -0
  141. data/_sass/bootstrap/mixins/_tab-focus.scss +9 -0
  142. data/_sass/bootstrap/mixins/_table-row.scss +28 -0
  143. data/_sass/bootstrap/mixins/_text-emphasis.scss +12 -0
  144. data/_sass/bootstrap/mixins/_text-overflow.scss +8 -0
  145. data/_sass/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  146. data/_sass/core.scss +12 -0
  147. data/_sass/core/404.scss +189 -0
  148. data/_sass/core/animations.scss +125 -0
  149. data/_sass/core/blog.scss +441 -0
  150. data/_sass/core/breadcrumb.scss +97 -0
  151. data/_sass/core/carousel-styles.scss +3 -0
  152. data/_sass/core/carousel.scss +318 -0
  153. data/_sass/core/cookieconsent.scss +42 -0
  154. data/_sass/core/critical.scss +0 -0
  155. data/_sass/core/custom.scss +3 -0
  156. data/_sass/core/fa.scss +2336 -0
  157. data/_sass/core/flipclock.scss +434 -0
  158. data/_sass/core/font-awesome.min.scss +4 -0
  159. data/_sass/core/fonts.scss +3 -0
  160. data/_sass/core/footer.scss +169 -0
  161. data/_sass/core/forms.scss +3 -0
  162. data/_sass/core/homepage.scss +106 -0
  163. data/_sass/core/jumbotron.scss +51 -0
  164. data/_sass/core/lightbox.scss +212 -0
  165. data/_sass/core/nav.scss +1004 -0
  166. data/_sass/core/owl.carousel.min.scss +6 -0
  167. data/_sass/core/owl.theme.default.min.scss +6 -0
  168. data/_sass/core/social-media-icons.scss +67 -0
  169. data/_sass/core/syntax.scss +65 -0
  170. data/_sass/core/tables.scss +145 -0
  171. data/_sass/core/theme.scss +630 -0
  172. data/_sass/core/twitter-feed.scss +414 -0
  173. data/_sass/core/universal-nav.scss +154 -0
  174. data/_sass/core/youtube.scss +65 -0
  175. data/_sass/home.scss +6 -0
  176. data/assets/css/main-404.scss +18 -0
  177. data/assets/css/main-blog.scss +19 -0
  178. data/assets/css/main-contact.scss +23 -0
  179. data/assets/css/main-home.scss +22 -0
  180. data/assets/css/main-lightbox.scss +29 -0
  181. data/assets/css/main-search.scss +13 -0
  182. data/assets/css/main.scss +12 -0
  183. data/assets/fonts/fontawesome-webfont.eot +0 -0
  184. data/assets/fonts/fontawesome-webfont.svg +2671 -0
  185. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  186. data/assets/fonts/fontawesome-webfont.woff +0 -0
  187. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  188. data/assets/fonts/fontello.eot +0 -0
  189. data/assets/fonts/fontello.svg +44 -0
  190. data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  191. data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  192. data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  193. data/assets/fonts/lato-regular/LICENSE.txt +93 -0
  194. data/assets/fonts/lato-regular/Lato-regular.eot +0 -0
  195. data/assets/fonts/lato-regular/Lato-regular.svg +435 -0
  196. data/assets/fonts/lato-regular/Lato-regular.ttf +0 -0
  197. data/assets/fonts/lato-regular/Lato-regular.woff +0 -0
  198. data/assets/fonts/lato-regular/Lato-regular.woff2 +0 -0
  199. data/assets/images/Linaro-Logo.svg +1 -0
  200. data/assets/images/Linaro-Logo_light.png +0 -0
  201. data/assets/images/Linaro-Logo_standard.svg +1 -0
  202. data/assets/images/Linaro-Sprinkle.png +0 -0
  203. data/assets/images/avatar-placeholder.png +0 -0
  204. data/assets/images/background-image.jpg +0 -0
  205. data/assets/images/banner.jpg +0 -0
  206. data/assets/images/breadcrumb-image.jpg +0 -0
  207. data/assets/images/close.png +0 -0
  208. data/assets/images/favicon.ico +0 -0
  209. data/assets/images/favicon.png +0 -0
  210. data/assets/images/loading.gif +0 -0
  211. data/assets/images/next.png +0 -0
  212. data/assets/images/owl.video.play.png +0 -0
  213. data/assets/images/placeholder.png +0 -0
  214. data/assets/images/prev.png +0 -0
  215. data/assets/images/social-media-image.png +0 -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 +143 -0
  221. data/assets/js/app/scroll-to-anchors.js +10 -0
  222. data/assets/js/app/sticky-tab-bar.js +72 -0
  223. data/assets/js/app/tables.js +35 -0
  224. data/assets/js/package-blog.js +10 -0
  225. data/assets/js/package-extended.js +14 -0
  226. data/assets/js/package-home.js +12 -0
  227. data/assets/js/package-main.js +10 -0
  228. data/assets/js/package-search.js +8 -0
  229. data/assets/js/vendor/bootstrap.js +2377 -0
  230. data/assets/js/vendor/cognito.js +11 -0
  231. data/assets/js/vendor/cookieconsent.js +1504 -0
  232. data/assets/js/vendor/jquery.js +10364 -0
  233. data/assets/js/vendor/jquery.rss.js +333 -0
  234. data/assets/js/vendor/jquery.validate.js +1601 -0
  235. data/assets/js/vendor/lazysizes.js +698 -0
  236. data/assets/js/vendor/lightbox.js +523 -0
  237. data/assets/js/vendor/loadCSS.js +35 -0
  238. data/assets/js/vendor/ls.unveilhooks.js +145 -0
  239. data/assets/js/vendor/mc.js +255 -0
  240. data/assets/js/vendor/owl.carousel.js +3475 -0
  241. data/assets/js/vendor/picturefill.js +1471 -0
  242. data/assets/js/vendor/shuffle.js +2004 -0
  243. metadata +242 -1
@@ -0,0 +1,11 @@
1
+ (function(){function r(){for(var t,i=arguments[0],n=1;n<arguments.length;n++)for(t in arguments[n])arguments[n].hasOwnProperty(t)&&(i[t]=arguments[n][t]);return i}var e,o,n,t,s,i,u,f;window.console=window.console||{log:function(){}};e=null;o=null;window.Cognito=window.Cognito||{};window.Cognito.deferredLoad=undefined;Cognito.sessionInit=function(){Cognito.deferredLoad&&Cognito.deferredLoad()};Cognito.config=r({},Cognito.config,{instanceId:636491919541478436,organizationCode:"Linaro1",sessionToken:"rUY5XaLmcsRUbGFmd3Dw+7R5tSE51S3tWLROcptdD2EmsW/mbwWmhfBHYvqb7YKr6yuTLSClwhuPcqzu4fv5TjXyFJw=",baseUrl:"https://services.cognitoforms.com/",mode:"public",maxClientErrors:15,cacheHash:"-322828110",key:"9850f42a-f689-4b76-ba93-a8063fbd758f",version:"0.01"});Cognito.resources=r({},Cognito.resources);n=document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0];document.querySelectorAll("script[src*='include/req/']").length===0&&(window.Cognito.load=function(){var n=arguments;window.Cognito.deferredLoad=function(){Cognito.load.apply(Cognito,n)}},t=document.createElement("script"),t.type="text/javascript",t.async=!1,s=!1,n.insertBefore(t,n.firstChild),t.src="https://services.cognitoforms.com/include/req/-322828110");document.querySelectorAll("link[href*=requiredcss]").length===0&&(i=document.createElement("link"),i.type="text/css",i.rel="stylesheet",i.href="https://services.cognitoforms.com/include/requiredcss/-322828110",n.insertBefore(i,n.firstChild));u=window.addEventListener?"addEventListener":"attachEvent";f=window.addEventListener?"load":"onload";window[u](f,function(){if(window.ExoJQuery===undefined){var n=XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");n.open("POST","https://services.cognitoforms.com/error",!0);n.setRequestHeader("Content-type","application/json");n.send(JSON.stringify({message:"Requred scripts not loaded ("+Cognito.config.organizationCode+")",type:"Error",url:document.location.href,refererUrl:document.referrer}))}})})()
2
+
3
+
4
+
5
+ $(document).ready(function(){
6
+ Cognito.load("forms", { id: "7", entry: {
7
+ "PageUrl": "{{site.url}}{{page.url}}" ,
8
+ "RedirectUrl" : "{{site.url}}/thank-you/?ref={{page.url}}"
9
+ }});
10
+
11
+ });
@@ -0,0 +1,1504 @@
1
+ (function(cc) {
2
+ // stop from running again, if accidently included more than once.
3
+ if (cc.hasInitialised) return;
4
+
5
+ var util = {
6
+ // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
7
+ escapeRegExp: function(str) {
8
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
9
+ },
10
+
11
+ hasClass: function(element, selector) {
12
+ var s = ' ';
13
+ return element.nodeType === 1 &&
14
+ (s + element.className + s).replace(/[\n\t]/g, s).indexOf(s + selector + s) >= 0;
15
+ },
16
+
17
+ addClass: function(element, className) {
18
+ element.className += ' ' + className;
19
+ },
20
+
21
+ removeClass: function(element, className) {
22
+ var regex = new RegExp('\\b' + this.escapeRegExp(className) + '\\b');
23
+ element.className = element.className.replace(regex, '');
24
+ },
25
+
26
+ interpolateString: function(str, callback) {
27
+ var marker = /{{([a-z][a-z0-9\-_]*)}}/ig;
28
+ return str.replace(marker, function(matches) {
29
+ return callback(arguments[1]) || '';
30
+ })
31
+ },
32
+
33
+ getCookie: function(name) {
34
+ var value = '; ' + document.cookie;
35
+ var parts = value.split('; ' + name + '=');
36
+ return parts.length != 2 ?
37
+ undefined : parts.pop().split(';').shift();
38
+ },
39
+
40
+ setCookie: function(name, value, expiryDays, domain, path) {
41
+ var exdate = new Date();
42
+ exdate.setDate(exdate.getDate() + (expiryDays || 365));
43
+
44
+ var cookie = [
45
+ name + '=' + value,
46
+ 'expires=' + exdate.toUTCString(),
47
+ 'path=' + (path || '/')
48
+ ];
49
+
50
+ if (domain) {
51
+ cookie.push('domain=' + domain);
52
+ }
53
+ document.cookie = cookie.join(';');
54
+ },
55
+
56
+ // only used for extending the initial options
57
+ deepExtend: function(target, source) {
58
+ for (var prop in source) {
59
+ if (source.hasOwnProperty(prop)) {
60
+ if (prop in target && this.isPlainObject(target[prop]) && this.isPlainObject(source[prop])) {
61
+ this.deepExtend(target[prop], source[prop]);
62
+ } else {
63
+ target[prop] = source[prop];
64
+ }
65
+ }
66
+ }
67
+ return target;
68
+ },
69
+
70
+ // only used for throttling the 'mousemove' event (used for animating the revoke button when `animateRevokable` is true)
71
+ throttle: function(callback, limit) {
72
+ var wait = false;
73
+ return function() {
74
+ if (!wait) {
75
+ callback.apply(this, arguments);
76
+ wait = true;
77
+ setTimeout(function() {
78
+ wait = false;
79
+ }, limit);
80
+ }
81
+ }
82
+ },
83
+
84
+ // only used for hashing json objects (used for hash mapping palette objects, used when custom colours are passed through JavaScript)
85
+ hash: function(str) {
86
+ var hash = 0,
87
+ i, chr, len;
88
+ if (str.length === 0) return hash;
89
+ for (i = 0, len = str.length; i < len; ++i) {
90
+ chr = str.charCodeAt(i);
91
+ hash = ((hash << 5) - hash) + chr;
92
+ hash |= 0;
93
+ }
94
+ return hash;
95
+ },
96
+
97
+ normaliseHex: function(hex) {
98
+ if (hex[0] == '#') {
99
+ hex = hex.substr(1);
100
+ }
101
+ if (hex.length == 3) {
102
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
103
+ }
104
+ return hex;
105
+ },
106
+
107
+ // used to get text colors if not set
108
+ getContrast: function(hex) {
109
+ hex = this.normaliseHex(hex);
110
+ var r = parseInt(hex.substr(0, 2), 16);
111
+ var g = parseInt(hex.substr(2, 2), 16);
112
+ var b = parseInt(hex.substr(4, 2), 16);
113
+ var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
114
+ return (yiq >= 128) ? '#000' : '#fff';
115
+ },
116
+
117
+ // used to change color on highlight
118
+ getLuminance: function(hex) {
119
+ var num = parseInt(this.normaliseHex(hex), 16),
120
+ amt = 38,
121
+ R = (num >> 16) + amt,
122
+ B = (num >> 8 & 0x00FF) + amt,
123
+ G = (num & 0x0000FF) + amt;
124
+ var newColour = (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (B<255?B<1?0:B:255)*0x100 + (G<255?G<1?0:G:255)).toString(16).slice(1);
125
+ return '#'+newColour;
126
+ },
127
+
128
+ isMobile: function() {
129
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
130
+ },
131
+
132
+ isPlainObject: function(obj) {
133
+ // The code "typeof obj === 'object' && obj !== null" allows Array objects
134
+ return typeof obj === 'object' && obj !== null && obj.constructor == Object;
135
+ },
136
+ };
137
+
138
+ // valid cookie values
139
+ cc.status = {
140
+ deny: 'deny',
141
+ allow: 'allow',
142
+ dismiss: 'dismiss'
143
+ };
144
+
145
+ // detects the `transitionend` event name
146
+ cc.transitionEnd = (function() {
147
+ var el = document.createElement('div');
148
+ var trans = {
149
+ t: "transitionend",
150
+ OT: "oTransitionEnd",
151
+ msT: "MSTransitionEnd",
152
+ MozT: "transitionend",
153
+ WebkitT: "webkitTransitionEnd",
154
+ };
155
+
156
+ for (var prefix in trans) {
157
+ if (trans.hasOwnProperty(prefix) && typeof el.style[prefix + 'ransition'] != 'undefined') {
158
+ return trans[prefix];
159
+ }
160
+ }
161
+ return '';
162
+ }());
163
+
164
+ cc.hasTransition = !!cc.transitionEnd;
165
+
166
+ // array of valid regexp escaped statuses
167
+ var __allowedStatuses = Object.keys(cc.status).map(util.escapeRegExp);
168
+
169
+ // contains references to the custom <style> tags
170
+ cc.customStyles = {};
171
+
172
+ cc.Popup = (function() {
173
+
174
+ var defaultOptions = {
175
+
176
+ // if false, this prevents the popup from showing (useful for giving to control to another piece of code)
177
+ enabled: true,
178
+
179
+ // optional (expecting a HTML element) if passed, the popup is appended to this element. default is `document.body`
180
+ container: null,
181
+
182
+ // defaults cookie options - it is RECOMMENDED to set these values to correspond with your server
183
+ cookie: {
184
+ // This is the name of this cookie - you can ignore this
185
+ name: 'cookieconsent_status',
186
+
187
+ // This is the url path that the cookie 'name' belongs to. The cookie can only be read at this location
188
+ path: '/',
189
+
190
+ // This is the domain that the cookie 'name' belongs to. The cookie can only be read on this domain.
191
+ // - Guide to cookie domains - http://erik.io/blog/2014/03/04/definitive-guide-to-cookie-domains/
192
+ domain: '',
193
+
194
+ // The cookies expire date, specified in days (specify -1 for no expiry)
195
+ expiryDays: 365,
196
+ },
197
+
198
+ // these callback hooks are called at certain points in the program execution
199
+ onPopupOpen: function() {},
200
+ onPopupClose: function() {},
201
+ onInitialise: function(status) {},
202
+ onStatusChange: function(status, chosenBefore) {},
203
+ onRevokeChoice: function() {},
204
+
205
+ // each item defines the inner text for the element that it references
206
+ content: {
207
+ header: 'Cookies used on the website!',
208
+ message: 'This website uses cookies to ensure you get the best experience on our website.',
209
+ dismiss: 'Got it!',
210
+ allow: 'Allow cookies',
211
+ deny: 'Decline',
212
+ link: 'Learn more',
213
+ href: 'http://cookiesandyou.com',
214
+ close: '&#x274c;',
215
+ },
216
+
217
+ // This is the HTML for the elements above. The string {{header}} will be replaced with the equivalent text below.
218
+ // You can remove "{{header}}" and write the content directly inside the HTML if you want.
219
+ //
220
+ // - ARIA rules suggest to ensure controls are tabbable (so the browser can find the first control),
221
+ // and to set the focus to the first interactive control (http://w3c.github.io/aria-in-html/)
222
+ elements: {
223
+ header: '<span class="cc-header">{{header}}</span>&nbsp;',
224
+ message: '<span id="cookieconsent:desc" class="cc-message">{{message}}</span>',
225
+ messagelink: '<span id="cookieconsent:desc" class="cc-message">{{message}} <a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" rel="noopener noreferrer nofollow" target="_blank">{{link}}</a></span>',
226
+ dismiss: '<a aria-label="dismiss cookie message" role=button tabindex="0" class="cc-btn cc-dismiss">{{dismiss}}</a>',
227
+ allow: '<a aria-label="allow cookies" role=button tabindex="0" class="cc-btn cc-allow">{{allow}}</a>',
228
+ deny: '<a aria-label="deny cookies" role=button tabindex="0" class="cc-btn cc-deny">{{deny}}</a>',
229
+ link: '<a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" target="_blank">{{link}}</a>',
230
+ close: '<span aria-label="dismiss cookie message" role=button tabindex="0" class="cc-close">{{close}}</span>',
231
+
232
+ //compliance: compliance is also an element, but it is generated by the application, depending on `type` below
233
+ },
234
+
235
+ // The placeholders {{classes}} and {{children}} both get replaced during initialisation:
236
+ // - {{classes}} is where additional classes get added
237
+ // - {{children}} is where the HTML children are placed
238
+ window: '<div role="dialog" aria-live="polite" aria-label="cookieconsent" aria-describedby="cookieconsent:desc" class="cc-window {{classes}}"><!--googleoff: all-->{{children}}<!--googleon: all--></div>',
239
+
240
+ // This is the html for the revoke button. This only shows up after the user has selected their level of consent
241
+ // It can be enabled of disabled using the `revokable` option
242
+ revokeBtn: '<div class="cc-revoke {{classes}}">Cookie Policy</div>',
243
+
244
+ // define types of 'compliance' here. '{{value}}' strings in here are linked to `elements`
245
+ compliance: {
246
+ 'info': '<div class="cc-compliance">{{dismiss}}</div>',
247
+ 'opt-in': '<div class="cc-compliance cc-highlight">{{dismiss}}{{allow}}</div>',
248
+ 'opt-out': '<div class="cc-compliance cc-highlight">{{deny}}{{dismiss}}</div>',
249
+ },
250
+
251
+ // select your type of popup here
252
+ type: 'info', // refers to `compliance` (in other words, the buttons that are displayed)
253
+
254
+ // define layout layouts here
255
+ layouts: {
256
+ // the 'block' layout tend to be for square floating popups
257
+ 'basic': '{{messagelink}}{{compliance}}',
258
+ 'basic-close': '{{messagelink}}{{compliance}}{{close}}',
259
+ 'basic-header': '{{header}}{{message}}{{link}}{{compliance}}',
260
+
261
+ // add a custom layout here, then add some new css with the class '.cc-layout-my-cool-layout'
262
+ //'my-cool-layout': '<div class="my-special-layout">{{message}}{{compliance}}</div>{{close}}',
263
+ },
264
+
265
+ // default layout (see above)
266
+ layout: 'basic',
267
+
268
+ // this refers to the popup windows position. we currently support:
269
+ // - banner positions: top, bottom
270
+ // - floating positions: top-left, top-right, bottom-left, bottom-right
271
+ //
272
+ // adds a class `cc-floating` or `cc-banner` which helps when styling
273
+ position: 'bottom', // default position is 'bottom'
274
+
275
+ // Available styles
276
+ // -block (default, no extra classes)
277
+ // -edgeless
278
+ // -classic
279
+ // use your own style name and use `.cc-theme-STYLENAME` class in CSS to edit.
280
+ // Note: style "wire" is used for the configurator, but has no CSS styles of its own, only palette is used.
281
+ theme: 'block',
282
+
283
+ // The popup is `fixed` by default, but if you want it to be static (inline with the page content), set this to false
284
+ // Note: by default, we animate the height of the popup from 0 to full size
285
+ static: false,
286
+
287
+ // if you want custom colours, pass them in here. this object should look like this.
288
+ // ideally, any custom colours/themes should be created in a separate style sheet, as this is more efficient.
289
+ // {
290
+ // popup: {background: '#000000', text: '#fff', link: '#fff'},
291
+ // button: {background: 'transparent', border: '#f8e71c', text: '#f8e71c'},
292
+ // highlight: {background: '#f8e71c', border: '#f8e71c', text: '#000000'},
293
+ // }
294
+ // `highlight` is optional and extends `button`. if it exists, it will apply to the first button
295
+ // only background needs to be defined for every element. if not set, other colors can be calculated from it
296
+ palette: null,
297
+
298
+ // Some countries REQUIRE that a user can change their mind. You can configure this yourself.
299
+ // Most of the time this should be false, but the `cookieconsent.law` can change this to `true` if it detects that it should
300
+ revokable: false,
301
+
302
+ // if true, the revokable button will tranlate in and out
303
+ animateRevokable: true,
304
+
305
+ // used to disable link on existing layouts
306
+ // replaces element messagelink with message and removes content of link
307
+ showLink: true,
308
+
309
+ // set value as scroll range to enable
310
+ dismissOnScroll: false,
311
+
312
+ // set value as time in milliseconds to autodismiss after set time
313
+ dismissOnTimeout: false,
314
+
315
+ // The application automatically decide whether the popup should open.
316
+ // Set this to false to prevent this from happening and to allow you to control the behaviour yourself
317
+ autoOpen: true,
318
+
319
+ // By default the created HTML is automatically appended to the container (which defaults to <body>). You can prevent this behaviour
320
+ // by setting this to false, but if you do, you must attach the `element` yourself, which is a public property of the popup instance:
321
+ //
322
+ // var instance = cookieconsent.factory(options);
323
+ // document.body.appendChild(instance.element);
324
+ //
325
+ autoAttach: true,
326
+
327
+ // simple whitelist/blacklist for pages. specify page by:
328
+ // - using a string : '/index.html' (matches '/index.html' exactly) OR
329
+ // - using RegExp : /\/page_[\d]+\.html/ (matched '/page_1.html' and '/page_2.html' etc)
330
+ whitelistPage: [],
331
+ blacklistPage: [],
332
+
333
+ // If this is defined, then it is used as the inner html instead of layout. This allows for ultimate customisation.
334
+ // Be sure to use the classes `cc-btn` and `cc-allow`, `cc-deny` or `cc-dismiss`. They enable the app to register click
335
+ // handlers. You can use other pre-existing classes too. See `src/styles` folder.
336
+ overrideHTML: null,
337
+ };
338
+
339
+ function CookiePopup() {
340
+ this.initialise.apply(this, arguments);
341
+ }
342
+
343
+ CookiePopup.prototype.initialise = function(options) {
344
+ if (this.options) {
345
+ this.destroy(); // already rendered
346
+ }
347
+
348
+ // set options back to default options
349
+ util.deepExtend(this.options = {}, defaultOptions);
350
+
351
+ // merge in user options
352
+ if (util.isPlainObject(options)) {
353
+ util.deepExtend(this.options, options);
354
+ }
355
+
356
+ // returns true if `onComplete` was called
357
+ if (checkCallbackHooks.call(this)) {
358
+ // user has already answered
359
+ this.options.enabled = false;
360
+ }
361
+
362
+ // apply blacklist / whitelist
363
+ if (arrayContainsMatches(this.options.blacklistPage, location.pathname)) {
364
+ this.options.enabled = false;
365
+ }
366
+ if (arrayContainsMatches(this.options.whitelistPage, location.pathname)) {
367
+ this.options.enabled = true;
368
+ }
369
+
370
+ // the full markup either contains the wrapper or it does not (for multiple instances)
371
+ var cookiePopup = this.options.window
372
+ .replace('{{classes}}', getPopupClasses.call(this).join(' '))
373
+ .replace('{{children}}', getPopupInnerMarkup.call(this));
374
+
375
+ // if user passes html, use it instead
376
+ var customHTML = this.options.overrideHTML;
377
+ if (typeof customHTML == 'string' && customHTML.length) {
378
+ cookiePopup = customHTML;
379
+ }
380
+
381
+ // if static, we need to grow the element from 0 height so it doesn't jump the page
382
+ // content. we wrap an element around it which will mask the hidden content
383
+ if (this.options.static) {
384
+ // `grower` is a wrapper div with a hidden overflow whose height is animated
385
+ var wrapper = appendMarkup.call(this, '<div class="cc-grower">' + cookiePopup + '</div>');
386
+
387
+ wrapper.style.display = ''; // set it to visible (because appendMarkup hides it)
388
+ this.element = wrapper.firstChild; // get the `element` reference from the wrapper
389
+ this.element.style.display = 'none';
390
+ util.addClass(this.element, 'cc-invisible');
391
+ } else {
392
+ this.element = appendMarkup.call(this, cookiePopup);
393
+ }
394
+
395
+ applyAutoDismiss.call(this);
396
+
397
+ applyRevokeButton.call(this);
398
+
399
+ if (this.options.autoOpen) {
400
+ this.autoOpen();
401
+ }
402
+ };
403
+
404
+ CookiePopup.prototype.destroy = function() {
405
+ if (this.onButtonClick && this.element) {
406
+ this.element.removeEventListener('click', this.onButtonClick);
407
+ this.onButtonClick = null;
408
+ }
409
+
410
+ if (this.dismissTimeout) {
411
+ clearTimeout(this.dismissTimeout);
412
+ this.dismissTimeout = null;
413
+ }
414
+
415
+ if (this.onWindowScroll) {
416
+ window.removeEventListener('scroll', this.onWindowScroll);
417
+ this.onWindowScroll = null;
418
+ }
419
+
420
+ if (this.onMouseMove) {
421
+ window.removeEventListener('mousemove', this.onMouseMove);
422
+ this.onMouseMove = null;
423
+ }
424
+
425
+ if (this.element && this.element.parentNode) {
426
+ this.element.parentNode.removeChild(this.element);
427
+ }
428
+ this.element = null;
429
+
430
+ if (this.revokeBtn && this.revokeBtn.parentNode) {
431
+ this.revokeBtn.parentNode.removeChild(this.revokeBtn);
432
+ }
433
+ this.revokeBtn = null;
434
+
435
+ removeCustomStyle(this.options.palette);
436
+ this.options = null;
437
+ };
438
+
439
+ CookiePopup.prototype.open = function(callback) {
440
+ if (!this.element) return;
441
+
442
+ if (!this.isOpen()) {
443
+ if (cc.hasTransition) {
444
+ this.fadeIn();
445
+ } else {
446
+ this.element.style.display = '';
447
+ }
448
+
449
+ if (this.options.revokable) {
450
+ this.toggleRevokeButton();
451
+ }
452
+ this.options.onPopupOpen.call(this);
453
+ }
454
+
455
+ return this;
456
+ };
457
+
458
+ CookiePopup.prototype.close = function(showRevoke) {
459
+ if (!this.element) return;
460
+
461
+ if (this.isOpen()) {
462
+ if (cc.hasTransition) {
463
+ this.fadeOut();
464
+ } else {
465
+ this.element.style.display = 'none';
466
+ }
467
+
468
+ if (showRevoke && this.options.revokable) {
469
+ this.toggleRevokeButton(true);
470
+ }
471
+ this.options.onPopupClose.call(this);
472
+ }
473
+
474
+ return this;
475
+ };
476
+
477
+ CookiePopup.prototype.fadeIn = function() {
478
+ var el = this.element;
479
+
480
+ if (!cc.hasTransition || !el)
481
+ return;
482
+
483
+ // This should always be called AFTER fadeOut (which is governed by the 'transitionend' event).
484
+ // 'transitionend' isn't all that reliable, so, if we try and fadeIn before 'transitionend' has
485
+ // has a chance to run, then we run it ourselves
486
+ if (this.afterTransition) {
487
+ afterFadeOut.call(this, el)
488
+ }
489
+
490
+ if (util.hasClass(el, 'cc-invisible')) {
491
+ el.style.display = '';
492
+
493
+ if (this.options.static) {
494
+ var height = this.element.clientHeight;
495
+ this.element.parentNode.style.maxHeight = height + 'px';
496
+ }
497
+
498
+ var fadeInTimeout = 20; // (ms) DO NOT MAKE THIS VALUE SMALLER. See below
499
+
500
+ // Although most browsers can handle values less than 20ms, it should remain above this value.
501
+ // This is because we are waiting for a "browser redraw" before we remove the 'cc-invisible' class.
502
+ // If the class is remvoed before a redraw could happen, then the fadeIn effect WILL NOT work, and
503
+ // the popup will appear from nothing. Therefore we MUST allow enough time for the browser to do
504
+ // its thing. The actually difference between using 0 and 20 in a set timeout is neglegible anyway
505
+ this.openingTimeout = setTimeout(afterFadeIn.bind(this, el), fadeInTimeout);
506
+ }
507
+ };
508
+
509
+ CookiePopup.prototype.fadeOut = function() {
510
+ var el = this.element;
511
+
512
+ if (!cc.hasTransition || !el)
513
+ return;
514
+
515
+ if (this.openingTimeout) {
516
+ clearTimeout(this.openingTimeout);
517
+ afterFadeIn.bind(this, el);
518
+ }
519
+
520
+ if (!util.hasClass(el, 'cc-invisible')) {
521
+ if (this.options.static) {
522
+ this.element.parentNode.style.maxHeight = '';
523
+ }
524
+
525
+ this.afterTransition = afterFadeOut.bind(this, el);
526
+ el.addEventListener(cc.transitionEnd, this.afterTransition);
527
+
528
+ util.addClass(el, 'cc-invisible');
529
+ }
530
+ };
531
+
532
+ CookiePopup.prototype.isOpen = function() {
533
+ return this.element && this.element.style.display == '' && (cc.hasTransition ? !util.hasClass(this.element, 'cc-invisible') : true);
534
+ };
535
+
536
+ CookiePopup.prototype.toggleRevokeButton = function(show) {
537
+ if (this.revokeBtn) this.revokeBtn.style.display = show ? '' : 'none';
538
+ };
539
+
540
+ CookiePopup.prototype.revokeChoice = function(preventOpen) {
541
+ this.options.enabled = true;
542
+ this.clearStatus();
543
+
544
+ this.options.onRevokeChoice.call(this);
545
+
546
+ if (!preventOpen) {
547
+ this.autoOpen();
548
+ }
549
+ };
550
+
551
+ // returns true if the cookie has a valid value
552
+ CookiePopup.prototype.hasAnswered = function(options) {
553
+ return Object.keys(cc.status).indexOf(this.getStatus()) >= 0;
554
+ };
555
+
556
+ // returns true if the cookie indicates that consent has been given
557
+ CookiePopup.prototype.hasConsented = function(options) {
558
+ var val = this.getStatus();
559
+ return val == cc.status.allow || val == cc.status.dismiss;
560
+ };
561
+
562
+ // opens the popup if no answer has been given
563
+ CookiePopup.prototype.autoOpen = function(options) {
564
+ !this.hasAnswered() && this.options.enabled && this.open();
565
+ };
566
+
567
+ CookiePopup.prototype.setStatus = function(status) {
568
+ var c = this.options.cookie;
569
+ var value = util.getCookie(c.name);
570
+ var chosenBefore = Object.keys(cc.status).indexOf(value) >= 0;
571
+
572
+ // if `status` is valid
573
+ if (Object.keys(cc.status).indexOf(status) >= 0) {
574
+ util.setCookie(c.name, status, c.expiryDays, c.domain, c.path);
575
+
576
+ this.options.onStatusChange.call(this, status, chosenBefore);
577
+ } else {
578
+ this.clearStatus();
579
+ }
580
+ };
581
+
582
+ CookiePopup.prototype.getStatus = function() {
583
+ return util.getCookie(this.options.cookie.name);
584
+ };
585
+
586
+ CookiePopup.prototype.clearStatus = function() {
587
+ var c = this.options.cookie;
588
+ util.setCookie(c.name, '', -1, c.domain, c.path);
589
+ };
590
+
591
+ // This needs to be called after 'fadeIn'. This is the code that actually causes the fadeIn to work
592
+ // There is a good reason why it's called in a timeout. Read 'fadeIn';
593
+ function afterFadeIn(el) {
594
+ this.openingTimeout = null;
595
+ util.removeClass(el, 'cc-invisible');
596
+ }
597
+
598
+ // This is called on 'transitionend' (only on the transition of the fadeOut). That's because after we've faded out, we need to
599
+ // set the display to 'none' (so there aren't annoying invisible popups all over the page). If for whenever reason this function
600
+ // is not called (lack of support), the open/close mechanism will still work.
601
+ function afterFadeOut(el) {
602
+ el.style.display = 'none'; // after close and before open, the display should be none
603
+ el.removeEventListener(cc.transitionEnd, this.afterTransition);
604
+ this.afterTransition = null;
605
+ }
606
+
607
+ // this function calls the `onComplete` hook and returns true (if needed) and returns false otherwise
608
+ function checkCallbackHooks() {
609
+ var complete = this.options.onInitialise.bind(this);
610
+
611
+ if (!window.navigator.cookieEnabled) {
612
+ complete(cc.status.deny);
613
+ return true;
614
+ }
615
+
616
+ if (window.CookiesOK || window.navigator.CookiesOK) {
617
+ complete(cc.status.allow);
618
+ return true;
619
+ }
620
+
621
+ var allowed = Object.keys(cc.status);
622
+ var answer = this.getStatus();
623
+ var match = allowed.indexOf(answer) >= 0;
624
+
625
+ if (match) {
626
+ complete(answer);
627
+ }
628
+ return match;
629
+ }
630
+
631
+ function getPositionClasses() {
632
+ var positions = this.options.position.split('-'); // top, bottom, left, right
633
+ var classes = [];
634
+
635
+ // top, left, right, bottom
636
+ positions.forEach(function(cur) {
637
+ classes.push('cc-' + cur);
638
+ });
639
+
640
+ return classes;
641
+ }
642
+
643
+ function getPopupClasses() {
644
+ var opts = this.options;
645
+ var positionStyle = (opts.position == 'top' || opts.position == 'bottom') ? 'banner' : 'floating';
646
+
647
+ if (util.isMobile()) {
648
+ positionStyle = 'floating';
649
+ }
650
+
651
+ var classes = [
652
+ 'cc-' + positionStyle, // floating or banner
653
+ 'cc-type-' + opts.type, // add the compliance type
654
+ 'cc-theme-' + opts.theme, // add the theme
655
+ ];
656
+
657
+ if (opts.static) {
658
+ classes.push('cc-static');
659
+ }
660
+
661
+ classes.push.apply(classes, getPositionClasses.call(this));
662
+
663
+ // we only add extra styles if `palette` has been set to a valid value
664
+ var didAttach = attachCustomPalette.call(this, this.options.palette);
665
+
666
+ // if we override the palette, add the class that enables this
667
+ if (this.customStyleSelector) {
668
+ classes.push(this.customStyleSelector);
669
+ }
670
+
671
+ return classes;
672
+ }
673
+
674
+ function getPopupInnerMarkup() {
675
+ var interpolated = {};
676
+ var opts = this.options;
677
+
678
+ // removes link if showLink is false
679
+ if (!opts.showLink) {
680
+ opts.elements.link = '';
681
+ opts.elements.messagelink = opts.elements.message;
682
+ }
683
+
684
+ Object.keys(opts.elements).forEach(function(prop) {
685
+ interpolated[prop] = util.interpolateString(opts.elements[prop], function(name) {
686
+ var str = opts.content[name];
687
+ return (name && typeof str == 'string' && str.length) ? str : '';
688
+ })
689
+ });
690
+
691
+ // checks if the type is valid and defaults to info if it's not
692
+ var complianceType = opts.compliance[opts.type];
693
+ if (!complianceType) {
694
+ complianceType = opts.compliance.info;
695
+ }
696
+
697
+ // build the compliance types from the already interpolated `elements`
698
+ interpolated.compliance = util.interpolateString(complianceType, function(name) {
699
+ return interpolated[name];
700
+ });
701
+
702
+ // checks if the layout is valid and defaults to basic if it's not
703
+ var layout = opts.layouts[opts.layout];
704
+ if (!layout) {
705
+ layout = opts.layouts.basic;
706
+ }
707
+
708
+ return util.interpolateString(layout, function(match) {
709
+ return interpolated[match];
710
+ });
711
+ }
712
+
713
+ function appendMarkup(markup) {
714
+ var opts = this.options;
715
+ var div = document.createElement('div');
716
+ var cont = (opts.container && opts.container.nodeType === 1) ? opts.container : document.body;
717
+
718
+ div.innerHTML = markup;
719
+
720
+ var el = div.children[0];
721
+
722
+ el.style.display = 'none';
723
+
724
+ if (util.hasClass(el, 'cc-window') && cc.hasTransition) {
725
+ util.addClass(el, 'cc-invisible');
726
+ }
727
+
728
+ // save ref to the function handle so we can unbind it later
729
+ this.onButtonClick = handleButtonClick.bind(this);
730
+
731
+ el.addEventListener('click', this.onButtonClick);
732
+
733
+ if (opts.autoAttach) {
734
+ if (!cont.firstChild) {
735
+ cont.appendChild(el);
736
+ } else {
737
+ cont.insertBefore(el, cont.firstChild)
738
+ }
739
+ }
740
+
741
+ return el;
742
+ }
743
+
744
+ function handleButtonClick(event) {
745
+ var targ = event.target;
746
+ if (util.hasClass(targ, 'cc-btn')) {
747
+
748
+ var matches = targ.className.match(new RegExp("\\bcc-(" + __allowedStatuses.join('|') + ")\\b"));
749
+ var match = (matches && matches[1]) || false;
750
+
751
+ if (match) {
752
+ this.setStatus(match);
753
+ this.close(true);
754
+ }
755
+ }
756
+ if (util.hasClass(targ, 'cc-close')) {
757
+ this.setStatus(cc.status.dismiss);
758
+ this.close(true);
759
+ }
760
+ if (util.hasClass(targ, 'cc-revoke')) {
761
+ this.revokeChoice();
762
+ }
763
+ }
764
+
765
+ // I might change this function to use inline styles. I originally chose a stylesheet because I could select many elements with a
766
+ // single rule (something that happened a lot), the apps has changed slightly now though, so inline styles might be more applicable.
767
+ function attachCustomPalette(palette) {
768
+ var hash = util.hash(JSON.stringify(palette));
769
+ var selector = 'cc-color-override-' + hash;
770
+ var isValid = util.isPlainObject(palette);
771
+
772
+ this.customStyleSelector = isValid ? selector : null;
773
+
774
+ if (isValid) {
775
+ addCustomStyle(hash, palette, '.' + selector);
776
+ }
777
+ return isValid;
778
+ }
779
+
780
+ function addCustomStyle(hash, palette, prefix) {
781
+
782
+ // only add this if a style like it doesn't exist
783
+ if (cc.customStyles[hash]) {
784
+ // custom style already exists, so increment the reference count
785
+ ++cc.customStyles[hash].references;
786
+ return;
787
+ }
788
+
789
+ var colorStyles = {};
790
+ var popup = palette.popup;
791
+ var button = palette.button;
792
+ var highlight = palette.highlight;
793
+
794
+ // needs background colour, text and link will be set to black/white if not specified
795
+ if (popup) {
796
+ // assumes popup.background is set
797
+ popup.text = popup.text ? popup.text : util.getContrast(popup.background);
798
+ popup.link = popup.link ? popup.link : popup.text;
799
+ colorStyles[prefix + '.cc-window'] = [
800
+ 'color: ' + popup.text,
801
+ 'background-color: ' + popup.background
802
+ ];
803
+ colorStyles[prefix + '.cc-revoke'] = [
804
+ 'color: ' + popup.text,
805
+ 'background-color: ' + popup.background
806
+ ];
807
+ colorStyles[prefix + ' .cc-link,' + prefix + ' .cc-link:active,' + prefix + ' .cc-link:visited'] = [
808
+ 'color: ' + popup.link
809
+ ];
810
+
811
+ if (button) {
812
+ // assumes button.background is set
813
+ button.text = button.text ? button.text : util.getContrast(button.background);
814
+ button.border = button.border ? button.border : 'transparent';
815
+ colorStyles[prefix + ' .cc-btn'] = [
816
+ 'color: ' + button.text,
817
+ 'border-color: ' + button.border,
818
+ 'background-color: ' + button.background
819
+ ];
820
+
821
+ if(button.background != 'transparent')
822
+ colorStyles[prefix + ' .cc-btn:hover, ' + prefix + ' .cc-btn:focus'] = [
823
+ 'background-color: ' + getHoverColour(button.background)
824
+ ];
825
+
826
+ if (highlight) {
827
+ //assumes highlight.background is set
828
+ highlight.text = highlight.text ? highlight.text : util.getContrast(highlight.background);
829
+ highlight.border = highlight.border ? highlight.border : 'transparent';
830
+ colorStyles[prefix + ' .cc-highlight .cc-btn:first-child'] = [
831
+ 'color: ' + highlight.text,
832
+ 'border-color: ' + highlight.border,
833
+ 'background-color: ' + highlight.background
834
+ ];
835
+ } else {
836
+ // sets highlight text color to popup text. background and border are transparent by default.
837
+ colorStyles[prefix + ' .cc-highlight .cc-btn:first-child'] = [
838
+ 'color: ' + popup.text
839
+ ];
840
+ }
841
+ }
842
+
843
+ }
844
+
845
+ // this will be interpretted as CSS. the key is the selector, and each array element is a rule
846
+ var style = document.createElement('style');
847
+ document.head.appendChild(style);
848
+
849
+ // custom style doesn't exist, so we create it
850
+ cc.customStyles[hash] = {
851
+ references: 1,
852
+ element: style.sheet
853
+ };
854
+
855
+ var ruleIndex = -1;
856
+ for (var prop in colorStyles) {
857
+ if (colorStyles.hasOwnProperty(prop)) {
858
+ style.sheet.insertRule(prop + '{' + colorStyles[prop].join(';') + '}', ++ruleIndex);
859
+ }
860
+ }
861
+ }
862
+
863
+ function getHoverColour(hex) {
864
+ hex = util.normaliseHex(hex);
865
+ // for black buttons
866
+ if (hex == '000000') {
867
+ return '#222';
868
+ }
869
+ return util.getLuminance(hex);
870
+ }
871
+
872
+ function removeCustomStyle(palette) {
873
+ if (util.isPlainObject(palette)) {
874
+ var hash = util.hash(JSON.stringify(palette));
875
+ var customStyle = cc.customStyles[hash];
876
+ if (customStyle && !--customStyle.references) {
877
+ var styleNode = customStyle.element.ownerNode;
878
+ if (styleNode && styleNode.parentNode) {
879
+ styleNode.parentNode.removeChild(styleNode);
880
+ }
881
+ cc.customStyles[hash] = null;
882
+ }
883
+ }
884
+ }
885
+
886
+ function arrayContainsMatches(array, search) {
887
+ for (var i = 0, l = array.length; i < l; ++i) {
888
+ var str = array[i];
889
+ // if regex matches or string is equal, return true
890
+ if ((str instanceof RegExp && str.test(search)) ||
891
+ (typeof str == 'string' && str.length && str === search)) {
892
+ return true;
893
+ }
894
+ }
895
+ return false;
896
+ }
897
+
898
+ function applyAutoDismiss() {
899
+ var setStatus = this.setStatus.bind(this);
900
+
901
+ var delay = this.options.dismissOnTimeout;
902
+ if (typeof delay == 'number' && delay >= 0) {
903
+ this.dismissTimeout = window.setTimeout(function() {
904
+ setStatus(cc.status.dismiss);
905
+ }, Math.floor(delay));
906
+ }
907
+
908
+ var scrollRange = this.options.dismissOnScroll;
909
+ if (typeof scrollRange == 'number' && scrollRange >= 0) {
910
+ var onWindowScroll = function(evt) {
911
+ if (window.pageYOffset > Math.floor(scrollRange)) {
912
+ setStatus(cc.status.dismiss);
913
+
914
+ window.removeEventListener('scroll', onWindowScroll);
915
+ this.onWindowScroll = null;
916
+ }
917
+ };
918
+
919
+ this.onWindowScroll = onWindowScroll;
920
+ window.addEventListener('scroll', onWindowScroll);
921
+ }
922
+ }
923
+
924
+ function applyRevokeButton() {
925
+ // revokable is true if advanced compliance is selected
926
+ if (this.options.type != 'info') this.options.revokable = true;
927
+ // animateRevokable false for mobile devices
928
+ if (util.isMobile()) this.options.animateRevokable = false;
929
+
930
+ if (this.options.revokable) {
931
+ var classes = getPositionClasses.call(this);
932
+ if (this.options.animateRevokable) {
933
+ classes.push('cc-animate');
934
+ }
935
+ if (this.customStyleSelector) {
936
+ classes.push(this.customStyleSelector)
937
+ }
938
+ var revokeBtn = this.options.revokeBtn.replace('{{classes}}', classes.join(' '));
939
+ this.revokeBtn = appendMarkup.call(this, revokeBtn);
940
+
941
+ var btn = this.revokeBtn;
942
+ if (this.options.animateRevokable) {
943
+ var wait = false;
944
+ var onMouseMove = util.throttle(function(evt) {
945
+ var active = false;
946
+ var minY = 20;
947
+ var maxY = (window.innerHeight - 20);
948
+
949
+ if (util.hasClass(btn, 'cc-top') && evt.clientY < minY) active = true;
950
+ if (util.hasClass(btn, 'cc-bottom') && evt.clientY > maxY) active = true;
951
+
952
+ if (active) {
953
+ if (!util.hasClass(btn, 'cc-active')) {
954
+ util.addClass(btn, 'cc-active');
955
+ }
956
+ } else {
957
+ if (util.hasClass(btn, 'cc-active')) {
958
+ util.removeClass(btn, 'cc-active');
959
+ }
960
+ }
961
+ }, 200);
962
+
963
+ this.onMouseMove = onMouseMove;
964
+ window.addEventListener('mousemove', onMouseMove);
965
+ }
966
+ }
967
+ }
968
+
969
+ return CookiePopup
970
+ }());
971
+
972
+ cc.Location = (function() {
973
+
974
+ // An object containing all the location services we have already set up.
975
+ // When using a service, it could either return a data structure in plain text (like a JSON object) or an executable script
976
+ // When the response needs to be executed by the browser, then `isScript` must be set to true, otherwise it won't work.
977
+
978
+ // When the service uses a script, the chances are that you'll have to use the script to make additional requests. In these
979
+ // cases, the services `callback` property is called with a `done` function. When performing async operations, this must be called
980
+ // with the data (or Error), and `cookieconsent.locate` will take care of the rest
981
+ var defaultOptions = {
982
+
983
+ // The default timeout is 5 seconds. This is mainly needed to catch JSONP requests that error.
984
+ // Otherwise there is no easy way to catch JSONP errors. That means that if a JSONP fails, the
985
+ // app will take `timeout` milliseconds to react to a JSONP network error.
986
+ timeout: 5000,
987
+
988
+ // the order that services will be attempted in
989
+ services: [
990
+ 'freegeoip',
991
+ 'ipinfo',
992
+ 'maxmind'
993
+
994
+ /*
995
+
996
+ // 'ipinfodb' requires some options, so we define it using an object
997
+ // this object will be passed to the function that defines the service
998
+
999
+ {
1000
+ name: 'ipinfodb',
1001
+ interpolateUrl: {
1002
+ // obviously, this is a fake key
1003
+ api_key: 'vOgI3748dnIytIrsJcxS7qsDf6kbJkE9lN4yEDrXAqXcKUNvjjZPox3ekXqmMMld'
1004
+ },
1005
+ },
1006
+
1007
+ // as well as defining an object, you can define a function that returns an object
1008
+
1009
+ function () {
1010
+ return {name: 'ipinfodb'};
1011
+ },
1012
+
1013
+ */
1014
+ ],
1015
+
1016
+ serviceDefinitions: {
1017
+
1018
+ freegeoip: function() {
1019
+ return {
1020
+ // This service responds with JSON, but they do not have CORS set, so we must use JSONP and provide a callback
1021
+ // The `{callback}` is automatically rewritten by the tool
1022
+ url: '//freegeoip.net/json/?callback={callback}',
1023
+ isScript: true, // this is JSONP, therefore we must set it to run as a script
1024
+ callback: function(done, response) {
1025
+ try{
1026
+ var json = JSON.parse(response);
1027
+ return json.error ? toError(json) : {
1028
+ code: json.country_code
1029
+ };
1030
+ } catch (err) {
1031
+ return toError({error: 'Invalid response ('+err+')'});
1032
+ }
1033
+ }
1034
+ }
1035
+ },
1036
+
1037
+ ipinfo: function() {
1038
+ return {
1039
+ // This service responds with JSON, so we simply need to parse it and return the country code
1040
+ url: '//ipinfo.io',
1041
+ headers: ['Accept: application/json'],
1042
+ callback: function(done, response) {
1043
+ try{
1044
+ var json = JSON.parse(response);
1045
+ return json.error ? toError(json) : {
1046
+ code: json.country
1047
+ };
1048
+ } catch (err) {
1049
+ return toError({error: 'Invalid response ('+err+')'});
1050
+ }
1051
+ }
1052
+ }
1053
+ },
1054
+
1055
+ // This service requires an option to define `key`. Options are proived using objects or functions
1056
+ ipinfodb: function(options) {
1057
+ return {
1058
+ // This service responds with JSON, so we simply need to parse it and return the country code
1059
+ url: '//api.ipinfodb.com/v3/ip-country/?key={api_key}&format=json&callback={callback}',
1060
+ isScript: true, // this is JSONP, therefore we must set it to run as a script
1061
+ callback: function(done, response) {
1062
+ try{
1063
+ var json = JSON.parse(response);
1064
+ return json.statusCode == 'ERROR' ? toError({error: json.statusMessage}) : {
1065
+ code: json.countryCode
1066
+ };
1067
+ } catch (err) {
1068
+ return toError({error: 'Invalid response ('+err+')'});
1069
+ }
1070
+ }
1071
+ }
1072
+ },
1073
+
1074
+ maxmind: function() {
1075
+ return {
1076
+ // This service responds with a JavaScript file which defines additional functionality. Once loaded, we must
1077
+ // make an additional AJAX call. Therefore we provide a `done` callback that can be called asynchronously
1078
+ url: '//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js',
1079
+ isScript: true, // this service responds with a JavaScript file, so it must be run as a script
1080
+ callback: function(done) {
1081
+ // if everything went okay then `geoip2` WILL be defined
1082
+ if (!window.geoip2) {
1083
+ done(new Error('Unexpected response format. The downloaded script should have exported `geoip2` to the global scope'));
1084
+ return;
1085
+ }
1086
+
1087
+ geoip2.country(function(location) {
1088
+ try {
1089
+ done({
1090
+ code: location.country.iso_code
1091
+ });
1092
+ } catch (err) {
1093
+ done(toError(err));
1094
+ }
1095
+ }, function(err) {
1096
+ done(toError(err));
1097
+ });
1098
+
1099
+ // We can't return anything, because we need to wait for the second AJAX call to return.
1100
+ // Then we can 'complete' the service by passing data or an error to the `done` callback.
1101
+ }
1102
+ }
1103
+ },
1104
+ },
1105
+ };
1106
+
1107
+ function Location(options) {
1108
+ // Set up options
1109
+ util.deepExtend(this.options = {}, defaultOptions);
1110
+
1111
+ if (util.isPlainObject(options)) {
1112
+ util.deepExtend(this.options, options);
1113
+ }
1114
+
1115
+ this.currentServiceIndex = -1; // the index (in options) of the service we're currently using
1116
+ }
1117
+
1118
+ Location.prototype.getNextService = function() {
1119
+ var service;
1120
+
1121
+ do {
1122
+ service = this.getServiceByIdx(++this.currentServiceIndex);
1123
+ } while (this.currentServiceIndex < this.options.services.length && !service);
1124
+
1125
+ return service;
1126
+ };
1127
+
1128
+ Location.prototype.getServiceByIdx = function(idx) {
1129
+ // This can either be the name of a default locationService, or a function.
1130
+ var serviceOption = this.options.services[idx];
1131
+
1132
+ // If it's a string, use one of the location services.
1133
+ if (typeof serviceOption === 'function') {
1134
+ var dynamicOpts = serviceOption();
1135
+ if (dynamicOpts.name) {
1136
+ util.deepExtend(dynamicOpts, this.options.serviceDefinitions[dynamicOpts.name](dynamicOpts));
1137
+ }
1138
+ return dynamicOpts;
1139
+ }
1140
+
1141
+ // If it's a string, use one of the location services.
1142
+ if (typeof serviceOption === 'string') {
1143
+ return this.options.serviceDefinitions[serviceOption]();
1144
+ }
1145
+
1146
+ // If it's an object, assume {name: 'ipinfo', ...otherOptions}
1147
+ // Allows user to pass in API keys etc.
1148
+ if (util.isPlainObject(serviceOption)) {
1149
+ return this.options.serviceDefinitions[serviceOption.name](serviceOption);
1150
+ }
1151
+
1152
+ return null;
1153
+ };
1154
+
1155
+ // This runs the service located at index `currentServiceIndex`.
1156
+ // If the service fails, `runNextServiceOnError` will continue trying each service until all fail, or one completes successfully
1157
+ Location.prototype.locate = function(complete, error) {
1158
+ var service = this.getNextService();
1159
+
1160
+ if (!service) {
1161
+ error(new Error('No services to run'));
1162
+ return;
1163
+ }
1164
+
1165
+ this.callbackComplete = complete;
1166
+ this.callbackError = error;
1167
+
1168
+ this.runService(service, this.runNextServiceOnError.bind(this));
1169
+ };
1170
+
1171
+ // Potentially adds a callback to a url for jsonp.
1172
+ Location.prototype.setupUrl = function(service) {
1173
+ var serviceOpts = this.getCurrentServiceOpts();
1174
+ return service.url.replace(/\{(.*?)\}/g, function(_, param) {
1175
+ if (param === 'callback') {
1176
+ var tempName = 'callback' + Date.now();
1177
+ window[tempName] = function(res) {
1178
+ service.__JSONP_DATA = JSON.stringify(res);
1179
+ }
1180
+ return tempName;
1181
+ }
1182
+ if (param in serviceOpts.interpolateUrl) {
1183
+ return serviceOpts.interpolateUrl[param];
1184
+ }
1185
+ });
1186
+ };
1187
+
1188
+ // requires a `service` object that defines at least a `url` and `callback`
1189
+ Location.prototype.runService = function(service, complete) {
1190
+ var self = this;
1191
+
1192
+ // basic check to ensure it resembles a `service`
1193
+ if (!service || !service.url || !service.callback) {
1194
+ return;
1195
+ }
1196
+
1197
+ // we call either `getScript` or `makeAsyncRequest` depending on the type of resource
1198
+ var requestFunction = service.isScript ? getScript : makeAsyncRequest;
1199
+
1200
+ var url = this.setupUrl(service);
1201
+
1202
+ // both functions have similar signatures so we can pass the same arguments to both
1203
+ requestFunction(url, function(xhr) {
1204
+ // if `!xhr`, then `getScript` function was used, so there is no response text
1205
+ var responseText = xhr ? xhr.responseText : '';
1206
+
1207
+ // if the resource is a script, then this function is called after the script has been run.
1208
+ // if the script is JSONP, then a time defined function `callback_{Date.now}` has already
1209
+ // been called (as the JSONP callback). This callback sets the __JSONP_DATA property
1210
+ if (service.__JSONP_DATA) {
1211
+ responseText = service.__JSONP_DATA;
1212
+ delete service.__JSONP_DATA;
1213
+ }
1214
+
1215
+ // call the service callback with the response text (so it can parse the response)
1216
+ self.runServiceCallback.call(self, complete, service, responseText);
1217
+
1218
+ }, this.options.timeout, service.data, service.headers);
1219
+
1220
+ // `service.data` and `service.headers` are optional (they only count if `!service.isScript` anyway)
1221
+ };
1222
+
1223
+ // The service request has run (and possibly has a `responseText`) [no `responseText` if `isScript`]
1224
+ // We need to run its callback which determines if its successful or not
1225
+ // `complete` is called on success or failure
1226
+ Location.prototype.runServiceCallback = function(complete, service, responseText) {
1227
+ var self = this;
1228
+ // this is the function that is called if the service uses the async callback in its handler method
1229
+ var serviceResultHandler = function (asyncResult) {
1230
+ // if `result` is a valid value, then this function shouldn't really run
1231
+ // even if it is called by `service.callback`
1232
+ if (!result) {
1233
+ self.onServiceResult.call(self, complete, asyncResult)
1234
+ }
1235
+ };
1236
+
1237
+ // the function `service.callback` will either extract a country code from `responseText` and return it (in `result`)
1238
+ // or (if it has to make additional requests) it will call a `done` callback with the country code when it is ready
1239
+ var result = service.callback(serviceResultHandler, responseText);
1240
+
1241
+ if (result) {
1242
+ this.onServiceResult.call(this, complete, result);
1243
+ }
1244
+ };
1245
+
1246
+ // This is called with the `result` from `service.callback` regardless of how it provided that result (sync or async).
1247
+ // `result` will be whatever is returned from `service.callback`. A service callback should provide an object with data
1248
+ Location.prototype.onServiceResult = function(complete, result) {
1249
+ // convert result to nodejs style async callback
1250
+ if (result instanceof Error || (result && result.error)) {
1251
+ complete.call(this, result, null);
1252
+ } else {
1253
+ complete.call(this, null, result);
1254
+ }
1255
+ };
1256
+
1257
+ // if `err` is set, the next service handler is called
1258
+ // if `err` is null, the `onComplete` handler is called with `data`
1259
+ Location.prototype.runNextServiceOnError = function(err, data) {
1260
+ if (err) {
1261
+ this.logError(err);
1262
+
1263
+ var nextService = this.getNextService();
1264
+
1265
+ if (nextService) {
1266
+ this.runService(nextService, this.runNextServiceOnError.bind(this));
1267
+ } else {
1268
+ this.completeService.call(this, this.callbackError, new Error('All services failed'));
1269
+ }
1270
+ } else {
1271
+ this.completeService.call(this, this.callbackComplete, data);
1272
+ }
1273
+ };
1274
+
1275
+ Location.prototype.getCurrentServiceOpts = function() {
1276
+ var val = this.options.services[this.currentServiceIndex];
1277
+
1278
+ if (typeof val == 'string') {
1279
+ return {name: val};
1280
+ }
1281
+
1282
+ if (typeof val == 'function') {
1283
+ return val();
1284
+ }
1285
+
1286
+ if (util.isPlainObject(val)) {
1287
+ return val;
1288
+ }
1289
+
1290
+ return {};
1291
+ };
1292
+
1293
+ // calls the `onComplete` callback after resetting the `currentServiceIndex`
1294
+ Location.prototype.completeService = function(fn, data) {
1295
+ this.currentServiceIndex = -1;
1296
+
1297
+ fn && fn(data);
1298
+ };
1299
+
1300
+ Location.prototype.logError = function (err) {
1301
+ var idx = this.currentServiceIndex;
1302
+ var service = this.getServiceByIdx(idx);
1303
+
1304
+ console.error('The service[' + idx + '] (' + service.url + ') responded with the following error', err);
1305
+ };
1306
+
1307
+ function getScript(url, callback, timeout) {
1308
+ var timeoutIdx, s = document.createElement('script');
1309
+
1310
+ s.type = 'text/' + (url.type || 'javascript');
1311
+ s.src = url.src || url;
1312
+ s.async = false;
1313
+
1314
+ s.onreadystatechange = s.onload = function() {
1315
+ // this code handles two scenarios, whether called by onload or onreadystatechange
1316
+ var state = s.readyState;
1317
+
1318
+ clearTimeout(timeoutIdx);
1319
+
1320
+ if (!callback.done && (!state || /loaded|complete/.test(state))) {
1321
+ callback.done = true;
1322
+ callback();
1323
+ s.onreadystatechange = s.onload = null;
1324
+ }
1325
+ };
1326
+
1327
+ document.body.appendChild(s);
1328
+
1329
+ // You can't catch JSONP Errors, because it's handled by the script tag
1330
+ // one way is to use a timeout
1331
+ timeoutIdx = setTimeout(function () {
1332
+ callback.done = true;
1333
+ callback();
1334
+ s.onreadystatechange = s.onload = null;
1335
+ }, timeout);
1336
+ }
1337
+
1338
+ function makeAsyncRequest(url, onComplete, timeout, postData, requestHeaders) {
1339
+ var xhr = new(window.XMLHttpRequest || window.ActiveXObject)('MSXML2.XMLHTTP.3.0');
1340
+
1341
+ xhr.open(postData ? 'POST' : 'GET', url, 1);
1342
+
1343
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1344
+ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
1345
+
1346
+ if (Array.isArray(requestHeaders)) {
1347
+ for (var i = 0, l = requestHeaders.length; i < l; ++i) {
1348
+ var split = requestHeaders[i].split(':', 2)
1349
+ xhr.setRequestHeader(split[0].replace(/^\s+|\s+$/g, ''), split[1].replace(/^\s+|\s+$/g, ''));
1350
+ }
1351
+ }
1352
+
1353
+ if (typeof onComplete == 'function') {
1354
+ xhr.onreadystatechange = function() {
1355
+ if (xhr.readyState > 3) {
1356
+ onComplete(xhr);
1357
+ }
1358
+ };
1359
+ }
1360
+
1361
+ xhr.send(postData);
1362
+ }
1363
+
1364
+ function toError(obj) {
1365
+ return new Error('Error [' + (obj.code || 'UNKNOWN') + ']: ' + obj.error);
1366
+ }
1367
+
1368
+ return Location;
1369
+ }());
1370
+
1371
+ cc.Law = (function() {
1372
+
1373
+ var defaultOptions = {
1374
+ // Make this false if you want to disable all regional overrides for settings.
1375
+ // If true, options can differ by country, depending on their cookie law.
1376
+ // It does not affect hiding the popup for countries that do not have cookie law.
1377
+ regionalLaw: true,
1378
+
1379
+ // countries that enforce some version of a cookie law
1380
+ hasLaw: ['AT', 'BE', 'BG', 'HR', 'CZ', 'CY', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'SK', 'SI', 'ES', 'SE', 'GB', 'UK'],
1381
+
1382
+ // countries that say that all cookie consent choices must be revokable (a user must be able too change their mind)
1383
+ revokable: ['HR', 'CY', 'DK', 'EE', 'FR', 'DE', 'LV', 'LT', 'NL', 'PT', 'ES'],
1384
+
1385
+ // countries that say that a person can only "consent" if the explicitly click on "I agree".
1386
+ // in these countries, consent cannot be implied via a timeout or by scrolling down the page
1387
+ explicitAction: ['HR', 'IT', 'ES'],
1388
+ };
1389
+
1390
+ function Law(options) {
1391
+ this.initialise.apply(this, arguments);
1392
+ }
1393
+
1394
+ Law.prototype.initialise = function(options) {
1395
+ // set options back to default options
1396
+ util.deepExtend(this.options = {}, defaultOptions);
1397
+
1398
+ // merge in user options
1399
+ if (util.isPlainObject(options)) {
1400
+ util.deepExtend(this.options, options);
1401
+ }
1402
+ };
1403
+
1404
+ Law.prototype.get = function(countryCode) {
1405
+ var opts = this.options;
1406
+ return {
1407
+ hasLaw: opts.hasLaw.indexOf(countryCode) >= 0,
1408
+ revokable: opts.revokable.indexOf(countryCode) >= 0,
1409
+ explicitAction: opts.explicitAction.indexOf(countryCode) >= 0,
1410
+ };
1411
+ };
1412
+
1413
+ Law.prototype.applyLaw = function(options, countryCode) {
1414
+ var country = this.get(countryCode);
1415
+
1416
+ if (!country.hasLaw) {
1417
+ // The country has no cookie law
1418
+ options.enabled = false;
1419
+ }
1420
+
1421
+ if (this.options.regionalLaw) {
1422
+ if (country.revokable) {
1423
+ // We must provide an option to revoke consent at a later time
1424
+ options.revokable = true;
1425
+ }
1426
+
1427
+ if (country.explicitAction) {
1428
+ // The user must explicitly click the consent button
1429
+ options.dismissOnScroll = false;
1430
+ options.dismissOnTimeout = false;
1431
+ }
1432
+ }
1433
+ return options;
1434
+ };
1435
+
1436
+ return Law;
1437
+ }());
1438
+
1439
+ // This function initialises the app by combining the use of the Popup, Locator and Law modules
1440
+ // You can string together these three modules yourself however you want, by writing a new function.
1441
+ cc.initialise = function(options, complete, error) {
1442
+ var law = new cc.Law(options.law);
1443
+
1444
+ if (!complete) complete = function() {};
1445
+ if (!error) error = function() {};
1446
+
1447
+ cc.getCountryCode(options, function(result) {
1448
+ // don't need the law or location options anymore
1449
+ delete options.law;
1450
+ delete options.location;
1451
+
1452
+ if (result.code) {
1453
+ options = law.applyLaw(options, result.code);
1454
+ }
1455
+
1456
+ complete(new cc.Popup(options));
1457
+ }, function(err) {
1458
+ // don't need the law or location options anymore
1459
+ delete options.law;
1460
+ delete options.location;
1461
+
1462
+ error(err, new cc.Popup(options));
1463
+ });
1464
+ };
1465
+
1466
+ // This function tries to find your current location. It either grabs it from a hardcoded option in
1467
+ // `options.law.countryCode`, or attempts to make a location service request. This function accepts
1468
+ // options (which can configure the `law` and `location` modules) and fires a callback with which
1469
+ // passes an object `{code: countryCode}` as the first argument (which can have undefined properties)
1470
+ cc.getCountryCode = function(options, complete, error) {
1471
+ if (options.law && options.law.countryCode) {
1472
+ complete({
1473
+ code: options.law.countryCode
1474
+ });
1475
+ return;
1476
+ }
1477
+ if (options.location) {
1478
+ var locator = new cc.Location(options.location);
1479
+ locator.locate(function(serviceResult) {
1480
+ complete(serviceResult || {});
1481
+ }, error);
1482
+ return;
1483
+ }
1484
+ complete({});
1485
+ };
1486
+
1487
+ // export utils (no point in hiding them, so we may as well expose them)
1488
+ cc.utils = util;
1489
+
1490
+ // prevent this code from being run twice
1491
+ cc.hasInitialised = true;
1492
+
1493
+ window.cookieconsent = cc;
1494
+
1495
+ }(window.cookieconsent || {}));
1496
+
1497
+
1498
+ window.addEventListener("load", function(){
1499
+ window.cookieconsent.initialise({
1500
+ "palette": {
1501
+ },
1502
+ "theme": "classic",
1503
+ "position": "bottom-right"
1504
+ })});