1/* 2 * Based on Cookie Consent by silktide 3 */ 4 5(function () { 6 // Stop from running again, if accidently included more than once. 7 if (window.hasCookieConsent) return; 8 window.hasCookieConsent = true; 9 10 /* 11 Constants 12 */ 13 14 // Client variable which may be present containing options to override with 15 var OPTIONS_VARIABLE = 'cookieconsent_options'; 16 17 // Change cookie consent options on the fly. 18 var OPTIONS_UPDATER = 'update_cookieconsent_options'; 19 20 // Name of cookie to be set when dismissed 21 var DISMISSED_COOKIE = 'cookieconsent_dismissed'; 22 23 // The path to built in themes (s3 bucket) 24 var THEME_BUCKET_PATH = '//s3.amazonaws.com/cc.silktide.com/'; 25 26 // No point going further if they've already dismissed. 27 if (document.cookie.indexOf(DISMISSED_COOKIE) > -1) { 28 return; 29 } 30 31 // IE8... 32 if (typeof String.prototype.trim !== 'function') { 33 String.prototype.trim = function () { 34 return this.replace(/^\s+|\s+$/g, ''); 35 }; 36 } 37 38 /* 39 Helper methods 40 */ 41 var Util = { 42 isArray: function (obj) { 43 var proto = Object.prototype.toString.call(obj); 44 return proto == '[object Array]'; 45 }, 46 47 isObject: function (obj) { 48 return Object.prototype.toString.call(obj) == '[object Object]'; 49 }, 50 51 each: function (arr, callback, /* optional: */ context, force) { 52 if (Util.isObject(arr) && !force) { 53 for (var key in arr) { 54 if (arr.hasOwnProperty(key)) { 55 callback.call(context, arr[key], key, arr); 56 } 57 } 58 } else { 59 for (var i = 0, ii = arr.length; i < ii; i++) { 60 callback.call(context, arr[i], i, arr); 61 } 62 } 63 }, 64 65 merge: function (obj1, obj2) { 66 if (!obj1) return; 67 Util.each(obj2, function (val, key) { 68 if (Util.isObject(val) && Util.isObject(obj1[key])) { 69 Util.merge(obj1[key], val); 70 } else { 71 obj1[key] = val; 72 } 73 }); 74 }, 75 76 bind: function (func, context) { 77 return function () { 78 return func.apply(context, arguments); 79 }; 80 }, 81 82 /* 83 find a property based on a . separated path. 84 i.e. queryObject({details: {name: 'Adam'}}, 'details.name') // -> 'Adam' 85 returns null if not found 86 */ 87 queryObject: function (object, query) { 88 var queryPart; 89 var i = 0; 90 var head = object; 91 query = query.split('.'); 92 while ( 93 (queryPart = query[i++]) && 94 head.hasOwnProperty(queryPart) && 95 (head = head[queryPart]) 96 ) { 97 if (i === query.length) return head; 98 } 99 return null; 100 }, 101 102 setCookie: function (name, value, expiryDays, domain, path) { 103 expiryDays = expiryDays || 365; 104 105 var exdate = new Date(); 106 exdate.setDate(exdate.getDate() + expiryDays); 107 108 var cookie = [ 109 name + '=' + value, 110 'expires=' + exdate.toUTCString(), 111 'path=' + path || '/', 112 ]; 113 114 if (domain) { 115 cookie.push('domain=' + domain); 116 } 117 118 document.cookie = cookie.join(';'); 119 }, 120 121 addEventListener: function (el, event, eventListener) { 122 if (el.addEventListener) { 123 el.addEventListener(event, eventListener); 124 } else { 125 el.attachEvent('on' + event, eventListener); 126 } 127 }, 128 }; 129 130 var DomBuilder = (function () { 131 /* 132 The attribute we store events in. 133 */ 134 var eventAttribute = 'data-cc-event'; 135 var conditionAttribute = 'data-cc-if'; 136 137 /* 138 Shim to make addEventListener work correctly with IE. 139 */ 140 var addEventListener = function (el, event, eventListener) { 141 // Add multiple event listeners at once if array is passed. 142 if (Util.isArray(event)) { 143 return Util.each(event, function (ev) { 144 addEventListener(el, ev, eventListener); 145 }); 146 } 147 148 if (el.addEventListener) { 149 el.addEventListener(event, eventListener); 150 } else { 151 el.attachEvent('on' + event, eventListener); 152 } 153 }; 154 155 /* 156 Replace {{variable.name}} with it's property on the scope 157 Also supports {{variable.name || another.name || 'string'}} 158 */ 159 var insertReplacements = function (htmlStr, scope) { 160 return htmlStr.replace(/\{\{(.*?)\}\}/g, function (_match, sub) { 161 var tokens = sub.split('||'); 162 var value; 163 var token; 164 while ((token = tokens.shift())) { 165 token = token.trim(); 166
167 // If string 168 if (token[0] === '"') return token.slice(1, token.length - 1); 169 170 // If query matches 171 value = Util.queryObject(scope, token); 172 173 if (value) return value; 174 } 175 176 return ''; 177 }); 178 }; 179 180 /* 181 Turn a string of html into DOM 182 */ 183 var buildDom = function (htmlStr) { 184 var container = document.createElement('div'); 185 container.innerHTML = htmlStr; 186 return container.children[0]; 187 }; 188 189 var applyToElementsWithAttribute = function (dom, attribute, func) { 190 var els = dom.parentNode.querySelectorAll('[' + attribute + ']'); 191 Util.each( 192 els, 193 function (element) { 194 var attributeVal = element.getAttribute(attribute); 195 func(element, attributeVal); 196 }, 197 window, 198 true, 199 ); 200 }; 201 202 /* 203 Parse event attributes in dom and set listeners to their matching scope methods 204 */ 205 var applyEvents = function (dom, scope) { 206 applyToElementsWithAttribute( 207 dom, 208 eventAttribute, 209 function (element, attributeVal) { 210 var parts = attributeVal.split(':'); 211 var listener = Util.queryObject(scope, parts[1]); 212 addEventListener(element, parts[0], Util.bind(listener, scope)); 213 }, 214 ); 215 }; 216 217 var applyConditionals = function (dom, scope) { 218 applyToElementsWithAttribute( 219 dom, 220 conditionAttribute, 221 function (element, attributeVal) { 222 var value = Util.queryObject(scope, attributeVal); 223 if (!value) { 224 element.parentNode.removeChild(element); 225 } 226 }, 227 ); 228 }; 229 230 return { 231 build: function (htmlStr, scope) { 232 if (Util.isArray(htmlStr)) htmlStr = htmlStr.join(''); 233 234 htmlStr = insertReplacements(htmlStr, scope); 235 var dom = buildDom(htmlStr); 236 applyEvents(dom, scope); 237 applyConditionals(dom, scope); 238 239 return dom; 240 }, 241 }; 242 })(); 243 244 /* 245 Plugin 246 */ 247 var cookieconsent = { 248 options: { 249 message: 250 'This website uses cookies to ensure you get the best experience on our website. ',
251 dismiss: 'Got it!', 252 learnMore: 'More info', 253 link: null, 254 container: null, // selector 255 theme: 'light-floating', 256 domain: null, // default to current domain. 257 path: '/', 258 expiryDays: 365, 259 markup: [ 260 '<div class="cc_banner-wrapper {{containerClasses}}" >', 261 '<div style="width: 1170px;margin: auto;">', 262 '<div class="cc_banner cc_position_{{options.position}} cc_container_border_{{options.border}} cc_container cc_container--open" style="background-color: {{options.backgroundColor}}">', 263 '<a href="" data-cc-event="click:dismiss" rel="nofollow" class="cc_btn cc_btn_accept_all btn btn-default waves-effect waves-light">{{options.dismiss}}</a>', 264 265 '<div class="cc_message">{{options.message}} <a data-cc-if="options.link" class="cc_more_info" href="{{options.link || "#null"}}">{{options.learnMore}}</a></div>', 266 267 '', 268 '</div>', 269 '</div>', 270 '</div>', 271 ], 272 appendToBottom: 0, 273 position: 'bottom', 274 }, 275 276 init: function () { 277 var options = window[OPTIONS_VARIABLE]; 278 if (options) this.setOptions(options); 279 280 if (this.options.appendToBottom) { 281 window.addEventListener('load', function () { 282 document.body.classList.add('cookie-padding'); 283 }); 284 } 285 286 this.setContainer(); 287 288 // Calls render when theme is loaded. 289 /* MSH EDIT 290 if (this.options.theme) { 291 this.loadTheme(this.render); 292 } else { 293 this.render(); 294 } 295 */ 296 this.render(); 297 }, 298 299 setOptionsOnTheFly: function (options) { 300 this.setOptions(options); 301 this.render(); 302 }, 303 304 setOptions: function (options) { 305 Util.merge(this.options, options); 306 }, 307 308 setContainer: function () { 309 if (this.options.container) { 310 this.container = document.querySelector(this.options.container); 311 } else { 312 this.container = document.body; 313 } 314 315 // Add class to container classes so we can specify css for IE8 only. 316 this.containerClasses = ''; 317 if (navigator.appVersion.indexOf('MSIE 8') > -1) { 318 this.containerClasses += ' cc_ie8'; 319 } 320 }, 321 322 loadTheme: function (callback) { 323 var theme = this.options.theme; 324 325 // If theme is specified by name 326 if (theme.indexOf('.css') === -1) { 327 theme = THEME_BUCKET_PATH + theme + '.css'; 328 } 329 330 var link = document.createElement('link'); 331 link.rel = 'stylesheet'; 332 link.type = 'text/css'; 333 link.href = theme; 334 335 var loaded = false; 336 link.onload = Util.bind(function () { 337 if (!loaded && callback) { 338 callback.call(this); 339 loaded = true; 340 } 341 }, this); 342 343 document.getElementsByTagName('head')[0].appendChild(link); 344 }, 345 346 render: function () { 347 // remove current element (if we've already rendered) 348 if (this.element && this.element.parentNode) { 349 this.element.parentNode.removeChild(this.element); 350 delete this.element; 351 } 352 353 this.element = DomBuilder.build(this.options.markup, this); 354 if (!this.container.firstChild) { 355 this.container.appendChild(this.element); 356 } else { 357 this.container.insertBefore(this.element, this.container.firstChild); 358 } 359 }, 360 361 dismiss: function (evt) { 362 evt.preventDefault && evt.preventDefault(); 363 evt.returnValue = false; 364 if (this.options.appendToBottom) { 365 document.body.classList.remove('cookie-padding'); 366 } 367 this.setDismissedCookie(); 368 this.container.removeChild(this.element); 369 }, 370 371 setDismissedCookie: function () { 372 Util.setCookie( 373 DISMISSED_COOKIE, 374 'yes', 375 this.options.expiryDays, 376 this.options.domain, 377 this.options.path, 378 ); 379 }, 380 }; 381 382 var init; 383 var initialized = false; 384 (init = function () { 385 if (!initialized && document.readyState == 'complete') { 386 cookieconsent.init(); 387 initialized = true; 388 window[OPTIONS_UPDATER] = Util.bind( 389 cookieconsent.setOptionsOnTheFly, 390 cookieconsent, 391 ); 392 } 393 })(); 394 395 Util.addEventListener(document, 'readystatechange', init); 396})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.