diff --git a/static/js/h.js b/static/js/h.js index eb0b39b..647d05a 100644 --- a/static/js/h.js +++ b/static/js/h.js @@ -1,297 +1,299 @@ /** * H.js * * Lightweight, extremely bare-bones library for manipulating the DOM and * saving some typing. */ var Element = function(domElement) { this.el = domElement; }; /** * Creates a toggle button that adds / removes the given class name from the * given element. * * @param {Element} $el - The element to modify. * @param {string} onClass - The class to add to the given element. * @param {function} onFunc - Additional actions when toggling on. * @param {function} offFunc - Additional actions when toggling off. */ Element.prototype.createToggle = function($el, onClass, onFunc, offFunc) { this.on('click', function(e) { if ($el.el.className === '') { $el.el.className = onClass; onFunc(new Element(this), e); } else { $el.el.className = ''; offFunc(new Element(this), e); } e.preventDefault(); }, false); }; Element.prototype.on = function(event, func) { events = event.split(' '); var el = this.el; if (el == null) { console.error("Error: element for event is null"); return; } var addEvent = function(e) { if (el.addEventListener) { el.addEventListener(e, func, false); } else if (el.attachEvent) { el.attachEvent(e, func); } }; if (events.length === 1) { addEvent(event); } else { for(var i=0; i lastLocalPublish) { return false; } } catch (e) { console.error("unable to parse draft updated time"); } } } return true; }, loadClassic: function($titleEl, $el, key, onlyLoadPopulated) { var val = localStorage.getItem(key); if (onlyLoadPopulated && val == null) { // Do nothing return; } if (val.indexOf("# ") === 0) { var eol = val.indexOf("\n"); title = val.substring("# ".length, eol); val = val.substring(eol+"\n\n".length); $titleEl.el.value = title; } $el.el.value = val; }, set: function(key, value) { localStorage.setItem(key, value); }, get: function(key, defaultValue) { var val = localStorage.getItem(key); if (val == null) { val = defaultValue; } return val; }, remove: function(key) { localStorage.removeItem(key); }, exists: function(key) { return localStorage.getItem(key) !== null; }, createPost: function(id, editToken, content, created) { var summaryLen = 200; var titleLen = 80; var getPostMeta = function(content) { var eol = content.indexOf("\n"); if (content.indexOf("# ") === 0) { // Title is in the format: // // # Some title var summary = content.substring(eol).trim(); if (summary.length > summaryLen) { summary = summary.substring(0, summaryLen) + "..."; } return { title: content.substring("# ".length, eol), summary: summary, }; } var blankLine = content.indexOf("\n\n"); if (blankLine !== -1 && blankLine <= eol && blankLine <= titleLen) { // Title is in the format: // // Some title // // The body starts after that blank line above it. var summary = content.substring(blankLine).trim(); if (summary.length > summaryLen) { summary = summary.substring(0, summaryLen) + "..."; } return { title: content.substring(0, blankLine), summary: summary, }; } // TODO: move this to the beginning var title = content.trim(); var summary = ""; if (title.length > titleLen) { // Content can't fit in the title, so figure out the summary summary = title; title = ""; if (summary.length > summaryLen) { summary = summary.substring(0, summaryLen) + "..."; } } else if (eol > 0) { summary = title.substring(eol+1); title = title.substring(0, eol); } return { title: title, summary: summary }; }; var post = getPostMeta(content); post.id = id; post.token = editToken; post.created = created ? new Date(created) : new Date(); post.client = "Pad"; return post; }, getTitleStrict: function(content) { var eol = content.indexOf("\n"); var title = ""; var newContent = content; if (content.indexOf("# ") === 0) { // Title is in the format: // # Some title if (eol !== -1) { // First line should start with # and end with \n newContent = content.substring(eol).leftTrim(); title = content.substring("# ".length, eol); } } return { title: title, content: newContent }; }, }; var He = { create: function(name) { return document.createElement(name); }, get: function(id) { return document.getElementById(id); }, $: function(selector) { var els = document.querySelectorAll(selector); return els; }, postJSON: function(url, params, callback) { var http = new XMLHttpRequest(); http.open("POST", url, true); // Send the proper header information along with the request http.setRequestHeader("Content-type", "application/json"); http.onreadystatechange = function() { if (http.readyState == 4) { - callback(http.status, JSON.parse(http.responseText)); + var resp = null; + try { resp = JSON.parse(http.responseText); } catch (e) {} + callback(http.status, resp); } } http.send(JSON.stringify(params)); }, }; String.prototype.leftTrim = function() { return this.replace(/^\s+/,""); }; diff --git a/static/js/postactions.js b/static/js/postactions.js index fbac850..d247ad8 100644 --- a/static/js/postactions.js +++ b/static/js/postactions.js @@ -1,122 +1,122 @@ var postActions = function() { var basePath = window.WF_BASE_PATH || ""; var $container = He.get('moving'); var MultiMove = function(el, id, singleUser) { var lbl = el.options[el.selectedIndex].textContent; var collAlias = el.options[el.selectedIndex].value; var $lbl = He.$('label[for=move-'+id+']')[0]; $lbl.textContent = "moving to "+lbl+"..."; var params; if (collAlias == '|anonymous|') { params = [id]; } else { params = [{ id: id }]; } var callback = function(code, resp) { if (code == 200) { for (var i=0; i"; var pre = "/"+collAlias; if (typeof singleUser !== 'undefined' && singleUser) { pre = ""; } var newPostURL = pre+"/"+resp.data[i].post.slug; try { // Posts page He.$('#post-'+resp.data[i].post.id+' > h3 > a')[0].href = newPostURL; } catch (e) { // Blog index var $article = He.get('post-'+resp.data[i].post.id); $article.className = 'norm moved'; if (collAlias == '|anonymous|') { var draftPre = ""; if (typeof singleUser !== 'undefined' && singleUser) { draftPre = "d/"; } $article.innerHTML = '

Unpublished post.

'; } else { $article.innerHTML = '

Moved to '+lbl+'.

'; } } } else { $lbl.innerHTML = "unable to move: "+resp.data[i].error_msg; } } } }; if (collAlias == '|anonymous|') { - He.postJSON(basePath + "{{subdir}}/api/posts/disperse", params, callback); + He.postJSON(basePath + "/api/posts/disperse", params, callback); } else { - He.postJSON(basePath + "{{subdir}}/api/collections/"+collAlias+"/collect", params, callback); + He.postJSON(basePath + "/api/collections/"+collAlias+"/collect", params, callback); } }; var Move = function(el, id, collAlias, singleUser) { var lbl = el.textContent; try { var m = lbl.match(/move to (.*)/); lbl = m[1]; } catch (e) { if (collAlias == '|anonymous|') { lbl = "draft"; } } el.textContent = "moving to "+lbl+"..."; if (collAlias == '|anonymous|') { params = [id]; } else { params = [{ id: id }]; } var callback = function(code, resp) { if (code == 200) { for (var i=0; i"; el.onclick = null; var pre = "/"+collAlias; if (typeof singleUser !== 'undefined' && singleUser) { pre = ""; } var newPostURL = pre+"/"+resp.data[i].post.slug; el.href = newPostURL; el.title = "View on "+lbl; try { // Posts page He.$('#post-'+resp.data[i].post.id+' > h3 > a')[0].href = newPostURL; } catch (e) { // Blog index var $article = He.get('post-'+resp.data[i].post.id); $article.className = 'norm moved'; if (collAlias == '|anonymous|') { var draftPre = ""; if (typeof singleUser !== 'undefined' && singleUser) { draftPre = "d/"; } $article.innerHTML = '

Unpublished post.

'; } else { $article.innerHTML = '

Moved to '+lbl+'.

'; } } } else { el.innerHTML = "unable to move: "+resp.data[i].error_msg; } } } } if (collAlias == '|anonymous|') { - He.postJSON(basePath + "{{subdir}}/api/posts/disperse", params, callback); + He.postJSON(basePath + "/api/posts/disperse", params, callback); } else { - He.postJSON(basePath + "{{subdir}}/api/collections/"+collAlias+"/collect", params, callback); + He.postJSON(basePath + "/api/collections/"+collAlias+"/collect", params, callback); } }; return { move: Move, multiMove: MultiMove, }; }(); diff --git a/templates/chorus-collection-post.tmpl b/templates/chorus-collection-post.tmpl index 1d82644..06af978 100644 --- a/templates/chorus-collection-post.tmpl +++ b/templates/chorus-collection-post.tmpl @@ -1,161 +1,162 @@ {{define "post"}} {{template "head-base" .}} {{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{.Collection.DisplayTitle}} {{if .CustomCSS}}{{end}} {{if .Collection.Favicon}}{{else}}{{end}} {{if gt .Views 1}} {{end}} {{if gt (len .Images) 0}}{{else}}{{end}} {{range .Images}}{{else}}{{end}} {{template "collection-meta" .}} {{if .Collection.StyleSheet}}{{end}} {{if .Collection.RenderMathJax}} {{template "mathjax" . }} {{end}} {{if .Collection.RenderMermaid}} {{template "mermaid" .}} {{end}} {{template "highlighting" .}}
{{template "user-navigation" .}} {{if .Silenced}} {{template "user-silenced"}} {{end}}
{{if .IsScheduled}}

Scheduled

{{end}}{{if .Title.String}}

{{.FormattedDisplayTitle}}

{{end}}{{if and $.Collection.Format.ShowDates (not .IsPinned)}}{{end}}
{{.HTMLContent}}
{{ if .Collection.ShowFooterBranding }}

Published by {{ if .IsOwner }} · {{largeNumFmt .Views}} {{pluralize "view" "views" .Views}} · Edit {{if .IsPinned}} · Unpin{{end}} {{ end }}


{{ end }} {{if .Collection.CanShowScript}} {{range .Collection.ExternalScripts}}{{end}} {{if .Collection.Script}}{{end}} {{end}} {{if and .Monetization (not .IsOwner)}} {{end}} {{end}} diff --git a/templates/chorus-collection.tmpl b/templates/chorus-collection.tmpl index f1bd6b2..aa1168b 100644 --- a/templates/chorus-collection.tmpl +++ b/templates/chorus-collection.tmpl @@ -1,242 +1,243 @@ {{define "collection"}} {{template "head-base" .}} {{.DisplayTitle}}{{if not .SingleUser}} — {{.SiteName}}{{end}} {{if .CustomCSS}}{{end}} {{if .Favicon}}{{else}}{{end}} {{if gt .CurrentPage 1}}{{end}} {{if lt .CurrentPage .TotalPages}}{{end}} {{if not .IsPrivate}}{{end}} {{template "collection-meta" .}} {{if .StyleSheet}}{{end}} {{if .RenderMathJax}} {{template "mathjax" .}} {{end}} {{if .RenderMermaid}} {{template "mermaid" .}} {{end}} {{template "highlighting" . }} {{template "user-navigation" .}} {{if .Silenced}} {{template "user-silenced"}} {{end}}

{{.DisplayTitle}}

{{if .Description}}

{{.Description}}

{{end}} {{/*if not .Public/*}} {{/*end*/}} {{if .PinnedPosts}} {{end}}
{{if .Posts}}
{{else}}
{{end}} {{if .IsWelcome}}

Welcome, {{.Username}}!

This is your new blog.

Start writing, or customize your blog.

Check out our writing guide to see what else you can do, and get in touch anytime with questions or feedback.

{{end}} {{template "posts" .}} {{if gt .TotalPages 1}}{{end}} {{if .Posts}}
{{else}}{{end}} {{if .ShowFooterBranding }} {{ end }} {{if .CanShowScript}} {{range .ExternalScripts}}{{end}} {{if .Script}}{{end}} {{end}} + {{end}} diff --git a/templates/collection-post.tmpl b/templates/collection-post.tmpl index 91b6be3..9fa9480 100644 --- a/templates/collection-post.tmpl +++ b/templates/collection-post.tmpl @@ -1,152 +1,153 @@ {{define "post"}} {{template "head-base" .}} {{.PlainDisplayTitle}} {{localhtml "title dash" .Language.String}} {{.Collection.DisplayTitle}} {{if .CustomCSS}}{{end}} {{if .Collection.Favicon}}{{else}}{{end}} {{ if .IsFound }} {{if gt .Views 1}} {{end}} {{if gt (len .Images) 0}}{{else}}{{end}} {{range .Images}}{{else}}{{end}} {{ end }} {{template "collection-meta" .}} {{if .Collection.StyleSheet}}{{end}} {{if .Collection.RenderMathJax}} {{template "mathjax" . }} {{end}} {{if .Collection.RenderMermaid}} {{template "mermaid" .}} {{end}} {{template "highlighting" .}}

{{if .Silenced}} {{template "user-silenced"}} {{end}}
{{if .IsScheduled}}

Scheduled

{{end}}{{if .Title.String}}

{{.FormattedDisplayTitle}}

{{end}}{{if and $.Collection.Format.ShowDates (not .IsPinned) .IsFound}}{{end}}
{{.HTMLContent}}
{{ if .Collection.ShowFooterBranding }}

{{ end }} {{if .Collection.CanShowScript}} {{range .Collection.ExternalScripts}}{{end}} {{if .Collection.Script}}{{end}} {{end}} {{if and .Monetization (not .IsOwner)}} {{end}} {{end}} diff --git a/templates/collection-tags.tmpl b/templates/collection-tags.tmpl index 55fb983..abed7d2 100644 --- a/templates/collection-tags.tmpl +++ b/templates/collection-tags.tmpl @@ -1,217 +1,218 @@ {{define "collection-tags"}} {{template "head-base" .}} {{.Tag}} — {{.Collection.DisplayTitle}} {{if .CustomCSS}}{{end}} {{if .Favicon}}{{else}}{{end}} {{if not .Collection.IsPrivate}}{{end}} {{if gt .Views 1}} {{end}} {{template "collection-meta" .}} {{if .Collection.StyleSheet}}{{end}} {{if .Collection.RenderMathJax}} {{template "mathjax" .}} {{end}} {{if .Collection.RenderMermaid}} {{template "mermaid" .}} {{end}} {{template "highlighting" . }}

{{.Collection.DisplayTitle}}

{{if .Silenced}} {{template "user-silenced"}} {{end}} {{if .Posts}}
{{else}}
{{end}}

{{.Tag}}

{{template "posts" .}} {{if gt .TotalPages 1}}{{end}} {{if .Posts}}
{{else}}{{end}} {{ if .Collection.ShowFooterBranding }} {{ end }} {{if .CanShowScript}} {{range .ExternalScripts}}{{end}} {{if .Collection.Script}}{{end}} {{end}} {{if .IsOwner}} + {{end}} {{end}} diff --git a/templates/collection.tmpl b/templates/collection.tmpl index 6c57cb4..87338fe 100644 --- a/templates/collection.tmpl +++ b/templates/collection.tmpl @@ -1,267 +1,268 @@ {{define "collection"}} {{template "head-base" .}} {{.DisplayTitle}}{{if not .SingleUser}} — {{.SiteName}}{{end}} {{if .CustomCSS}}{{end}} {{if .Favicon}}{{else}}{{end}} {{if gt .CurrentPage 1}}{{end}} {{if lt .CurrentPage .TotalPages}}{{end}} {{if not .IsPrivate}}{{end}} {{template "collection-meta" .}} {{if .StyleSheet}}{{end}} {{if .RenderMathJax}} {{template "mathjax" .}} {{end}} {{if .RenderMermaid}} {{template "mermaid" .}} {{end}} {{template "highlighting" . }} {{if or .IsOwner .SingleUser}} {{else if .IsCollLoggedIn}} {{end}}
{{if .Silenced}} {{template "user-silenced"}} {{end}}

{{if .Posts}}{{else}}write.as {{end}}{{.DisplayTitle}}

{{if .Description}}

{{.DisplayDescription}}

{{end}} {{/*if not .Public/*}} {{/*end*/}} {{if .PinnedPosts}} {{end}}
{{if .Posts}}
{{else}}
{{end}} {{if .IsWelcome}}

Welcome, {{.Username}}!

This is your new blog.

Start writing, or customize your blog.

Check out our writing guide to see what else you can do, and get in touch anytime with questions or feedback.

{{end}} {{if .Flash}}

{{.Flash}}

{{end}} {{template "posts" .}} {{if gt .TotalPages 1}}{{end}} {{if not .IsWelcome}}{{template "emailsubscribe" .}}{{end}} {{if .Posts}}
{{else}}{{end}} {{if .ShowFooterBranding }} {{ end }} {{if .CanShowScript}} {{range .ExternalScripts}}{{end}} {{if .Script}}{{end}} {{end}} + {{end}} diff --git a/templates/password-collection.tmpl b/templates/password-collection.tmpl index b343919..7d6194e 100644 --- a/templates/password-collection.tmpl +++ b/templates/password-collection.tmpl @@ -1,89 +1,90 @@ {{define "password-collection"}} {{template "head-base" .}} {{.DisplayTitle}}{{if not .SingleUser}} — {{.SiteName}}{{end}} {{if .CustomCSS}}{{end}} {{if .Favicon}}{{else}}{{end}} {{if .StyleSheet}}{{end}} {{if .SingleUser}} {{end}}

{{.DisplayTitle}}

{{if .Flashes}}
    {{range .Flashes}}
  • {{.}}
  • {{end}}
{{else}}

This blog requires a password.

{{end}}

{{if and .Script .CanShowScript}}{{end}} + {{end}} diff --git a/templates/user/articles.tmpl b/templates/user/articles.tmpl index 7f16236..a9b684e 100644 --- a/templates/user/articles.tmpl +++ b/templates/user/articles.tmpl @@ -1,228 +1,229 @@ {{define "articles"}} {{template "header" .}}
{{if .Flashes}}
    {{range .Flashes}}
  • {{.}}
  • {{end}}
{{end}} {{if .Silenced}} {{template "user-silenced"}} {{end}}

Drafts

{{ if .AnonymousPosts }}

These are your draft posts. You can share them individually (without a blog) or move them to your blog when you're ready.

{{ range $el := .AnonymousPosts }}

edit delete {{ if $.Collections }} {{if gt (len $.Collections) 1}}
{{else}} {{range $.Collections}} move to {{.DisplayTitle}} {{end}} {{end}} {{ end }}

{{if .Summary}}

{{.SummaryHTML}}

{{end}}
{{end}}
{{if eq (len .AnonymousPosts) 10}}

Load more...

{{end}} {{ else }}

Your anonymous and draft posts will show up here once you've published some. You'll be able to share them individually (without a blog) or move them to a blog when you're ready.

{{if not .SingleUser}}

Alternatively, see your blogs and their posts on your Blogs page.

{{end}}

Start writing

{{ end }}
{{ if .Collections }}
{{if gt (len .Collections) 1}}
{{else}} {{range .Collections}} move to {{.DisplayTitle}} {{end}} {{end}}
{{ end }} + {{template "footer" .}} {{end}} diff --git a/templates/user/collection.tmpl b/templates/user/collection.tmpl index 0071ef2..9d5acd0 100644 --- a/templates/user/collection.tmpl +++ b/templates/user/collection.tmpl @@ -1,341 +1,343 @@ {{define "collection"}} {{template "header" .}}
{{if .Silenced}} {{template "user-silenced"}} {{end}} {{template "collection-breadcrumbs" .}}

Customize

{{template "collection-nav" (dict "Alias" .Alias "Path" .Path "SingleUser" .SingleUser)}} {{if .Flashes}}
    {{range .Flashes}}
  • {{.}}
  • {{end}}
{{end}} -
+

URL

{{if eq .Alias .Username}}

This blog uses your username in its URL{{if .Federation}} and fediverse handle{{end}}. You can change it in your Account Settings.

{{end}}
  • {{.FriendlyHost}}/{{.Alias}}/
  • @{{.Alias}}@{{.FriendlyHost}}

Publicity

  • This blog is visible to {{if .Private}}any registered user on this instance{{else}}anyone with its link{{end}}.

  • Only you may read this blog (while you're logged in).

  • A password is required to read this blog.

  • {{if not .SingleUser}}
  • {{if .LocalTimeline}}

    This blog is displayed on the public reader, and is visible to {{if .Private}}any registered user on this instance{{else}}anyone with its link{{end}}.

    {{else}}

    The public reader is currently turned off for this community.

    {{end}}
  • {{end}}

Updates

Keep readers updated with your latest posts wherever they are.

  • Readers can subscribe to your blog's RSS feed with their favorite RSS reader.

  • {{if .EmailCfg.Enabled}}
  • Let readers subscribe to your blog via email, and optionally accept private replies.

    Allow replies to this address:
  • {{end}} {{if .Federation}}
  • @{{.Alias}}@{{.FriendlyHost}}

    Allow others to follow your blog and interact with your posts in the fediverse. See how it works.

  • {{end}}

Display Format

Customize how your posts display on your page.

  • Dates are shown. Latest posts listed first.

  • No dates shown. Oldest posts first.

  • No dates shown. Latest posts first.

Text Rendering

Customize how plain text renders on your blog.

Custom CSS

See our guide on customization.

Post Signature

This content will be added to the end of every post on this blog, as if it were part of the post itself. Markdown, HTML, and shortcodes are allowed.

Verification

Verify that you own another site on the open web, fediverse, etc. For example, enter your Mastodon profile address here, then on Mastodon add a link back to this blog — it will show up as verified there.

This adds a rel="me" code in your blog's <head>.

Branding

Customize the visual identity of your blog.

Favicon URL

Link to a custom favicon image (e.g. https://example.com/favicon.ico). Shown in browser tabs.

Profile Picture URL

Link to a custom profile image. Used as your avatar in the fediverse and social media previews.

Thumbnail URL

Link to a thumbnail image used in social sharing previews (Open Graph / Twitter Card / Activity Pub Profile Header).

{{if .UserPage.StaticPage.AppCfg.Monetization}}

Web Monetization

Web Monetization enables you to receive micropayments from readers via Interledger. Add your payment pointer to enable Web Monetization on your blog.

{{end}}

View Blog

- {{if ne .Alias .Username}}

Delete Blog...

{{end}} + {{if ne .Alias .Username}}

Delete Blog...

{{end}}
{{template "footer" .}} {{end}} diff --git a/templates/user/collections.tmpl b/templates/user/collections.tmpl index 88be54b..e204361 100644 --- a/templates/user/collections.tmpl +++ b/templates/user/collections.tmpl @@ -1,116 +1,116 @@ {{define "collections"}} {{template "header" .}}
{{if .Flashes}}
    {{range .Flashes}}
  • {{.}}
  • {{end}}
{{end}} {{if .Silenced}} {{template "user-silenced"}} {{end}}

Blogs

    {{range $i, $el := .Collections}}
  • {{if .Title}}{{.Title}}{{else}}{{.Alias}}{{end}} {{if .IsPrivate}}private{{else}}{{.DisplayCanonicalURL}}{{end}}

    {{template "collection-nav" (dict "Alias" .Alias "Path" $.Path "SingleUser" $.SingleUser "CanPost" true )}} {{if .Description}}

    {{.Description}}

    {{end}}
  • {{end}}
  • {{if not .NewBlogsDisabled}} -
    +

    {{end}}
{{if not .NewBlogsDisabled}}

New blog

{{end}}
{{template "foot" .}} {{template "body-end" .}} {{end}}