From 8f1a0fa721fd99af47df385a691566c03064c357 Mon Sep 17 00:00:00 2001 From: strukturart Date: Sat, 30 Sep 2023 23:00:02 +0200 Subject: [PATCH] KaiOS 3 webActivity --- application/app.js | 98 +++++------ application/assets/css/main.css | 11 +- application/assets/js/ads.js | 2 +- application/manifest.webapp | 2 +- application/manifest.webmanifest | 6 +- application/oauth.js | 56 +++--- application/sw.js | 19 +- apps-ads.txt | 281 ++++++++++++++++++++++++++++++ docs/oauth.js | 56 +++--- images/kaios-marketing-banner.jpg | Bin 14828 -> 7307 bytes 10 files changed, 410 insertions(+), 121 deletions(-) create mode 100644 apps-ads.txt diff --git a/application/app.js b/application/app.js index a793f301..111e15db 100644 --- a/application/app.js +++ b/application/app.js @@ -40,7 +40,7 @@ const google_oauth_url = export let events = []; export let accounts = []; export let event_templates = []; - +export let closing_prohibited = false; export let search_history = []; const google_acc = { @@ -128,7 +128,6 @@ let style_calendar_cell = function () { } if (rrule_check(p).rrule == true) { - // e.classList.add('event'); e.classList.add('rrule'); if (rrule_check(p).count > 1) e.classList.add('multievent'); @@ -176,6 +175,7 @@ async function getClientInstance(item) { ///load events async function load_caldav(callback = false) { + closing_prohibited = true; // Clear events events = events.filter((e) => !e.isCaldav); @@ -233,11 +233,12 @@ async function load_caldav(callback = false) { document.getElementById('icon-loading').style.visibility = 'hidden'; if (callback) side_toaster('all event reloaded', 2000); } - + closing_prohibited = false; style_calendar_cell(currentYear, currentMonth); side_toaster('Data loaded', 3000); } catch (e) { if (m.route.get() === '/page_calendar') { + closing_prohibited = false; document.getElementById('icon-loading').style.visibility = 'hidden'; } } @@ -477,7 +478,7 @@ export let create_caldav = async function ( try { sort_array(events, 'dateStartUnix', 'number'); } catch (e) { - alert(e); + console.log(e); } }, 5000); } @@ -663,7 +664,6 @@ export let sync_caldav_callback = function () { ) == true ) { m.route.set('/page_events', { query: 'sort_by_last_mod' }); - status.sortEvents = 'startDate'; } }); }; @@ -692,21 +692,26 @@ localforage //load accounts data //load cached data -localforage - .getItem('accounts') - .then(function (value) { +async function loadAccounts() { + try { + const value = await localforage.getItem('accounts'); if (value == null) { accounts = []; return false; } accounts = value; - setTimeout(() => { - load_cached_caldav(); - }, 100); - }) - .catch(function (err) { + return true; + } catch (err) { console.log(err); - }); + return false; + } +} + +loadAccounts().then((result) => { + if (result) { + load_cached_caldav(); + } +}); //store templates let store_event_as_template = function ( @@ -1107,7 +1112,7 @@ let event_slider = function (date) { document.querySelectorAll('div#event-slider article')[0].style.display = 'block'; } catch (e) { - alert(e); + console.log(e); } } } @@ -1487,7 +1492,7 @@ var page_calendar = { id: 'time', oncreate: function () { document.getElementById('time').innerText = - dayjs().format('hh:mm'); + dayjs().format('HH:mm'); }, }, 'time is relative' @@ -1588,6 +1593,7 @@ var page_events = { if (!query) find_closest_date(); if (query == 'sort_by_last_mod') { sort_array_last_mod(); + status.sortEvents = 'startDate'; } bottom_bar( @@ -2201,7 +2207,6 @@ export let page_options = { onfocus: function () { bottom_bar('', 'open ads', ''); - alert('kk'); }, onblur: function () { bottom_bar('', 'open ads', ''); @@ -3464,16 +3469,13 @@ localforage if (value != null) { events = value; try { - sort_array(events, 'dateStartUnix', 'number'); style_calendar_cell(currentYear, currentMonth); } catch (e) { - alert(e); + console.log(e); } //check if calendar has updated - setTimeout(() => { - sync_caldav(sync_caldav_callback); - }, 1000); + sync_caldav(sync_caldav_callback); } }) .catch(function (err) {}); @@ -3624,12 +3626,11 @@ let nav = function (move) { highlight_current_day(); }; -if ('b2g' in Navigator) { +if ('b2g' in navigator) { try { navigator.serviceWorker .register(new URL('sw.js', import.meta.url), { type: 'module', - scope: '/', }) .then((registration) => { registration.systemMessageManager.subscribe('alarm').then( @@ -3706,7 +3707,7 @@ let add_alarm = function (date, message_text, id) { (err) => console.log('add err: ' + err) ); } catch (e) { - alert(e); + console.log(e); } } }; @@ -3763,7 +3764,7 @@ let remove_alarm = function (id) { }); }; } catch (e) { - alert(e); + console.log(e); } } }; @@ -4560,7 +4561,7 @@ function shortpress_action(param) { return true; } - if (m.route.get() == '/page_events') { + if (m.route.get().startsWith('/page_events')) { sort_events(); return true; } @@ -4585,10 +4586,7 @@ function shortpress_action(param) { if (m.route.get() == '/page_event_templates') { delete_template(document.activeElement.getAttribute('data-id')); } - if ( - m.route.get() == '/page_events' || - m.route.get().startsWith('/page_events_filtered') - ) { + if (m.route.get().startsWith('/page_events')) { if (document.activeElement.classList.contains('subscription')) { toaster('a subscription cannot be edited', 2000); return false; @@ -4673,11 +4671,12 @@ function shortpress_action(param) { if (events.length > 0) { if (m.route.get().startsWith('/page_events')) { + m.route.set('/page_calendar'); + if (document.activeElement.tagName == 'INPUT') - m.route.set('/page_calendar'); - setTimeout(() => { - jump_to_today(); - }, 1000); + setTimeout(() => { + jump_to_today(); + }, 1000); } else if ( m.route.get() === '/page_calendar' || m.route.get() === '/page_events' @@ -4738,6 +4737,9 @@ function shortpress_action(param) { break; case '0': + if(!settings.eventsfilter){ + side_toaster("no category selected, you can do that in the settings",4000) + } if (document.activeElement.tagName == 'INPUT') return false; m.route.set('/page_events_filtered', { query: settings.eventsfilter }); break; @@ -4754,12 +4756,12 @@ function handleKeyDown(evt) { } if (evt.key === 'Backspace' && m.route.get() == '/page_calendar') { - window.close(); + if (closing_prohibited == false) window.close(); } if (evt.key === 'EndCall') { evt.preventDefault(); - window.close(); + if (closing_prohibited == false) window.close(); } if (!evt.repeat) { longpress = false; @@ -4809,6 +4811,15 @@ let interval_is_running = false; let lastMessageTime; // Store the timestamp of the last received message let running = false; channel.addEventListener('message', (event) => { + //callback from Google OAuth + //ugly method to open a new window, because a window from sw clients.open can no longer be closed + + if (event.data.oauth_success) { + const l = event.data.oauth_success; + setTimeout(() => { + window.open(l); + }, 5000); + } if (event.data.action == 'parse') { lastMessageTime = Date.now(); // Update the timestamp for the last received message running = true; @@ -4820,21 +4831,8 @@ channel.addEventListener('message', (event) => { } } if (event.data.action == 'error') { - console.log(event.data.content); document.getElementById('icon-waiting').style.visibility = 'hidden'; } - - //callback from Google OAuth - //ugly method to open a new window, because a window from sw clients.open can no longer be closed - - if (event.data.oauth_succes) { - const l = event.data.oauth_success; - if (event.data.oauth_success) { - setTimeout(() => { - window.open(l); - }, 5000); - } - } }); let interval = () => { diff --git a/application/assets/css/main.css b/application/assets/css/main.css index 1ba7e882..fc2a551f 100644 --- a/application/assets/css/main.css +++ b/application/assets/css/main.css @@ -384,16 +384,19 @@ div#intro img { } #KaiOsAd { - height: 200px; + height: 264px; width: 240px; } #KaiOsAds-Wrapper { - padding: 10px; + padding: 0px; + height: 264px; + width: 240px; } #KaiOsAds-Wrapper iframe { - width: 220px; + width: 240px; + height: 264px; } /*/////////////////////////// @@ -857,7 +860,7 @@ div#options { position: absolute; z-index: 4; top: 0; - padding: 0px 5px 5px 0px; + padding: 0px 0px 0px 0px; height: 92vh; overflow: hidden; } diff --git a/application/assets/js/ads.js b/application/assets/js/ads.js index 6b98bdbc..183faa35 100644 --- a/application/assets/js/ads.js +++ b/application/assets/js/ads.js @@ -12,7 +12,7 @@ export let load_ads = function () { slot: 'greg', test: 0, timeout: 10000, - h: 100, + h: 264, w: 240, container: document.getElementById('KaiOsAds-Wrapper'), onerror: (err) => console.error('Error:', err), diff --git a/application/manifest.webapp b/application/manifest.webapp index d7e6a070..807bee90 100644 --- a/application/manifest.webapp +++ b/application/manifest.webapp @@ -1,5 +1,5 @@ { - "version": "2.2.4", + "version": "2.2.563", "name": "greg", "id": "greg", "categories": ["utilities"], diff --git a/application/manifest.webmanifest b/application/manifest.webmanifest index 5259ac71..00debe6a 100644 --- a/application/manifest.webmanifest +++ b/application/manifest.webmanifest @@ -23,7 +23,7 @@ ], "b2g_features": { - "version": "3.0.9", + "version": "3.0.210", "id": "greg", "subtitle": "easy to use calendar", "core": true, @@ -77,9 +77,9 @@ }, "feature-detection": { "description": "query which keys are available" - }, + } - "worker-activity": {} + } } diff --git a/application/oauth.js b/application/oauth.js index e93e83d3..32efbb3b 100644 --- a/application/oauth.js +++ b/application/oauth.js @@ -1,49 +1,49 @@ -"use strict"; +'use strict'; -import localforage from "localforage"; -import { uid } from "uid"; -import { google_cred } from "./assets/js/google_cred.js"; +import localforage from 'localforage'; +import { uid } from 'uid'; +import { google_cred } from './assets/js/google_cred.js'; localforage.setDriver(localforage.INDEXEDDB); -let authorizationCode = ""; +let authorizationCode = ''; let get_token = function () { var urlParams = new URLSearchParams(window.location.search); - const authorizationCode = urlParams.get("code"); + const authorizationCode = urlParams.get('code'); var myHeaders = new Headers(); - myHeaders.append("Content-Type", "application/x-www-form-urlencoded"); + myHeaders.append('Content-Type', 'application/x-www-form-urlencoded'); var urlencoded = new URLSearchParams(); //urlencoded.append("code", b[0]); - urlencoded.append("code", authorizationCode); - urlencoded.append("grant_type", "authorization_code"); + urlencoded.append('code', authorizationCode); + urlencoded.append('grant_type', 'authorization_code'); urlencoded.append( - "redirect_uri", - "https://greg.strukturart.com/redirect.html", + 'redirect_uri', + 'https://greg.strukturart.com/redirect.html' ); - urlencoded.append("client_id", google_cred.clientId); - urlencoded.append("client_secret", google_cred.clientSecret); + urlencoded.append('client_id', google_cred.clientId); + urlencoded.append('client_secret', google_cred.clientSecret); var requestOptions = { - method: "POST", + method: 'POST', headers: myHeaders, body: urlencoded, - redirect: "follow", + redirect: 'follow', }; - return fetch("https://oauth2.googleapis.com/token", requestOptions).then( - (response) => response.json(), + return fetch('https://oauth2.googleapis.com/token', requestOptions).then( + (response) => response.json() ); }; get_token().then((result) => { //localStorage.setItem("oauth_auth", JSON.stringify(result)); let accounts = []; - localStorage.setItem("oauth_back", "true"); + localStorage.setItem('oauth_back', 'true'); localforage - .getItem("accounts") + .getItem('accounts') .then(function (value) { if (value == null) { accounts = []; @@ -53,30 +53,30 @@ get_token().then((result) => { } accounts.push({ - server_url: "https://apidata.googleusercontent.com/caldav/v2/", + server_url: 'https://apidata.googleusercontent.com/caldav/v2/', tokens: result, authorizationCode: authorizationCode, - name: "Google", + name: 'Google', id: uid(32), - type: "oauth", + type: 'oauth', }); localforage - .setItem("accounts", accounts) + .setItem('accounts', accounts) .then(function () { - document.getElementById("success").innerText = - "Account successfully added to greg"; - localStorage.setItem("oauth_callback", "true"); + document.getElementById('success').innerText = + 'Account successfully added to greg'; + localStorage.setItem('oauth_callback', 'true'); setTimeout(function () { window.close(); }, 3000); }) .catch(function (err) { // This code runs if there were any errors - console.log(err); + alert(err); }); }) .catch(function (err) { - console.log(err); + alert(err); }); }); diff --git a/application/sw.js b/application/sw.js index 2ec9b701..7f5f1c67 100644 --- a/application/sw.js +++ b/application/sw.js @@ -1,6 +1,8 @@ import ICAL from 'ical.js'; import dayjs from 'dayjs'; +const channel = new BroadcastChannel('sw-messages'); + const parse_ics = function ( data, isSubscription, @@ -98,14 +100,10 @@ const parse_ics = function ( calendar_name: calendar_name, id: account_id, }; - - }); return imp; }; -const channel = new BroadcastChannel('sw-messages'); - self.addEventListener('message', (event) => { // Receive a message from the main thread if (!event.data) { @@ -127,6 +125,12 @@ self.addEventListener('message', (event) => { }); self.onsystemmessage = (evt) => { + try { + channel.postMessage({ action: 'info', content: evt.name }); + } catch (e) { + channel.postMessage({ action: 'error', content: e }); + } + try { let m = evt.data.json(); self.registration.showNotification('Greg', { @@ -135,7 +139,7 @@ self.onsystemmessage = (evt) => { } catch (e) {} try { - const serviceHandler = () => { + const serviceHandler = async () => { if (evt.name === 'activity') { handler = evt.data.webActivityRequestHandler(); const { name: activityName, data: activityData } = handler.source; @@ -149,6 +153,9 @@ self.onsystemmessage = (evt) => { } } }; + evt.waitUntil(serviceHandler()); - } catch (e) {} + } catch (e) { + channel.postMessage({ action: 'error', content: e }); + } }; diff --git a/apps-ads.txt b/apps-ads.txt new file mode 100644 index 00000000..e4777d90 --- /dev/null +++ b/apps-ads.txt @@ -0,0 +1,281 @@ +mars.media, 107588, DIRECT, 8624339f102fb076 +improvedigital.com, 1221, RESELLER +pubmatic.com, 160194, RESELLER, 5d62403b186f2ace +improvedigital.com, 1210, RESELLER +castify.ai, 127588, DIRECT +conversantmedia.com, 100293, RESELLER, 03113cd04947736d +improvedigital.com, 1662, RESELLER +themediagrid.com, PLTXGE, RESELLER, 35d5010d7789b49d +themediagrid.com, YUPM3V, RESELLER, 35d5010d7789b49d +appnexus.com, 12223, RESELLER, f5ab79cb980f11d1 +smartadserver.com, 4039, RESELLER +improvedigital.com, 1341, RESELLER +appnexus.com, 13074, RESELLER, f5ab79cb980f11d1 +aol.com, 59025, RESELLER, e1a5b5b6e3255540 +yahoo.com, 59025, RESELLER, e1a5b5b6e3255540 +rhythmone.com, 4270213217, RESELLER, a670c89d4a324e47 +smaato.com, 1100050531, RESELLER, 07bcf65f187117b4 +conversantmedia.com, 100343, RESELLER, 03113cd04947736d +video.unrulymedia.com, 4270213217, RESELLER +sonobi.com, a7c3746d6a, RESELLER, d1a215d9eb5aee9e +yieldmo.com, 2888605025750164242, RESELLER +gitberry.com, 64Q, DIRECT +pubmatic.com, 160195, RESELLER, 5d62403b186f2ace +beachfront.com, 805, RESELLER, e2541279e8e2ca4d +mars.media, 107588, DIRECT, 8624339f102fb076 +beachfront.com, 805, RESELLER, e2541279e8e2ca4d +improvedigital.com, 1210, RESELLER +improvedigital.com, 1221, RESELLER +improvedigital.com, 1341, RESELLER +appnexus.com, 12223, RESELLER, f5ab79cb980f11d1 +pubmatic.com, 160195, RESELLER, 5d62403b186f2ace +pubmatic.com, 160194, RESELLER, 5d62403b186f2ace +gitberry.com, 64Q, DIRECT +improvedigital.com, 1662, RESELLER +castify.ai, 127588, DIRECT +smartadserver.com, 4039, RESELLER +sonobi.com, a7c3746d6a, RESELLER, d1a215d9eb5aee9e +conversantmedia.com, 100293, RESELLER, 03113cd04947736d +appnexus.com, 13074, RESELLER, f5ab79cb980f11d1 +aol.com, 59025, RESELLER, e1a5b5b6e3255540 +yahoo.com, 59025, RESELLER, e1a5b5b6e3255540 +indexexchange.com, 195812, RESELLER, 50b1c356f2c5c8fc +yieldmo.com, 2888605025750164242, RESELLER +themediagrid.com, PLTXGE, RESELLER, 35d5010d7789b49d +themediagrid.com, YUPM3V, RESELLER, 35d5010d7789b49d +video.unrulymedia.com, 4270213217, RESELLER +rhythmone.com, 4270213217, RESELLER, a670c89d4a324e47 +smaato.com, 1100050531, RESELLER, 07bcf65f187117b4 +conversantmedia.com, 100343, RESELLER, 03113cd04947736d +admixer.net, b6d49994-83c5-4ff9-aa8a-c9eb99d1bc8c, RESELLER +contextweb.com, 558827, DIRECT, 89ff185a4c4e857c +contextweb.com, 562067, DIRECT, 89ff185a4c4e857c +appnexus.com, 12061, RESELLER, f5ab79cb980f11d1 +freewheel.tv, 1163473, RESELLER +newborntown.com, 108961, DIRECT +fout.jp, 1151, DIRECT +spotxchange.com, 246977, RESELLER, 7842df1d2fe2db34 +spotx.tv, 246977, RESELLER, 7842df1d2fe2db34 +tappx.com, 22230, RESELLER, 9f375a07da0318ec +adcolony.com, c490f6e7399a25d6, RESELLER, 1ad675c9de6b5176 +appnexus.com, 10824, RESELLER, f5ab79cb980f11d1 +appnexus.com, 9569, RESELLER, f5ab79cb980f11d1 +chartboost.com, 5da62a1035b91e0aff190bf7, RESELLER +groundtruth.com, 107, RESELLER, 81cbf0a75a5e0e9a +inmobi.com, ec6f6ceb8bb1440ba5455644ec96c275, RESELLER, 83e75a7ae333ca9d +pubmatic.com, 156435, RESELLER, 5d62403b186f2ace +pubmatic.com, 158111, RESELLER, 5d62403b186f2ace +pubmatic.com, 158112, RESELLER, 5d62403b186f2ace +pubmatic.com, 92509, RESELLER, 5d62403b186f2ace +rubiconproject.com, 13856, RESELLER, 0bfd66d529a55807 +smartadserver.com, 1692, RESELLER +google.com, pub-8207541904035788, DIRECT, f08c47fec0942fa0 +openx.com, 540163881, RESELLER, 6a698e2ec38604c6 +mobuppsrtb.com, 0fd7e4f42a8b4b4ef33394d35212b13e, DIRECT +loopme.com, 11185, DIRECT, 6c8d5f95897a5a3b +improvedigital.com, 1785, DIRECT +meitu.com, 433, DIRECT +admatic.com.tr, adm-pub-185375301865, DIRECT +airnow.com, 403001, DIRECT +airnow.com, 404001, DIRECT +onetag.com, 5e0db5c3f1904a6, DIRECT +admixer.net, 81aedb7e-ca73-4498-997c-74f3b92481ea, DIRECT +mobirtb.com, 137, DIRECT +ucfunnel.com, pub-627D23D82BA9DE2EFE344BA8B788D683, DIRECT +aralego.com, pub-627D23D82BA9DE2EFE344BA8B788D683, DIRECT +adiiix.com, pub-627D23D82BA9DE2EFE344BA8B788D683, DIRECT +rtb.gamoshi.io, 267-b850, RESELLER +sovrn.com, 299269, DIRECT, fafdf38b16bf6b2b +lijit.com, 299269, DIRECT, fafdf38b16bf6b2b +onetag.com, 59d216e971852f2, RESELLER +appnexus.com, 3153, RESELLER, f5ab79cb980f11d1 +meitu.com, 251, RESELLER +pubmatic.com, 157654, RESELLER, 5d62403b186f2ace +adcolony.com, f858ba060bce51ad, RESELLER, 1ad675c9de6b5176 +openx.com, 540899687, RESELLER, 6a698e2ec38604c6 +rubiconproject.com, 18224, RESELLER, 0bfd66d529a55807 +smartadserver.com, 1894, RESELLER +smartadserver.com, 3445, RESELLER +appnexus.com, 10490, RESELLER, f5ab79cb980f11d1 +supply.colossusssp.com, 211, DIRECT, 6c5b49d96ec1b458 +admixer.net, 81aedb7e-ca73-4498-997c-74f3b92481ea, RESELLER +aralego.com, par-D232D76A227923DA1D28D94AA9699AE8, RESELLER +ucfunnel.com, par-D232D76A227923DA1D28D94AA9699AE8, RESELLER +cmcm.com, 127, RESELLER +rhythmone.com, 3900035207, RESELLER, a670c89d4a324e47 +indexexchange.com, 182257, RESELLER, 50b1c356f2c5c8fc +spotxchange.com, 285547, RESELLER, 7842df1d2fe2db34 +spotx.tv, 285547, RESELLER, 7842df1d2fe2db34 +video.unrulymedia.com, 3900035207, RESELLER +advangelists.com, 1be3bc32e6564055d5ca3e5a354acbef, DIRECT, 60d26397ec060f98 +adform.com, 2600, DIRECT +stroeer.com, 14214, DIRECT +contextweb.com, 558750, DIRECT, 89ff185a4c4e857c +mobuppsrtb.com, c74d97b01eae257e44aa9d5bade97baf4471, RESELLER +improvedigital.com, 1785, RESELLER +indexexchange.com, 192104, DIRECT, 50b1c356f2c5c8fc +improvedigital.com, 912, RESELLER +pubmatic.com, 159078, RESELLER, 5d62403b186f2ace +stroeer.com, 17938, DIRECT +improvedigital.com, 1275, RESELLER +pubmatic.com, 159831, DIRECT, 5d62403b186f2ace +pubmatic.com, 159897, RESELLER, 5d62403b186f2ace +appnexus.com, 8217, RESELLER, f5ab79cb980f11d1 +openx.com, 540011801, RESELLER, 6a698e2ec38604c6 +loopme.com, 11281, RESELLER, 6c8d5f95897a5a3b +meitu.com, 253, DIRECT +smartyads.com, 1406, DIRECT, fd2bde0ff2e62c5d +smartyads.com, 1373, DIRECT, fd2bde0ff2e62c5d +smartyads.com, 1725, DIRECT, fd2bde0ff2e62c5d +improvedigital.com, 1797, RESELLER +sovrn.com, 289960, RESELLER, fafdf38b16bf6b2b +pubmatic.com, 158651, RESELLER, 5d62403b186f2ace +freewheel.tv, 1073329, RESELLER +freewheel.tv, 1073345, RESELLER +onetag.com, 5e3b68a4a263f95, RESELLER +waardex.com, 112907, DIRECT +epom.com, 9640d532-1239-4845-bb8e-0dc447b7b915, RESELLER, a05085f3142a1ca8 +tappx.com, 33376, DIRECT, 9f375a07da0318ec +improvedigital.com, 1678, RESELLER +loopme.com, 11272, RESELLER, 6c8d5f95897a5a3b +rubiconproject.com, 20744, RESELLER, 0bfd66d529a55807 +openx.com, 540298543, RESELLER, 6a698e2ec38604c6 +pubmatic.com, 158154, RESELLER, 5d62403b186f2ace +engagebdr.com, 80, DIRECT +vyadd.com, 12854, RESELLER +improvedigital.com, 1714, RESELLER +web3.us.com, 63207, DIRECT +mgid.com, 505794, DIRECT, d4c29acad76ce94f +admixer.net, 54355ed6-7634-45fe-b731-5e4e5a8515b9, DIRECT +e-planning.net, ec771b05828a67fa, RESELLER, c1ba615865ed87b2 +sovrn.com, 268876, RESELLER, fafdf38b16bf6b2b +lijit.com, 268876, RESELLER, fafdf38b16bf6b2b +openx.com, 541031350, RESELLER, 6a698e2ec38604c6 +improvedigital.com, 1556, RESELLER +axonix.com, 56222, RESELLER +contextweb.com, 562309, RESELLER, 89ff185a4c4e857c +conversantmedia.com, 100066, RESELLER, 03113cd04947736d +rubiconproject.com, 12186, RESELLER, 0bfd66d529a55807 +onetag.com, 59d216e971852f2, DIRECT +betweendigital.com, 43070, DIRECT +rubiconproject.com, 19724, RESELLER, 0bfd66d529a55807 +google.com, pub-5289985627731322, RESELLER, f08c47fec0942fa0 +meitu.com, 251, DIRECT +cmcm.com, 127, DIRECT +germaniavid.com, d9d4f495e875a2e075a1a4a6e1b9770f6900, RESELLER +improvedigital.com, 1728, RESELLER +admixer.net, c9ed39e8-724d-4012-ae61-38a5ac81bb0e, DIRECT +betweendigital.com, 43070, RESELLER +streamkey.tv, 3070, RESELLER, f5ab793he40f11d1 +telaria.com, j5en0-29eta, RESELLER, 1a4e959a1b50034a +meitu.com, 479, RESELLER +sonobi.com, 2b21773f25, DIRECT, d1a215d9eb5aee9e +rhythmone.com, 1059622079, RESELLER, a670c89d4a324e47 +contextweb.com, 560606, RESELLER, 89ff185a4c4e857c +rubiconproject.com, 22982, DIRECT, 0bfd66d529a55807 +taboola.com, 1304158, DIRECT, c228e6794e811952 +spotx.tv, 71451, RESELLER, 7842df1d2fe2db34 +quantumdex.io, EXU5919, RESELLER +ssp.e-volution.ai, AJxF6R108a9M6CaTvK, RESELLER +lunamedia.io, 3b57f8b19b67a806513dec9b47557783, RESELLER, 524ecb396915caaf +themediagrid.com, R28I9J, RESELLER, 35d5010d7789b49d +pubmatic.com, 160493, RESELLER, 5d62403b186f2ace +betweendigital.com, 43092, RESELLER +ssp.logan.ai, AJxF6R2a9M6CaTvK, RESELLER +spotxchange.com, 71451, RESELLER, 7842df1d2fe2db34 +advertising.com, 8603, RESELLER +pubmatic.com, 156307, RESELLER, 5d62403b186f2ace +appnexus.com, 3364, RESELLER, f5ab79cb980f11d1 +indexexchange.com, 183756, RESELLER, 50b1c356f2c5c8fc +contextweb.com, 560382, RESELLER, 89ff185a4c4e857c +openx.com, 539154393, RESELLER, 6a698e2ec38604c6 +tremorhub.com, z87wm, RESELLER, 1a4e959a1b50034a +rubiconproject.com, 16698, RESELLER, 0bfd66d529a55807 +freewheel.tv, 799921, RESELLER +rhythmone.com, 1166984029, RESELLER, a670c89d4a324e47 +smartadserver.com, 3563, RESELLER +beachfront.com, 13749, RESELLER, e2541279e8e2ca4d +advertising.com, 28458, RESELLER +emxdgt.com, 1643, RESELLER, 1e1d41537f7cad7f +improvedigital.com, 1577, RESELLER +video.unrulymedia.com, 1166984029, RESELLER +video.unrulymedia.com, 2252555169, DIRECT +rhythmone.com, 2252555169, DIRECT, a670c89d4a324e47 +gamoshi.io, 267-b4657, DIRECT +gamoshi.io, 267-b4657, RESELLER +sonobi.com, 94997de4e6, DIRECT, d1a215d9eb5aee9e +inmobi.com, 30f3571d1dec45cf80d13b74ed1fffb2, RESELLER, 83e75a7ae333ca9d +kaiads.com, 37907027-6df6-40cd-a683-98a5bb5f3da2, DIRECT +conversantmedia.com, 100264, RESELLER, 03113cd04947736d +adform.com, 2795, RESELLER +admixer.co.kr, 1538, RESELLER +ssp.logan.ai, LG4, RESELLER +betweendigital.com, 43837, RESELLER +outbrain.com, 0052a1ede0a266bb35758ae42f0a6f91db, DIRECT +appnexus.com, 7597, RESELLER, f5ab79cb980f11d1 +tremorhub.com, q017o-78mlk, RESELLER, 1a4e959a1b50034a +teads.tv, 15429, RESELLER, 15a9c44f6d26cbe1 +advertising.com, 26154, RESELLER +spotxchange.com, 225721, RESELLER +freewheel.tv, 741650, RESELLER +rubiconproject.com, 17130, RESELLER, 0bfd66d529a55807 +lkqd.net, 450, RESELLER, 59c49fa9598a0117 +openx.com, 540393169, RESELLER, 6a698e2ec38604c6 +spotx.tv, 238936, RESELLER, 7842df1d2fe2db34 +spotxchange.com, 238936, RESELLER, 7842df1d2fe2db34 +advertising.com, 28038, RESELLER +rubiconproject.com, 19668, RESELLER, 0bfd66d529a55807 +indexexchange.com, 190856, RESELLER, 50b1c356f2c5c8fc +pubmatic.com, 158615, RESELLER, 5d62403b186f2ace +vidazoo.com, 1773068026, RESELLER, b6ada874b4d7d0b2 +lkqd.net, 602, RESELLER, 59c49fa9598a0117 +beachfront.com, 14027, RESELLER, e2541279e8e2ca4d +smartadserver.com, 3820, RESELLER +rhythmone.com, 367782854, RESELLER, a670c89d4a324e47 +video.unrulymedia.com, 367782854, RESELLER +indexexchange.com, 193091, RESELLER, 50b1c356f2c5c8fc +pubmatic.com, 160065, RESELLER, 5d62403b186f2ace +synacor.com, 82423, RESELLER, e108f11b2cdf7d5b +improvedigital.com, 1863, RESELLER +freewheel.tv, 1220655, RESELLER +smaato.com, 1100048704, RESELLER, 07bcf65f187117b4 +vidoomy.com, 61107, RESELLER +contextweb.com, 562145, RESELLER, 89ff185a4c4e857c +mobupps.com, c74d97b01eae257e44aa9d5bade97baf4471, DIRECT +catapultx.com, 141027, DIRECT +e-planning.net,90db94ab9bfec725,DIRECT,c1ba615865ed87b2 +betweendigital.com, 43807, DIRECT +supply.colossusssp.com, 285, DIRECT, 6c5b49d96ec1b458 +appnexus.com,10490,RESELLER, f5ab79cb980f11d1 +contextweb.com,562060,DIRECT, 89ff185a4c4e857c +rhythmone.com,2147483647,RESELLER, a670c89d4a324e47 +video.unrulymedia.com,2147483647,RESELLER, a670c89d4a324e47 +pubmatic.com,160114,RESELLER, 5d62403b186f2ace +tpmn.io, 505, RESELLER +inmobi.com, ab915bcef5b24940bf745f1a8f427bec, RESELLER, 83e75a7ae333ca9d +rubiconproject.com, 11726, RESELLER, 0bfd66d529a55807 +tpmn.io, 504, RESELLER +motionspots.com, 117041, DIRECT, f0220652b4aaebdc +yeahmobi.com,5135235,DIRECT +adsgard.net, 902, DIRECT, 36a1c66e1a2f76dd +opera.com,pub5954318212352,DIRECT,55a0c5fd61378de3 +appnexus.com,13227,RESELLER +yahoo.com, 59052, RESELLER +risecodes.com,6022acddc8b2f90001767980, RESELLER +yahoo.com, 59040, RESELLER, e1a5b5b6e3255540 +emxdgt.com, 2014, RESELLER, 1e1d41537f7cad7f +pubmatic.com, 161463, RESELLER, 5d62403b186f2ace +germaniavid.com, 433197, RESELLER +vidoomy.com, 8219011, DIRECT +appnexus.com, 12475, RESELLER, f5ab79cb980f11d1 +yahoo.com, 56860, RESELLER, e1a5b5b6e3255540 +germaniavid.com, 433198, RESELLER +pubmatic.com, 156498, RESELLER, 5d62403b186f2ace +adform.com, 2742, RESELLER +opera.com, pub6794514651328, DIRECT, 55a0c5fd61378de3 +conversantmedia.com, 100269, RESELLER, 03113cd04947736d +triplelift.com, 10522, RESELLER, 6c33edb13117fd86 +yahoo.com, 58935, RESELLER, e1a5b5b6e3255540 +lemmatechnologies.com, 188, RESELLER, 7829010c5bebd1fb +appnexus.com, 13227, RESELLER +kaiads.com, 4408b6fa-4e1d-438f-af4d-f3be2fa97208, DIRECT diff --git a/docs/oauth.js b/docs/oauth.js index e93e83d3..32efbb3b 100644 --- a/docs/oauth.js +++ b/docs/oauth.js @@ -1,49 +1,49 @@ -"use strict"; +'use strict'; -import localforage from "localforage"; -import { uid } from "uid"; -import { google_cred } from "./assets/js/google_cred.js"; +import localforage from 'localforage'; +import { uid } from 'uid'; +import { google_cred } from './assets/js/google_cred.js'; localforage.setDriver(localforage.INDEXEDDB); -let authorizationCode = ""; +let authorizationCode = ''; let get_token = function () { var urlParams = new URLSearchParams(window.location.search); - const authorizationCode = urlParams.get("code"); + const authorizationCode = urlParams.get('code'); var myHeaders = new Headers(); - myHeaders.append("Content-Type", "application/x-www-form-urlencoded"); + myHeaders.append('Content-Type', 'application/x-www-form-urlencoded'); var urlencoded = new URLSearchParams(); //urlencoded.append("code", b[0]); - urlencoded.append("code", authorizationCode); - urlencoded.append("grant_type", "authorization_code"); + urlencoded.append('code', authorizationCode); + urlencoded.append('grant_type', 'authorization_code'); urlencoded.append( - "redirect_uri", - "https://greg.strukturart.com/redirect.html", + 'redirect_uri', + 'https://greg.strukturart.com/redirect.html' ); - urlencoded.append("client_id", google_cred.clientId); - urlencoded.append("client_secret", google_cred.clientSecret); + urlencoded.append('client_id', google_cred.clientId); + urlencoded.append('client_secret', google_cred.clientSecret); var requestOptions = { - method: "POST", + method: 'POST', headers: myHeaders, body: urlencoded, - redirect: "follow", + redirect: 'follow', }; - return fetch("https://oauth2.googleapis.com/token", requestOptions).then( - (response) => response.json(), + return fetch('https://oauth2.googleapis.com/token', requestOptions).then( + (response) => response.json() ); }; get_token().then((result) => { //localStorage.setItem("oauth_auth", JSON.stringify(result)); let accounts = []; - localStorage.setItem("oauth_back", "true"); + localStorage.setItem('oauth_back', 'true'); localforage - .getItem("accounts") + .getItem('accounts') .then(function (value) { if (value == null) { accounts = []; @@ -53,30 +53,30 @@ get_token().then((result) => { } accounts.push({ - server_url: "https://apidata.googleusercontent.com/caldav/v2/", + server_url: 'https://apidata.googleusercontent.com/caldav/v2/', tokens: result, authorizationCode: authorizationCode, - name: "Google", + name: 'Google', id: uid(32), - type: "oauth", + type: 'oauth', }); localforage - .setItem("accounts", accounts) + .setItem('accounts', accounts) .then(function () { - document.getElementById("success").innerText = - "Account successfully added to greg"; - localStorage.setItem("oauth_callback", "true"); + document.getElementById('success').innerText = + 'Account successfully added to greg'; + localStorage.setItem('oauth_callback', 'true'); setTimeout(function () { window.close(); }, 3000); }) .catch(function (err) { // This code runs if there were any errors - console.log(err); + alert(err); }); }) .catch(function (err) { - console.log(err); + alert(err); }); }); diff --git a/images/kaios-marketing-banner.jpg b/images/kaios-marketing-banner.jpg index 1f15c90874c587283539b74b697d19e3d670fa63..d61afbf290fba93a140b082e820cef8c8db05234 100644 GIT binary patch literal 7307 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 literal 14828 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

$KTFZUcJzAXwxU+%R*OAP~h(2ic2VB$ZeD4 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 YE(-FFM*{ab4sE&