From 674b66c621c98cef963da52bc3c35eaa3d369142 Mon Sep 17 00:00:00 2001 From: peteruithoven Date: Mon, 12 May 2014 14:41:34 +0200 Subject: [PATCH] Added updated add to homescreen library --- Gruntfile.js | 3 +- js/BoxesPage.js | 11 + js/libs/add2home.js | 344 ---------------------- js/libs/addtohomescreen.js | 566 +++++++++++++++++++++++++++++++++++++ less/add2home.css | 180 ------------ less/addtohomescreen.css | 236 ++++++++++++++++ less/styles.less | 27 ++ 7 files changed, 842 insertions(+), 525 deletions(-) delete mode 100644 js/libs/add2home.js create mode 100644 js/libs/addtohomescreen.js delete mode 100644 less/add2home.css create mode 100644 less/addtohomescreen.css diff --git a/Gruntfile.js b/Gruntfile.js index 5b04123..178e0d6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -98,7 +98,8 @@ module.exports = function(grunt) { ConnectAPI: true, NetworkAPI: true, InfoAPI: true, - ConfigAPI: true + ConfigAPI: true, + addToHomescreen: true }, browser: true, curly: true, diff --git a/js/BoxesPage.js b/js/BoxesPage.js index e177128..1695129 100644 --- a/js/BoxesPage.js +++ b/js/BoxesPage.js @@ -30,6 +30,17 @@ var BoxesPage = (function (w) { $.mobile.document.on( "pagebeforeshow", PAGE_ID, function( event, data ) { //console.log("Boxes page pagebeforeshow"); _connectAPI.start(); + }); + $.mobile.document.on( "pageshow", PAGE_ID, function( event, data ) { + //console.log("Boxes page pageshow"); + addToHomescreen(/*{ + debug: true, // activate debug mode in ios emulation + skipFirstVisit: false, // show at first access + startDelay: 0, // display the message right away + lifespan: 0, // do not automatically kill the call out + displayPace: 0, // do not obey the display pace + maxDisplayCount: 0 // do not obey the max display count + }*/); }); $.mobile.document.on( "pagehide", PAGE_ID, function( event, data ) { //console.log("Boxes page pagehide"); diff --git a/js/libs/add2home.js b/js/libs/add2home.js deleted file mode 100644 index 8709e30..0000000 --- a/js/libs/add2home.js +++ /dev/null @@ -1,344 +0,0 @@ -/*! - * Add to Homescreen v2.0.11 ~ Copyright (c) 2013 Matteo Spinelli, http://cubiq.org - * Released under MIT license, http://cubiq.org/license - */ -var addToHome = (function (w) { - var nav = w.navigator, - isIDevice = 'platform' in nav && (/iphone|ipod|ipad/gi).test(nav.platform), - isIPad, - isRetina, - isSafari, - isStandalone, - OSVersion, - startX = 0, - startY = 0, - lastVisit = 0, - isExpired, - isSessionActive, - isReturningVisitor, - balloon, - overrideChecks, - - positionInterval, - closeTimeout, - - options = { - autostart: true, // Automatically open the balloon - returningVisitor: false, // Show the balloon to returning visitors only (setting this to true is highly recommended) - animationIn: 'drop', // drop || bubble || fade - animationOut: 'fade', // drop || bubble || fade - startDelay: 2000, // 2 seconds from page load before the balloon appears - lifespan: 15000, // 15 seconds before it is automatically destroyed - bottomOffset: 14, // Distance of the balloon from bottom - expire: 0, // Minutes to wait before showing the popup again (0 = always displayed) - message: '', // Customize your message or force a language ('' = automatic) - touchIcon: false, // Display the touch icon - arrow: true, // Display the balloon arrow - hookOnLoad: true, // Should we hook to onload event? (really advanced usage) - closeButton: true, // Let the user close the balloon - iterations: 100 // Internal/debug use - }, - - intl = { - ar: 'قم بتثبيت هذا التطبيق على %device:انقر%icon ،ثم اضفه الى الشاشة الرئيسية.', - ca_es: 'Per instal·lar aquesta aplicació al vostre %device premeu %icon i llavors Afegir a pantalla d\'inici.', - cs_cz: 'Pro instalaci aplikace na Váš %device, stiskněte %icon a v nabídce Přidat na plochu.', - da_dk: 'Tilføj denne side til din %device: tryk på %icon og derefter Føj til hjemmeskærm.', - de_de: 'Installieren Sie diese App auf Ihrem %device: %icon antippen und dann Zum Home-Bildschirm.', - el_gr: 'Εγκαταστήσετε αυτήν την Εφαρμογή στήν συσκευή σας %device: %icon μετά πατάτε Προσθήκη σε Αφετηρία.', - en_us: 'Install this web app on your %device: tap %icon and then Add to Home Screen.', - es_es: 'Para instalar esta app en su %device, pulse %icon y seleccione Añadir a pantalla de inicio.', - fi_fi: 'Asenna tämä web-sovellus laitteeseesi %device: paina %icon ja sen jälkeen valitse Lisää Koti-valikkoon.', - fr_fr: 'Ajoutez cette application sur votre %device en cliquant sur %icon, puis Ajouter à l\'écran d\'accueil.', - he_il: 'התקן אפליקציה זו על ה-%device שלך: הקש %icon ואז הוסף למסך הבית.', - hr_hr: 'Instaliraj ovu aplikaciju na svoj %device: klikni na %icon i odaberi Dodaj u početni zaslon.', - hu_hu: 'Telepítse ezt a web-alkalmazást az Ön %device-jára: nyomjon a %icon-ra majd a Főképernyőhöz adás gombra.', - it_it: 'Installa questa applicazione sul tuo %device: premi su %icon e poi Aggiungi a Home.', - ja_jp: 'このウェブアプリをあなたの%deviceにインストールするには%iconをタップしてホーム画面に追加を選んでください。', - ko_kr: '%device에 웹앱을 설치하려면 %icon을 터치 후 "홈화면에 추가"를 선택하세요', - nb_no: 'Installer denne appen på din %device: trykk på %icon og deretter Legg til på Hjem-skjerm', - nl_nl: 'Installeer deze webapp op uw %device: tik %icon en dan Voeg toe aan beginscherm.', - pl_pl: 'Aby zainstalować tę aplikacje na %device: naciśnij %icon a następnie Dodaj jako ikonę.', - pt_br: 'Instale este aplicativo em seu %device: aperte %icon e selecione Adicionar à Tela Inicio.', - pt_pt: 'Para instalar esta aplicação no seu %device, prima o %icon e depois em Adicionar ao ecrã principal.', - ru_ru: 'Установите это веб-приложение на ваш %device: нажмите %icon, затем Добавить в «Домой».', - sv_se: 'Lägg till denna webbapplikation på din %device: tryck på %icon och därefter Lägg till på hemskärmen.', - th_th: 'ติดตั้งเว็บแอพฯ นี้บน %device ของคุณ: แตะ %icon และ เพิ่มที่หน้าจอโฮม', - tr_tr: 'Bu uygulamayı %device\'a eklemek için %icon simgesine sonrasında Ana Ekrana Ekle düğmesine basın.', - uk_ua: 'Встановіть цей веб сайт на Ваш %device: натисніть %icon, а потім На початковий екран.', - zh_cn: '您可以将此应用程式安装到您的 %device 上。请按 %icon 然后点选添加至主屏幕。', - zh_tw: '您可以將此應用程式安裝到您的 %device 上。請按 %icon 然後點選加入主畫面螢幕。' - }; - - function init () { - // Preliminary check, all further checks are performed on iDevices only - if ( !isIDevice ) return; - - var now = Date.now(), - i; - - // Merge local with global options - if ( w.addToHomeConfig ) { - for ( i in w.addToHomeConfig ) { - options[i] = w.addToHomeConfig[i]; - } - } - if ( !options.autostart ) options.hookOnLoad = false; - - isIPad = (/ipad/gi).test(nav.platform); - isRetina = w.devicePixelRatio && w.devicePixelRatio > 1; - isSafari = (/Safari/i).test(nav.appVersion) && !(/CriOS/i).test(nav.appVersion); - isStandalone = nav.standalone; - OSVersion = nav.appVersion.match(/OS (\d+_\d+)/i); - OSVersion = OSVersion && OSVersion[1] ? +OSVersion[1].replace('_', '.') : 0; - - lastVisit = +w.localStorage.getItem('addToHome'); - - isSessionActive = w.sessionStorage.getItem('addToHomeSession'); - isReturningVisitor = options.returningVisitor ? lastVisit && lastVisit + 28*24*60*60*1000 > now : true; - - if ( !lastVisit ) lastVisit = now; - - // If it is expired we need to reissue a new balloon - isExpired = isReturningVisitor && lastVisit <= now; - - if ( options.hookOnLoad ) w.addEventListener('load', loaded, false); - else if ( !options.hookOnLoad && options.autostart ) loaded(); - } - - function loaded () { - w.removeEventListener('load', loaded, false); - - if ( !isReturningVisitor ) w.localStorage.setItem('addToHome', Date.now()); - else if ( options.expire && isExpired ) w.localStorage.setItem('addToHome', Date.now() + options.expire * 60000); - - if ( !overrideChecks && ( !isSafari || !isExpired || isSessionActive || isStandalone || !isReturningVisitor ) ) return; - - var touchIcon = '', - platform = nav.platform.split(' ')[0], - language = nav.language.replace('-', '_'); - - balloon = document.createElement('div'); - balloon.id = 'addToHomeScreen'; - balloon.style.cssText += 'left:-9999px;-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0;-webkit-transform:translate3d(0,0,0);position:' + (OSVersion < 5 ? 'absolute' : 'fixed'); - - // Localize message - if ( options.message in intl ) { // You may force a language despite the user's locale - language = options.message; - options.message = ''; - } - if ( options.message === '' ) { // We look for a suitable language (defaulted to en_us) - options.message = language in intl ? intl[language] : intl['en_us']; - } - - if ( options.touchIcon ) { - touchIcon = isRetina ? - document.querySelector('head link[rel^=apple-touch-icon][sizes="114x114"],head link[rel^=apple-touch-icon][sizes="144x144"],head link[rel^=apple-touch-icon]') : - document.querySelector('head link[rel^=apple-touch-icon][sizes="57x57"],head link[rel^=apple-touch-icon]'); - - if ( touchIcon ) { - touchIcon = ''; - } - } - - balloon.className = (OSVersion >=7 ? 'addToHomeIOS7 ' : '') + (isIPad ? 'addToHomeIpad' : 'addToHomeIphone') + (touchIcon ? ' addToHomeWide' : ''); - balloon.innerHTML = touchIcon + - options.message.replace('%device', platform).replace('%icon', OSVersion >= 4.2 ? '' : '+') + - (options.arrow ? '= 7 && isIPad && touchIcon ? ' style="margin-left:-32px"' : '') + '>' : '') + - (options.closeButton ? '\u00D7' : ''); - - document.body.appendChild(balloon); - - // Add the close action - if ( options.closeButton ) balloon.addEventListener('click', clicked, false); - - if ( !isIPad && OSVersion >= 6 ) window.addEventListener('orientationchange', orientationCheck, false); - - setTimeout(show, options.startDelay); - } - - function show () { - var duration, - iPadXShift = 208; - - // Set the initial position - if ( isIPad ) { - if ( OSVersion < 5 ) { - startY = w.scrollY; - startX = w.scrollX; - } else if ( OSVersion < 6 ) { - iPadXShift = 160; - } else if ( OSVersion >= 7 ) { - iPadXShift = 143; - } - - balloon.style.top = startY + options.bottomOffset + 'px'; - balloon.style.left = Math.max(startX + iPadXShift - Math.round(balloon.offsetWidth / 2), 9) + 'px'; - - switch ( options.animationIn ) { - case 'drop': - duration = '0.6s'; - balloon.style.webkitTransform = 'translate3d(0,' + -(w.scrollY + options.bottomOffset + balloon.offsetHeight) + 'px,0)'; - break; - case 'bubble': - duration = '0.6s'; - balloon.style.opacity = '0'; - balloon.style.webkitTransform = 'translate3d(0,' + (startY + 50) + 'px,0)'; - break; - default: - duration = '1s'; - balloon.style.opacity = '0'; - } - } else { - startY = w.innerHeight + w.scrollY; - - if ( OSVersion < 5 ) { - startX = Math.round((w.innerWidth - balloon.offsetWidth) / 2) + w.scrollX; - balloon.style.left = startX + 'px'; - balloon.style.top = startY - balloon.offsetHeight - options.bottomOffset + 'px'; - } else { - balloon.style.left = '50%'; - balloon.style.marginLeft = -Math.round(balloon.offsetWidth / 2) - ( w.orientation%180 && OSVersion >= 6 && OSVersion < 7 ? 40 : 0 ) + 'px'; - balloon.style.bottom = options.bottomOffset + 'px'; - } - - switch (options.animationIn) { - case 'drop': - duration = '1s'; - balloon.style.webkitTransform = 'translate3d(0,' + -(startY + options.bottomOffset) + 'px,0)'; - break; - case 'bubble': - duration = '0.6s'; - balloon.style.webkitTransform = 'translate3d(0,' + (balloon.offsetHeight + options.bottomOffset + 50) + 'px,0)'; - break; - default: - duration = '1s'; - balloon.style.opacity = '0'; - } - } - - balloon.offsetHeight; // repaint trick - balloon.style.webkitTransitionDuration = duration; - balloon.style.opacity = '1'; - balloon.style.webkitTransform = 'translate3d(0,0,0)'; - balloon.addEventListener('webkitTransitionEnd', transitionEnd, false); - - closeTimeout = setTimeout(close, options.lifespan); - } - - function manualShow (override) { - if ( !isIDevice || balloon ) return; - - overrideChecks = override; - loaded(); - } - - function close () { - clearInterval( positionInterval ); - clearTimeout( closeTimeout ); - closeTimeout = null; - - // check if the popup is displayed and prevent errors - if ( !balloon ) return; - - var posY = 0, - posX = 0, - opacity = '1', - duration = '0'; - - if ( options.closeButton ) balloon.removeEventListener('click', clicked, false); - if ( !isIPad && OSVersion >= 6 ) window.removeEventListener('orientationchange', orientationCheck, false); - - if ( OSVersion < 5 ) { - posY = isIPad ? w.scrollY - startY : w.scrollY + w.innerHeight - startY; - posX = isIPad ? w.scrollX - startX : w.scrollX + Math.round((w.innerWidth - balloon.offsetWidth)/2) - startX; - } - - balloon.style.webkitTransitionProperty = '-webkit-transform,opacity'; - - switch ( options.animationOut ) { - case 'drop': - if ( isIPad ) { - duration = '0.4s'; - opacity = '0'; - posY += 50; - } else { - duration = '0.6s'; - posY += balloon.offsetHeight + options.bottomOffset + 50; - } - break; - case 'bubble': - if ( isIPad ) { - duration = '0.8s'; - posY -= balloon.offsetHeight + options.bottomOffset + 50; - } else { - duration = '0.4s'; - opacity = '0'; - posY -= 50; - } - break; - default: - duration = '0.8s'; - opacity = '0'; - } - - balloon.addEventListener('webkitTransitionEnd', transitionEnd, false); - balloon.style.opacity = opacity; - balloon.style.webkitTransitionDuration = duration; - balloon.style.webkitTransform = 'translate3d(' + posX + 'px,' + posY + 'px,0)'; - } - - - function clicked () { - w.sessionStorage.setItem('addToHomeSession', '1'); - isSessionActive = true; - close(); - } - - function transitionEnd () { - balloon.removeEventListener('webkitTransitionEnd', transitionEnd, false); - - balloon.style.webkitTransitionProperty = '-webkit-transform'; - balloon.style.webkitTransitionDuration = '0.2s'; - - // We reached the end! - if ( !closeTimeout ) { - balloon.parentNode.removeChild(balloon); - balloon = null; - return; - } - - // On iOS 4 we start checking the element position - if ( OSVersion < 5 && closeTimeout ) positionInterval = setInterval(setPosition, options.iterations); - } - - function setPosition () { - var matrix = new WebKitCSSMatrix(w.getComputedStyle(balloon, null).webkitTransform), - posY = isIPad ? w.scrollY - startY : w.scrollY + w.innerHeight - startY, - posX = isIPad ? w.scrollX - startX : w.scrollX + Math.round((w.innerWidth - balloon.offsetWidth) / 2) - startX; - - // Screen didn't move - if ( posY == matrix.m42 && posX == matrix.m41 ) return; - - balloon.style.webkitTransform = 'translate3d(' + posX + 'px,' + posY + 'px,0)'; - } - - // Clear local and session storages (this is useful primarily in development) - function reset () { - w.localStorage.removeItem('addToHome'); - w.sessionStorage.removeItem('addToHomeSession'); - } - - function orientationCheck () { - balloon.style.marginLeft = -Math.round(balloon.offsetWidth / 2) - ( w.orientation%180 && OSVersion >= 6 && OSVersion < 7 ? 40 : 0 ) + 'px'; - } - - // Bootstrap! - init(); - - return { - show: manualShow, - close: close, - reset: reset - }; -})(window); diff --git a/js/libs/addtohomescreen.js b/js/libs/addtohomescreen.js new file mode 100644 index 0000000..6480b35 --- /dev/null +++ b/js/libs/addtohomescreen.js @@ -0,0 +1,566 @@ +/* Add to Homescreen v3.0.4 ~ (c) 2014 Matteo Spinelli ~ @license: http://cubiq.org/license */ +(function (window, document) { +/* + _ _ _____ _____ + ___ _| |_| |_ _|___| | |___ _____ ___ ___ ___ ___ ___ ___ ___ +| .'| . | . | | | | . | | . | | -_|_ -| _| _| -_| -_| | +|__,|___|___| |_| |___|__|__|___|_|_|_|___|___|___|_| |___|___|_|_| + by Matteo Spinelli ~ http://cubiq.org +*/ + +// Check if document is loaded, needed by autostart +var _DOMReady = false; +window.addEventListener('load', loaded, false); +function loaded () { + window.removeEventListener('load', loaded, false); + _DOMReady = true; +} + +// regex used to detect if app has been added to the homescreen +var _reSmartURL = /\/ath(\/)?$/; +var _reQueryString = /([\?&]ath=[^&]*$|&ath=[^&]*(&))/; + +// singleton +var _instance; +function ath (options) { + _instance = _instance || new ath.Class(options); + + return _instance; +} + +// message in all supported languages +ath.intl = { + en_us: { + message: 'To add this web app to the home screen: tap %icon and then %action.', + action: { ios: 'Add to Home Screen', android: 'Add to homescreen', windows: 'pin to start' } + }, + + es_es: { + message: 'Para añadir esta aplicación web a la pantalla de inicio: pulsa %icon y selecciona %action.', + action: { ios: 'Añadir a pantalla de inicio', android: 'Añadir a pantalla de inicio', windows: 'Añadir a inicio' } + }, + + it_it: { + message: 'Per Aggiungere questa web app alla schermata iniziale: premi %icon e poi %action.', + action: { ios: 'Aggiungi a Home', android: 'Aggiungi alla homescreen', windows: 'aggiungi a start' } + }, + + nl_nl: { + message: 'Om deze webapp op je telefoon te installeren, klik op %icon en dan %action.', + action: { ios: 'Voeg toe aan beginscherm', android: 'Toevoegen aan startscherm', windows: 'Aan startscherm vastmaken' } + } +}; + +// default options +ath.defaults = { + appID: 'org.cubiq.addtohome', // local storage name (no need to change) + fontSize: 15, // base font size, used to properly resize the popup based on viewport scale factor + debug: false, // override browser checks + modal: false, // prevent further actions until the message is closed + mandatory: false, // you can't proceed if you don't add the app to the homescreen + autostart: true, // show the message automatically + skipFirstVisit: false, // show only to returning visitors (ie: skip the first time you visit) + startDelay: 1, // display the message after that many seconds from page load + lifespan: 15, // life of the message in seconds + displayPace: 1440, // minutes before the message is shown again (0: display every time, default 24 hours) + maxDisplayCount: 0, // absolute maximum number of times the message will be shown to the user (0: no limit) + icon: true, // add touch icon to the message + message: '', // the message can be customized + validLocation: [], // list of pages where the message will be shown (array of regexes) + onInit: null, // executed on instance creation + onShow: null, // executed when the message is shown + onRemove: null, // executed when the message is removed + onAdd: null, // when the application is launched the first time from the homescreen (guesstimate) + onPrivate: null, // executed if user is in private mode + detectHomescreen: false // try to detect if the site has been added to the homescreen (false | true | 'hash' | 'queryString' | 'smartURL') +}; + +// browser info and capability +var _ua = window.navigator.userAgent; +var _nav = window.navigator; +_extend(ath, { + hasToken: document.location.hash == '#ath' || _reSmartURL.test(document.location.href) || _reQueryString.test(document.location.search), + isRetina: window.devicePixelRatio && window.devicePixelRatio > 1, + isIDevice: (/iphone|ipod|ipad/i).test(_ua), + isMobileChrome: _ua.indexOf('Android') > -1 && (/Chrome\/[.0-9]*/).test(_ua), + isMobileIE: _ua.indexOf('Windows Phone') > -1, + language: _nav.language && _nav.language.toLowerCase().replace('-', '_') || '' +}); + +// normalize language string so it always looks like aa_bb +if ( ath.language.length == 2 ) { + ath.language += '_' + ath.language; +} +// falls back to en_us if language is unsupported +ath.language = ath.language && ath.language in ath.intl ? ath.language : 'en_us'; + +ath.isMobileSafari = ath.isIDevice && _ua.indexOf('Safari') > -1 && _ua.indexOf('CriOS') < 0; +ath.OS = ath.isIDevice ? 'ios' : ath.isMobileChrome ? 'android' : ath.isMobileIE ? 'windows' : 'unsupported'; + +ath.OSVersion = _ua.match(/(OS|Android) (\d+[_\.]\d+)/); +ath.OSVersion = ath.OSVersion && ath.OSVersion[2] ? +ath.OSVersion[2].replace('_', '.') : 0; + +ath.isStandalone = window.navigator.standalone || ( ath.isMobileChrome && ( screen.height - document.documentElement.clientHeight < 40 ) ); // TODO: check the lame polyfill +ath.isTablet = (ath.isMobileSafari && _ua.indexOf('iPad') > -1) || (ath.isMobileChrome && _ua.indexOf('Mobile') < 0); + +ath.isCompatible = (ath.isMobileSafari && ath.OSVersion >= 6) || ath.isMobileChrome; // TODO: add winphone + +var _defaultSession = { + lastDisplayTime: 0, // last time we displayed the message + returningVisitor: false, // is this the first time you visit + displayCount: 0, // number of times the message has been shown + optedout: false, // has the user opted out + added: false // has been actually added to the homescreen +}; + +ath.removeSession = function (appID) { + try { + localStorage.removeItem(appID || ath.defaults.appID); + } catch (e) { + // we are most likely in private mode + } +}; + +ath.Class = function (options) { + // merge default options with user config + this.options = _extend({}, ath.defaults); + _extend(this.options, options); + + // normalize some options + this.options.mandatory = this.options.mandatory && ( 'standalone' in window.navigator || this.options.debug ); + this.options.modal = this.options.modal || this.options.mandatory; + if ( this.options.mandatory ) { + this.options.startDelay = -0.5; // make the popup hasty + } + this.options.detectHomescreen = this.options.detectHomescreen === true ? 'hash' : this.options.detectHomescreen; + + // setup the debug environment + if ( this.options.debug ) { + ath.isCompatible = true; + ath.OS = typeof this.options.debug == 'string' ? this.options.debug : ath.OS == 'unsupported' ? 'android' : ath.OS; + ath.OSVersion = ath.OS == 'ios' ? '7' : '4'; + } + + // the element the message will be appended to + this.container = document.documentElement; + + // load session + this.session = JSON.parse(localStorage.getItem(this.options.appID)); + + // user most likely came from a direct link containing our token, we don't need it and we remove it + if ( ath.hasToken && ( !ath.isCompatible || !this.session ) ) { + ath.hasToken = false; + _removeToken(); + } + + // the device is not supported + if ( !ath.isCompatible ) { + return; + } + + this.session = this.session || _defaultSession; + + // check if we can use the local storage + try { + localStorage.setItem(this.options.appID, JSON.stringify(this.session)); + ath.hasLocalStorage = true; + } catch (e) { + // we are most likely in private mode + ath.hasLocalStorage = false; + + if ( this.options.onPrivate ) { + this.options.onPrivate.call(this); + } + } + + // check if this is a valid location + var isValidLocation = !this.options.validLocation.length; + for ( var i = this.options.validLocation.length; i--; ) { + if ( this.options.validLocation[i].test(document.location.href) ) { + isValidLocation = true; + break; + } + } + + // check compatibility with old versions of add to homescreen. Opt-out if an old session is found + if ( localStorage.getItem('addToHome') ) { + this.optOut(); + } + + // critical errors: + // user opted out, already added to the homescreen, not a valid location + if ( this.session.optedout || this.session.added || !isValidLocation ) { + return; + } + + // check if the app is in stand alone mode + if ( ath.isStandalone ) { + // execute the onAdd event if we haven't already + if ( !this.session.added ) { + this.session.added = true; + this.updateSession(); + + if ( this.options.onAdd && ath.hasLocalStorage ) { // double check on localstorage to avoid multiple calls to the custom event + this.options.onAdd.call(this); + } + } + + return; + } + + // (try to) check if the page has been added to the homescreen + if ( this.options.detectHomescreen ) { + // the URL has the token, we are likely coming from the homescreen + if ( ath.hasToken ) { + _removeToken(); // we don't actually need the token anymore, we remove it to prevent redistribution + + // this is called the first time the user opens the app from the homescreen + if ( !this.session.added ) { + this.session.added = true; + this.updateSession(); + + if ( this.options.onAdd && ath.hasLocalStorage ) { // double check on localstorage to avoid multiple calls to the custom event + this.options.onAdd.call(this); + } + } + + return; + } + + // URL doesn't have the token, so add it + if ( this.options.detectHomescreen == 'hash' ) { + history.replaceState('', window.document.title, document.location.href + '#ath'); + } else if ( this.options.detectHomescreen == 'smartURL' ) { + history.replaceState('', window.document.title, document.location.href.replace(/(\/)?$/, '/ath$1')); + } else { + history.replaceState('', window.document.title, document.location.href + (document.location.search ? '&' : '?' ) + 'ath='); + } + } + + // check if this is a returning visitor + if ( !this.session.returningVisitor ) { + this.session.returningVisitor = true; + this.updateSession(); + + // we do not show the message if this is your first visit + if ( this.options.skipFirstVisit ) { + return; + } + } + + // we do no show the message in private mode + if ( !ath.hasLocalStorage ) { + return; + } + + // all checks passed, ready to display + this.ready = true; + + if ( this.options.onInit ) { + this.options.onInit.call(this); + } + + if ( this.options.autostart ) { + this.show(); + } +}; + +ath.Class.prototype = { + // event type to method conversion + events: { + load: '_delayedShow', + error: '_delayedShow', + orientationchange: 'resize', + resize: 'resize', + scroll: 'resize', + click: 'remove', + touchmove: '_preventDefault', + transitionend: '_removeElements', + webkitTransitionEnd: '_removeElements', + MSTransitionEnd: '_removeElements' + }, + + handleEvent: function (e) { + var type = this.events[e.type]; + if ( type ) { + this[type](e); + } + }, + + show: function (force) { + // in autostart mode wait for the document to be ready + if ( this.options.autostart && !_DOMReady ) { + setTimeout(this.show.bind(this), 50); + return; + } + + // message already on screen + if ( this.shown ) { + return; + } + + var now = Date.now(); + var lastDisplayTime = this.session.lastDisplayTime; + + if ( force !== true ) { + // this is needed if autostart is disabled and you programmatically call the show() method + if ( !this.ready ) { + return; + } + + // we obey the display pace (prevent the message to popup too often) + if ( now - lastDisplayTime < this.options.displayPace * 60000 ) { + return; + } + + // obey the maximum number of display count + if ( this.options.maxDisplayCount && this.session.displayCount >= this.options.maxDisplayCount ) { + return; + } + } + + this.shown = true; + + // increment the display count + this.session.lastDisplayTime = now; + this.session.displayCount++; + this.updateSession(); + + // try to get the highest resolution application icon + if ( !this.applicationIcon ) { + if ( ath.OS == 'ios' ) { + this.applicationIcon = document.querySelector('head link[rel^=apple-touch-icon][sizes="152x152"],head link[rel^=apple-touch-icon][sizes="144x144"],head link[rel^=apple-touch-icon][sizes="120x120"],head link[rel^=apple-touch-icon][sizes="114x114"],head link[rel^=apple-touch-icon]'); + } else { + this.applicationIcon = document.querySelector('head link[rel^="shortcut icon"][sizes="196x196"],head link[rel^=apple-touch-icon]'); + } + } + + var message = ''; + + if ( this.options.message in ath.intl ) { // you can force the locale + message = ath.intl[this.options.message].message.replace('%action', ath.intl[this.options.message].action[ath.OS]); + } else if ( this.options.message !== '' ) { // or use a custom message + message = this.options.message; + } else { // otherwise we use our message + message = ath.intl[ath.language].message.replace('%action', ath.intl[ath.language].action[ath.OS]); + } + + // add the action icon + message = '

' + message.replace('%icon', 'icon') + '

'; + + // create the message container + this.viewport = document.createElement('div'); + this.viewport.className = 'ath-viewport'; + if ( this.options.modal ) { + this.viewport.className += ' ath-modal'; + } + if ( this.options.mandatory ) { + this.viewport.className += ' ath-mandatory'; + } + this.viewport.style.position = 'absolute'; + + // create the actual message element + this.element = document.createElement('div'); + this.element.className = 'ath-container ath-' + ath.OS + ' ath-' + ath.OS + (ath.OSVersion + '').substr(0,1) + ' ath-' + (ath.isTablet ? 'tablet' : 'phone'); + this.element.style.cssText = '-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0;-webkit-transform:translate3d(0,0,0);transition-property:transform,opacity;transition-duration:0;transform:translate3d(0,0,0);-webkit-transition-timing-function:ease-out'; + this.element.style.webkitTransform = 'translate3d(0,-' + window.innerHeight + 'px,0)'; + this.element.style.webkitTransitionDuration = '0s'; + + // add the application icon + if ( this.options.icon && this.applicationIcon ) { + this.element.className += ' ath-icon'; + this.img = document.createElement('img'); + this.img.className = 'ath-application-icon'; + this.img.addEventListener('load', this, false); + this.img.addEventListener('error', this, false); + + this.img.src = this.applicationIcon.href; + this.element.appendChild(this.img); + } + + this.element.innerHTML += message; + + // we are not ready to show, place the message out of sight + this.viewport.style.left = '-99999em'; + + // attach all elements to the DOM + this.viewport.appendChild(this.element); + this.container.appendChild(this.viewport); + + // if we don't have to wait for an image to load, show the message right away + if ( !this.img ) { + this._delayedShow(); + } + }, + + _delayedShow: function (e) { + setTimeout(this._show.bind(this), this.options.startDelay * 1000 + 500); + }, + + _show: function () { + var that = this; + + // update the viewport size and orientation + this.updateViewport(); + + // reposition/resize the message on orientation change + window.addEventListener('resize', this, false); + window.addEventListener('scroll', this, false); + window.addEventListener('orientationchange', this, false); + + if ( this.options.modal ) { + // lock any other interaction + document.addEventListener('touchmove', this, true); + } + + // Enable closing after 1 second + if ( !this.options.mandatory ) { + setTimeout(function () { + that.element.addEventListener('click', that, true); + }, 1000); + } + + // kick the animation + setTimeout(function () { + that.element.style.webkitTransform = 'translate3d(0,0,0)'; + that.element.style.webkitTransitionDuration = '1.2s'; + }, 0); + + // set the destroy timer + if ( this.options.lifespan ) { + this.removeTimer = setTimeout(this.remove.bind(this), this.options.lifespan * 1000); + } + + // fire the custom onShow event + if ( this.options.onShow ) { + this.options.onShow.call(this); + } + }, + + remove: function () { + clearTimeout(this.removeTimer); + + // clear up the event listeners + if ( this.img ) { + this.img.removeEventListener('load', this, false); + this.img.removeEventListener('error', this, false); + } + + window.removeEventListener('resize', this, false); + window.removeEventListener('scroll', this, false); + window.removeEventListener('orientationchange', this, false); + document.removeEventListener('touchmove', this, true); + this.element.removeEventListener('click', this, true); + + // remove the message element on transition end + this.element.addEventListener('transitionend', this, false); + this.element.addEventListener('webkitTransitionEnd', this, false); + this.element.addEventListener('MSTransitionEnd', this, false); + + // start the fade out animation + this.element.style.webkitTransitionDuration = '0.3s'; + this.element.style.opacity = '0'; + }, + + _removeElements: function () { + this.element.removeEventListener('transitionend', this, false); + this.element.removeEventListener('webkitTransitionEnd', this, false); + this.element.removeEventListener('MSTransitionEnd', this, false); + + // remove the message from the DOM + this.container.removeChild(this.viewport); + + this.shown = false; + + // fire the custom onRemove event + if ( this.options.onRemove ) { + this.options.onRemove.call(this); + } + }, + + updateViewport: function () { + if ( !this.shown ) { + return; + } + + this.viewport.style.width = window.innerWidth + 'px'; + this.viewport.style.height = window.innerHeight + 'px'; + this.viewport.style.left = window.scrollX + 'px'; + this.viewport.style.top = window.scrollY + 'px'; + + var clientWidth = document.documentElement.clientWidth; + + this.orientation = clientWidth > document.documentElement.clientHeight ? 'landscape' : 'portrait'; + + var screenWidth = ath.OS == 'ios' ? this.orientation == 'portrait' ? screen.width : screen.height : screen.width; + this.scale = screen.width > clientWidth ? 1 : screenWidth / window.innerWidth; + + this.element.style.fontSize = this.options.fontSize / this.scale + 'px'; + }, + + resize: function () { + clearTimeout(this.resizeTimer); + this.resizeTimer = setTimeout(this.updateViewport.bind(this), 100); + }, + + updateSession: function () { + if ( ath.hasLocalStorage === false ) { + return; + } + + localStorage.setItem(this.options.appID, JSON.stringify(this.session)); + }, + + clearSession: function () { + this.session = _defaultSession; + this.updateSession(); + }, + + optOut: function () { + this.session.optedout = true; + this.updateSession(); + }, + + optIn: function () { + this.session.optedout = false; + this.updateSession(); + }, + + clearDisplayCount: function () { + this.session.displayCount = 0; + this.updateSession(); + }, + + _preventDefault: function (e) { + e.preventDefault(); + e.stopPropagation(); + } +}; + +// utility +function _extend (target, obj) { + for ( var i in obj ) { + target[i] = obj[i]; + } + + return target; +} + +function _removeToken () { + if ( document.location.hash == '#ath' ) { + history.replaceState('', window.document.title, document.location.href.split('#')[0]); + } + + if ( _reSmartURL.test(document.location.href) ) { + history.replaceState('', window.document.title, document.location.href.replace(_reSmartURL, '$1')); + } + + if ( _reQueryString.test(document.location.search) ) { + history.replaceState('', window.document.title, document.location.href.replace(_reQueryString, '$2')); + } +} + +// expose to the world +window.addToHomescreen = ath; + +})(window, document); diff --git a/less/add2home.css b/less/add2home.css deleted file mode 100644 index a2d64ae..0000000 --- a/less/add2home.css +++ /dev/null @@ -1,180 +0,0 @@ -/** - * - * Main container - * - */ -#addToHomeScreen { - z-index:9999; - -webkit-user-select:none; - user-select:none; - -webkit-box-sizing:border-box; - box-sizing:border-box; - -webkit-touch-callout:none; - touch-callout:none; - width:240px; - font-size:15px; - padding:12px 14px; - text-align:left; - font-family:helvetica; - background-image:-webkit-gradient(linear,0 0,0 100%,color-stop(0,#fff),color-stop(0.02,#eee),color-stop(0.98,#ccc),color-stop(1,#a3a3a3)); - border:1px solid #505050; - -webkit-border-radius:8px; - -webkit-background-clip:padding-box; - color:#333; - text-shadow:0 1px 0 rgba(255,255,255,0.75); - line-height:130%; - -webkit-box-shadow:0 0 4px rgba(0,0,0,0.5); -} - -#addToHomeScreen.addToHomeIOS7 { - background:#f2f2f2 !important; - -webkit-border-radius:1px !important; - border:1px solid #ccc; - -webkit-box-shadow:0 0 4px rgba(0,0,0,0.2); -} - -#addToHomeScreen.addToHomeIpad { - width:268px; - font-size:18px; - padding:14px; -} - -/** - * - * The 'wide' class is added when the popup contains the touch icon - * - */ -#addToHomeScreen.addToHomeWide { - width:296px; -} - -#addToHomeScreen.addToHomeIpad.addToHomeWide { - width:320px; - font-size:18px; - padding:14px; -} - -/** - * - * The balloon arrow - * - */ -#addToHomeScreen .addToHomeArrow { - position:absolute; - background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(0,rgba(204,204,204,0)),color-stop(0.4,rgba(204,204,204,0)),color-stop(0.4,#ccc)); - border-width:0 1px 1px 0; - border-style:solid; - border-color:#505050; - width:16px; height:16px; - -webkit-transform:rotateZ(45deg); - bottom:-9px; - left:50%; - margin-left:-8px; - -webkit-box-shadow:inset -1px -1px 0 #a9a9a9; - -webkit-border-bottom-right-radius:2px; -} - -#addToHomeScreen.addToHomeIOS7 .addToHomeArrow { - background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(0,rgba(204,204,204,0)),color-stop(0.4,rgba(204,204,204,0)),color-stop(0.4,#f2f2f2)) !important; - -webkit-box-shadow:inset -1px -1px 0 #fff !important; - border-color:#ccc !important; -} - -/** - * - * The balloon arrow for iPad - * - */ -#addToHomeScreen.addToHomeIpad .addToHomeArrow { - -webkit-transform:rotateZ(-135deg); - background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(0,rgba(238,238,238,0)),color-stop(0.4,rgba(238,238,238,0)),color-stop(0.4,#eee)); - -webkit-box-shadow:inset -1px -1px 0 #fff; - top:-9px; bottom:auto; left:50%; -} - - -/** - * - * Close button - * - */ -#addToHomeScreen .addToHomeClose { - -webkit-box-sizing:border-box; - position:absolute; - right:4px; - top:4px; - width:18px; - height:18px; line-height:14px; - text-align:center; - text-indent:1px; - -webkit-border-radius:9px; - background:rgba(0,0,0,0.12); - color:#888; - -webkit-box-shadow:0 1px 0 #fff; - font-size:16px; -} - -#addToHomeScreen.addToHomeIOS7 .addToHomeClose { - line-height:12px; - padding-right:1px; - background:transparent; - border: 1px solid #888; - -webkit-box-shadow:none; -} - -/** - * - * The '+' icon, displayed only on iOS < 4.2 - * - */ -#addToHomeScreen .addToHomePlus { - font-weight:bold; - font-size:1.3em; -} - - -/** - * - * The 'share' icon, displayed only on iOS >= 4.2 - * - */ -#addToHomeScreen .addToHomeShare { - display:inline-block; - width:18px; - height:15px; - background-repeat:no-repeat; - background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAeCAQAAADu6HTYAAADPElEQVR4Xq3TX2gcRRzA8e/M7mVv2+TSNpc/TZtrY6jUGqgaSAmEChKLrYK0YH0RFC2CSCkEfCghiKU04J8qNigq6os+iQV98MHWFwVBrQQRWs21lBw5cw3NNb1/udu72RGG5Y77IzXW77D7sAwf5scyYoL6BGXSDKFZwaGpLvIUaeoCkvX1MmsM0Ny6oRSQYOLuIS+YZOpfQdqslpUxcZrzTVAz4qPwW2O3CeIwC/RSzeY6Ow1QhUrkr+YOWfEKDkEP8Rij7CHKJmrFSDHBdwGEE5wiGChPN+PnT8VdRtEIl1d4gRj/1EVe5ZSBKGh8iqQpo/Fo5+3C/gz0MYg4zgwbqday1/Q4B8BGQ45d/Hi54lakCrU5obOcidJpu1+Lg9whjabyaOYLnrIBFFaRD+xe2ybMDWY66GmP/WA9cGfGp0CWhy0wkMN8inepFiH2rV1j0NQSNQbFLRQnS8/8YSDBBpadfv4CYDub2fmeHDNAsL1MBWUel0iA+Xik6eHcyvD3vAMSU1TGuA/YRS+dD7ovCQN43GKRFCU20Kd3V/avDVVyAZ5niTEuLA5/zBGWg9EEEhfJKN200Tat8CmRAQb9+wv7soPlHt2tQorsz1uPbr0HTY4sJwrH47zJZwABBAKLMBoQXepwgTwdHCo+fXMkQ4lrxEmQ5AaXipPqDY9V2vn09tgvTPI71EEGYxM+/uMJLJ4svpgaWGKOi/xKgmqLSUGSUd5f2vIVJ/CgBaTIUsZ7ZBsn0+NzfMOXLFCXQyTcybN6ep5ZZgUOHn7jpfUpsZshdugPGf+E5zjbyHTSRyQ8xfRPPM/s63RHeuknSoT22mjmmnAOIMkUZ6D1xSfPPAfd1WFKM3sO2CMaHx8M1NjnXKHaAGGkOW0C02WeYHUz4qMtx+w5gUDS8NckYe5lHsMYwCZEPyEEmjLDZFmAS7CDviMdxyTkMNVBKEmYLvbiQQBIBBbCQG04bGQvFWz6CfsCQLWCigILFwcfkGYBiOpbYuOizTAyYyDdCtrGaRG1LCkIgMYEFhI0WqQZoSlbGRyHKe4qOx7iv2bVQW9dp4dlM/x6kmwnWQcd/Q3FCqwTEiT5s+6D5v/pb0SSHyg7uhMWAAAAAElFTkSuQmCC); - background-size:18px 15px; - text-indent:-9999em; - overflow:hidden; -} - -#addToHomeScreen.addToHomeIOS7 .addToHomeShare { - width:11px; - background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAA8CAYAAAAQTCjdAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAASCQAAEgkB80sG3AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAKjSURBVGiB7dpPiFVVHMDxz7m9NCtMyI2bEJEC25WrEkzHUXCRraIwdNE8ZxfYIlcis1ZEbGEzT1QCF4XgH1CyWhUoJKIWNRGEiCNKmkSiYTzfcfGuOokx77x3ZlS8382959zfn+/invvn3RdijHIRBrwkOINCYXEcdjpb7VyiYdBsLScwt5y6IloYdzqXo36Ro0gY9IKWo+5JwmzBt2HQnBw9ehYNazyn5TBee8Dh+Vq+CWu92GufnkTDR6ab7gDeBNHouMM/l9tXTXM0fGBmL726Fg1Dam74EsvKqR8VNowL2Yzj5f7rnnE4DHq2235diYYhhTGfC94up35T0y+6di/ITU0rKVd+sEi0P7xr2pSJOu8zvF+OzqEv7vDH/WFxt7/cshy/ticsN8sXYUht0kXDOlsF9XJ4UaEvNoz9X3zc5bKaZThbyr5jzJ4wlNY7KTgM+ES0vhz+KeiPw36fKC/ucAF9uFBOrTZm26SJCtaV27+xIo7cXdkTEhvOoh+XyxprU1qnim7CQdGK2HAyKRexYVShT3RItDElN+mkjiP2Ym+S3f01hv2EVal5WW6hU0ElmptaqJuBpXg6MbeFH2LDpU6CQ93zWIKnEvs0cayGU3glMfkOo1jQYewZzOuyz7FC95Jwo5OgUFfgeg993hh/eTqCTxOSm/iuk8DY0Ap1b2GhtHXxsfZN4j/X0fOx4auEIknEhqv4OiUn1L13Z/+xWfWVaG4q0dxUormpRHNTieamEs1NJZqbJ1Q0jHvdiJo5S2cVjSNOCHZhn3/SnuYnIvl3yomIIz7MXZMn9hydRCrR3FSiualEc1OJ5qYSzU0lmptKNDePjWgwcPePT7/g+4cp8wCW4GXaryK3tL+mLdD5x62ppllgu7bso8q/2HIbzGWdNmWnSJwAAAAASUVORK5CYII=); - background-size:11px 15px; -} - -/** - * - * The touch icon (if available) - * - */ -#addToHomeScreen .addToHomeTouchIcon { - display:block; - float:left; - -webkit-border-radius:6px; - border-radius:6px; - -webkit-box-shadow:0 1px 3px rgba(0,0,0,0.5), - inset 0 0 2px rgba(255,255,255,0.9); - box-shadow:0 1px 3px rgba(0,0,0,0.5), - inset 0 0 2px rgba(255,255,255,0.9); - background-repeat:no-repeat; - width:57px; height:57px; - -webkit-background-size:57px 57px; - background-size:57px 57px; - margin:0 12px 0 0; - border:1px solid #333; - -webkit-background-clip:padding-box; - background-clip:padding-box; -} diff --git a/less/addtohomescreen.css b/less/addtohomescreen.css new file mode 100644 index 0000000..328211f --- /dev/null +++ b/less/addtohomescreen.css @@ -0,0 +1,236 @@ +.ath-viewport * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.ath-viewport { + position: relative; + z-index: 2147483641; + + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + -ms-text-size-adjust: none; + -o-text-size-adjust: none; + text-size-adjust: none; +} + +.ath-modal { + background: rgba(0,0,0,0.6); +} + +.ath-mandatory { + background: #000; +} + +.ath-container { + position: absolute; + z-index: 2147483641; + padding: 0.7em 0.6em; + width: 18em; + + background: #eee; + background-size: 100% auto; + + box-shadow: 0 0.2em 0 #d1d1d1; + + font-family: sans-serif; + font-size: 15px; + line-height: 1.5em; + text-align: center; +} + +.ath-ios.ath-phone { + bottom: 1.8em; + left: 50%; + margin-left: -9em; +} + +.ath-ios7.ath-tablet { + left: 0.7em; + top: 1.8em; +} + +.ath-ios6.ath-tablet { + left: 5em; + top: 1.8em; +} + +.ath-android { + right: 1.5em; + top: 1.8em; +} + +/* close icon */ +.ath-container:before { + content: '×'; + position: relative; + display: block; + float: right; + margin: -0.3em -0.25em 0 0.1em; + background-color: rgba(255,255,255,0.7); + width: 1.2em; + height: 1.2em; + text-align: center; + overflow: hidden; + font-size: 2.3em; + color: #a33; + z-index: 2147483642; +} + +.ath-container.ath-icon:before { + position: absolute; + top: 0; + right: 0; + margin: 0; + float: none; +} + +.ath-mandatory .ath-container:before { + display: none; +} + +.ath-android:before { + line-height: 1.2em; +} + +.ath-ios:before { + line-height: 1em; +} + +.ath-container.ath-android:before { + float: left; + margin: -0.3em 0.1em 0 -0.2em; +} + +.ath-container.ath-android.ath-icon:before { + position: absolute; + right: auto; + left: 0; + margin: 0; + float: none; +} + + +/* applied only if the application icon is shown */ +.ath-container.ath-icon { + +} + +.ath-action-icon { + display: inline-block; + vertical-align: middle; + background-position: 50%; + background-repeat: no-repeat; + text-indent: -9999em; + overflow: hidden; +} + +.ath-android .ath-action-icon { + width: 1.2em; + height: 1.8em; + background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAADcBAMAAAAig/QJAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAFtDAABbQwH5xg68AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAB5QTFRFAAAA////cXFxaWlp////ZmZmnJycoaGhpqam////1D9b6wAAAAV0Uk5TAAgJERExZxYzAAAAYklEQVRYw+3WoQ2AUBAE0SsBOiBUQEIDCArA4FFoHBaJxNItFYz/x5+xz282VmwJTdM0rRzbsS1e7Pm9zdgUVn491rkFmqZpSezEjqo/Sos1HoAEjdjgFmiapiWxG7tq/igfnYteFlnOWZEAAAAASUVORK5CYII=); + background-size: auto 100%; +} + +.ath-ios7 .ath-action-icon { + width: 1.6em; + height: 1.6em; + background-image:url(data:image/png;base64,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); + margin-top: -0.3em; + background-size: auto 100%; +} + +.ath-ios6 .ath-action-icon { + width: 1.8em; + height: 1.8em; + background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAAB0CAQAAADAmnOnAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAAWwEAAFsBAXkZiFwAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAGaklEQVR42u3cfUxVZRwH8O8FRERRfNfKt4zM2UzNMszZFPMPW5KWzizJ0JJWitOU3mYs54ZuNRk6zblSaebUnKllSpopaRorJiqmtjRNK4sNEBR5+fbH45ELwrnn5Tnn3gPP7/cv9/7O/eyc5zyvAF6PrlgAFTrRHcQmtFIQekDEYXRRFA3GzP4gCOI39FcaDcQ7g24BEUUYrTz0gIhKvKZE9IAIIhNhSkUPiNiGaOWiB0Tko4eS0QMi/sQQZaMHRJRivNLRAyKqkKZ89IAIYg1aKCDq5l60U0D6WYDeCkg/r2KEAtLPG5iqgPSzBukKKFB+ikgFpJ+56KyA9PMcHjBXYYwjGRmyQMR/GGWmAqVnNV4N4TuIICowPXhA1ZgR0o+Y6Yk1uTyVeD7E26Da3GpsYk0iTwQ3kSS5nbLboAj0wnBMwGwsRhaysRO5yEMe8iJP2bjig+joIlALbhE86xguCWUgXkYmduMMbjrQVhLEWfRzCagldwmelfTZhOmM8ViGXJQ7hFI3iwK906SUieLXgifTFs9DeA/HUOMKjP87LdlhoFb8RvB8ZJHHhxHIxEWXYfzzY0Q4BtSG3wueDyzhxCAFvwSRJuA7zeYXx/CQ4LEy/3sPlqMkBHBEHkN36UBt+YPgWWgapzfWoiJkcERewECpQB2YR5I1nG/6PbUcN0IMR2QJxhkEWsi0gPkjSVYzxRROS6SjLCRxGplYa+QPq2goqjnTFM8wFIQwjpZZCJcDVMmppu6dTNf7OFbzEDoFAKrcx5yA+ZIJnh444hEckcfRUxcoXe5wMwH/eIqHIK7gUbeAklHlOR4xCElyA2iWR3mIGixyHijDoziMqRw8xflH7H2v8vTjKfIyhzoLNNurPM+xVHRksp0EesabbU84M1hDklVMo885oMdcmhGUnO25W9w7xUx0sh8Ui/Ne5InjCcFTwL4BetI2gbZ5kedZreXZwjYBx2K2gKZ7DydMa3mqRcvjJFAcrnmNJ5ZfiXunlBMNzgfZAPrSazx9eVzwnOB9hmcULQM96TWeCSwRPFv9Wx6ngMKQ3zRaHqeAXvQSTzttNfgaJ5leOLQE5EOhd3j6MF/wnGSchZVVS0Bj5f6ELhzKiZzLdC7nOm7nAebzPIvqZKHF7x7DfwXPNsZYWpu3BLTD/iptPFO4mnt5muWGVg0uW6ozj5UBWh4ngPpYHZxG8nGmcTPPsJpmwzxQK34mPlrGKTY2UFkAWmJ+y8wopnM/y/QEilnAQ9zJbGZxMedzBif559EF5mr24s/ie3/nIFtb8CwAnTV+md04hzm83hBIFQu5mUv5Op/mQMbK3YKXyGJR5Vt2NPqzZAH1N3aJrTmNu1lRn6WUOVzGJA5hlHN7FFNFy0N+yAjbu1xNA70duFOWwPXaeFmLIu7gmxxm5oKtAUVxvahYzhfMVZAFdES/GU7m6bo0Z7mMw2n7jLsxoB78SVQ9T9OHfeUARfluNv5QzeNFf5pCvssBbm4DHsm/ReXvaOGkhhyg+MbeU3N4pZamhGs53O190m/wprZ/0tKDLAdo7p3f4GMSL9Ti/MpZbO32RvIofiKqX2eS1QpSgMI+r//5+7mvFucgE+nQf9TQA7qbR0X9PzjUegUpQG1O1F04eau2j3OAw4JzFGGE9nDvYQc7FaQARRf7rwwc1nDOcbLtbeUWgVK0vtYK2jw5LwMo2nf7c8navVPORWY7fbKAorlRXMMNJtuvIAMoTusKLhXzc2QO74UrcSfQXdodfEnOwy0D6GGxY3qPNj+XBNeiPlCCNs+TY3y05ThQ7EiwK4+JCztjdJTsBFCaNtpaJe9AlgSgsVN6aQOJzWwLBAcokqu1lucVmRUkAC2eeElsKE+F66EBdWOuyXkeF4EYT7LCzZanPtBoXtXmeTrJriAD6AmW8SkgWEC3W541bCm/ggygRxiPIMWSB1cInAqTRyJcnw8KUrD7rXmewY5VaAJA++W3PE0JKMPUPE8MEpoXkLnBcBL+wqpmBWQiemIXCCqghiIcadoxvvYbFFD9GIDDtb9s3EkF5B9RyKj7jy0UkH+MvnNBXAFp0QEbGjoCqoC0mNPwL1NACshYhKUqIN2YvFEB6ca0LxSQAlJACkgBKSAFpICsADXdVEAKSAEpIAWkgBSQAlJACkgBKaDgA41hc8vUXHM3UPOLVQpIAbkH9D87oz0rvnJrOgAAAABJRU5ErkJggg==); + margin-bottom: 0.4em; + background-size: 100% auto; +} + +.ath-container p { + margin: 0; + padding: 0; + position: relative; + z-index: 2147483642; + text-shadow: 0 0.1em 0 #fff; + font-size: 1.1em; +} + +.ath-ios.ath-phone:after { + content: ''; + background: #eee; + position: absolute; + width: 2em; + height: 2em; + bottom: -0.9em; + left: 50%; + margin-left: -1em; + -webkit-transform: scaleX(0.9) rotate(45deg); + transform: scaleX(0.9) rotate(45deg); + box-shadow: 0.2em 0.2em 0 #d1d1d1; +} + +.ath-ios.ath-tablet:after { + content: ''; + background: #eee; + position: absolute; + width: 2em; + height: 2em; + top: -0.9em; + left: 50%; + margin-left: -1em; + -webkit-transform: scaleX(0.9) rotate(45deg); + transform: scaleX(0.9) rotate(45deg); + z-index: 2147483641; +} + +.ath-android:after { + content: ''; + background: #eee; + background: -webkit-linear-gradient(-45deg, rgba(238,238,238,0) 0%,rgba(238,238,238,0) 50%,rgba(238,238,238,1) 50%,rgba(238,238,238,1) 100%); + position: absolute; + width: 2em; + height: 2em; + top: -1.5em; + right: 0; +} + +.ath-application-icon { + position: relative; + padding: 0; + border: 0; + margin: 0 auto 0.2em auto; + height: 6em; + width: 6em; + z-index: 2147483642; +} + +/* OS specific classes */ +.ath-container.ath-ios .ath-application-icon { + border-radius: 1em; + box-shadow: 0 0.2em 0.4em rgba(0,0,0,0.3), + inset 0 0.07em 0 rgba(255,255,255,0.5); + margin: 0 auto 0.4em auto; +} + +@media only screen and (orientation: landscape) { + .ath-container.ath-phone { + width: 24em; + } + + .ath-ios.ath-phone { + margin-left: -12em; + } + + .ath-ios6:after { + left: 39%; + } +} diff --git a/less/styles.less b/less/styles.less index 817abf7..5bb2a69 100644 --- a/less/styles.less +++ b/less/styles.less @@ -58,4 +58,31 @@ body.ui-mobile-viewport { } .ui-loading .ui-loader.fadeIn { opacity: 0.18; +} + +/* Add to home */ +.ath-viewport { + .ath-container { + box-shadow: 0 0 0 0.2em #D1D1D1; + background-color: #fff; + } + .ath-ios.ath-phone:after, + .ath-ios.ath-tablet:after, + .ath-android:after { + background-color: #fff; + } + .ath-android:after { + background: -webkit-linear-gradient(-45deg, rgba(255,255,255,0) 0, + rgba(255,255,255,0) 50%, + rgba(255,255,255,1) 50%, + rgba(255,255,255,1) 100%); + } + // add shadow around up arrow + .ath-ios.ath-tablet:after { + box-shadow: -.2em -.2em 0 #d1d1d1; + } + // close cross color + .ath-container:before { + color: #F18DB1; + } } \ No newline at end of file