Permalink
Browse files

More changes to support mobile site

  • Loading branch information...
mjibson committed Sep 26, 2016
1 parent a567e89 commit e86cdd13306bd48c362d2e4b46642e0f5528fea2

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="shortcut icon" href="/static/media/favicon.073a9b34.png"><link rel="manifest" href="/manifest.json"><title>go read</title><link href="/static/css/main.65b84ec7.css" rel="stylesheet"></head><body><div id="root"></div><script>"serviceWorker"in navigator&&navigator.serviceWorker.register("service-worker.js")["catch"](function(e){console.warn(e),console.warn("(This warning can be safely ignored outside of the production build.)")})</script><script type="text/javascript" src="/static/js/main.481aa287.js"></script></body></html>

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,12 @@
{
"name": "go read",
"icons": [
{
"src": "/static/icon.svg",
"sizes": "144x144",
"type": "image/svg"
}
],
"start_url": "/",
"display": "standalone"
}
View
Binary file not shown.
@@ -0,0 +1,232 @@
/**
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// DO NOT EDIT THIS GENERATED OUTPUT DIRECTLY!
// This file should be overwritten as part of your build process.
// If you need to extend the behavior of the generated service worker, the best approach is to write
// additional code and include it using the importScripts option:
// https://github.com/GoogleChrome/sw-precache#importscripts-arraystring
//
// Alternatively, it's possible to make changes to the underlying template file and then use that as the
// new base for generating output, via the templateFilePath option:
// https://github.com/GoogleChrome/sw-precache#templatefilepath-string
//
// If you go that route, make sure that whenever you update your sw-precache dependency, you reconcile any
// changes made to this original template file with your modified copy.
// This generated service worker JavaScript will precache your site's resources.
// The code needs to be saved in a .js file at the top-level of your site, and registered
// from your pages in order to be used. See
// https://github.com/googlechrome/sw-precache/blob/master/demo/app/js/service-worker-registration.js
// for an example of how you can register this script and handle various service worker events.
/* eslint-env worker, serviceworker */
/* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */
'use strict';
var precacheConfig = [["index.html","fc0e7e7092ba0bed4543d4d0a0352fb2"],["manifest.json","209d80d668b987158d352259ca743178"],["static/css/main.65b84ec7.css","f3010f1e061717e0179e78007ac41d7a"],["static/js/main.481aa287.js","bb27cbb8b26d2adc2a67ea8da8906027"],["static/media/favicon.073a9b34.png","073a9b34b0aca23d287ae80efbde921c"]];
var cacheName = 'sw-precache-v2-sw-precache-' + (self.registration ? self.registration.scope : '');
var ignoreUrlParametersMatching = [/^utm_/];
var addDirectoryIndex = function (originalUrl, index) {
var url = new URL(originalUrl);
if (url.pathname.slice(-1) === '/') {
url.pathname += index;
}
return url.toString();
};
var createCacheKey = function (originalUrl, paramName, paramValue,
dontCacheBustUrlsMatching) {
// Create a new URL object to avoid modifying originalUrl.
var url = new URL(originalUrl);
// If dontCacheBustUrlsMatching is not set, or if we don't have a match,
// then add in the extra cache-busting URL parameter.
if (!dontCacheBustUrlsMatching ||
!(url.toString().match(dontCacheBustUrlsMatching))) {
url.search += (url.search ? '&' : '') +
encodeURIComponent(paramName) + '=' + encodeURIComponent(paramValue);
}
return url.toString();
};
var isPathWhitelisted = function (whitelist, absoluteUrlString) {
// If the whitelist is empty, then consider all URLs to be whitelisted.
if (whitelist.length === 0) {
return true;
}
// Otherwise compare each path regex to the path of the URL passed in.
var path = (new URL(absoluteUrlString)).pathname;
return whitelist.some(function(whitelistedPathRegex) {
return path.match(whitelistedPathRegex);
});
};
var stripIgnoredUrlParameters = function (originalUrl,
ignoreUrlParametersMatching) {
var url = new URL(originalUrl);
url.search = url.search.slice(1) // Exclude initial '?'
.split('&') // Split into an array of 'key=value' strings
.map(function(kv) {
return kv.split('='); // Split each 'key=value' string into a [key, value] array
})
.filter(function(kv) {
return ignoreUrlParametersMatching.every(function(ignoredRegex) {
return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes.
});
})
.map(function(kv) {
return kv.join('='); // Join each [key, value] array into a 'key=value' string
})
.join('&'); // Join the array of 'key=value' strings into a string with '&' in between each
return url.toString();
};
var hashParamName = '_sw-precache';
var urlsToCacheKeys = new Map(
precacheConfig.map(function(item) {
var relativeUrl = item[0];
var hash = item[1];
var absoluteUrl = new URL(relativeUrl, self.location);
var cacheKey = createCacheKey(absoluteUrl, hashParamName, hash, false);
return [absoluteUrl.toString(), cacheKey];
})
);
function setOfCachedUrls(cache) {
return cache.keys().then(function(requests) {
return requests.map(function(request) {
return request.url;
});
}).then(function(urls) {
return new Set(urls);
});
}
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return setOfCachedUrls(cache).then(function(cachedUrls) {
return Promise.all(
Array.from(urlsToCacheKeys.values()).map(function(cacheKey) {
// If we don't have a key matching url in the cache already, add it.
if (!cachedUrls.has(cacheKey)) {
return cache.add(new Request(cacheKey, {credentials: 'same-origin'}));
}
})
);
});
}).then(function() {
// Force the SW to transition from installing -> active state
return self.skipWaiting();
})
);
});
self.addEventListener('activate', function(event) {
var setOfExpectedUrls = new Set(urlsToCacheKeys.values());
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.keys().then(function(existingRequests) {
return Promise.all(
existingRequests.map(function(existingRequest) {
if (!setOfExpectedUrls.has(existingRequest.url)) {
return cache.delete(existingRequest);
}
})
);
});
}).then(function() {
return self.clients.claim();
})
);
});
self.addEventListener('fetch', function(event) {
if (event.request.method === 'GET') {
// Should we call event.respondWith() inside this fetch event handler?
// This needs to be determined synchronously, which will give other fetch
// handlers a chance to handle the request if need be.
var shouldRespond;
// First, remove all the ignored parameter and see if we have that URL
// in our cache. If so, great! shouldRespond will be true.
var url = stripIgnoredUrlParameters(event.request.url, ignoreUrlParametersMatching);
shouldRespond = urlsToCacheKeys.has(url);
// If shouldRespond is false, check again, this time with 'index.html'
// (or whatever the directoryIndex option is set to) at the end.
var directoryIndex = 'index.html';
if (!shouldRespond && directoryIndex) {
url = addDirectoryIndex(url, directoryIndex);
shouldRespond = urlsToCacheKeys.has(url);
}
// If shouldRespond is still false, check to see if this is a navigation
// request, and if so, whether the URL matches navigateFallbackWhitelist.
var navigateFallback = '';
if (!shouldRespond &&
navigateFallback &&
(event.request.mode === 'navigate') &&
isPathWhitelisted([], event.request.url)) {
url = new URL(navigateFallback, self.location).toString();
shouldRespond = urlsToCacheKeys.has(url);
}
// If shouldRespond was set to true at any point, then call
// event.respondWith(), using the appropriate cache key.
if (shouldRespond) {
event.respondWith(
caches.open(cacheName).then(function(cache) {
return cache.match(urlsToCacheKeys.get(url)).then(function(response) {
if (response) {
return response;
}
throw Error('The cached response that was expected is missing.');
});
}).catch(function(e) {
// Fall back to just fetch()ing the request if some unexpected error
// prevented the cached response from being valid.
console.warn('Couldn\'t serve response for "%s" from cache: %O', event.request.url, e);
return fetch(event.request);
})
);
}
}
});
View
@@ -319,6 +319,7 @@
<li><a href="#" ng-click="shown = 'import-opml'">import opml</a></li>
<li class="divider"></li>
<li><a href="{{url "export-opml"}}">export opml</a></li>
<li><a href="#" ng-click="mobileSite()">mobile site</a></li>
<li><a href="{{url "logout"}}">logout</a></li>
<li class="divider"></li>
<li><a href="#" data-url="{{url "feed-history"}}" id="feed-history" ng-click="getFeedHistory()">feed history</a></li>
View
39 main.go
@@ -20,9 +20,11 @@ import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/mjibson/goread/_third_party/github.com/MiniProfiler/go/miniprofiler"
@@ -34,8 +36,11 @@ import (
"appengine/datastore"
)
var router = new(mux.Router)
var templates *template.Template
var (
router = new(mux.Router)
templates *template.Template
mobileIndex []byte
)
func init() {
var err error
@@ -50,6 +55,10 @@ func init() {
); err != nil {
log.Fatal(err)
}
mobileIndex, err = ioutil.ReadFile("static/index.html")
if err != nil {
log.Fatal(err)
}
miniprofiler.ToggleShortcut = "Alt+C"
miniprofiler.Position = "bottomleft"
@@ -122,21 +131,33 @@ func RegisterHandlers(r *mux.Router) {
func wrap(f func(mpg.Context, http.ResponseWriter, *http.Request)) http.Handler {
handler := mpg.NewHandler(f)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
o := r.Header.Get("Origin")
if isDevServer || o == "https://m.goread.io" || o == "http://localhost:3000" {
w.Header().Add("Access-Control-Allow-Origin", o)
if isDevServer {
w.Header().Add("Access-Control-Allow-Origin", r.Header.Get("Origin"))
w.Header().Add("Access-Control-Allow-Credentials", "true")
}
handler.ServeHTTP(w, r)
})
}
func Main(c mpg.Context, w http.ResponseWriter, r *http.Request) {
if err := templates.ExecuteTemplate(w, "base.html", includes(c, w, r)); err != nil {
c.Errorf("%v", err)
serveError(w, err)
ua := r.Header.Get("User-Agent")
mobile := strings.Contains(ua, "Mobi")
if desktop, _ := r.Cookie("goread-desktop"); desktop != nil {
switch desktop.Value {
case "desktop":
mobile = false
case "mobile":
mobile = true
}
}
if mobile {
w.Write(mobileIndex)
} else {
if err := templates.ExecuteTemplate(w, "base.html", includes(c, w, r)); err != nil {
c.Errorf("%v", err)
serveError(w, err)
}
}
return
}
func addFeed(c mpg.Context, userid string, outline *OpmlOutline) error {
View
@@ -66,9 +66,7 @@ func LoginRedirect(c mpg.Context, w http.ResponseWriter, r *http.Request) {
serveError(w, err)
return
}
b, _ := json.Marshal(url)
w.Header().Add("Access-Control-Allow-Origin", "*")
w.Write(b)
http.Redirect(w, r, url, http.StatusFound)
}
func Logout(c mpg.Context, w http.ResponseWriter, r *http.Request) {

0 comments on commit e86cdd1

Please sign in to comment.