1/*! 2 * Lightweight Smart Banner with no frameworks requirement 3 * Based on 'jQuery Smart Banner' by Arnold Daniels <[email protected]> https://github.com/jasny/jquery.smartbanner 4 */ 5/*global navigator, window, document */ 6(function () { 7 'use strict'; 8 9 // Simple object extend function 10 var extend = function (where) { 11 Array.prototype.slice.call(arguments, 1).forEach(function (source) { 12 var key; 13 for (key in source) { 14 if (source.hasOwnProperty(key)) { 15 where[key] = source[key]; 16 } 17 } 18 }); 19 return where; 20 }; 21 22 // Simple one element selector function 23 var $ = function (selector, element) { 24 var el = element || document.documentElement; 25 return el.querySelector(selector); 26 }; 27 28 // Bind for old safari 29 if (!Function.prototype.bind) { 30 Function.prototype.bind = function (obj) { 31 var args = [].slice.call(arguments, 1), 32 self = this, 33 nop = function () { }, 34 bound = function () { 35 return self.apply(this instanceof nop ? this : (obj || {}), 36 args.concat([].slice.call(arguments))); 37 }; 38 nop.prototype = self.prototype; 39 bound.prototype = new nop(); 40 return bound; 41 }; 42 } 43 44 var addClass, removeClass; 45 var e = document.createElement('input'); 46 if ('classList' in e) { 47 addClass = function (el, c) { 48 el.classList.add(c); 49 }; 50 removeClass = function (el, c) { 51 el.classList.remove(c); 52 }; 53 } else { 54 var classReg = function (c) { 55 return new RegExp('(^|\\s+)' + c + '(\\s+|$)'); 56 }; 57 if (!String.prototype.trim) { 58 String.prototype.trim = function (s) { 59 return s.replace(/(^\s*|\s*$)/g, ''); 60 } 61 } 62 addClass = function (el, c) { 63 el.className = (el.className + ' ' + c).trim(); 64 }; 65 removeClass = function (el, c) { 66 el.className = el.className.replace(classReg(c), ' ').trim(); 67 }; 68 } 69 70 var getCookie = function (name) { 71 var cookies = document.cookie.split(";"); 72 73 for (var i = 0; i < cookies.length; i++) { 74 var x = cookies[i].substr(0, cookies[i].indexOf("=")); 75 var y = cookies[i].substr(cookies[i].indexOf("=") + 1); 76 x = x.replace(/^\s+|\s+$/g, ""); 77 if (x == name) { 78 return decodeURIComponent(y); 79 } 80 } 81 return null; 82 }; 83 84 var setCookie = function (name, value, exdays) { 85 var exdate = new Date(); 86 exdate.setDate(exdate.getDate() + exdays); 87 value = encodeURIComponent(value) + (exdays == null ? '' : ('; expires=' + exdate.toUTCString())); 88 document.cookie = name + '=' + value + '; path=/;'; 89 }; 90 91 // platform dependent functionality 92 var mixins = { 93 ios: { 94 appMeta: 'myiOSAppStore', 95 iconRels: ['apple-touch-icon-precomposed', 'apple-touch-icon'], 96 getStoreLink: function () { 97 return 'https://itunes.apple.com/' + this.options.appStoreLanguage + '/app/id' + this.appId; 98 } 99 }, 100 android: { 101 appMeta: 'google-play-app', 102 iconRels: ['android-touch-icon', 'apple-touch-icon-precomposed', 'apple-touch-icon'], 103 getStoreLink: function () { 104 return 'market://details?id=' + this.appId; 105 } 106 } 107 }; 108 109 var SmartBanner = function (options) { 110 var userAgent = navigator.userAgent; 111 this.options = extend({}, { 112 daysHidden: 15, 113 daysReminder: 90, 114 appStoreLanguage: 'us', // Language code for App Store 115 button: 'VIEW', // Text for the install button 116 store: { 117 ios: 'On the App Store', 118 android: 'In Google Play' 119 }, 120 price: { 121 ios: 'FREE', 122 android: 'FREE' 123 }, 124 force: false // put platform type (ios, android, etc.) here for emulation 125 }, options || {}); 126 127 if (this.options.force) { 128 this.type = this.options.force; 129 } 130 else if (userAgent.match(/Android/i) !== null) { 131 this.type = 'android'; 132 } 133 else if (userAgent.match(/iPad|iPhone|iPod/i) !== null) { 134 //if (userAgent.match(/Safari/i) !== null && 135 // (userAgent.match(/CriOS/i) !== null ||
136 // window.Number(userAgent.substr(userAgent.indexOf('OS ') + 3, 3).replace('_', '.')) < 6)) { 137 this.type = 'ios'; 138 //} // Check webview and native smart banner support (iOS 6+) 139 } 140 141 // Don't show banner if device isn't iOS or Android, website is loaded in app, user dismissed banner, or we have no app id in meta 142 if (!this.type 143 || navigator.standalone 144 || getCookie('smartbanner-closed') 145 || getCookie('smartbanner-installed')) { 146 return; 147 } 148 149 extend(this, mixins[this.type]); 150 151 if (!this.parseAppId()) { 152 return; 153 } 154 155 this.create(); 156 this.show(); 157 }; 158 159 SmartBanner.prototype = { 160 constructor: SmartBanner, 161 162 create: function () { 163 var link = this.getStoreLink(); 164 var inStore = this.options.price[this.type] + this.options.store[this.type];//this.options.price[this.type] + ' - ' + this.options.store[this.type]; 165 var icon; 166 for (var i = 0; i < this.iconRels.length; i++) { 167 var rel = $('link[rel="' + this.iconRels[i] + '"]'); 168 if (rel) { 169 icon = rel.getAttribute('href'); 170 break; 171 } 172 } 173 174 var banner = document.getElementById('mobile_banner'); 175 var sb = document.createElement('div'); 176 addClass(sb, 'smartbanner'); 177 addClass(sb, 'smartbanner_' + this.type); 178 179 sb.innerHTML = '<div class="smartbanner__container">' + 180 '<a href="javascript:void(0);" class="smartbanner__close">×</a>' + 181 '<span class="smartbanner__icon" style="background-image: url(' + icon + ')"></span>' + 182 '<div class="smartbanner__info">' + 183 '<div class="smartbanner__title">' + this.options.title + '</div>' + 184 '<div>' + this.options.author + '</div>' + 185 '<span>' + inStore + '</span>' + 186 '</div>' + 187 '<a href="' + link + '" class="smartbanner-button">' + 188 '<span class="smartbanner-button__text">' + this.options.button + '</span>' + 189 '</a>' + 190 '</div>'; 191 192 banner.appendChild(sb); 193 $('.smartbanner-button', sb).addEventListener('click', this.install.bind(this), false); 194 $('.smartbanner__close', sb).addEventListener('click', this.close.bind(this), false); 195 196 }, 197 hide: function () { 198 removeClass(document.documentElement, 'smartbanner_show'); 199 }, 200 show: function () { 201 addClass(document.documentElement, 'smartbanner_show'); 202 }, 203 close: function () { 204 this.hide(); 205 setCookie('smartbanner-closed', 'true', this.options.daysHidden); 206 }, 207 install: function () { 208 this.hide(); 209 setCookie('smartbanner-installed', 'true', this.options.daysReminder); 210 }, 211 parseAppId: function () { 212 var meta = $('meta[name="' + this.appMeta + '"]'); 213 if (!meta) { 214 return; 215 } 216 this.appId = /app-id=([^\s,]+)/.exec(meta.getAttribute('content'))[1]; 217 218 return this.appId; 219 } 220 }; 221 222 window.SmartBanner = SmartBanner; 223}());
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.