aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig4
-rw-r--r--site.tmpl136
-rw-r--r--src/comments.html100
-rw-r--r--src/static/comments.js76
4 files changed, 212 insertions, 104 deletions
diff --git a/.editorconfig b/.editorconfig
index 1923d41..eebf0a8 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,3 +6,7 @@ indent_size = 2
6charset = utf-8 6charset = utf-8
7trim_trailing_whitespace = true 7trim_trailing_whitespace = true
8insert_final_newline = true 8insert_final_newline = true
9
10[Makefile]
11indent_style = tab
12indent_size = 4
diff --git a/site.tmpl b/site.tmpl
index 39e8c6c..c745997 100644
--- a/site.tmpl
+++ b/site.tmpl
@@ -1,6 +1,7 @@
1{{ define "header" }} 1{{ define "header" }}
2 <!doctype html> 2<!doctype html>
3 <html lang="en"> 3<html lang="en">
4
4 <head> 5 <head>
5 <meta charset="utf-8"> 6 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -25,74 +26,75 @@
25 <meta name="twitter:card" content="summary"> 26 <meta name="twitter:card" content="summary">
26 <meta name="twitter:site" content="{{ html .Site.Other.Twitter_handle }}"> 27 <meta name="twitter:site" content="{{ html .Site.Other.Twitter_handle }}">
27 </head> 28 </head>
28 <body>
29 <main>
30{{ end }}
31 29
32{{ define "footer" }} 30 <body>
33 </main> 31 <main>
34 {{ template "ga" . }} 32 {{ end }}
33 {{ define "footer" }}
34 </main>
35 {{ template "ga" . }}
35 </body> 36 </body>
36 </html> 37
38</html>
37{{ end }} 39{{ end }}
38 40
39{{ define "navigation" }} 41{{ define "navigation" }}
40 <nav> 42<nav>
41 <a href="/">{{ html .Site.Other.Author }}</a> 43 <a href="/">{{ html .Site.Other.Author }}</a>
42 <a href="/curriculum-vitae.html">CV</a> 44 <a href="/curriculum-vitae.html">CV</a>
43 <a href="https://twitter.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Twitter</a> 45 <a href="https://twitter.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Twitter</a>
44 <a href="https://github.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Github</a> 46 <a href="https://github.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Github</a>
45 </nav> 47</nav>
46{{ end }} 48{{ end }}
47 49
48{{ define "author" }} 50{{ define "author" }}
49 <span>by {{ html .Site.Other.Author }}</span> 51<span>by {{ html .Site.Other.Author }}</span>
50{{ end }} 52{{ end }}
51 53
52{{define "date"}} 54{{define "date"}}
53 <time datetime="{{ .Format "2006-01-02T15:04:05Z07:00" }}"> 55<time datetime="{{ .Format "2006-01-02T15:04:05Z07:00" }}">
54 {{ .Format "2006, January 02" }} 56 {{ .Format "2006, January 02" }}
55 </time> 57</time>
56{{end}} 58{{end}}
57 59
58{{define "modified"}} 60{{define "modified"}}
59 <p class="modified">Modified on {{ .ModTime.Format "2006-01-02T15:04:05" }}</p> 61<p class="modified">Modified on {{ .ModTime.Format "2006-01-02T15:04:05" }}</p>
60{{end}} 62{{end}}
61 63
62{{ define "page" }} 64{{ define "page" }}
63 {{ template "header" . }} 65{{ template "header" . }}
64 {{ template "navigation" . }} 66{{ template "navigation" . }}
65 {{ .Content }} 67{{ .Content }}
66 {{ template "prism" . }} 68{{ template "prism" . }}
67 {{ template "mathjax" . }} 69{{ template "mathjax" . }}
68 {{ template "footer" . }} 70{{ template "footer" . }}
69{{ end }} 71{{ end }}
70 72
71{{ define "post" }} 73{{ define "post" }}
72 <article> 74<article>
73 <header> 75 <header>
74 <h1>{{ .Title }}</h1> 76 <h1>{{ .Title }}</h1>
75 {{ if eq .Other.Type "post" }} 77 {{ if eq .Other.Type "post" }}
76 <div class="info"> 78 <div class="info">
77 {{ template "date" .Date }} 79 {{ template "date" .Date }}
78 {{ template "author" . }} 80 {{ template "author" . }}
79 </div> 81 </div>
80 {{ end }} 82 {{ end }}
81 </header> 83 </header>
82 <section> 84 <section>
83 {{ .Content }} 85 {{ .Content }}
84 </section> 86 </section>
85 </article> 87</article>
86 88
87 {{ if eq .Other.Type "post" }} 89{{ if eq .Other.Type "post" }}
88 {{ template "comments" . }} 90{{ template "comments" . }}
89 {{ end }} 91{{ end }}
90 92
91 {{ template "modified" . }} 93{{ template "modified" . }}
92{{ end }} 94{{ end }}
93 95
94{{ define "mathjax" }} 96{{ define "mathjax" }}
95 <script type="text/x-mathjax-config"> 97<script type="text/x-mathjax-config">
96 MathJax.Hub.Config({ 98 MathJax.Hub.Config({
97 TeX: { equationNumbers: { autoNumber: "AMS" } }, 99 TeX: { equationNumbers: { autoNumber: "AMS" } },
98 tex2jax: { 100 tex2jax: {
@@ -101,38 +103,38 @@
101 processEscapes: true 103 processEscapes: true
102 }}); 104 }});
103 </script> 105 </script>
104 <script src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" async="async"></script> 106<script src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" async="async"></script>
105{{ end }} 107{{ end }}
106 108
107{{ define "ga" }} 109{{ define "ga" }}
108 <script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-12769079-10"></script> 110<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-12769079-10"></script>
109 <script> 111<script>
110 window.dataLayer = window.dataLayer || []; 112 window.dataLayer = window.dataLayer || [];
111 function gtag() { 113 function gtag() {
112 dataLayer.push(arguments); 114 dataLayer.push(arguments);
113 } 115 }
114 gtag('js', new Date()); 116 gtag('js', new Date());
115 gtag('config', 'UA-12769079-10'); 117 gtag('config', 'UA-12769079-10');
116 </script> 118</script>
117{{ end }} 119{{ end }}
118 120
119{{ define "prism" }} 121{{ define "prism" }}
120 <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-core.min.js"></script> 122<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-core.min.js"></script>
121 <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/autoloader/prism-autoloader.min.js"></script> 123<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/autoloader/prism-autoloader.min.js"></script>
122{{ end }} 124{{ end }}
123 125
124{{ define "comments" }} 126{{ define "comments" }}
125 <div class="comments"> 127<div class="comments">
126 <h3>Comments</h3> 128 <h3>Comments</h3>
127 <div class="form"> 129 <div class="form">
128 <div><input id="name" placeholder="Your name" maxlength="20"></div> 130 <div><input id="name" placeholder="Your name" maxlength="20"></div>
129 <div><textarea id="comment" placeholder="Your comment" maxlength="500"></textarea></div> 131 <div><textarea id="comment" placeholder="Your comment" maxlength="500"></textarea></div>
130 <div><button id="submit">Post a comment</button></div> 132 <div><button id="submit">Post a comment</button></div>
131 </div>
132 <ul></ul>
133 </div> 133 </div>
134 <ul></ul>
135</div>
134 136
135 <script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-app.js"></script> 137<script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-app.js"></script>
136 <script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-database.js"></script> 138<script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-database.js"></script>
137 <script src="{{ .Rel "static/comments.js" }}?v={{ .ModTime.Format "20060102150405" }}" async></script> 139<script src="{{ .Rel "static/comments.js" }}?v={{ .ModTime.Format "20060102150405" }}" async></script>
138{{ end }} 140{{ end }}
diff --git a/src/comments.html b/src/comments.html
new file mode 100644
index 0000000..3d990da
--- /dev/null
+++ b/src/comments.html
@@ -0,0 +1,100 @@
1<!DOCTYPE html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6 <meta name="theme-color" content="#ffffff">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <meta http-equiv="X-UA-Compatible" content="ie=edge">
9 <title>Commenta dashboard</title>
10
11 <style>
12 th {
13 text-align: left;
14 }
15
16 .comment-item {
17 padding: 10px 0 30px 0;
18 border-bottom: 2px inset gray;
19 }
20 </style>
21
22 </head>
23
24 <body>
25
26 <h1>Comments</h1>
27 <div id="results"></div>
28
29 <script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-app.js"></script>
30 <script src="https://www.gstatic.com/firebasejs/7.2.1/firebase-database.js"></script>
31 <script src="static/comments.js"></script>
32
33 <script>
34
35 // var tableResults = document.querySelector('#results tbody');
36 var resultsPlaceholder = document.querySelector('#results');
37
38 function snapshotToArray(snapshot) {
39 var returnArr = [];
40 snapshot.forEach(function (childSnapshot) {
41 var arrItem = childSnapshot.val();
42 arrItem.key = childSnapshot.key;
43 returnArr.push(arrItem);
44 });
45
46 var comments = [];
47 returnArr.forEach(function (item) {
48 var keys = Object.keys(item);
49 for (var key of keys) {
50 let group = item.key;
51 if (key !== 'key') {
52 for (var itemKey of Object.keys(item[key])) {
53 item[key][itemKey].slug = key;
54 item[key][itemKey].group = group;
55 item[key][itemKey].itemKey = itemKey
56 comments.push(item[key][itemKey]);
57 }
58 }
59 }
60 });
61
62 return comments;
63 };
64
65 var path = window.location.hostname.replace('.', '-') + '/comments';
66 var ref = firebase.database().ref(path);
67 ref.on("value", function (snap) {
68 resultsPlaceholder.innerHTML = '';
69 var comments = snapshotToArray(snap);
70 comments.forEach(function (item) {
71 var commentContent = document.createElement('div');
72
73 commentContent.classList.add('comment-item');
74 commentContent.innerHTML = `
75 <p><b>${item.name} (${item.published})</b><br>
76 <i>${item.group}/${item.slug}</i></p>
77 <p>${item.comment}</p>
78 `;
79
80 var buttonDelete = document.createElement('button');
81 buttonDelete.innerText = 'Delete comment';
82 buttonDelete.dataset.id = `${window.location.hostname.replace('.', '-')}/comments/${item.group}/${item.slug}/${item.itemKey}`;
83 buttonDelete.addEventListener('click', function (evt) {
84 if (confirm('Are you sure you want to delete this comment?')) {
85 firebase.database().ref(evt.target.dataset.id).remove();
86 }
87 });
88
89 commentContent.appendChild(buttonDelete);
90 resultsPlaceholder.appendChild(commentContent);
91 });
92 }, function (errorObject) {
93 console.log(`The read failed: ${errorObject.code}`);
94 });
95
96 </script>
97
98 </body>
99
100</html>
diff --git a/src/static/comments.js b/src/static/comments.js
index c8234d2..3f373e5 100644
--- a/src/static/comments.js
+++ b/src/static/comments.js
@@ -10,7 +10,7 @@ var firebaseConfig = {
10firebase.initializeApp(firebaseConfig); 10firebase.initializeApp(firebaseConfig);
11 11
12var database = firebase.database(); 12var database = firebase.database();
13var docPath = 'comments' + window.location.pathname.replace('.html', ''); 13var docPath = window.location.hostname.replace('.', '-') + '/comments' + window.location.pathname.replace('.html', '');
14var submit = document.querySelector('#submit'); 14var submit = document.querySelector('#submit');
15var comments = document.querySelector('.comments ul'); 15var comments = document.querySelector('.comments ul');
16var textName = document.querySelector('#name'); 16var textName = document.querySelector('#name');
@@ -21,43 +21,45 @@ function encodeHTML(s) {
21 return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;'); 21 return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
22} 22}
23 23
24ref.on("value", function (snapshot) { 24if (submit) {
25 comments.innerHTML = ''; 25 ref.on("value", function (snapshot) {
26 var commentList = Array(); 26 comments.innerHTML = '';
27 var commentList = Array();
27 28
28 // generating normal array 29 // generating normal array
29 snapshot.forEach(function (item) { 30 snapshot.forEach(function (item) {
30 commentList.push(item.val()) 31 commentList.push(item.val())
31 }); 32 });
32 33
33 // rendering html 34 // rendering html
34 commentList.reverse().forEach(function (item) { 35 commentList.reverse().forEach(function (item) {
35 var liItem = `<li> 36 var liItem = `<li>
36 <div><b>${encodeHTML(item.name)}</b> - ${encodeHTML(item.published)}</div> 37 <div><b>${encodeHTML(item.name)}</b> - ${encodeHTML(item.published)}</div>
37 <div>${encodeHTML(item.comment)}</div> 38 <div>${encodeHTML(item.comment)}</div>
38 </li>`; 39 </li>`;
39 comments.innerHTML += liItem; 40 comments.innerHTML += liItem;
40 }); 41 });
41 42
42}, function (errorObject) { 43 }, function (errorObject) {
43 console.log("The read failed: " + errorObject.code); 44 console.log("The read failed: " + errorObject.code);
44}); 45 });
45 46
46submit.addEventListener('click', function (evt) { 47 submit.addEventListener('click', function (evt) {
47 if (textName.value && textComment.value) { 48 if (textName.value && textComment.value) {
48 submit.disabled = true; 49 submit.disabled = true;
49 firebase.database().ref(docPath + '/' + Date.now()).set({ 50 firebase.database().ref(docPath + '/' + Date.now()).set({
50 name: textName.value, 51 name: textName.value,
51 comment: textComment.value, 52 comment: textComment.value,
52 published: new Date().toISOString().slice(0, 16).replace('T', ' '), 53 published: new Date().toISOString().slice(0, 16).replace('T', ' '),
53 }, function (error) { 54 }, function (error) {
54 if (error) { 55 if (error) {
55 alert('Data could not be saved.' + error); 56 alert('Data could not be saved.' + error);
56 } else { 57 } else {
57 textName.value = ''; 58 textName.value = '';
58 textComment.value = ''; 59 textComment.value = '';
59 submit.disabled = false; 60 submit.disabled = false;
60 } 61 }
61 }); 62 });
62 } 63 }
63}); 64 });
65}