1/*! 2 * jQuery Smart Banner 3 * Copyright (c) 2012 Arnold Daniels <[email protected]> 4 * Based on 'jQuery Smart Web App Banner' by Kurt Zenisek @ kzeni.com 5 */ 6!function ($) { 7 var SmartBanner = function (options) { 8 this.origHtmlMargin = parseFloat($('html').css('margin-top')) // Get the original margin-top of the HTML element so we can take that into account 9 this.options = $.extend({}, $.smartbanner.defaults, options) 10 11 var standalone = navigator.standalone // Check if it's already a standalone web app or running within a webui view of an app (not mobile safari) 12 , UA = navigator.userAgent 13 14 // Detect banner type (iOS or Android) 15 if (this.options.force) { 16 this.type = this.options.force 17 } else if (UA.match(/iPad|iPhone|iPod/i) != null) { 18 if (UA.match(/Safari/i) != null && 19 (UA.match(/CriOS/i) != null || 20 window.Number(navigator.userAgent.substr(navigator.userAgent.indexOf('OS ') + 3, 3).replace('_', '.')) < 6)) this.type = 'ios' // Check webview and native smart banner support (iOS 6+) 21 } else if (UA.match(/Android/i) != null) { 22 this.type = 'android' 23 } else if (UA.match(/Windows NT 6.2/i) != null && UA.match(/Touch/i) !== null) { 24 this.type = 'windows' 25 } 26 27 // Don't show banner if device isn't iOS or Android, website is loaded in app or user dismissed banner 28 if (!this.type || standalone || this.getCookie('sb-closed') || this.getCookie('sb-installed')) { 29 return 30 } 31 32 // Calculate scale 33 this.scale = this.options.scale == 'auto' ? $(window).width() / window.screen.width : this.options.scale 34 if (this.scale < 1) this.scale = 1 35 36 // Get info from meta data 37 var meta = $(this.type == 'android' ? 'meta[name="google-play-app"]' : 38 this.type == 'ios' ? 'meta[name="apple-itunes-app"]' : 'meta[name="msApplication-ID"]'); 39 if (meta.length == 0) return 40 41 // For Windows Store apps, get the PackageFamilyName for protocol launch 42 if (this.type == 'windows') { 43 this.pfn = $('meta[name="msApplication-PackageFamilyName"]').attr('content'); 44 this.appId = meta.attr('content')[1] 45 } else { 46 this.appId = /app-id=([^\s,]+)/.exec(meta.attr('content'))[1] 47 } 48 49 this.title = this.options.title ? this.options.title : $('title').text().replace(/\s*[|\-·].*$/, '') 50 this.author = this.options.author ? this.options.author : ($('meta[name="author"]').length ? $('meta[name="author"]').attr('content') : window.location.hostname) 51 52 // Create banner 53 this.create() 54 this.show() 55 this.listen() 56 } 57 58 SmartBanner.prototype = { 59 60 constructor: SmartBanner 61 62 , create: function() { 63 var iconURL 64 , link=(this.options.url ? this.options.url : (this.type == 'windows' ? 'ms-windows-store:PDP?PFN=' + this.pfn : (this.type == 'android' ? 'market://details?id=' : 'https://itunes.apple.com/' + this.options.appStoreLanguage + '/app/id')) + this.appId) 65 , inStore=this.options.price ? this.options.price + ' - ' + (this.type == 'android' ? this.options.inGooglePlay : this.type == 'ios' ? this.options.inAppStore : this.options.inWindowsStore) : '' 66 , gloss=this.options.iconGloss === null ? (this.type=='ios') : this.options.iconGloss 67 68 $('body').append('<div id="smartbanner" class="'+this.type+'"><div class="sb-container"><a href="#" class="sb-close">×</a><span class="sb-icon"></span><div class="sb-info"><strong>'+this.title+'</strong><span>'+this.author+'</span><span>'+inStore+'</span></div><a href="'+link+'" class="sb-button"><span>'+this.options.button+'</span></a></div></div>') 69 70 if (this.options.icon) { 71 iconURL = this.options.icon 72 } else if ($('link[rel="apple-touch-icon-precomposed"]').length > 0) { 73 iconURL = $('link[rel="apple-touch-icon-precomposed"]').attr('href')
74 if (this.options.iconGloss === null) gloss = false 75 } else if ($('link[rel="apple-touch-icon"]').length > 0) { 76 iconURL = $('link[rel="apple-touch-icon"]').attr('href') 77 } else if ($('meta[name="msApplication-TileImage"]').length > 0) { 78 iconURL = $('meta[name="msApplication-TileImage"]').attr('content') 79 } else if ($('meta[name="msapplication-TileImage"]').length > 0) { /* redundant because ms docs show two case usages */ 80 iconURL = $('meta[name="msapplication-TileImage"]').attr('content') 81 } 82 83 if (iconURL) { 84 $('#smartbanner .sb-icon').css('background-image','url('+iconURL+')') 85 if (gloss) $('#smartbanner .sb-icon').addClass('gloss') 86 } else{ 87 $('#smartbanner').addClass('no-icon') 88 } 89 90 this.bannerHeight = $('#smartbanner').outerHeight() + 2 91 92 if (this.scale > 1) { 93 $('#smartbanner') 94 .css('top', parseFloat($('#smartbanner').css('top')) * this.scale) 95 .css('height', parseFloat($('#smartbanner').css('height')) * this.scale) 96 $('#smartbanner .sb-container') 97 .css('-webkit-transform', 'scale('+this.scale+')') 98 .css('-msie-transform', 'scale('+this.scale+')') 99 .css('-moz-transform', 'scale('+this.scale+')') 100 .css('width', $(window).width() / this.scale) 101 } 102 } 103 104 , listen: function () { 105 $('#smartbanner .sb-close').on('click',$.proxy(this.close, this)) 106 $('#smartbanner .sb-button').on('click',$.proxy(this.install, this)) 107 } 108 109 , show: function(callback) { 110 $('#smartbanner').stop().animate({top:0},this.options.speedIn).addClass('shown') 111 $('html').animate({marginTop:this.origHtmlMargin+(this.bannerHeight*this.scale)},this.options.speedIn,'swing',callback) 112 } 113 114 , hide: function(callback) { 115 $('#smartbanner').stop().animate({top:-1*this.bannerHeight*this.scale},this.options.speedOut).removeClass('shown') 116 $('html').animate({marginTop:this.origHtmlMargin},this.options.speedOut,'swing',callback) 117 } 118 119 , close: function(e) { 120 e.preventDefault() 121 this.hide() 122 this.setCookie('sb-closed','true',this.options.daysHidden) 123 } 124 125 , install: function(e) { 126 this.hide() 127 this.setCookie('sb-installed','true',this.options.daysReminder) 128 } 129 130 , setCookie: function(name, value, exdays) { 131 var exdate = new Date() 132 exdate.setDate(exdate.getDate()+exdays) 133 value=escape(value)+((exdays==null)?'':'; expires='+exdate.toUTCString()) 134 document.cookie=name+'='+value+'; path=/;' 135 } 136 137 , getCookie: function(name) { 138 var i,x,y,ARRcookies = document.cookie.split(";") 139 for(i=0;i<ARRcookies.length;i++) { 140 x = ARRcookies[i].substr(0,ARRcookies[i].indexOf("=")) 141 y = ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1) 142 x = x.replace(/^\s+|\s+$/g,"") 143 if (x==name) { 144 return unescape(y) 145 } 146 } 147 return null 148 } 149 150 // Demo only 151 , switchType: function() { 152 var that = this 153 154 this.hide(function () { 155 that.type = that.type == 'android' ? 'ios' : 'android' 156 var meta = $(that.type == 'android' ? 'meta[name="google-play-app"]' : 'meta[name="apple-itunes-app"]').attr('content') 157 that.appId = /app-id=([^\s,]+)/.exec(meta)[1] 158 159 $('#smartbanner').detach() 160 that.create() 161 that.show() 162 }) 163 } 164 } 165 166 $.smartbanner = function (option) { 167 var $window = $(window) 168 , data = $window.data('typeahead') 169 , options = typeof option == 'object' && option 170 if (!data) $window.data('typeahead', (data = new SmartBanner(options))) 171 if (typeof option == 'string') data[option]() 172 } 173 174 // override these globally if you like (they are all optional) 175 $.smartbanner.defaults = { 176 title: null, // What the title of the app should be in the banner (defaults to <title>) 177 author: null, // What the author of the app should be in the banner (defaults to <meta name="author"> or hostname) 178 price: 'FREE', // Price of the app 179 appStoreLanguage: 'us', // Language code for App Store 180 inAppStore: 'On the App Store', // Text of price for iOS 181 inGooglePlay: 'In Google Play', // Text of price for Android 182 inWindowsStore: 'In the Windows Store', //Text of price for Windows 183 icon: null, // The URL of the icon (defaults to <meta name="apple-touch-icon">) 184 iconGloss: null, // Force gloss effect for iOS even for precomposed 185 button: 'VIEW', // Text for the install button 186 url: null, // The URL for the button. Keep null if you want the button to link to the app store. 187 scale: 'auto', // Scale based on viewport size (set to 1 to disable) 188 speedIn: 300, // Show animation speed of the banner 189 speedOut: 400, // Close animation speed of the banner 190 daysHidden: 15, // Duration to hide the banner after being closed (0 = always show banner) 191 daysReminder: 90, // Duration to hide the banner after "VIEW" is clicked *separate from when the close button is clicked* (0 = always show banner) 192 force: null // Choose 'ios', 'android' or 'windows'. Don't do a browser check, just always show this banner 193 } 194 195 $.smartbanner.Constructor = SmartBanner 196 197}(window.jQuery);
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.