This repository has been archived by the owner before Nov 9, 2022. It is now read-only.
Permalink
Aug 19, 2016
Apr 6, 2014
Apr 6, 2014
Nov 22, 2014
Apr 6, 2014
Apr 6, 2014
May 22, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Nov 18, 2014
Apr 6, 2014
Nov 18, 2014
Apr 6, 2014
Nov 18, 2014
May 17, 2015
Nov 18, 2014
Aug 13, 2015
Nov 18, 2014
Apr 6, 2014
Nov 18, 2014
Nov 18, 2014
Nov 18, 2014
Nov 18, 2014
May 17, 2015
Nov 18, 2014
Apr 6, 2014
Jun 6, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 6, 2014
Apr 7, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
May 8, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
May 2, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Nov 22, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Nov 18, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Nov 18, 2014
Apr 6, 2014
Apr 29, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
Apr 6, 2014
May 17, 2015
Apr 6, 2014
Newer
100644
750 lines (614 sloc)
32.1 KB
1
/* Add to Homescreen v3.2.3 ~ (c) 2015 Matteo Spinelli ~ @license: http://cubiq.org/license */
2
(function (window, document) {
3
/*
6
| .'| . | . | | | | . | | . | | -_|_ -| _| _| -_| -_| |
7
|__,|___|___| |_| |___|__|__|___|_|_|_|___|___|___|_| |___|___|_|_|
8
by Matteo Spinelli ~ http://cubiq.org
9
*/
10
11
// Check for addEventListener browser support (prevent errors in IE<9)
12
var _eventListener = 'addEventListener' in window;
14
// Check if document is loaded, needed by autostart
15
var _DOMReady = false;
17
_DOMReady = true;
20
}
21
22
function loaded () {
23
window.removeEventListener('load', loaded, false);
24
_DOMReady = true;
25
}
26
27
// regex used to detect if app has been added to the homescreen
28
var _reSmartURL = /\/ath(\/)?$/;
29
var _reQueryString = /([\?&]ath=[^&]*$|&ath=[^&]*(&))/;
30
31
// singleton
32
var _instance;
33
function ath (options) {
35
37
}
38
39
// message in all supported languages
40
ath.intl = {
41
cs_cs: {
42
ios: 'Pro přidáni této webové aplikace na úvodní obrazovku: stlačte %icon a pak <strong>Přidat na úvodní obrazovku</strong>.',
43
android: 'Pro přidáni této webové aplikace na úvodní obrazovku otevřete menu nastavení prohlížeče a stlačte <strong>Přidat na úvodní obrazovku</strong>. <small>K menu se dostanete stlačením hardwaroveho tlačítka, když ho vaše zařízení má, nebo stlačením pravé horní menu ikony <span class="ath-action-icon">icon</span>.</small>'
44
},
47
ios: 'Um diese Web-App zum Home-Bildschirm hinzuzufügen, tippen Sie auf %icon und dann <strong>Zum Home-Bildschirm</strong>.',
48
android: 'Um diese Web-App zum Home-Bildschirm hinzuzufügen, öffnen Sie das Menü und tippen dann auf <strong>Zum Startbildschirm hinzufügen</strong>. <small>Wenn Ihr Gerät eine Menütaste hat, lässt sich das Browsermenü über diese öffnen. Ansonsten tippen Sie auf %icon.</small>'
51
da_dk: {
52
ios: 'For at tilføje denne web app til hjemmeskærmen: Tryk %icon og derefter <strong>Føj til hjemmeskærm</strong>.',
53
android: 'For at tilføje denne web app til hjemmeskærmen, åbn browser egenskaber menuen og tryk på <strong>Føj til hjemmeskærm</strong>. <small>Denne menu kan tilgås ved at trykke på menu knappen, hvis din enhed har en, eller ved at trykke på det øverste højre menu ikon %icon.</small>'
56
el_gr: {
57
ios: 'Για να προσθέσετε την εφαρμογή στην αρχική οθόνη: πατήστε το %icon και μετά <strong>Πρόσθεσε στην αρχική οθόνη</strong>.',
58
android: 'Για να προσθέσετε την εφαρμογή στην αρχική οθόνη, ανοίξτε τις επιλογές του browser σας και πατήστε το <strong>Προσθήκη στην αρχική οθόνη</strong>. <small>Μπορείτε να έχετε πρόσβαση στο μενού, πατώντας το κουμπί του μενού του κινητού σας ή το πάνω δεξιά κουμπί του μενού %icon.</small>'
59
},
60
61
en_us: {
62
ios: 'To add this web app to the home screen: tap %icon and then <strong>Add to Home Screen</strong>.',
63
android: 'To add this web app to the home screen open the browser option menu and tap on <strong>Add to homescreen</strong>. <small>The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon %icon.</small>'
64
},
65
67
ios: 'Para añadir esta aplicación web a la pantalla de inicio: pulsa %icon y selecciona <strong>Añadir a pantalla de inicio</strong>.',
68
android: 'Para añadir esta aplicación web a la pantalla de inicio, abre las opciones y pulsa <strong>Añadir a pantalla inicio</strong>. <small>El menú se puede acceder pulsando el botón táctil en caso de tenerlo, o bien el icono de la parte superior derecha de la pantalla %icon.</small>'
71
fi_fi: {
72
ios: 'Liitä tämä sovellus kotivalikkoon: klikkaa %icon ja tämän jälkeen <strong>Lisää kotivalikkoon</strong>.',
73
android: 'Lisätäksesi tämän sovelluksen aloitusnäytölle, avaa selaimen valikko ja klikkaa tähti -ikonia tai <strong>Lisää aloitusnäytölle tekstiä</strong>. <small>Valikkoon pääsee myös painamalla menuvalikkoa, jos laitteessasi on sellainen tai koskettamalla oikealla yläkulmassa menu ikonia %icon.</small>'
77
ios: 'Pour ajouter cette application web sur l\'écran d\'accueil : Appuyez %icon et sélectionnez <strong>Ajouter sur l\'écran d\'accueil</strong>.',
78
android: 'Pour ajouter cette application web sur l\'écran d\'accueil : Appuyez sur le bouton "menu", puis sur <strong>Ajouter sur l\'écran d\'accueil</strong>. <small>Le menu peut-être accessible en appuyant sur le bouton "menu" du téléphone s\'il en possède un <i class="fa fa-bars"></i>. Sinon, il se trouve probablement dans la coin supérieur droit du navigateur %icon.</small>'
79
},
80
81
he_il: {
82
ios: '<span dir="rtl">להוספת האפליקציה למסך הבית: ללחוץ על %icon ואז <strong>הוסף למסך הבית</strong>.</span>',
83
android: 'To add this web app to the home screen open the browser option menu and tap on <strong>Add to homescreen</strong>. <small>The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon %icon.</small>'
87
ios: 'Ha hozzá szeretné adni ezt az alkalmazást a kezdőképernyőjéhez, érintse meg a következő ikont: %icon , majd a <strong>Hozzáadás a kezdőképernyőhöz</strong> menüpontot.',
88
android: 'Ha hozzá szeretné adni ezt az alkalmazást a kezdőképernyőjéhez, a böngésző menüjében kattintson a <strong>Hozzáadás a kezdőképernyőhöz</strong> menüpontra. <small>A böngésző menüjét a következő ikon megérintésével tudja megnyitni: %icon.</small>'
91
it_it: {
92
ios: 'Per aggiungere questa web app alla schermata iniziale: premi %icon e poi <strong>Aggiungi a Home</strong>.',
93
android: 'Per aggiungere questa web app alla schermata iniziale, apri il menu opzioni del browser e premi su <strong>Aggiungi alla homescreen</strong>. <small>Puoi accedere al menu premendo il pulsante hardware delle opzioni se la tua device ne ha uno, oppure premendo l\'icona %icon in alto a destra.</small>'
97
ios: 'このウェプアプリをホーム画面に追加するには、%iconをタップして<strong>ホーム画面に追加</strong>してください。',
98
android: 'このウェプアプリをホーム画面に追加するには、ブラウザのオプションメニューから<strong>ホーム画面に追加</strong>をタップしてください。<small>オプションメニューは、一部の機種ではデバイスのメニューボタンから、それ以外では画面右上の%iconからアクセスできます。</small>'
103
android: '브라우저 옵션 메뉴의 <string>홈 화면에 추가</string>를 클릭하여 홈화면에 바로가기를 생성할 수 있습니다. <small>옵션 메뉴는 장치의 메뉴 버튼을 누르거나 오른쪽 상단의 메뉴 아이콘 %icon을 클릭하여 접근할 수 있습니다.</small>'
107
ios: 'For å installere denne appen på hjem-skjermen: trykk på %icon og deretter <strong>Legg til på Hjem-skjerm</strong>.',
108
android: 'For å legge til denne webappen på startsiden åpner en nettlesermenyen og velger <strong>Legg til på startsiden</strong>. <small>Menyen åpnes ved å trykke på den fysiske menyknappen hvis enheten har det, eller ved å trykke på menyikonet øverst til høyre %icon.</small>'
109
},
110
111
pt_br: {
112
ios: 'Para adicionar este app à tela de início: clique %icon e então <strong>Tela de início</strong>.',
113
android: 'Para adicionar este app à tela de início, abra o menu de opções do navegador e selecione <strong>Adicionar à tela inicial</strong>. <small>O menu pode ser acessado pressionando o "menu" button se o seu dispositivo tiver um, ou selecionando o ícone %icon no canto superior direito.</small>'
114
},
115
116
pt_pt: {
117
ios: 'Para adicionar esta app ao ecrã principal: clique %icon e depois <strong>Ecrã principal</strong>.',
118
android: 'Para adicionar esta app web ecrã principal, abra o menu de opções do navegador e selecione <strong>Adicionar à tela inicial</strong>. <small>O menu pode ser acessado pressionando o "menu" button se o seu dispositivo tiver um, ou selecionando o ícone %icon no canto superior direito.</small>'
122
ios: 'Om deze webapp aan je startscherm toe te voegen, klik op %icon en dan <strong>Zet in startscherm</strong>.',
123
android: 'Om deze webapp aan je startscherm toe te voegen, open de browserinstellingen en tik op <strong>Toevoegen aan startscherm</strong>. <small>Gebruik de "menu" knop als je telefoon die heeft, anders het menu-icoon rechtsbovenin %icon.</small>'
126
ru_ru: {
127
ios: 'Чтобы добавить этот сайт на свой домашний экран, нажмите на иконку %icon и затем <strong>На экран "Домой"</strong>.',
128
android: 'Чтобы добавить сайт на свой домашний экран, откройте меню браузера и нажмите на <strong>Добавить на главный экран</strong>. <small>Меню можно вызвать, нажав на кнопку меню вашего телефона, если она есть. Или найдите иконку сверху справа %icon[иконка].</small>'
131
sk_sk: {
132
ios: 'Pre pridanie tejto webovej aplikácie na úvodnú obrazovku: stlačte %icon a potom <strong>Pridať na úvodnú obrazovku</strong>.',
133
android: 'Pre pridanie tejto webovej aplikácie na úvodnú obrazovku otvorte menu nastavenia prehliadača a stlačte <strong>Pridať na úvodnú obrazovku</strong>. <small>K menu sa dostanete stlačením hardwaroveho tlačidla, ak ho vaše zariadenie má, alebo stlačením pravej hornej menu ikony <span class="ath-action-icon">icon</span>.</small>'
134
},
137
ios: 'För att lägga till denna webbapplikation på hemskärmen: tryck på %icon och därefter <strong>Lägg till på hemskärmen</strong>.',
138
android: 'För att lägga till den här webbappen på hemskärmen öppnar du webbläsarens alternativ-meny och väljer <strong>Lägg till på startskärmen</strong>. <small>Man hittar menyn genom att trycka på hårdvaruknappen om din enhet har en sådan, eller genom att trycka på menyikonen högst upp till höger %icon.</small>'
139
},
140
141
tr_tr: {
142
ios: 'Uygulamayı ana ekrana eklemek için, %icon ve ardından <strong>ana ekrana ekle</strong> butonunu tıklayın.',
143
android: 'Uygulamayı ana ekrana eklemek için, menüye girin ve <strong>ana ekrana ekle</strong> butonunu tıklayın. <small>Cihazınız menü tuşuna sahip ise menüye girmek için menü tuşunu tıklayın. Aksi takdirde %icon butonunu tıklayın.</small>'
147
ios: 'Щоб додати цей сайт на початковий екран, натисніть %icon, а потім <strong>На початковий екран</strong>.',
148
android: 'Щоб додати цей сайт на домашній екран, відкрийте меню браузера та виберіть <strong>Додати на головний екран</strong>. <small>Це можливо зробити, натиснувши кнопку меню на вашому смартфоні, якщо така є. Або ж на іконці зверху справа %icon.</small>'
153
android: 'To add this web app to the home screen open the browser option menu and tap on <strong>Add to homescreen</strong>. <small>The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon %icon.</small>'
158
android: 'To add this web app to the home screen open the browser option menu and tap on <strong>Add to homescreen</strong>. <small>The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon %icon.</small>'
160
};
161
162
// Add 2 characters language support (Android mostly)
163
for ( var lang in ath.intl ) {
164
ath.intl[lang.substr(0, 2)] = ath.intl[lang];
165
}
166
167
// default options
168
ath.defaults = {
169
appID: 'org.cubiq.addtohome', // local storage name (no need to change)
170
fontSize: 15, // base font size, used to properly resize the popup based on viewport scale factor
171
debug: false, // override browser checks
172
logging: false, // log reasons for showing or not showing to js console; defaults to true when debug is true
173
modal: false, // prevent further actions until the message is closed
174
mandatory: false, // you can't proceed if you don't add the app to the homescreen
175
autostart: true, // show the message automatically
176
skipFirstVisit: false, // show only to returning visitors (ie: skip the first time you visit)
178
lifespan: 15, // life of the message in seconds
179
displayPace: 1440, // minutes before the message is shown again (0: display every time, default 24 hours)
180
maxDisplayCount: 0, // absolute maximum number of times the message will be shown to the user (0: no limit)
181
icon: true, // add touch icon to the message
182
message: '', // the message can be customized
183
validLocation: [], // list of pages where the message will be shown (array of regexes)
184
onInit: null, // executed on instance creation
185
onShow: null, // executed when the message is shown
186
onRemove: null, // executed when the message is removed
187
onAdd: null, // when the application is launched the first time from the homescreen (guesstimate)
188
onPrivate: null, // executed if user is in private mode
190
detectHomescreen: false // try to detect if the site has been added to the homescreen (false | true | 'hash' | 'queryString' | 'smartURL')
191
};
192
193
// browser info and capability
194
var _ua = window.navigator.userAgent;
196
var _nav = window.navigator;
197
_extend(ath, {
198
hasToken: document.location.hash == '#ath' || _reSmartURL.test(document.location.href) || _reQueryString.test(document.location.search),
199
isRetina: window.devicePixelRatio && window.devicePixelRatio > 1,
200
isIDevice: (/iphone|ipod|ipad/i).test(_ua),
201
isMobileChrome: _ua.indexOf('Android') > -1 && (/Chrome\/[.0-9]*/).test(_ua) && _ua.indexOf("Version") == -1,
202
isMobileIE: _ua.indexOf('Windows Phone') > -1,
204
});
205
206
// falls back to en_us if language is unsupported
207
ath.language = ath.language && ath.language in ath.intl ? ath.language : 'en_us';
209
ath.isMobileSafari = ath.isIDevice && _ua.indexOf('Safari') > -1 && _ua.indexOf('CriOS') < 0;
210
ath.OS = ath.isIDevice ? 'ios' : ath.isMobileChrome ? 'android' : ath.isMobileIE ? 'windows' : 'unsupported';
211
213
ath.OSVersion = ath.OSVersion && ath.OSVersion[2] ? +ath.OSVersion[2].replace('_', '.') : 0;
214
215
ath.isStandalone = 'standalone' in window.navigator && window.navigator.standalone;
216
ath.isTablet = (ath.isMobileSafari && _ua.indexOf('iPad') > -1) || (ath.isMobileChrome && _ua.indexOf('Mobile') < 0);
217
218
ath.isCompatible = (ath.isMobileSafari && ath.OSVersion >= 6) || ath.isMobileChrome; // TODO: add winphone
219
220
var _defaultSession = {
221
lastDisplayTime: 0, // last time we displayed the message
222
returningVisitor: false, // is this the first time you visit
223
displayCount: 0, // number of times the message has been shown
224
optedout: false, // has the user opted out
225
added: false // has been actually added to the homescreen
226
};
227
228
ath.removeSession = function (appID) {
229
try {
234
localStorage.removeItem(appID || ath.defaults.appID);
235
} catch (e) {
236
// we are most likely in private mode
237
}
238
};
239
240
ath.doLog = function (logStr) {
241
if ( this.options.logging ) {
242
console.log(logStr);
243
}
244
};
245
246
ath.Class = function (options) {
250
// merge default options with user config
251
this.options = _extend({}, ath.defaults);
252
_extend(this.options, options);
254
if ( this.options && this.options.debug && (typeof this.options.logging === "undefined") ) {
257
258
// IE<9 so exit (I hate you, really)
259
if ( !_eventListener ) {
260
return;
261
}
262
263
// normalize some options
264
this.options.mandatory = this.options.mandatory && ( 'standalone' in window.navigator || this.options.debug );
265
this.options.modal = this.options.modal || this.options.mandatory;
266
if ( this.options.mandatory ) {
267
this.options.startDelay = -0.5; // make the popup hasty
268
}
269
this.options.detectHomescreen = this.options.detectHomescreen === true ? 'hash' : this.options.detectHomescreen;
270
271
// setup the debug environment
272
if ( this.options.debug ) {
273
ath.isCompatible = true;
274
ath.OS = typeof this.options.debug == 'string' ? this.options.debug : ath.OS == 'unsupported' ? 'android' : ath.OS;
276
}
277
278
// the element the message will be appended to
280
281
// load session
284
285
// user most likely came from a direct link containing our token, we don't need it and we remove it
286
if ( ath.hasToken && ( !ath.isCompatible || !this.session ) ) {
287
ath.hasToken = false;
288
_removeToken();
289
}
290
292
if ( !ath.isCompatible ) {
293
this.doLog("Add to homescreen: not displaying callout because device not supported");
294
return;
295
}
297
this.session = this.session || _defaultSession;
298
299
// check if we can use the local storage
300
try {
305
localStorage.setItem(this.options.appID, JSON.stringify(this.session));
306
ath.hasLocalStorage = true;
307
} catch (e) {
308
// we are most likely in private mode
309
ath.hasLocalStorage = false;
310
311
if ( this.options.onPrivate ) {
312
this.options.onPrivate.call(this);
313
}
314
}
315
316
// check if this is a valid location
317
var isValidLocation = !this.options.validLocation.length;
318
for ( var i = this.options.validLocation.length; i--; ) {
319
if ( this.options.validLocation[i].test(document.location.href) ) {
320
isValidLocation = true;
321
break;
322
}
323
}
324
325
// check compatibility with old versions of add to homescreen. Opt-out if an old session is found
330
// critical errors:
331
if ( this.session.optedout ) {
332
this.doLog("Add to homescreen: not displaying callout because user opted out");
333
return;
334
}
335
if ( this.session.added ) {
336
this.doLog("Add to homescreen: not displaying callout because already added to the homescreen");
337
return;
338
}
339
if ( !isValidLocation ) {
340
this.doLog("Add to homescreen: not displaying callout because not a valid location");
341
return;
342
}
343
344
// check if the app is in stand alone mode
345
if ( ath.isStandalone ) {
346
// execute the onAdd event if we haven't already
347
if ( !this.session.added ) {
348
this.session.added = true;
349
this.updateSession();
350
351
if ( this.options.onAdd && ath.hasLocalStorage ) { // double check on localstorage to avoid multiple calls to the custom event
352
this.options.onAdd.call(this);
353
}
354
}
355
356
this.doLog("Add to homescreen: not displaying callout because in standalone mode");
357
return;
358
}
359
360
// (try to) check if the page has been added to the homescreen
361
if ( this.options.detectHomescreen ) {
362
// the URL has the token, we are likely coming from the homescreen
363
if ( ath.hasToken ) {
364
_removeToken(); // we don't actually need the token anymore, we remove it to prevent redistribution
366
// this is called the first time the user opens the app from the homescreen
367
if ( !this.session.added ) {
368
this.session.added = true;
369
this.updateSession();
370
371
if ( this.options.onAdd && ath.hasLocalStorage ) { // double check on localstorage to avoid multiple calls to the custom event
372
this.options.onAdd.call(this);
373
}
374
}
375
376
this.doLog("Add to homescreen: not displaying callout because URL has token, so we are likely coming from homescreen");
377
return;
378
}
379
381
if ( this.options.detectHomescreen == 'hash' ) {
382
history.replaceState('', window.document.title, document.location.href + '#ath');
383
} else if ( this.options.detectHomescreen == 'smartURL' ) {
384
history.replaceState('', window.document.title, document.location.href.replace(/(\/)?$/, '/ath$1'));
385
} else {
386
history.replaceState('', window.document.title, document.location.href + (document.location.search ? '&' : '?' ) + 'ath=');
387
}
388
}
389
390
// check if this is a returning visitor
391
if ( !this.session.returningVisitor ) {
392
this.session.returningVisitor = true;
393
this.updateSession();
394
395
// we do not show the message if this is your first visit
396
if ( this.options.skipFirstVisit ) {
397
this.doLog("Add to homescreen: not displaying callout because skipping first visit");
398
return;
399
}
400
}
401
402
// we do no show the message in private mode
404
this.doLog("Add to homescreen: not displaying callout because browser is in private mode");
405
return;
406
}
407
409
this.ready = true;
410
411
if ( this.options.onInit ) {
412
this.options.onInit.call(this);
413
}
414
415
if ( this.options.autostart ) {
417
this.show();
418
}
419
};
420
421
ath.Class.prototype = {
422
// event type to method conversion
423
events: {
424
load: '_delayedShow',
426
orientationchange: 'resize',
427
resize: 'resize',
428
scroll: 'resize',
429
click: 'remove',
430
touchmove: '_preventDefault',
431
transitionend: '_removeElements',
432
webkitTransitionEnd: '_removeElements',
433
MSTransitionEnd: '_removeElements'
434
},
435
436
handleEvent: function (e) {
437
var type = this.events[e.type];
438
if ( type ) {
439
this[type](e);
440
}
441
},
442
443
show: function (force) {
444
// in autostart mode wait for the document to be ready
445
if ( this.options.autostart && !_DOMReady ) {
446
setTimeout(this.show.bind(this), 50);
447
// we are not displaying callout because DOM not ready, but don't log that because
448
// it would log too frequently
449
return;
450
}
451
454
this.doLog("Add to homescreen: not displaying callout because already shown on screen");
458
var now = Date.now();
459
var lastDisplayTime = this.session.lastDisplayTime;
460
461
if ( force !== true ) {
462
// this is needed if autostart is disabled and you programmatically call the show() method
463
if ( !this.ready ) {
467
468
// we obey the display pace (prevent the message to popup too often)
469
if ( now - lastDisplayTime < this.options.displayPace * 60000 ) {
470
this.doLog("Add to homescreen: not displaying callout because displayed recently");
473
474
// obey the maximum number of display count
475
if ( this.options.maxDisplayCount && this.session.displayCount >= this.options.maxDisplayCount ) {
476
this.doLog("Add to homescreen: not displaying callout because displayed too many times already");
479
}
480
481
this.shown = true;
482
483
// increment the display count
484
this.session.lastDisplayTime = now;
485
this.session.displayCount++;
486
this.updateSession();
487
488
// try to get the highest resolution application icon
489
if ( !this.applicationIcon ) {
490
if ( ath.OS == 'ios' ) {
491
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]');
492
} else {
493
this.applicationIcon = document.querySelector('head link[rel^="shortcut icon"][sizes="196x196"],head link[rel^=apple-touch-icon]');
494
}
495
}
496
497
var message = '';
498
499
if ( typeof this.options.message == 'object' && ath.language in this.options.message ) { // use custom language message
500
message = this.options.message[ath.language][ath.OS];
501
} else if ( typeof this.options.message == 'object' && ath.OS in this.options.message ) { // use custom os message
502
message = this.options.message[ath.OS];
506
message = this.options.message;
509
}
510
511
// add the action icon
512
message = '<p>' + message.replace(/%icon(?:\[([^\]]+)\])?/gi, function(matches, group1) {
513
return '<span class="ath-action-icon">' + (!!group1 ? group1 : 'icon') + '</span>';
515
516
// create the message container
517
this.viewport = document.createElement('div');
518
this.viewport.className = 'ath-viewport';
519
if ( this.options.modal ) {
520
this.viewport.className += ' ath-modal';
521
}
522
if ( this.options.mandatory ) {
523
this.viewport.className += ' ath-mandatory';
524
}
525
this.viewport.style.position = 'absolute';
526
527
// create the actual message element
528
this.element = document.createElement('div');
529
this.element.className = 'ath-container ath-' + ath.OS + ' ath-' + ath.OS + (parseInt(ath.OSVersion) || '') + ' ath-' + (ath.isTablet ? 'tablet' : 'phone');
530
this.element.style.cssText = '-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0s;-webkit-transition-timing-function:ease-out;transition-property:transform,opacity;transition-duration:0s;transition-timing-function:ease-out;';
531
this.element.style.webkitTransform = 'translate3d(0,-' + window.innerHeight + 'px,0)';
533
534
// add the application icon
535
if ( this.options.icon && this.applicationIcon ) {
536
this.element.className += ' ath-icon';
537
this.img = document.createElement('img');
538
this.img.className = 'ath-application-icon';
539
this.img.addEventListener('load', this, false);
540
this.img.addEventListener('error', this, false);
541
542
this.img.src = this.applicationIcon.href;
543
this.element.appendChild(this.img);
544
}
545
546
this.element.innerHTML += message;
547
548
// we are not ready to show, place the message out of sight
549
this.viewport.style.left = '-99999em';
550
551
// attach all elements to the DOM
552
this.viewport.appendChild(this.element);
553
this.container.appendChild(this.viewport);
554
555
// if we don't have to wait for an image to load, show the message right away
556
if ( this.img ) {
557
this.doLog("Add to homescreen: not displaying callout because waiting for img to load");
558
} else {
559
this._delayedShow();
560
}
561
},
562
564
setTimeout(this._show.bind(this), this.options.startDelay * 1000 + 500);
565
},
566
567
_show: function () {
568
var that = this;
569
570
// update the viewport size and orientation
571
this.updateViewport();
572
573
// reposition/resize the message on orientation change
574
window.addEventListener('resize', this, false);
575
window.addEventListener('scroll', this, false);
576
window.addEventListener('orientationchange', this, false);
577
578
if ( this.options.modal ) {
579
// lock any other interaction
580
document.addEventListener('touchmove', this, true);
581
}
582
583
// Enable closing after 1 second
584
if ( !this.options.mandatory ) {
585
setTimeout(function () {
586
that.element.addEventListener('click', that, true);
587
}, 1000);
588
}
589
590
// kick the animation
591
setTimeout(function () {
592
that.element.style.webkitTransitionDuration = '1.2s';
593
that.element.style.transitionDuration = '1.2s';
594
that.element.style.webkitTransform = 'translate3d(0,0,0)';
595
that.element.style.transform = 'translate3d(0,0,0)';
596
}, 0);
597
598
// set the destroy timer
599
if ( this.options.lifespan ) {
600
this.removeTimer = setTimeout(this.remove.bind(this), this.options.lifespan * 1000);
601
}
602
603
// fire the custom onShow event
604
if ( this.options.onShow ) {
605
this.options.onShow.call(this);
606
}
607
},
608
609
remove: function () {
610
clearTimeout(this.removeTimer);
611
612
// clear up the event listeners
613
if ( this.img ) {
614
this.img.removeEventListener('load', this, false);
615
this.img.removeEventListener('error', this, false);
616
}
617
618
window.removeEventListener('resize', this, false);
619
window.removeEventListener('scroll', this, false);
621
document.removeEventListener('touchmove', this, true);
622
this.element.removeEventListener('click', this, true);
623
625
this.element.addEventListener('transitionend', this, false);
626
this.element.addEventListener('webkitTransitionEnd', this, false);
627
this.element.addEventListener('MSTransitionEnd', this, false);
628
629
// start the fade out animation
630
this.element.style.webkitTransitionDuration = '0.3s';
631
this.element.style.opacity = '0';
632
},
633
634
_removeElements: function () {
635
this.element.removeEventListener('transitionend', this, false);
636
this.element.removeEventListener('webkitTransitionEnd', this, false);
637
this.element.removeEventListener('MSTransitionEnd', this, false);
638
639
// remove the message from the DOM
640
this.container.removeChild(this.viewport);
641
642
this.shown = false;
643
644
// fire the custom onRemove event
645
if ( this.options.onRemove ) {
646
this.options.onRemove.call(this);
647
}
648
},
649
650
updateViewport: function () {
651
if ( !this.shown ) {
652
return;
653
}
654
655
this.viewport.style.width = window.innerWidth + 'px';
656
this.viewport.style.height = window.innerHeight + 'px';
657
this.viewport.style.left = window.scrollX + 'px';
658
this.viewport.style.top = window.scrollY + 'px';
659
660
var clientWidth = document.documentElement.clientWidth;
661
662
this.orientation = clientWidth > document.documentElement.clientHeight ? 'landscape' : 'portrait';
663
664
var screenWidth = ath.OS == 'ios' ? this.orientation == 'portrait' ? screen.width : screen.height : screen.width;
665
this.scale = screen.width > clientWidth ? 1 : screenWidth / window.innerWidth;
666
667
this.element.style.fontSize = this.options.fontSize / this.scale + 'px';
668
},
669
670
resize: function () {
671
clearTimeout(this.resizeTimer);
672
this.resizeTimer = setTimeout(this.updateViewport.bind(this), 100);
673
},
674
675
updateSession: function () {
676
if ( ath.hasLocalStorage === false ) {
677
return;
678
}
679
680
if (localStorage) {
681
localStorage.setItem(this.options.appID, JSON.stringify(this.session));
682
}
683
},
684
685
clearSession: function () {
686
this.session = _defaultSession;
687
this.updateSession();
688
},
689
696
return localStorage.getItem(item);
697
} catch(e) {
698
// Preventing exception for some browsers when fetching localStorage key
699
ath.hasLocalStorage = false;
700
}
701
},
703
optOut: function () {
704
this.session.optedout = true;
705
this.updateSession();
706
},
707
708
optIn: function () {
709
this.session.optedout = false;
710
this.updateSession();
711
},
712
713
clearDisplayCount: function () {
714
this.session.displayCount = 0;
715
this.updateSession();
716
},
717
718
_preventDefault: function (e) {
719
e.preventDefault();
720
e.stopPropagation();
721
}
722
};
723
724
// utility
725
function _extend (target, obj) {
726
for ( var i in obj ) {
727
target[i] = obj[i];
728
}
729
730
return target;
731
}
732
733
function _removeToken () {
734
if ( document.location.hash == '#ath' ) {
735
history.replaceState('', window.document.title, document.location.href.split('#')[0]);
736
}
737
738
if ( _reSmartURL.test(document.location.href) ) {
739
history.replaceState('', window.document.title, document.location.href.replace(_reSmartURL, '$1'));
740
}
741
742
if ( _reQueryString.test(document.location.search) ) {
743
history.replaceState('', window.document.title, document.location.href.replace(_reQueryString, '$2'));
744
}
745
}
746
747
// expose to the world
748
window.addToHomescreen = ath;
749