1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-02 02:36:24 -07:00

Add HTML, JS, and JSON minification

Also remove that stupid filter for password input fields that Firefox (and maybe other browsers) adds
This commit is contained in:
Eggbertx 2019-12-07 12:52:36 -08:00
parent 267a5eeb6f
commit e361223084
18 changed files with 127 additions and 1177 deletions

View file

@ -204,7 +204,8 @@ while [ -n "$1" ]; do
github.com/aquilax/tripcode \
golang.org/x/crypto/bcrypt \
github.com/frustra/bbcode \
github.com/mattn/go-sqlite3
github.com/mattn/go-sqlite3 \
github.com/tdewolff/minify
;;
docker-image)
# echo "Docker image creation not yet implemented"

View file

@ -1,120 +1 @@
h1#board-title {
font-family: serif !important;
font-size: 24pt;
color: #AF0A0F;
}
.postblock {
background: #9988EE;
}
div.file-info {
font-size: 12px;
font-family: sans-serif;
}
.postername {
font-size: 12px;
font-family: serif;
color: #117743;
font-weight: 800;
}
.reply, .thread-ddown-menu {
background: #D6DAF0;
}
.thread-ddown-menu {
border: 1px solid #9295a4;
}
#site-title {
font-family: sans-serif;
padding-top: 88px;
}
#site-slogan {
font-size: 9pt;
font-style: italic;
}
.tab {
background-color: #dfdffe;
border: 1px solid #9295a4;
}
#current-tab {
margin-top: 16px;
border-bottom: 0px;
}
#current-tab, div.section-title-block {
background-color: #bfc6e7;
}
.loginbox input {
height: 20%;
}
.manage-header {
background-color: #EEF2FF;
border-radius: 8px;
}
body {
font: sans-serif 12pt;
background: #EEF2FF;
margin: 8px;
}
a, a:visited {
color: #34345C;
text-decoration: none;
}
h1 {
margin: 0;
text-align: center;
}
h2 {
margin: 0px 0px 0px 0px;
font-size: 140%;
}
h2 a {
text-decoration: none;
color: #550;
}
h3 {
margin: 0px;
text-align: center;
font-size: medium;
}
h1, h2 {
font-family: Verdana, Tahoma, sans-serif;
}
h1, h2, h3 {
font-weight: bold;
color: #333;
}
div#topbar {
-moz-box-shadow: 3px 3px 5px 6px #555555;
-ms-box-shadow: 3px 3px 5px 6px #555555;
-webkit-box-shadow: 3px 3px 5px 6px #555555;
box-shadow: 3px 3px 5px 6px #555555;
height: 30px;
}
div#topbar, .topbar-item, .topbar-item:visited, .dropdown-button, .dropdown-menu, .dropdown-menu a {
background-color: #000A89;
color: #EEF2FF !important;
}
div#footer {
font-size: 8pt;
}
h1#board-title{font-family:serif !important;font-size:24pt;color:#af0a0f}.postblock{background:#98e}div.file-info{font-size:12px;font-family:sans-serif}.postername{font-size:12px;font-family:serif;color:#117743;font-weight:800}.reply,.thread-ddown-menu{background:#d6daf0}.thread-ddown-menu{border:1px solid #9295a4}#site-title{font-family:sans-serif;padding-top:88px}#site-slogan{font-size:9pt;font-style:italic}.tab{background-color:#dfdffe;border:1px solid #9295a4}#current-tab{margin-top:16px;border-bottom:0px}#current-tab,div.section-title-block{background-color:#bfc6e7}.loginbox input{height:20%}.manage-header{background-color:#eef2ff;border-radius:8px}body{font:sans-serif 12pt;background:#eef2ff;margin:8px}a,a:visited{color:#34345c;text-decoration:none}h1{margin:0;text-align:center}h2{margin:0px 0px 0px 0px;font-size:140%}h2 a{text-decoration:none;color:#550}h3{margin:0px;text-align:center;font-size:medium}h1,h2{font-family:Verdana,Tahoma,sans-serif}h1,h2,h3{font-weight:bold;color:#333}div#topbar{-moz-box-shadow:3px 3px 5px 6px #555;-ms-box-shadow:3px 3px 5px 6px #555;-webkit-box-shadow:3px 3px 5px 6px #555;box-shadow:3px 3px 5px 6px #555;height:30px}div#topbar,.topbar-item,.topbar-item:visited,.dropdown-button,.dropdown-menu,.dropdown-menu a{background-color:#000a89;color:#eef2ff !important}div#footer{font-size:8pt}

File diff suppressed because one or more lines are too long

View file

@ -1,217 +1 @@
@import url(http://fonts.googleapis.com/css?family=Walter+Turncoat);
#site-title {
color: #ff0;
font-size: 50px;
}
#top-pane {
height: 75px;
left: 0;
position: absolute;
text-align: center;
top: 0;
width: 100%;
}
#topmenu {
left: 16%;
position: absolute;
top: 76px;
}
#topmenu li {
background-color: #F0E0D6;
border: 1px solid #9295a4;
border-left: none;
color: maroon;
display: block;
float: left;
margin-top: -7px;
padding: 3px 10px 2px;
}
#topmenu li.current {
background-color: #d0c0c6;
border-bottom: none;
margin-top: -8px;
padding-top: 5px;
}
#topmenu li.first {
border-left: 1px solid #F0E0D6;
}
.content {
margin-left: 0 !important;
padding-left: 0 !important;
text-align: justify;
}
.newssub {
background-color: #D0C0C6;
position: absolute;
}
.permalink {
display: block;
text-align: right;
}
.permalink a {
color: blue;
text-decoration: none;
}
ul.boardmenu li:hover, ul.modmenulink li:hover {
background: #C6DAF0;
}
ul.boardmenu, ul.modmenulink, div#topmenu ul {
list-style: none;
margin: 0;
padding-left: 0;
}
.file-info {
background: inherit;
color: #CC1105;
font-weight: 800;
}
#board-title {
color: maroon;
font-size: 2em;
text-align: center;
}
.manage-header {
background: #AA6;
color: #400000;
padding: 0;
}
.omittedposts {
color: #707070;
}
.passvalid {
background: #000;
color: #fff;
text-align: center;
width: 100%;
}
.postblock {
background: #000;
color: #fff;
font-weight: 800;
}
.postername {
color: #117743;
font-weight: 700;
}
.postertrip {
color: #228854;
}
.postlists {
background: #FFF;
color: maroon;
padding: 0;
width: 100%;
}
.reply {
background: #F0E0D6;
color: maroon;
}
.replytitle {
color: #CC1105;
font-size: 1.2em;
font-weight: 800;
}
.theader {
background: #E04000;
color: #FFF;
padding: 2px;
text-align: center;
width: 100%;
}
.file-deleted-box {
color: maroon;
font-size: small;
}
.greentext {
background: inert;
color: #789922;
}
a:hover {
color: #D00;
}
body {
margin: 0;
padding: 0;
background: #135;
color: #fff;
font-family: "comic sans ms", "Walter Turncoat", cursive;
}
h1 {
color: #000;
font-size: 150%;
margin: 0;
}
h1, h2 {
color: white;
}
h1, h3, .menu {
font-family: Verdana, Tahoma, sans-serif;
}
h2 {
font-size: 100%;
margin: 1em 0 0;
}
h2 a {
color: #550;
text-decoration: none;
}
h3 {
color: #800;
font-size: medium;
font-weight: 400;
margin: 0;
text-align: center;
}
a {
color: #ff0;
text-decoration: none;
}
li {
margin: 0;
}
li a {
display: block;
width: 100%;
}
.footer {
font-family: serif;
font-size: 12px;
text-align: center;
}
@import"http://fonts.googleapis.com/css?family=Walter+Turncoat";#site-title{color:#ff0;font-size:50px}#top-pane{height:75px;left:0;position:absolute;text-align:center;top:0;width:100%}#topmenu{left:16%;position:absolute;top:76px}#topmenu li{background-color:#f0e0d6;border:1px solid #9295a4;border-left:none;color:maroon;display:block;float:left;margin-top:-7px;padding:3px 10px 2px}#topmenu li.current{background-color:#d0c0c6;border-bottom:none;margin-top:-8px;padding-top:5px}#topmenu li.first{border-left:1px solid #f0e0d6}.content{margin-left:0 !important;padding-left:0 !important;text-align:justify}.newssub{background-color:#d0c0c6;position:absolute}.permalink{display:block;text-align:right}.permalink a{color:blue;text-decoration:none}ul.boardmenu li:hover,ul.modmenulink li:hover{background:#c6daf0}ul.boardmenu,ul.modmenulink,div#topmenu ul{list-style:none;margin:0;padding-left:0}.file-info{background:inherit;color:#cc1105;font-weight:800}#board-title{color:maroon;font-size:2em;text-align:center}.manage-header{background:#aa6;color:#400000;padding:0}.omittedposts{color:#707070}.passvalid{background:#000;color:#fff;text-align:center;width:100%}.postblock{background:#000;color:#fff;font-weight:800}.postername{color:#117743;font-weight:700}.postertrip{color:#228854}.postlists{background:#fff;color:maroon;padding:0;width:100%}.reply{background:#f0e0d6;color:maroon}.replytitle{color:#cc1105;font-size:1.2em;font-weight:800}.theader{background:#e04000;color:#fff;padding:2px;text-align:center;width:100%}.file-deleted-box{color:maroon;font-size:small}.greentext{background:inert;color:#789922}a:hover{color:#d00}body{margin:0;padding:0;background:#135;color:#fff;font-family:"comic sans ms","Walter Turncoat",cursive}h1{color:#000;font-size:150%;margin:0}h1,h2{color:#fff}h1,h3,.menu{font-family:Verdana,Tahoma,sans-serif}h2{font-size:100%;margin:1em 0 0}h2 a{color:#550;text-decoration:none}h3{color:#800;font-size:medium;font-weight:400;margin:0;text-align:center}a{color:#ff0;text-decoration:none}li{margin:0}li a{display:block;width:100%}.footer{font-family:serif;font-size:12px;text-align:center}

View file

@ -1,59 +1 @@
div.reply {
background-color: #ddd;
border: 1px solid #ccc;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
span.subject {
color: #024;
}
div.section-title-block {
background-color: #ccc;
}
div.section-block {
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
background-color: #FCFCFC;
border: 1px solid #D7D7D7;
}
body {
background-color: #eee;
font: 15px "Trebuchet MS", Trebuchet, sans-serif;
}
a {
text-decoration: none;
}
div#topbar, div.dropdown-menu {
background-color: #000;
opacity: 0.7;
padding: 2px;
}
div#topbar {
-moz-box-shadow: 0px 2px 2px 2px #292929;
-ms-box-shadow: 0px 2px 2px 2px #292929;
-webkit-box-shadow: 0px 2px 2px 2px #292929;
box-shadow: 0px 2px 2px 2px #292929;
}
div.dropdown-menu {
color: #FFF;
}
header, div#top-pane, a {
color: #f60;
}
span#site-title, div#board-title {
font-weight: 800;
}
div.reply{background-color:#ddd;border:1px solid #ccc;-moz-border-radius:5px;-ms-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}span.subject{color:#024}div.section-title-block{background-color:#ccc}div.section-block{-moz-border-radius:5px;-ms-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;background-color:#fcfcfc;border:1px solid #d7d7d7}body{background-color:#eee;font:15px "Trebuchet MS",Trebuchet,sans-serif}a{text-decoration:none}div#topbar,div.dropdown-menu{background-color:#000;opacity:.7;padding:2px}div#topbar{-moz-box-shadow:0px 2px 2px 2px #292929;-ms-box-shadow:0px 2px 2px 2px #292929;-webkit-box-shadow:0px 2px 2px 2px #292929;box-shadow:0px 2px 2px 2px #292929}div.dropdown-menu{color:#fff}header,div#top-pane,a{color:#f60}span#site-title,div#board-title{font-weight:800}

View file

@ -1,172 +1 @@
.dropdown-button:hover {
background-color: #404040;
}
.dropdown-menu {
background-color: #202020;
box-shadow: 2px 2px 2px 3px #101010;
z-index: 0;
}
.section-body {
background-color: #606060;
}
.section-title-block {
background-color: #202020;
border-radius: 4px 8px 4px 8px;
}
.tab {
background-color: #404040 !important;
border: 1px solid #202020;
}
#current-tab {
background-color: #202020 !important;
}
div#recent-posts-header {
-moz-box-shadow: 0px 2px 2px 3px #101010;
-ms-box-shadow: 0px 2px 2px 3px #101010;
-webkit-box-shadow: 0px 2px 2px 3px #101010;
box-shadow: 0px 2px 2px 3px #101010;
margin-bottom: 8px;
padding: 4px 8px 4px 8px;
}
.postblock {
background-color: #202020;
font-weight: 700;
}
.loginbox input {
height: 20%;
}
.manage-header {
background-color: #202020;
-moz-box-shadow: 2px 2px 3px 4px #101010;
-ms-box-shadow: 2px 2px 3px 4px #101010;
-webkit-box-shadow: 2px 2px 3px 4px #101010;
box-shadow: 2px 2px 3px 4px #101010;
border-radius: 8px;
}
.dropdown-button:hover {
background-color: #404040;
}
.dropdown-menu {
background-color: #202020;
-moz-box-shadow: 2px 2px 2px 3px #101010;
-ms-box-shadow: 2px 2px 2px 3px #101010;
-webkit-box-shadow: 2px 2px 2px 3px #101010;
box-shadow: 2px 2px 2px 3px #101010;
z-index: 0;
}
ul.staffmenu li:hover {
background: #404040;
}
img.thumbnail {
float: left;
max-width: 100%;
margin: 5px 10px 10px 0px;
}
.reply, .inlinepostprev, .postprev {
background-color: #25272D;
border: 1px solid #8C94AB;
}
.postblock {
background-color: #25272D;
font-weight: 700;
}
.postername {
color: #FC0;
font-weight: 700;
}
.postername a {
color: #ffcc00 !important;
text-decoration: underline;
}
.subject {
color: #F90;
}
.thread-ddown a {
font-size: 75%;
vertical-align: middle;
}
.tripcode {
color: #FC0;
}
form#postform input[type=text], form#postform input[type=password], form#postform input[type=file], form#postform textarea, form#postform .thread-ddown-menu {
background-color: #25272D;
border: 1px solid #8C94AB;
color: #FFF;
}
.thread-ddown-menu, input#reason, input#password {
background-color: #25272D;
border: 1px solid #8C94AB;
color: #FFF;
}
.thread-ddown-menu li:hover {
background-color: #404040;
}
* {
outline: none;
}
body {
background-color: #363942;
background-image: url(res/pipes_bg.png);
color: #d8d0b9;
font: 12pt sans-serif;
}
header h1, span#site-title {
color: #e1b400;
}
a {
color: #f90;
font: 12pt sans-serif;
text-decoration: none;
}
a:hover {
background: inherit;
color: #ffd43f;
}
a.topbar-item:hover {
background-color: #404040;
}
div#footer, div#footer * {
font-size: 9pt;
}
div#topbar {
background-color: #202020;
-moz-box-shadow: 0px 2px 2px 3px #101010;
-ms-box-shadow: 0px 2px 2px 3px #101010;
-webkit-box-shadow: 0px 2px 2px 3px #101010;
box-shadow: 0px 2px 2px 3px #101010;
z-index: 9001;
}
div#topbar li:hover {
background-color: #404040;
}
.dropdown-button:hover{background-color:#404040}.dropdown-menu{background-color:#202020;box-shadow:2px 2px 2px 3px #101010;z-index:0}.section-body{background-color:#606060}.section-title-block{background-color:#202020;border-radius:4px 8px 4px 8px}.tab{background-color:#404040 !important;border:1px solid #202020}#current-tab{background-color:#202020 !important}div#recent-posts-header{-moz-box-shadow:0px 2px 2px 3px #101010;-ms-box-shadow:0px 2px 2px 3px #101010;-webkit-box-shadow:0px 2px 2px 3px #101010;box-shadow:0px 2px 2px 3px #101010;margin-bottom:8px;padding:4px 8px 4px 8px}.postblock{background-color:#202020;font-weight:700}.loginbox input{height:20%}.manage-header{background-color:#202020;-moz-box-shadow:2px 2px 3px 4px #101010;-ms-box-shadow:2px 2px 3px 4px #101010;-webkit-box-shadow:2px 2px 3px 4px #101010;box-shadow:2px 2px 3px 4px #101010;border-radius:8px}.dropdown-button:hover{background-color:#404040}.dropdown-menu{background-color:#202020;-moz-box-shadow:2px 2px 2px 3px #101010;-ms-box-shadow:2px 2px 2px 3px #101010;-webkit-box-shadow:2px 2px 2px 3px #101010;box-shadow:2px 2px 2px 3px #101010;z-index:0}ul.staffmenu li:hover{background:#404040}img.thumbnail{float:left;max-width:100%;margin:5px 10px 10px 0px}.reply,.inlinepostprev,.postprev{background-color:#25272d;border:1px solid #8c94ab}.postblock{background-color:#25272d;font-weight:700}.postername{color:#fc0;font-weight:700}.postername a{color:#fc0 !important;text-decoration:underline}.subject{color:#f90}.thread-ddown a{font-size:75%;vertical-align:middle}.tripcode{color:#fc0}input:not([type=submit]):not([type=button]),textarea,select,.thread-ddown-menu{background-color:#25272d;border:1px solid #8c94ab;color:#fff;filter:none}.thread-ddown-menu{background-color:#25272d;border:1px solid #8c94ab;color:#fff}.thread-ddown-menu li:hover{background-color:#404040}*{outline:none}body{background-color:#363942;background-image:url(res/pipes_bg.png);color:#d8d0b9;font:12pt sans-serif}header h1,span#site-title{color:#e1b400}a{color:#f90;font:12pt sans-serif;text-decoration:none}a:hover{background:inherit;color:#ffd43f}a.topbar-item:hover{background-color:#404040}div#footer,div#footer *{font-size:9pt}div#topbar{background-color:#202020;-moz-box-shadow:0px 2px 2px 3px #101010;-ms-box-shadow:0px 2px 2px 3px #101010;-webkit-box-shadow:0px 2px 2px 3px #101010;box-shadow:0px 2px 2px 3px #101010;z-index:9001}div#topbar li:hover{background-color:#404040}

View file

@ -7,6 +7,6 @@
<h1>404: File not found</h1>
<img src="/error/lol 404.gif" border="0" alt="">
<p>The requested file could not be found on this server. Are you just typing random stuff in the address bar? If you followed a link from this site here, then post <a href="/site">here</a></p>
<hr><address>http://gochan.org powered by Gochan v2.9.0</address>
<hr><address>http://gochan.org powered by Gochan v2.11.0</address>
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>500: Internal Server error</h1>
<img src="/error/derpy server.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon has he/she/it can.</p>
<hr><address>http://gochan.org powered by Gochan v2.9.0</address>
<hr><address>http://gochan.org powered by Gochan v2.11.0</address>
</body>
</html>

View file

@ -4,6 +4,6 @@ If you want, you can install [Sass](https://sass-lang.com/install) to streamline
To use sass, run `sass --style expanded --no-source-map sass:html/css`.
To have sass watch the input directory for changes as you edit and save the files, run `sass --style expanded --no-source-map --watch sass:html/css`
In either case, `--style expanded` is optional. Run `sass -h` for more info about it.
In either case, `--style expanded` is optional. If you replace expanded with compressed, it will minify the generated CSS files. Run `sass -h` for more info about it.
If you are upgading from gochan 2.2, delete your html/css directory unless you have made themes that you want to keep. Then rebuild the pages. (/manage?action=rebuildall)

View file

@ -54,15 +54,14 @@ img.thumbnail {
color: #FC0;
}
form#postform {
input[type=text], input[type=password], input[type=file], textarea, .thread-ddown-menu {
background-color: #25272D;
border: 1px solid #8C94AB;
color: #FFF;
}
input:not([type=submit]):not([type=button]), textarea, select, .thread-ddown-menu {
background-color: #25272D;
border: 1px solid #8C94AB;
color: #FFF;
filter: none;
}
.thread-ddown-menu, input#reason, input#password {
.thread-ddown-menu {
background-color: #25272D;
border: 1px solid #8C94AB;
color: #FFF;

View file

@ -5,13 +5,60 @@ package main
import (
"encoding/json"
"fmt"
"io"
"os"
"path"
"strconv"
"syscall"
"text/template"
"time"
"github.com/tdewolff/minify"
minifyHTML "github.com/tdewolff/minify/html"
minifyJS "github.com/tdewolff/minify/js"
minifyJSON "github.com/tdewolff/minify/json"
)
var minifier *minify.M
func initMinifier() {
if !config.MinifyHTML && !config.MinifyJS {
return
}
minifier = minify.New()
if config.MinifyHTML {
minifier.AddFunc("text/html", minifyHTML.Minify)
}
if config.MinifyJS {
minifier.AddFunc("text/javascript", minifyJS.Minify)
minifier.AddFunc("application/json", minifyJSON.Minify)
}
}
func canMinify(mediaType string) bool {
return (mediaType == "text/html" && config.MinifyHTML) || ((mediaType == "application/json" || mediaType == "text/javascript") && config.MinifyJS)
}
func minifyTemplate(tmpl *template.Template, data interface{}, writer io.Writer, mediaType string) error {
if !canMinify(mediaType) {
return tmpl.Execute(writer, data)
}
minWriter := minifier.Writer(mediaType, writer)
defer minWriter.Close()
return tmpl.Execute(minWriter, data)
}
func minifyWriter(writer io.Writer, data []byte, mediaType string) (int, error) {
if !canMinify(mediaType) {
return writer.Write(data)
}
minWriter := minifier.Writer(mediaType, writer)
defer minWriter.Close()
return minWriter.Write(data)
}
// build front page using templates/front.html
func buildFrontPage() string {
err := initTemplates("front")
@ -71,12 +118,12 @@ func buildFrontPage() string {
}
}
if err = frontPageTmpl.Execute(frontFile, map[string]interface{}{
if err = minifyTemplate(frontPageTmpl, map[string]interface{}{
"config": config,
"sections": allSections,
"boards": allBoards,
"recent_posts": recentPostsArr,
}); err != nil {
}, frontFile, "text/html"); err != nil {
return handleError(1, "Failed executing front page template: "+err.Error())
}
return "Front page rebuilt successfully."
@ -105,7 +152,8 @@ func buildBoardListJSON() (html string) {
if err != nil {
return handleError(1, "Failed marshal to JSON: "+err.Error()) + "<br />\n"
}
if _, err = boardListFile.Write(boardJSON); err != nil {
if _, err = minifyWriter(boardListFile, boardJSON, "application/json"); err != nil {
return handleError(1, "Failed writing boards.json file: "+err.Error()) + "<br />\n"
}
return "Board list JSON rebuilt successfully.<br />"
@ -237,13 +285,13 @@ func buildBoardPages(board *Board) (html string) {
// Render board page template to the file,
// packaging the board/section list, threads, and board info
if err = boardpageTmpl.Execute(boardPageFile, map[string]interface{}{
if err = minifyTemplate(boardpageTmpl, map[string]interface{}{
"config": config,
"boards": allBoards,
"sections": allSections,
"threads": threads,
"board": board,
}); err != nil {
}, boardPageFile, "text/html"); err != nil {
html += handleError(1, "Failed building /"+board.Dir+"/: "+err.Error()) + "<br />"
return
}
@ -280,8 +328,8 @@ func buildBoardPages(board *Board) (html string) {
continue
}
// Render the boardpage template, don't forget config
if err = boardpageTmpl.Execute(currentPageFile, map[string]interface{}{
// Render the boardpage template
if err = minifyTemplate(boardpageTmpl, map[string]interface{}{
"config": config,
"boards": allBoards,
"sections": allSections,
@ -290,7 +338,7 @@ func buildBoardPages(board *Board) (html string) {
"posts": []interface{}{
Post{BoardID: board.ID},
},
}); err != nil {
}, currentPageFile, "text/html"); err != nil {
html += handleError(1, "Failed building /"+board.Dir+"/ boardpage: "+err.Error()) + "<br />"
return
}
@ -382,7 +430,7 @@ func buildJSConstants() string {
return handleError(1, "Error opening '"+jsPath+"' for writing: "+err.Error())
}
if err = jsTmpl.Execute(jsFile, config); err != nil {
if err = minifyTemplate(jsTmpl, config, jsFile, "text/javascript"); err != nil {
return handleError(1, "Error building '"+jsPath+"': "+err.Error())
}
return "Built '" + jsPath + "' successfully."
@ -416,13 +464,13 @@ func buildCatalog(which int) string {
}
threadPages := paginate(config.PostsPerThreadPage, threadInterfaces)
if err = catalogTmpl.Execute(catalogFile, map[string]interface{}{
if err = minifyTemplate(catalogTmpl, map[string]interface{}{
"boards": allBoards,
"config": config,
"board": board,
"sections": allSections,
"threadPages": threadPages,
}); err != nil {
}, catalogFile, "text/html"); err != nil {
return handleError(1, "Error building catalog for /%s/: %s", board.Dir, err.Error())
}
return fmt.Sprintf("Built catalog for /%s/ successfully", board.Dir)
@ -471,14 +519,14 @@ func buildThreadPages(op *Post) (html string) {
}
// render main page
if err = threadpageTmpl.Execute(currentPageFile, map[string]interface{}{
if err = minifyTemplate(threadpageTmpl, map[string]interface{}{
"config": config,
"boards": allBoards,
"board": board,
"sections": allSections,
"posts": replies,
"op": op,
}); err != nil {
}, currentPageFile, "text/html"); err != nil {
html += handleError(1, "Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error()) + "<br />\n"
return
}
@ -520,14 +568,14 @@ func buildThreadPages(op *Post) (html string) {
return
}
if err = threadpageTmpl.Execute(currentPageFile, map[string]interface{}{
if err = minifyTemplate(threadpageTmpl, map[string]interface{}{
"config": config,
"boards": allBoards,
"board": board,
"sections": allSections,
"posts": pagePosts,
"op": op,
}); err != nil {
}, currentPageFile, "text/html"); err != nil {
html += handleError(1, "<br />Failed building /%s/%d: %s", board.Dir, op.ID, err.Error())
return
}

View file

@ -59,7 +59,7 @@ func serveCaptcha(writer http.ResponseWriter, request *http.Request) {
if useJSON {
writer.Header().Add("Content-Type", "application/json")
str, _ := marshalJSON("", captchaStruct, false)
writer.Write([]byte(str))
minifyWriter(writer, []byte(str), "application/json")
return
}
if request.FormValue("reload") == "Reload" {
@ -93,7 +93,7 @@ func serveCaptcha(writer http.ResponseWriter, request *http.Request) {
captchaStruct.Result = "Incorrect CAPTCHA"
}
}
if err = captchaTmpl.Execute(writer, captchaStruct); err != nil {
if err = minifyTemplate(captchaTmpl, captchaStruct, writer, "text/html"); err != nil {
handleError(0, customError(err))
fmt.Fprintf(writer, "Error executing captcha template")
}

View file

@ -22,6 +22,7 @@ func main() {
}
}()
initConfig()
initMinifier()
printf(0, "Starting gochan v%s.%s, using verbosity level %d\n", versionStr, buildtimeString, config.Verbosity)
connectToSQLServer()
parseCommandLine()

View file

@ -373,7 +373,8 @@ var manageFunctions = map[string]ManageFunction{
config.ImagesOpenNewTab = (request.PostFormValue("ImagesOpenNewTab") == "on")
config.MakeURLsHyperlinked = (request.PostFormValue("MakeURLsHyperlinked") == "on")
config.NewTabOnOutlinks = (request.PostFormValue("NewTabOnOutlinks") == "on")
config.EnableQuickReply = (request.PostFormValue("EnableQuickReply") == "on")
config.MinifyHTML = (request.PostFormValue("MinifyHTML") == "on")
config.MinifyJS = (request.PostFormValue("MinifyJS") == "on")
config.DateTimeFormat = request.PostFormValue("DateTimeFormat")
AkismetAPIKey := request.PostFormValue("AkismetAPIKey")
@ -383,6 +384,20 @@ var manageFunctions = map[string]ManageFunction{
config.AkismetAPIKey = AkismetAPIKey
}
config.UseCaptcha = (request.PostFormValue("UseCaptcha") == "on")
CaptchaWidth, err := strconv.Atoi(request.PostFormValue("CaptchaWidth"))
if err != nil {
status += err.Error() + "<br />\n"
} else {
config.CaptchaWidth = CaptchaWidth
}
CaptchaHeight, err := strconv.Atoi(request.PostFormValue("CaptchaHeight"))
if err != nil {
status += err.Error() + "<br />\n"
} else {
config.CaptchaHeight = CaptchaHeight
}
config.EnableGeoIP = (request.PostFormValue("EnableGeoIP") == "on")
config.GeoIPDBlocation = request.PostFormValue("GeoIPDBlocation")

View file

@ -583,10 +583,9 @@ func makePost(writer http.ResponseWriter, request *http.Request) {
if isBanned(banStatus, boards[post.BoardID-1].Dir) {
var banpageBuffer bytes.Buffer
banpageBuffer.Write([]byte(""))
if err = banpageTmpl.Execute(&banpageBuffer, map[string]interface{}{
if err = minifyTemplate(banpageTmpl, map[string]interface{}{
"config": config, "ban": banStatus, "banBoards": boards[post.BoardID-1].Dir,
}); err != nil {
}, writer, "text/html"); err != nil {
writer.Write([]byte(handleError(1, err.Error())))
return
}
@ -748,14 +747,10 @@ func banHandler(writer http.ResponseWriter, request *http.Request) {
return
}
var banpageBuffer bytes.Buffer
banpageBuffer.Write([]byte(""))
if err = banpageTmpl.Execute(&banpageBuffer, map[string]interface{}{
if err = minifyTemplate(banpageTmpl, map[string]interface{}{
"config": config, "ban": banStatus, "banBoards": banStatus.Boards, "post": Post{},
}); err != nil {
}, writer, "text/html"); err != nil {
fmt.Fprintf(writer, handleError(1, err.Error())+"\n</body>\n</html>")
return
}
writer.Write(banpageBuffer.Bytes())
}

View file

@ -38,19 +38,26 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
}
//the file exists, or there is a folder here
var extension string
if results.IsDir() {
//check to see if one of the specified index pages exists
var found bool
for _, value := range config.FirstPage {
newPath := path.Join(filePath, value)
_, err := os.Stat(newPath)
if err == nil {
filePath = newPath
found = true
break
}
}
if !found {
serveNotFound(writer, request)
return
}
} else {
//the file exists, and is not a folder
extension := strings.ToLower(getFileExtension(request.URL.Path))
extension = strings.ToLower(getFileExtension(request.URL.Path))
switch extension {
case "png":
writer.Header().Add("Content-Type", "image/png")
@ -88,7 +95,15 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
fileBytes, _ = ioutil.ReadFile(filePath)
writer.Header().Add("Cache-Control", "max-age=86400")
writer.Write(fileBytes)
if extension == "html" {
minifyWriter(writer, fileBytes, "text/html")
} else if extension == "js" {
minifyWriter(writer, fileBytes, "text/javascript")
} else if extension == "json" {
minifyWriter(writer, fileBytes, "application/json")
} else {
writer.Write(fileBytes)
}
}
func serveNotFound(writer http.ResponseWriter, request *http.Request) {
@ -96,21 +111,21 @@ func serveNotFound(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(404)
errorPage, err := ioutil.ReadFile(config.DocumentRoot + "/error/404.html")
if err != nil {
_, _ = writer.Write([]byte("Requested page not found, and 404 error page not found"))
writer.Write([]byte("Requested page not found, and 404 error page not found"))
} else {
_, _ = writer.Write(errorPage)
minifyWriter(writer, errorPage, "text/html")
}
errorLog.Print("Error: 404 Not Found from " + getRealIP(request) + " @ " + request.URL.Path)
}
func serveErrorPage(writer http.ResponseWriter, err string) {
errorpageTmpl.Execute(writer, map[string]interface{}{
minifyTemplate(errorpageTmpl, map[string]interface{}{
"config": config,
"ErrorTitle": "Error :c",
// "ErrorImage": "/error/lol 404.gif",
"ErrorHeader": "Error",
"ErrorText": err,
})
}, writer, "text/html")
}
func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {

View file

@ -337,7 +337,9 @@ type GochanConfig struct {
ImagesOpenNewTab bool `description:"If checked, thumbnails will open the respective image/video in a new tab instead of expanding them." default:"unchecked"`
MakeURLsHyperlinked bool `description:"If checked, URLs in posts will be turned into a hyperlink. If unchecked, ExpandButton and NewTabOnOutlinks are ignored." default:"checked"`
NewTabOnOutlinks bool `description:"If checked, links to external sites will open in a new tab." default:"checked"`
EnableQuickReply bool `description:"If checked, an optional quick reply box is used. This may end up being removed." default:"checked"`
MinifyHTML bool `description:"If checked, gochan will minify html files when building" default:"checked"`
MinifyJS bool `description:"If checked, gochan will minify js and json files when building" default:"checked"`
DateTimeFormat string `description:"The format used for dates. See <a href=\"https://golang.org/pkg/time/#Time.Format\">here</a> for more info." default:"Mon, January 02, 2006 15:04 PM"`
AkismetAPIKey string `description:"The API key to be sent to Akismet for post spam checking. If the key is invalid, Akismet won't be used."`

View file

@ -1 +1 @@
2.10.0
2.11.0