working on super simple offline behavior
This commit is contained in:
parent
9fb14910d2
commit
f8e4ce1d62
13 changed files with 249 additions and 1516 deletions
|
@ -1,5 +1,8 @@
|
|||
$(function(){
|
||||
if (navigator.serviceWorker) {
|
||||
navigator.serviceWorker.register('./sw.js')
|
||||
}
|
||||
|
||||
$(function(){
|
||||
function updateTimestamps() {
|
||||
$(".permalink time").each(function() {
|
||||
var absolute = $(this).attr('datetime');
|
||||
|
@ -20,22 +23,6 @@ $(function(){
|
|||
});
|
||||
}
|
||||
|
||||
function clickShowReplyForm(evt) {
|
||||
var a = $(this);
|
||||
evt.preventDefault();
|
||||
$(".like-form", a.parent()).hide();
|
||||
$(".reply-form", a.parent()).toggle();//css('display', 'inherit');
|
||||
//a.css('display', 'none');
|
||||
}
|
||||
|
||||
function clickShowLikeForm(evt) {
|
||||
var a = $(this);
|
||||
evt.preventDefault();
|
||||
$(".reply-form", a.parent()).hide();
|
||||
$(".like-form", a.parent()).toggle();
|
||||
//a.css('display', 'none');
|
||||
}
|
||||
|
||||
function submitMicropubForm(evt) {
|
||||
evt.preventDefault();
|
||||
|
70
frontend/indieconfig.js
Normal file
70
frontend/indieconfig.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*jslint browser: true, plusplus: true, vars: true, indent: 2 */
|
||||
window.loadIndieConfig = (function () {
|
||||
'use strict';
|
||||
|
||||
// Indie-Config Loading script
|
||||
// by Pelle Wessman, voxpelli.com
|
||||
// MIT-licensed
|
||||
// http://indiewebcamp.com/indie-config
|
||||
|
||||
var config, configFrame, configTimeout,
|
||||
callbacks = [],
|
||||
handleConfig, parseConfig;
|
||||
|
||||
// When the configuration has been loaded – deregister all loading mechanics and call all callbacks
|
||||
handleConfig = function () {
|
||||
config = config || {};
|
||||
|
||||
configFrame.parentNode.removeChild(configFrame);
|
||||
configFrame = undefined;
|
||||
|
||||
window.removeEventListener('message', parseConfig);
|
||||
|
||||
clearTimeout(configTimeout);
|
||||
|
||||
while (callbacks[0]) {
|
||||
callbacks.shift()(config);
|
||||
}
|
||||
};
|
||||
|
||||
// When we receive a message, check if the source is right and try to parse it
|
||||
parseConfig = function (message) {
|
||||
var correctSource = (configFrame && message.source === configFrame.contentWindow);
|
||||
|
||||
if (correctSource && config === undefined) {
|
||||
try {
|
||||
config = JSON.parse(message.data);
|
||||
} catch (ignore) {}
|
||||
|
||||
handleConfig();
|
||||
}
|
||||
};
|
||||
|
||||
return function (callback) {
|
||||
// If the config is already loaded, call callback right away
|
||||
if (config) {
|
||||
callback(config);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise add the callback to the queue
|
||||
callbacks.push(callback);
|
||||
|
||||
// Are we already trying to load the Indie-Config, then wait
|
||||
if (configFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the iframe that will load the Indie-Config
|
||||
configFrame = document.createElement('iframe');
|
||||
configFrame.src = 'web+action:load';
|
||||
document.getElementsByTagName('body')[0].appendChild(configFrame);
|
||||
configFrame.style.display = 'none';
|
||||
|
||||
// Listen for messages so we will catch the Indie-Config message
|
||||
window.addEventListener('message', parseConfig);
|
||||
|
||||
// And if no such Indie-Config message has been loaded in a while, abort the loading
|
||||
configTimeout = setTimeout(handleConfig, 3000);
|
||||
};
|
||||
}());
|
16
frontend/manifest.json
Normal file
16
frontend/manifest.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "Woodwind",
|
||||
"short_name": "Woodwind",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"theme_color": "#9b6137",
|
||||
"background_color": "#9b6137",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/logo.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
}
|
||||
]
|
||||
}
|
33
frontend/package.json
Normal file
33
frontend/package.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "woodwind-fe",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/kylewm/woodwind.git"
|
||||
},
|
||||
"keywords": [
|
||||
"indieweb",
|
||||
"reader"
|
||||
],
|
||||
"author": "Kyle Mahan",
|
||||
"license": "BSD-2-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/kylewm/woodwind/issues"
|
||||
},
|
||||
"homepage": "https://github.com/kylewm/woodwind#readme",
|
||||
"devDependencies": {
|
||||
"babel": "^6.5.2",
|
||||
"babel-cli": "^6.9.0",
|
||||
"babel-preset-es2015": "^6.9.0",
|
||||
"mocha": "^2.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^2.2.4",
|
||||
"moment": "^2.13.0"
|
||||
}
|
||||
}
|
31
frontend/sw.js
Normal file
31
frontend/sw.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
var version = 'v2';
|
||||
|
||||
this.addEventListener('install', function (event) {
|
||||
event.waitUntil(
|
||||
caches.open(version).then(function (cache) {
|
||||
return cache.addAll([
|
||||
'/static/logo.png',
|
||||
'/static/style.css',
|
||||
'/offline',
|
||||
])
|
||||
})
|
||||
);
|
||||
})
|
||||
|
||||
this.addEventListener('fetch', function (event) {
|
||||
console.log('caught fetch: ' + event)
|
||||
event.respondWith(
|
||||
caches.match(event.request)
|
||||
.then(function (response) {
|
||||
console.log('cache got response: ' + response)
|
||||
return response || fetch(event.request);
|
||||
})
|
||||
.then(function (response) {
|
||||
console.log('fetch got response: ' + response)
|
||||
return response
|
||||
})
|
||||
.catch(function (err) {
|
||||
return caches.match('/offline')
|
||||
})
|
||||
)
|
||||
})
|
63
frontend/webaction.js
Normal file
63
frontend/webaction.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*jslint browser: true, plusplus: true, vars: true, indent: 2 */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var loadingClassRegexp = /(^|\s)indieconfig-loading(\s|$)/;
|
||||
|
||||
var doTheAction = function (indieConfig) {
|
||||
var href, action, anchors;
|
||||
|
||||
// Don't block the tag anymore as the queued action is now handled
|
||||
this.className = this.className.replace(loadingClassRegexp, ' ');
|
||||
|
||||
// Pick the correct endpoint for the correct action
|
||||
action = this.getAttribute('do');
|
||||
href = indieConfig[action];
|
||||
|
||||
// If no endpoint is found, try the URL of the first a-tag within it
|
||||
if (!href) {
|
||||
anchors = this.getElementsByTagName('a');
|
||||
if (anchors[0]) {
|
||||
href = anchors[0].href;
|
||||
}
|
||||
}
|
||||
|
||||
// We have found an endpoint!
|
||||
if (href) {
|
||||
//Resolve a relative target
|
||||
var target = document.createElement('a');
|
||||
target.href = this.getAttribute('with');
|
||||
target = target.href;
|
||||
|
||||
// Insert the target into the endpoint
|
||||
href = href.replace('{url}', encodeURIComponent(target || window.location.href));
|
||||
|
||||
// And redirect to it
|
||||
window.open( href, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
// Event handler for a click on an indie-action tag
|
||||
var handleTheAction = function (e) {
|
||||
// Prevent the default of eg. any a-tag fallback within the indie-action tag
|
||||
e.preventDefault();
|
||||
|
||||
// Make sure this tag hasn't already been queued for the indieconfig-load
|
||||
if (!loadingClassRegexp.test(this.className)) {
|
||||
this.className += ' indieconfig-loading';
|
||||
// Set "doTheAction" to be called when the indie-config has been loaded
|
||||
window.loadIndieConfig(doTheAction.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
// Once the page is loased add click event listeners to all indie-action tags
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
var actions = document.querySelectorAll('indie-action'),
|
||||
i,
|
||||
length = actions.length;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
actions[i].addEventListener('click', handleTheAction);
|
||||
}
|
||||
});
|
||||
}());
|
|
@ -8,11 +8,11 @@ db = SQLAlchemy()
|
|||
micropub = MicropubClient(client_id='https://woodwind.xyz/')
|
||||
login_mgr = LoginManager()
|
||||
login_mgr.login_view = 'views.index'
|
||||
toolbar = DebugToolbarExtension()
|
||||
#toolbar = DebugToolbarExtension()
|
||||
|
||||
|
||||
def init_app(app):
|
||||
db.init_app(app)
|
||||
micropub.init_app(app)
|
||||
login_mgr.init_app(app)
|
||||
toolbar.init_app(app)
|
||||
# toolbar.init_app(app)
|
||||
|
|
File diff suppressed because one or more lines are too long
7
woodwind/static/moment.min.js
vendored
7
woodwind/static/moment.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -10,9 +10,11 @@
|
|||
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', version='2016-03-08') }}"/>
|
||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"/>
|
||||
<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='moment.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='cassis.js') }}"></script>
|
||||
|
||||
<link rel="manifest" href="/manifest.json"/>
|
||||
|
||||
<script src="/node_modules/jquery/dist/jquery.js"></script>
|
||||
<script src="/node_modules/moment/moment.js"></script>
|
||||
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
@ -52,6 +54,8 @@
|
|||
<div class="flash">{{ message }}</div>
|
||||
{% endfor %}
|
||||
|
||||
{% block login %}
|
||||
|
||||
{% if not current_user.is_authenticated %}
|
||||
<form action="{{ url_for('.login') }}" method="POST">
|
||||
<input type="url" name="me" placeholder="https://yourdomain.com" />
|
||||
|
@ -59,9 +63,10 @@
|
|||
<button style="text-align: right;" type="submit">Login</button>
|
||||
</form>
|
||||
Your Woodwind account is tied to your personal domain name. Check out IndieWebCamp's <a href="http://indiewebcamp.com/Getting_Started" target="_blank">Getting Started</a> page for details.
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock login %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
|
||||
</header>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% if ws_topic %}
|
||||
<script>var WS_TOPIC = "{{ ws_topic }}";</script>
|
||||
{% endif %}
|
||||
<script src="{{url_for('static', filename='feed.js', version='2016-05-21')}}"></script>
|
||||
<script src="/feed.js"></script>
|
||||
|
||||
{% if current_user and current_user.settings
|
||||
and current_user.settings.get('reply-method') == 'indie-config' %}
|
||||
|
|
9
woodwind/templates/offline.jinja2
Normal file
9
woodwind/templates/offline.jinja2
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% extends "base.jinja2" %}
|
||||
|
||||
{% block login %}{% endblock login %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
Offline, and it feels so good
|
||||
|
||||
{% endblock body %}
|
|
@ -24,6 +24,10 @@ IMAGE_TAG_RE = re.compile(r'<img([^>]*) src="(https?://[^">]+)"')
|
|||
|
||||
views = flask.Blueprint('views', __name__)
|
||||
|
||||
@views.route('/offline')
|
||||
def offline():
|
||||
return flask.render_template('offline.jinja2')
|
||||
|
||||
|
||||
@views.route('/')
|
||||
def index():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue