Page MenuHomeMusing Studio

No OneTemporary

diff --git a/templates/collection-tags.tmpl b/templates/collection-tags.tmpl
index 6849fee..7cad3b7 100644
--- a/templates/collection-tags.tmpl
+++ b/templates/collection-tags.tmpl
@@ -1,194 +1,194 @@
{{define "collection-tags"}}<!DOCTYPE HTML>
<html>
<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<meta charset="utf-8">
<title>{{.Tag}} &mdash; {{.Collection.DisplayTitle}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
<link rel="shortcut icon" href="/favicon.ico" />
{{if not .Collection.IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.Tag}} posts on {{.DisplayTitle}}" href="{{.CanonicalURL}}tag:{{.Tag}}/feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="canonical" href="{{.CanonicalURL}}tag:{{.Tag | tolower}}" />
<meta name="generator" content="Write.as">
<meta name="title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}">
<meta name="description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="application-name" content="Write.as">
<meta name="application-url" content="https://write.as">
{{if gt .Views 1}}<meta name="twitter:label1" value="Views">
<meta name="twitter:data1" value="{{largeNumFmt .Views}}">{{end}}
<meta itemprop="name" content="{{.Collection.DisplayTitle}}">
<meta itemprop="description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@writeas__">
<meta name="twitter:description" content="{{.Tag}} posts on {{.Collection.DisplayTitle}}">
<meta name="twitter:title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}">
<meta name="twitter:image" content="{{.Collection.AvatarURL}}">
<meta property="og:title" content="{{.Tag}} &mdash; {{.Collection.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}tag:{{.Tag}}" />
<meta property="og:image" content="{{.Collection.AvatarURL}}">
{{if .Collection.StyleSheet}}<style type="text/css">{{.Collection.StyleSheetDisplay}}</style>{{end}}
{{if .Collection.RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" .}}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" . }}
</head>
<body id="subpage">
<div id="overlay"></div>
<header>
<h1 dir="{{.Direction}}" id="blog-title"><a href="{{if .IsTopLevel}}/{{else}}/{{.Collection.Alias}}/{{end}}" class="h-card p-author">{{.Collection.DisplayTitle}}</a></h1>
<nav>
{{if .PinnedPosts}}
{{range .PinnedPosts}}<a class="pinned" href="{{if not $.SingleUser}}/{{$.Collection.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL}}{{end}}">{{.DisplayTitle}}</a>{{end}}
{{end}}
</nav>
</header>
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
<h1>{{.Tag}}</h1>
{{template "posts" .}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{ if .Collection.ShowFooterBranding }}
<footer dir="ltr">
<hr>
<nav>
<p style="font-size: 0.9em"><a class="home pubd" href="/">{{.SiteName}}</a> &middot; powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a></p>
</nav>
</footer>
{{ end }}
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Collection.Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
{{if .IsOwner}}
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
{{end}}
<script type="text/javascript">
{{if .IsOwner}}
var deleting = false;
function delPost(e, id, owned) {
e.preventDefault();
if (deleting) {
return;
}
// TODO: UNDO!
if (window.confirm('Are you sure you want to delete this post?')) {
// AJAX
deletePost(id, "", function() {
// Remove post from list
var $postEl = document.getElementById('post-' + id);
$postEl.parentNode.removeChild($postEl);
// TODO: add next post from this collection at the bottom
});
}
}
var deletePost = function(postID, token, callback) {
deleting = true;
var $delBtn = document.getElementById('post-' + postID).getElementsByClassName('delete action')[0];
$delBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/posts/" + postID;
http.open("DELETE", url, true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
deleting = false;
if (http.status == 204) {
callback();
} else if (http.status == 409) {
$delBtn.innerHTML = 'delete';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$delBtn.innerHTML = 'delete';
alert("Failed to delete." + (http.status>=500?" Please try again.":""));
}
}
}
http.send();
};
var pinning = false;
function pinPost(e, postID, slug, title) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var callback = function() {
// Visibly remove post from collection
var $postEl = document.getElementById('post-' + postID);
$postEl.parentNode.removeChild($postEl);
var $header = document.getElementsByTagName('header')[0];
var $pinnedNavs = $header.getElementsByTagName('nav');
// Add link to nav
- var link = '<a class="pinned" href="/{{.Alias}}/'+slug+'">'+title+'</a>';
+ var link = '<a class="pinned" href="{{if not .SingleUser}}/{{.Alias}}/{{end}}'+slug+'">'+title+'</a>';
if ($pinnedNavs.length == 0) {
$header.insertAdjacentHTML("beforeend", '<nav>'+link+'</nav>');
} else {
$pinnedNavs[0].insertAdjacentHTML("beforeend", link);
}
};
var $pinBtn = document.getElementById('post-' + postID).getElementsByClassName('pin action')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}/pin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
} else if (http.status == 409) {
$pinBtn.innerHTML = 'pin';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$pinBtn.innerHTML = 'pin';
alert("Failed to pin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
{{end}}
try { // Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
</html>{{end}}
diff --git a/templates/collection.tmpl b/templates/collection.tmpl
index 18942a9..6623a2e 100644
--- a/templates/collection.tmpl
+++ b/templates/collection.tmpl
@@ -1,229 +1,229 @@
{{define "collection"}}<!DOCTYPE HTML>
<html {{if .Language}}lang="{{.Language}}"{{end}} dir="{{.Direction}}">
<head>
<meta charset="utf-8">
<title>{{.DisplayTitle}}{{if not .SingleUser}} &mdash; {{.SiteName}}{{end}}</title>
<link rel="stylesheet" type="text/css" href="/css/write.css" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="canonical" href="{{.CanonicalURL}}">
{{if gt .CurrentPage 1}}<link rel="prev" href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">{{end}}
{{if lt .CurrentPage .TotalPages}}<link rel="next" href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">{{end}}
{{if not .IsPrivate}}<link rel="alternate" type="application/rss+xml" title="{{.DisplayTitle}} &raquo; Feed" href="{{.CanonicalURL}}feed/" />{{end}}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="WriteFreely">
<meta name="description" content="{{.Description}}">
<meta itemprop="name" content="{{.DisplayTitle}}">
<meta itemprop="description" content="{{.Description}}">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{.DisplayTitle}}">
<meta name="twitter:image" content="{{.AvatarURL}}">
<meta name="twitter:description" content="{{.Description}}">
<meta property="og:title" content="{{.DisplayTitle}}" />
<meta property="og:site_name" content="{{.DisplayTitle}}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{.CanonicalURL}}" />
<meta property="og:description" content="{{.Description}}" />
<meta property="og:image" content="{{.AvatarURL}}">
{{if .StyleSheet}}<style type="text/css">{{.StyleSheetDisplay}}</style>{{end}}
{{if .RenderMathJax}}
<!-- Add mathjax logic -->
{{template "mathjax" .}}
{{end}}
<!-- Add highlighting logic -->
{{template "highlighting" . }}
</head>
<body id="collection" itemscope itemtype="http://schema.org/WebPage">
{{if or .IsOwner .SingleUser}}<nav id="manage"><ul>
<li><a onclick="void(0)">&#9776; Menu</a>
<ul>
{{ if .IsOwner }}
{{if .SingleUser}}
<li><a href="/me/new">New Post</a></li>
{{else}}
<li><a href="/#{{.Alias}}" class="write">{{.SiteName}}</a></li>
{{end}}
<li><a href="/me/c/{{.Alias}}">Customize</a></li>
<li><a href="/me/c/{{.Alias}}/stats">Stats</a></li>
<li class="separator"><hr /></li>
{{if not .SingleUser}}<li><a href="/me/c/"><img class="ic-18dp" src="/img/ic_blogs_dark@2x.png" /> View Blogs</a></li>{{end}}
<li><a href="/me/posts/"><img class="ic-18dp" src="/img/ic_list_dark@2x.png" /> View Drafts</a></li>
{{ else }}
<li><a href="/login">Log in</a></li>
{{ end }}
</ul>
</li>
</ul></nav>{{end}}
<header>
<h1 dir="{{.Direction}}" id="blog-title">{{if .Posts}}{{else}}<span class="writeas-prefix"><a href="/">write.as</a></span> {{end}}<a href="/{{if .IsTopLevel}}{{else}}{{.Prefix}}{{.Alias}}/{{end}}" class="h-card p-author u-url" rel="me author">{{.DisplayTitle}}</a></h1>
{{if .Description}}<p class="description p-note">{{.Description}}</p>{{end}}
{{/*if not .Public/*}}
<!--p class="meta-note"><span>Private collection</span>. Only you can see this page.</p-->
{{/*end*/}}
{{if .PinnedPosts}}<nav>
{{range .PinnedPosts}}<a class="pinned" href="{{if not $.SingleUser}}/{{$.Alias}}/{{.Slug.String}}{{else}}{{.CanonicalURL}}{{end}}">{{.PlainDisplayTitle}}</a>{{end}}</nav>
{{end}}
</header>
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
{{if .IsWelcome}}
<div id="welcome">
<h2>Welcome, <strong>{{.Username}}</strong>!</h2>
<p>This is your new blog.</p>
<p><a class="simple-cta" href="/#{{.Alias}}">Start writing</a>, or <a class="simple-cta" href="/me/c/{{.Alias}}">customize</a> your blog.</p>
<p>Check out our <a class="simple-cta" href="https://guides.write.as/writing/?pk_campaign=welcome">writing guide</a> to see what else you can do, and <a class="simple-cta" href="/contact">get in touch</a> anytime with questions or feedback.</p>
</div>
{{end}}
{{template "posts" .}}
{{if gt .TotalPages 1}}<nav id="paging" class="content-container clearfix">
{{if or (and .Format.Ascending (lt .CurrentPage .TotalPages)) (isRTL .Direction)}}
{{if gt .CurrentPage 1}}<a href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">&#8672; {{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Previous{{else}}Newer{{end}}</a>{{end}}
{{if lt .CurrentPage .TotalPages}}<a style="float:right;" href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">{{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Next{{else}}Older{{end}} &#8674;</a>{{end}}
{{else}}
{{if lt .CurrentPage .TotalPages}}<a href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">&#8672; Older</a>{{end}}
{{if gt .CurrentPage 1}}<a style="float:right;" href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">Newer &#8674;</a>{{end}}
{{end}}
</nav>{{end}}
{{if .Posts}}</section>{{else}}</div>{{end}}
{{if .ShowFooterBranding }}
<footer>
<hr />
<nav dir="ltr">
{{if not .SingleUser}}<a class="home pubd" href="/">{{.SiteName}}</a> &middot; {{end}}powered by <a style="margin-left:0" href="https://writefreely.org">writefreely</a>
</nav>
</footer>
{{ end }}
</body>
{{if .CanShowScript}}
{{range .ExternalScripts}}<script type="text/javascript" src="{{.}}" async></script>{{end}}
{{if .Script}}<script type="text/javascript">{{.ScriptDisplay}}</script>{{end}}
{{end}}
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
<script type="text/javascript">
var deleting = false;
function delPost(e, id, owned) {
e.preventDefault();
if (deleting) {
return;
}
// TODO: UNDO!
if (window.confirm('Are you sure you want to delete this post?')) {
// AJAX
deletePost(id, "", function() {
// Remove post from list
var $postEl = document.getElementById('post-' + id);
$postEl.parentNode.removeChild($postEl);
// TODO: add next post from this collection at the bottom
});
}
}
var deletePost = function(postID, token, callback) {
deleting = true;
var $delBtn = document.getElementById('post-' + postID).getElementsByClassName('delete action')[0];
$delBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/posts/" + postID;
http.open("DELETE", url, true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
deleting = false;
if (http.status == 204) {
callback();
} else if (http.status == 409) {
$delBtn.innerHTML = 'delete';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$delBtn.innerHTML = 'delete';
alert("Failed to delete." + (http.status>=500?" Please try again.":""));
}
}
}
http.send();
};
var pinning = false;
function pinPost(e, postID, slug, title) {
e.preventDefault();
if (pinning) {
return;
}
pinning = true;
var callback = function() {
// Visibly remove post from collection
var $postEl = document.getElementById('post-' + postID);
$postEl.parentNode.removeChild($postEl);
var $header = document.getElementsByTagName('header')[0];
var $pinnedNavs = $header.getElementsByTagName('nav');
// Add link to nav
- var link = '<a class="pinned" href="/{{.Alias}}/'+slug+'">'+title+'</a>';
+ var link = '<a class="pinned" href="{{if not .SingleUser}}/{{.Alias}}/{{end}}'+slug+'">'+title+'</a>';
if ($pinnedNavs.length == 0) {
$header.insertAdjacentHTML("beforeend", '<nav>'+link+'</nav>');
} else {
$pinnedNavs[0].insertAdjacentHTML("beforeend", link);
}
};
var $pinBtn = document.getElementById('post-' + postID).getElementsByClassName('pin action')[0];
$pinBtn.innerHTML = '...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}/pin";
var params = [ { "id": postID } ];
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
pinning = false;
if (http.status == 200) {
callback();
} else if (http.status == 409) {
$pinBtn.innerHTML = 'pin';
alert("Post is synced to another account. Delete the post from that account instead.");
// TODO: show "remove" button instead of "delete" now
// Persist that state.
// Have it remove the post locally only.
} else {
$pinBtn.innerHTML = 'pin';
alert("Failed to pin." + (http.status>=500?" Please try again.":""));
}
}
}
http.send(JSON.stringify(params));
};
try {
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin', 'Open+Sans:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) {}
</script>
</html>{{end}}
diff --git a/templates/user/articles.tmpl b/templates/user/articles.tmpl
index 4956301..67d3e0b 100644
--- a/templates/user/articles.tmpl
+++ b/templates/user/articles.tmpl
@@ -1,145 +1,145 @@
{{define "articles"}}
{{template "header" .}}
<div class="snug content-container">
{{if .Flashes}}<ul class="errors">
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}}
</ul>{{end}}
<h2 id="posts-header">drafts</h2>
{{ if .AnonymousPosts }}<div class="atoms posts">
{{ range $el := .AnonymousPosts }}<div id="post-{{.ID}}" class="post">
<h3><a href="/{{if $.SingleUser}}d/{{end}}{{.ID}}" itemprop="url">{{.DisplayTitle}}</a></h3>
<h4>
<date datetime="{{.Created}}" pubdate itemprop="datePublished" content="{{.Created}}">{{.DisplayDate}}</date>
<a class="action" href="/{{if $.SingleUser}}d/{{end}}{{.ID}}/edit">edit</a>
<a class="delete action" href="/{{.ID}}" onclick="delPost(event, '{{.ID}}', true)">delete</a>
{{ if $.Collections }}
{{if gt (len $.Collections) 1}}<div class="action flat-select">
<select id="move-{{.ID}}" onchange="postActions.multiMove(this, '{{.ID}}', {{if $.SingleUser}}true{{else}}false{{end}})" title="Move this post to one of your blogs">
<option style="display:none"></option>
{{range $.Collections}}<option value="{{.Alias}}">{{.DisplayTitle}}</option>{{end}}
</select>
<label for="move-{{.ID}}">move to...</label>
<img class="ic-18dp" src="/img/ic_down_arrow_dark@2x.png" />
</div>{{else}}
{{range $.Collections}}
<a class="action" href="/{{$el.ID}}" title="Publish this post to your blog '{{.DisplayTitle}}'" onclick="postActions.move(this, '{{$el.ID}}', '{{.Alias}}', {{if $.SingleUser}}true{{else}}false{{end}});return false">move to {{.DisplayTitle}}</a>
{{end}}
{{end}}
{{ end }}
</h4>
{{if .Summary}}<p>{{.Summary}}</p>{{end}}
</div>{{end}}
</div>{{ else }}<div id="no-posts-published"><p>You haven't saved any drafts yet.</p>
- <p>They'll show up here once you do. Find your blog posts from the <a href="/me/c/">Blogs</a> page.</p>
- <p class="text-cta"><a href="/">Start writing</a></p></div>{{ end }}
+ <p>They'll show up here once you do. {{if not .SingleUser}}Find your blog posts from the <a href="/me/c/">Blogs</a> page.{{end}}</p>
+ <p class="text-cta"><a href="{{if .SingleUser}}/me/new{{else}}/{{end}}">Start writing</a></p></div>{{ end }}
<div id="moving"></div>
<h2 id="unsynced-posts-header" style="display: none">unsynced posts</h2>
<div id="unsynced-posts-info" style="margin-top: 1em"></div>
<div id="unsynced-posts" class="atoms"></div>
</div>
<script src="/js/h.js"></script>
<script src="/js/postactions.js"></script>
<script>
var auth = true;
function postsLoaded(n) {
if (n == 0) {
return;
}
document.getElementById('unsynced-posts-header').style.display = 'block';
var syncing = false;
var $pInfo = document.getElementById('unsynced-posts-info');
$pInfo.className = 'alert info';
var plural = n != 1;
$pInfo.innerHTML = '<p>You have <strong>'+n+'</strong> post'+(plural?'s that aren\'t':' that isn\'t')+' synced to your account yet. <a href="#" id="btn-sync">Sync '+(plural?'them':'it')+' now</a>.</p>';
var $noPosts = document.getElementById('no-posts-published');
if ($noPosts != null) {
$noPosts.style.display = 'none';
document.getElementById('posts-header').style.display = 'none';
}
H.getEl('btn-sync').on('click', function(e) {
e.preventDefault();
if (syncing) {
return;
}
var http = new XMLHttpRequest();
var params = [];
var posts = JSON.parse(H.get('posts', '[]'));
if (posts.length > 0) {
for (var i=0; i<posts.length; i++) {
params.push({id: posts[i].id, token: posts[i].token});
}
}
this.style.fontWeight = 'bold';
this.innerText = 'Syncing '+(plural?'them':'it')+' now...';
http.open("POST", "/api/posts/claim", true);
// Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
syncing = false;
this.innerText = 'Importing '+(plural?'them':'it')+' now...';
if (http.status == 200) {
var res = JSON.parse(http.responseText);
if (res.data.length > 0) {
if (res.data.length != posts.length) {
// TODO: handle something that royally fucked up
console.error("Request and result array length didn't match!");
return;
}
for (var i=0; i<res.data.length; i++) {
if (res.data[i].code == 200) {
// Post successfully claimed.
for (var j=0; j<posts.length; j++) {
// Find post in local store
if (posts[j].id == res.data[i].post.id) {
// Remove this post
posts.splice(j, 1);
break;
}
}
} else {
for (var j=0; j<posts.length; j++) {
// Find post in local store
if (posts[j].id == res.data[i].id) {
// Note the error in the local post
posts[j].error = res.data[i].error_msg;
break;
}
}
}
}
H.set('posts', JSON.stringify(posts));
location.reload();
}
} else {
// TODO: handle error visually (option to retry)
console.error("Didn't work at all, man.");
this.style.fontWeight = 'normal';
this.innerText = 'Sync '+(plural?'them':'it')+' now';
}
}
}
http.send(JSON.stringify(params));
syncing = true;
});
}
</script>
<script src="/js/posts.js"></script>
{{template "footer" .}}
{{end}}
diff --git a/templates/user/collection.tmpl b/templates/user/collection.tmpl
index 08e8886..8af3bda 100644
--- a/templates/user/collection.tmpl
+++ b/templates/user/collection.tmpl
@@ -1,236 +1,238 @@
{{define "upgrade"}}
<p><a href="/me/plan?to=/me/c/{{.Alias}}">Upgrade</a> for <span>$40 / year</span> to edit.</p>
{{end}}
{{define "collection"}}
{{template "header" .}}
<div class="content-container snug">
<div id="overlay"></div>
<h2>Customize {{.DisplayTitle}} <a href="{{if .SingleUser}}/{{else}}/{{.Alias}}/{{end}}">view blog</a></h2>
{{if .Flashes}}<ul class="errors">
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}}
</ul>{{end}}
<form name="customize-form" action="/api/collections/{{.Alias}}" method="post" onsubmit="return disableSubmit()">
<div id="collection-options">
<div style="text-align:center">
<h1><input type="text" name="title" id="title" value="{{.DisplayTitle}}" placeholder="Title" /></h1>
<p><input type="text" name="description" id="description" value="{{.Description}}" placeholder="Description" /></p>
</div>
<div class="option">
<h2><a name="preferred-url"></a>URL</h2>
<div class="section">
{{if eq .Alias .Username}}<p style="font-size: 0.8em">This blog uses your username in its URL{{if .Federation}} and fediverse handle{{end}}. You can change it in your <a href="/me/settings">Account Settings</a>.</p>{{end}}
<ul style="list-style:none">
<li>
{{.FriendlyHost}}/<strong>{{.Alias}}</strong>/
</li>
<li>
<strong id="normal-handle-env" class="fedi-handle" {{if not .Federation}}style="display:none"{{end}}>@<span id="fedi-handle">{{.Alias}}</span>@<span id="fedi-domain">{{.FriendlyHost}}</span></strong>
</li>
</ul>
</div>
</div>
<div class="option">
<h2>Publicity</h2>
<div class="section">
<ul style="list-style:none">
<li>
<label><input type="radio" name="visibility" id="visibility-unlisted" value="0" {{if .IsUnlisted}}checked="checked"{{end}} />
Unlisted
</label>
<p>This blog is visible to {{if .Private}}any registered user on this instance{{else}}anyone with its link{{end}}.</p>
</li>
<li>
<label class="option-text"><input type="radio" name="visibility" id="visibility-private" value="2" {{if .IsPrivate}}checked="checked"{{end}} />
Private
</label>
<p>Only you may read this blog (while you're logged in).</p>
</li>
<li>
<label class="option-text"><input type="radio" name="visibility" id="visibility-protected" value="4" {{if .IsProtected}}checked="checked"{{end}} />
Password-protected: <input type="password" class="low-profile" name="password" id="collection-pass" autocomplete="new-password" placeholder="{{if .IsProtected}}xxxxxxxxxxxxxxxx{{else}}a memorable password{{end}}" />
</label>
<p>A password is required to read this blog.</p>
</li>
+ {{if not .SingleUser}}
<li>
<label class="option-text{{if not .LocalTimeline}} disabled{{end}}"><input type="radio" name="visibility" id="visibility-public" value="1" {{if .IsPublic}}checked="checked"{{end}} {{if not .LocalTimeline}}disabled="disabled"{{end}} />
Public
</label>
{{if .LocalTimeline}}<p>This blog is displayed on the public <a href="/read">reader</a>, and is visible to {{if .Private}}any registered user on this instance{{else}}anyone with its link{{end}}.</p>
{{else}}<p>The public reader is currently turned off for this community.</p>{{end}}
</li>
+ {{end}}
</ul>
</div>
</div>
<div class="option">
<h2>Display Format</h2>
<div class="section">
<p class="explain">Customize how your posts display on your page.
</p>
<ul style="list-style:none">
<li>
<label><input type="radio" name="format" id="format-blog" value="blog" {{if or (not .Format) (eq .Format "blog")}}checked="checked"{{end}} />
Blog
</label>
<p>Dates are shown. Latest posts listed first.</p>
</li>
<li>
<label class="option-text"><input type="radio" name="format" id="format-novel" value="novel" {{if eq .Format "novel"}}checked="checked"{{end}} />
Novel
</label>
<p>No dates shown. Oldest posts first.</p>
</li>
<li>
<label class="option-text"><input type="radio" name="format" id="format-notebook" value="notebook" {{if eq .Format "notebook"}}checked="checked"{{end}} />
Notebook
</label>
<p>No dates shown. Latest posts first.</p>
</li>
</ul>
</div>
</div>
<div class="option">
<h2>Text Rendering</h2>
<div class="section">
<p class="explain">Customize how plain text renders on your blog.</p>
<ul style="list-style:none">
<li>
<label class="option-text disabled"><input type="checkbox" name="markdown" checked="checked" disabled />
Markdown
</label>
</li>
<li>
<label><input type="checkbox" name="mathjax" {{if .RenderMathJax}}checked="checked"{{end}} />
MathJax
</label>
</li>
</ul>
</div>
</div>
<div class="option">
<h2>Custom CSS</h2>
<div class="section">
<textarea id="css-editor" class="section codable" name="style_sheet">{{.StyleSheet}}</textarea>
<p class="explain">See our guide on <a href="https://guides.write.as/customizing/#custom-css">customization</a>.</p>
</div>
</div>
<div class="option" style="text-align: center; margin-top: 4em;">
<input type="submit" id="save-changes" value="Save changes" />
<p><a href="{{if .SingleUser}}/{{else}}/{{.Alias}}/{{end}}">View Blog</a></p>
{{if ne .Alias .Username}}<p><a class="danger" href="#modal-delete" onclick="promptDelete();">Delete Blog...</a></p>{{end}}
</div>
</div>
</form>
</div>
<div id="modal-delete" class="modal">
<h2>Are you sure you want to delete this blog?</h2>
<div class="body short">
<p style="text-align:left">This will permanently erase <strong>{{.DisplayTitle}}</strong> ({{.FriendlyHost}}/{{.Alias}}) from the internet. Any posts on this blog will be saved and made into drafts (found on your <a href="/me/posts/">Drafts</a> page).</p>
<p>If you're sure you want to delete this blog, enter its name in the box below and press <strong>Delete</strong>.</p>
<ul id="delete-errors" class="errors"></ul>
<input id="confirm-text" placeholder="{{.Alias}}" type="text" class="boxy" style="margin-top: 0.5em;" />
<div style="text-align:right; margin-top: 1em;">
<a id="cancel-delete" style="margin-right:2em" href="#">Cancel</a>
<button id="btn-delete" class="danger" onclick="deleteBlog(); return false;">Delete</button>
</div>
</div>
</div>
<script src="/js/h.js"></script>
<script src="/js/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
// Begin shared modal code
function showModal(id) {
document.getElementById('overlay').style.display = 'block';
document.getElementById('modal-'+id).style.display = 'block';
}
var closeModals = function(e) {
e.preventDefault();
document.getElementById('overlay').style.display = 'none';
var modals = document.querySelectorAll('.modal');
for (var i=0; i<modals.length; i++) {
modals[i].style.display = 'none';
}
};
H.getEl('overlay').on('click', closeModals);
H.getEl('cancel-delete').on('click', closeModals);
// end
var deleteBlog = function(e) {
if (document.getElementById('confirm-text').value != '{{.Alias}}') {
document.getElementById('delete-errors').innerHTML = '<li class="urgent">Enter <strong>{{.Alias}}</strong> in the box below.</li>';
return;
}
// Clear errors
document.getElementById('delete-errors').innerHTML = '';
document.getElementById('btn-delete').innerHTML = 'Deleting...';
var http = new XMLHttpRequest();
var url = "/api/collections/{{.Alias}}?web=1";
http.open("DELETE", url, true);
http.setRequestHeader("Content-type", "application/json");
http.onreadystatechange = function() {
if (http.readyState == 4) {
if (http.status == 204) {
window.location = '/me/c/';
} else {
var data = JSON.parse(http.responseText);
document.getElementById('delete-errors').innerHTML = '<li class="urgent">'+data.error_msg+'</li>';
document.getElementById('btn-delete').innerHTML = 'Delete';
}
}
};
http.send(null);
};
function createHidden(theForm, key, value) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = value;
theForm.appendChild(input);
}
function disableSubmit() {
var $form = document.forms['customize-form'];
createHidden($form, 'style_sheet', cssEditor.getSession().getValue());
var $btn = document.getElementById("save-changes");
$btn.value = "Saving changes...";
$btn.disabled = true;
return true;
}
function promptDelete() {
showModal("delete");
}
var $fediDomain = document.getElementById('fedi-domain');
var $fediCustomDomain = document.getElementById('fedi-custom-domain');
var $customDomain = document.getElementById('domain-alias');
var $customHandleEnv = document.getElementById('custom-handle-env');
var $normalHandleEnv = document.getElementById('normal-handle-env');
var opt = {
showLineNumbers: false,
showPrintMargin: 0,
};
var theme = "ace/theme/chrome";
var cssEditor = ace.edit("css-editor");
cssEditor.setTheme(theme);
cssEditor.session.setMode("ace/mode/css");
cssEditor.setOptions(opt);
</script>
{{template "footer" .}}
{{end}}
diff --git a/templates/user/include/footer.tmpl b/templates/user/include/footer.tmpl
index 36a69fa..572d9d6 100644
--- a/templates/user/include/footer.tmpl
+++ b/templates/user/include/footer.tmpl
@@ -1,36 +1,36 @@
{{define "footer"}}
{{template "foot" .}}
{{template "body-end" .}}
{{end}}
{{define "foot"}}
</div>
<footer>
<hr />
<nav>
<a class="home" href="/">{{.SiteName}}</a>
- <a href="/about">about</a>
+ {{if not .SingleUser}}<a href="/about">about</a>{{end}}
{{if and (not .SingleUser) .LocalTimeline}}<a href="/read">reader</a>{{end}}
<a href="https://writefreely.org/guide/{{.OfficialVersion}}" target="guide">writer's guide</a>
- <a href="/privacy">privacy</a>
+ {{if not .SingleUser}}<a href="/privacy">privacy</a>{{end}}
<a href="https://writefreely.org">writefreely {{.Version}}</a>
</nav>
</footer>
<script type="text/javascript">
try { // Google Fonts
WebFontConfig = {
custom: { families: [ 'Lora:400,700:latin' ], urls: [ '/css/fonts.css' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = '/js/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
} catch (e) { /* ¯\_(ツ)_/¯ */ }
</script>
{{end}}
{{define "body-end"}}</body>
</html>{{end}}

File Metadata

Mime Type
text/x-diff
Expires
Fri, May 16, 5:56 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3240295

Event Timeline