mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-20 09:26:23 -07:00
Completely redo front.html to make it more mobile-friendly
Also add Photon theme
This commit is contained in:
parent
06ec16938c
commit
d558bcc0d0
22 changed files with 338 additions and 252 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,6 +7,6 @@ vagrant/.vagrant/
|
|||
vagrant/*.log
|
||||
html/boards.json
|
||||
html/index.html
|
||||
html/test/
|
||||
html/test*
|
||||
templates/override/
|
||||
**/*.bak
|
|
@ -36,7 +36,8 @@
|
|||
|
||||
"Styles": [
|
||||
{ "Name": "Pipes", "Filename": "pipes.css" },
|
||||
{ "Name": "Burichan", "Filename": "burichan.css" }
|
||||
{ "Name": "Burichan", "Filename": "burichan.css" },
|
||||
{ "Name": "Photon", "Filename": "photon.css" }
|
||||
],
|
||||
"DefaultStyle": "pipes.css",
|
||||
|
||||
|
@ -79,6 +80,7 @@
|
|||
"_comment": "set GeoIPDBlocation to cf to use Cloudflare's GeoIP",
|
||||
"GeoIPDBlocation": "/usr/share/GeoIP/GeoIP.dat",
|
||||
"MaxRecentPosts": 3,
|
||||
"RecentPostsWithNoFile": false,
|
||||
"Verbosity": 0,
|
||||
"EnableAppeals": true,
|
||||
"MaxLogDays": 14,
|
||||
|
|
|
@ -266,18 +266,28 @@ col#recent {
|
|||
}
|
||||
|
||||
div#recent-posts {
|
||||
margin-right: 8px;
|
||||
margin: auto;
|
||||
display: block;
|
||||
width: 90%;
|
||||
}
|
||||
div#recent-posts div.recent-post {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
div#recent-posts img {
|
||||
padding-right: 8px;
|
||||
}
|
||||
div#recent-posts div.section-body {
|
||||
padding-top: 8px;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
padding: 5px 0 3px;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
max-height: 320px;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#main {
|
||||
div#frontpage {
|
||||
overflow: hidden;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
a.permalink {
|
||||
|
|
59
html/css/photon.css
Normal file
59
html/css/photon.css
Normal file
|
@ -0,0 +1,59 @@
|
|||
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;
|
||||
}
|
|
@ -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.5</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v2.6</address>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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.5</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v2.6</address>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -197,63 +197,6 @@ function showMessage(msg) {
|
|||
});
|
||||
}
|
||||
|
||||
// organize front page into tabs
|
||||
function changeFrontPage(page_name) {
|
||||
var tabs = $jq(".tab");
|
||||
var pages = $jq(".page");
|
||||
var current_page = window.location.hash.replace("#","");
|
||||
pages.hide();
|
||||
if(current_page=="") {
|
||||
$jq(pages[0]).show();
|
||||
} else {
|
||||
for(var p = 0; p < pages.length; p++) {
|
||||
var page = $jq(pages[p]);
|
||||
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
|
||||
page.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
var child = $jq(tabs[i]).children(0)
|
||||
var tabname = child.text();
|
||||
if(tabname.toLowerCase() == current_page) {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
child.parent().attr({"id":"current-tab"});
|
||||
}
|
||||
}
|
||||
|
||||
tabs.find("a").click(function(event) {
|
||||
var current_page = this.href.substring(this.href.lastIndexOf("#")+1);
|
||||
|
||||
if(current_page == "") {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
$jq(tabs[0]).attr({"id":"current-tab"});
|
||||
} else {
|
||||
for(var i = 0; i < tabs.length; i++) {
|
||||
var child = $jq(tabs[i]).children(0)
|
||||
var tabname = child.text();
|
||||
if(tabname.toLowerCase() == current_page) {
|
||||
$jq("#current-tab").attr({"id":""});
|
||||
$jq(tabs[i]).attr({"id":"current-tab"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pages.hide()
|
||||
if(current_page=="") {
|
||||
$jq(pages[0]).show();
|
||||
} else {
|
||||
for(var p = 0; p < pages.length; p++) {
|
||||
var page = $jq(pages[p]);
|
||||
if(page.attr("id").replace("-page","").replace("page","") == current_page) {
|
||||
page.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// heavily based on 4chan's quote() function, with a few tweaks
|
||||
function quote(e) {
|
||||
|
@ -614,8 +557,7 @@ $jq(document).ready(function() {
|
|||
addStaffButtons();
|
||||
}
|
||||
|
||||
if(pageThread.board == "") changeFrontPage(window.location.hash);
|
||||
else {
|
||||
if(pageThread.board != "") {
|
||||
prepareThumbnails();
|
||||
if(getCookie("useqr") == "true") initQR(pageThread);
|
||||
}
|
||||
|
@ -637,22 +579,21 @@ $jq(document).ready(function() {
|
|||
var post_id = $jq(this).parent().parent().parent().attr("id");
|
||||
var is_op = $jq(this).parent().parent().parent().attr("class") == "thread";
|
||||
|
||||
if(post_id != undefined) {
|
||||
if($jq(this).parent().find("div.thread-ddown-menu").length == 0) {
|
||||
$jq("div.thread-ddown-menu").remove();
|
||||
if(post_id == undefined) return;
|
||||
if($jq(this).parent().find("div.thread-ddown-menu").length == 0) {
|
||||
$jq("div.thread-ddown-menu").remove();
|
||||
|
||||
menu_html = "<div class=\"thread-ddown-menu\" id=\""+post_id+"\">";
|
||||
if(!is_op) menu_html += "<ul><li><a href=\"javascript:hidePost("+post_id+");\" class=\"hide-post\">Show/Hide post</a></li>";
|
||||
menu_html +="<li><a href=\"javascript:deletePost("+post_id+");\" class=\"delete-post\">Delete post</a></li>" +
|
||||
"<li><a href=\"javascript:reportPost("+post_id+");\" class=\"report-post\">Report Post</a></li></ul>" +
|
||||
"</div>";
|
||||
menu_html = "<div class=\"thread-ddown-menu\" id=\""+post_id+"\">";
|
||||
if(!is_op) menu_html += "<ul><li><a href=\"javascript:hidePost("+post_id+");\" class=\"hide-post\">Show/Hide post</a></li>";
|
||||
menu_html +="<li><a href=\"javascript:deletePost("+post_id+");\" class=\"delete-post\">Delete post</a></li>" +
|
||||
"<li><a href=\"javascript:reportPost("+post_id+");\" class=\"report-post\">Report Post</a></li></ul>" +
|
||||
"</div>";
|
||||
|
||||
$jq(this).parent().append(menu_html);
|
||||
thread_menu_open = true;
|
||||
} else {
|
||||
$jq("div.thread-ddown-menu").remove();
|
||||
thread_menu_open = false;
|
||||
}
|
||||
$jq(this).parent().append(menu_html);
|
||||
thread_menu_open = true;
|
||||
} else {
|
||||
$jq("div.thread-ddown-menu").remove();
|
||||
thread_menu_open = false;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -46,20 +46,30 @@ col#recent {
|
|||
}
|
||||
|
||||
div#recent-posts {
|
||||
margin-right: 8px;
|
||||
display: inline-block;
|
||||
img {
|
||||
padding-right: 8px;
|
||||
}
|
||||
div.section-body {
|
||||
padding-top: 8px;
|
||||
margin:auto;
|
||||
display: block;
|
||||
width:90%;
|
||||
div.recent-post {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
padding: 5px 0 3px;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
max-height: 320px;
|
||||
margin-bottom: 10px;
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
|
||||
div#main {
|
||||
overflow: hidden
|
||||
div#frontpage {
|
||||
overflow: hidden;
|
||||
width: 80%;
|
||||
margin:auto;
|
||||
}
|
||||
|
||||
a.permalink {
|
||||
float: right;
|
||||
}
|
||||
}
|
34
sass/photon.scss
Normal file
34
sass/photon.scss
Normal file
|
@ -0,0 +1,34 @@
|
|||
@import 'photon/colors';
|
||||
@import 'photon/img';
|
||||
@import 'util';
|
||||
|
||||
body {
|
||||
background-color: $bgcol;
|
||||
font: 15px $font;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#topbar, div.dropdown-menu {
|
||||
background-color: #000;
|
||||
opacity: 0.7;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
div#topbar {
|
||||
@include box-shadow(0px 2px 2px 2px $shadowcol);
|
||||
}
|
||||
|
||||
div.dropdown-menu {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
header, div#top-pane, a {
|
||||
color: $linkcol;
|
||||
}
|
||||
|
||||
span#site-title, div#board-title {
|
||||
font-weight: 800;
|
||||
}
|
11
sass/photon/_colors.scss
Normal file
11
sass/photon/_colors.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
$bgcol: #eee;
|
||||
$replycol: #ddd;
|
||||
$replyborder: #ccc;
|
||||
$fontcol: #333;
|
||||
$linkcol: #f60;
|
||||
$subjectcol: #024;
|
||||
$shadowcol: #292929;
|
||||
$sectionbg: #FCFCFC;
|
||||
$sectionborder: #D7D7D7;
|
||||
|
||||
$font: 'Trebuchet MS',Trebuchet,sans-serif;
|
0
sass/photon/_front.scss
Normal file
0
sass/photon/_front.scss
Normal file
22
sass/photon/_img.scss
Normal file
22
sass/photon/_img.scss
Normal file
|
@ -0,0 +1,22 @@
|
|||
@import '../util';
|
||||
@import 'colors';
|
||||
|
||||
div.reply {
|
||||
background-color: $replycol;
|
||||
border: 1px solid $replyborder;
|
||||
@include border-radius(5px);
|
||||
}
|
||||
|
||||
span.subject {
|
||||
color: $subjectcol;
|
||||
}
|
||||
|
||||
div.section-title-block {
|
||||
background-color: $replyborder;
|
||||
}
|
||||
|
||||
div.section-block {
|
||||
@include border-radius(5px);
|
||||
background-color: $sectionbg;
|
||||
border: 1px solid $sectionborder;
|
||||
}
|
|
@ -13,11 +13,9 @@ import (
|
|||
)
|
||||
|
||||
// build front page using templates/front.html
|
||||
// TODO: provide alternative layouts (like 4chan, tinyboard, etc)
|
||||
func buildFrontPage() (html string) {
|
||||
initTemplates()
|
||||
var front_arr []interface{}
|
||||
var recent_posts_arr []interface{}
|
||||
var recentPostsArr []interface{}
|
||||
|
||||
os.Remove(path.Join(config.DocumentRoot, "index.html"))
|
||||
front_file, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
|
@ -26,54 +24,49 @@ func buildFrontPage() (html string) {
|
|||
return handleError(1, "Failed opening front page for writing: "+err.Error()) + "<br />\n"
|
||||
}
|
||||
|
||||
// get front pages
|
||||
rows, err := querySQL("SELECT * FROM `" + config.DBprefix + "frontpage`")
|
||||
defer closeRows(rows)
|
||||
if err != nil {
|
||||
return handleError(1, "Failed getting front page rows: "+err.Error())
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
frontpage := new(FrontTable)
|
||||
if err = rows.Scan(&frontpage.ID, &frontpage.Page, &frontpage.Order, &frontpage.Subject,
|
||||
&frontpage.Message, &frontpage.Timestamp, &frontpage.Poster, &frontpage.Email); err != nil {
|
||||
return handleError(1, err.Error())
|
||||
}
|
||||
front_arr = append(front_arr, frontpage)
|
||||
}
|
||||
|
||||
// get recent posts
|
||||
rows, err = querySQL("SELECT `"+config.DBprefix+"posts`.`id`, "+
|
||||
"`"+config.DBprefix+"posts`.`parentid`, "+
|
||||
"`"+config.DBprefix+"boards`.`dir` AS boardname, "+
|
||||
"`"+config.DBprefix+"posts`.`boardid` AS boardid, "+
|
||||
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` "+
|
||||
"FROM `"+config.DBprefix+"posts`, `"+config.DBprefix+"boards` "+
|
||||
"WHERE `"+config.DBprefix+"posts`.`deleted_timestamp` = ? "+
|
||||
"AND `boardid` = `"+config.DBprefix+"boards`.`id` "+
|
||||
"ORDER BY `timestamp` DESC LIMIT ?",
|
||||
nilTimestamp, config.MaxRecentPosts,
|
||||
)
|
||||
recentQueryStr := "SELECT `" + config.DBprefix + "posts`.`id`, " +
|
||||
"`" + config.DBprefix + "posts`.`parentid`, " +
|
||||
"`" + config.DBprefix + "boards`.`dir` AS boardname, " +
|
||||
"`" + config.DBprefix + "posts`.`boardid` AS boardid, " +
|
||||
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` " +
|
||||
"FROM `" + config.DBprefix + "posts`, `" + config.DBprefix + "boards` " +
|
||||
"WHERE `" + config.DBprefix + "posts`.`deleted_timestamp` = ? "
|
||||
if !config.RecentPostsWithNoFile {
|
||||
recentQueryStr += "AND `" + config.DBprefix + "posts`.`filename` != '' AND `" + config.DBprefix + "posts`.filename != 'deleted' "
|
||||
}
|
||||
recentQueryStr += "AND `boardid` = `" + config.DBprefix + "boards`.`id` " +
|
||||
"ORDER BY `timestamp` DESC LIMIT ?"
|
||||
|
||||
rows, err := querySQL(recentQueryStr, nilTimestamp, config.MaxRecentPosts)
|
||||
defer closeRows(rows)
|
||||
if err != nil {
|
||||
return handleError(1, err.Error())
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
recent_post := new(RecentPost)
|
||||
err = rows.Scan(&recent_post.PostID, &recent_post.ParentID, &recent_post.BoardName, &recent_post.BoardID, &recent_post.Name, &recent_post.Tripcode, &recent_post.Message, &recent_post.Filename, &recent_post.ThumbW, &recent_post.ThumbH)
|
||||
if err != nil {
|
||||
recentPost := new(RecentPost)
|
||||
if err = rows.Scan(
|
||||
&recentPost.PostID, &recentPost.ParentID, &recentPost.BoardName, &recentPost.BoardID,
|
||||
&recentPost.Name, &recentPost.Tripcode, &recentPost.Message, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH,
|
||||
); err != nil {
|
||||
return handleError(1, "Failed getting list of recent posts for front page: "+err.Error())
|
||||
}
|
||||
recent_posts_arr = append(recent_posts_arr, recent_post)
|
||||
recentPostsArr = append(recentPostsArr, recentPost)
|
||||
}
|
||||
|
||||
for i := range allBoards {
|
||||
board := allBoards[i].(BoardsTable)
|
||||
if board.Section == 0 {
|
||||
board.Section = 1
|
||||
}
|
||||
}
|
||||
|
||||
if err = front_page_tmpl.Execute(front_file, map[string]interface{}{
|
||||
"config": config,
|
||||
"fronts": front_arr,
|
||||
"boards": allBoards,
|
||||
"sections": allSections,
|
||||
"recent_posts": recent_posts_arr,
|
||||
"boards": allBoards,
|
||||
"recent_posts": recentPostsArr,
|
||||
}); err != nil {
|
||||
return handleError(1, "Failed executing front page template: "+err.Error())
|
||||
}
|
||||
|
|
|
@ -973,6 +973,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
initTemplates()
|
||||
resetBoardSectionArrays()
|
||||
return buildFrontPage() + "<hr />\n" +
|
||||
buildBoardListJSON() + "<hr />\n" +
|
||||
buildBoards(true, 0) + "<hr />\n"
|
||||
|
|
|
@ -58,6 +58,7 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
|
|||
writer.Header().Add("Content-Type", "image/gif")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
writer.Header().Add("Content-Type", "image/jpeg")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case "css":
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
x_html "golang.org/x/net/html"
|
||||
)
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
|
@ -112,6 +114,21 @@ var funcMap = template.FuncMap{
|
|||
}
|
||||
return msg
|
||||
},
|
||||
"stripHTML": func(htmlStr string) string {
|
||||
dom := x_html.NewTokenizer(strings.NewReader(htmlStr))
|
||||
for tokenType := dom.Next(); tokenType != x_html.ErrorToken; {
|
||||
if tokenType != x_html.TextToken {
|
||||
tokenType = dom.Next()
|
||||
continue
|
||||
}
|
||||
txtContent := strings.TrimSpace(x_html.UnescapeString(string(dom.Text())))
|
||||
if len(txtContent) > 0 {
|
||||
return x_html.EscapeString(txtContent)
|
||||
}
|
||||
tokenType = dom.Next()
|
||||
}
|
||||
return ""
|
||||
},
|
||||
"truncateString": func(msg string, limit int, ellipsis bool) string {
|
||||
if len(msg) > limit {
|
||||
if ellipsis {
|
||||
|
@ -138,6 +155,27 @@ var funcMap = template.FuncMap{
|
|||
}
|
||||
return
|
||||
},
|
||||
"getPostURL": func(post_i interface{}, typeOf string, withDomain bool) (postURL string) {
|
||||
if withDomain {
|
||||
postURL = config.SiteDomain
|
||||
}
|
||||
postURL += config.SiteWebfolder
|
||||
|
||||
if typeOf == "recent" {
|
||||
post, ok := post_i.(*RecentPost)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
postURL = post.GetURL(withDomain)
|
||||
} else {
|
||||
post, ok := post_i.(*PostTable)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
postURL = post.GetURL(withDomain)
|
||||
}
|
||||
return
|
||||
},
|
||||
"getThreadThumbnail": func(img string) string {
|
||||
return getThumbnailPath("thread", img)
|
||||
},
|
||||
|
@ -341,7 +379,7 @@ func initTemplates() error {
|
|||
return templateError("manage_header.html", err)
|
||||
}
|
||||
|
||||
front_page_tmpl, err = loadTemplate("front.html", "global_footer.html")
|
||||
front_page_tmpl, err = loadTemplate("front.html", "front_intro.html", "img_header.html", "global_footer.html")
|
||||
if err != nil {
|
||||
return templateError("front.html", err)
|
||||
}
|
||||
|
|
48
src/types.go
48
src/types.go
|
@ -7,6 +7,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/frustra/bbcode"
|
||||
|
@ -37,6 +38,21 @@ type RecentPost struct {
|
|||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (p *RecentPost) GetURL(includeDomain bool) string {
|
||||
postURL := ""
|
||||
if includeDomain {
|
||||
postURL += config.SiteDomain
|
||||
}
|
||||
idStr := strconv.Itoa(p.PostID)
|
||||
postURL += config.SiteWebfolder + p.BoardName + "/res/"
|
||||
if p.ParentID == 0 {
|
||||
postURL += idStr + ".html#" + idStr
|
||||
} else {
|
||||
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
|
||||
}
|
||||
return postURL
|
||||
}
|
||||
|
||||
type Thread struct {
|
||||
OP PostTable
|
||||
NumReplies int
|
||||
|
@ -234,6 +250,27 @@ type PostTable struct {
|
|||
Sillytag bool
|
||||
}
|
||||
|
||||
func (p *PostTable) GetURL(includeDomain bool) string {
|
||||
postURL := ""
|
||||
if includeDomain {
|
||||
postURL += config.SiteDomain
|
||||
}
|
||||
|
||||
board, err := getBoardFromID(p.BoardID)
|
||||
if err != nil {
|
||||
return postURL
|
||||
}
|
||||
|
||||
idStr := strconv.Itoa(p.ID)
|
||||
postURL += config.SiteWebfolder + board.Dir + "/res/"
|
||||
if p.ParentID == 0 {
|
||||
postURL += idStr + ".html#" + idStr
|
||||
} else {
|
||||
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
|
||||
}
|
||||
return postURL
|
||||
}
|
||||
|
||||
// Sanitize escapes HTML strings in a post. This should be run immediately before
|
||||
// the post is inserted into the database
|
||||
func (p *PostTable) Sanitize() {
|
||||
|
@ -421,11 +458,12 @@ type GochanConfig struct {
|
|||
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"`
|
||||
|
||||
DateTimeFormat string `description:"The format used for dates. See <a href=\"https://golang.org/pkg/time/#Time.Format\">here</a> for more info."`
|
||||
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."`
|
||||
EnableGeoIP bool `description:"If checked, this enables the usage of GeoIP for posts." default:"checked"`
|
||||
GeoIPDBlocation string `description:"Specifies the location of the GeoIP database file. If you're using CloudFlare, you can set it to cf to rely on CloudFlare for GeoIP information." default:"/usr/share/GeoIP/GeoIP.dat"`
|
||||
MaxRecentPosts int `description:"The maximum number of posts to show on the Recent Posts list on the front page." default:"3"`
|
||||
DateTimeFormat string `description:"The format used for dates. See <a href=\"https://golang.org/pkg/time/#Time.Format\">here</a> for more info."`
|
||||
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."`
|
||||
EnableGeoIP bool `description:"If checked, this enables the usage of GeoIP for posts." default:"checked"`
|
||||
GeoIPDBlocation string `description:"Specifies the location of the GeoIP database file. If you're using CloudFlare, you can set it to cf to rely on CloudFlare for GeoIP information." default:"/usr/share/GeoIP/GeoIP.dat"`
|
||||
MaxRecentPosts int `description:"The maximum number of posts to show on the Recent Posts list on the front page." default:"3"`
|
||||
RecentPostsWithNoFile bool `description:"If checked, recent posts with no image/upload are shown on the front page (as well as those with images" default:"unchecked"`
|
||||
// Verbosity = 0 for no debugging info. Critical errors and general output only
|
||||
// Verbosity = 1 for non-critical warnings and important info
|
||||
// Verbosity = 2 for all debugging/benchmarks/warnings
|
||||
|
|
|
@ -1,108 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.config.SiteName}}</title>
|
||||
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var styles = [{{range $ii, $style := .config.Styles}}{{if gt $ii 0}}, {{end}}{Name: "{{$style.Name}}", Filename: "{{$style.Filename}}"}{{end}}];
|
||||
var defaultStyle = "{{.config.DefaultStyle}}";
|
||||
var webroot = "{{.config.SiteWebfolder}}"
|
||||
</script>
|
||||
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/gochan.js"></script>
|
||||
<script type="text/javascript" src="{{.config.SiteWebfolder}}javascript/manage.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="{{.config.SiteWebfolder}}css/global.css" />
|
||||
<link id="theme" rel="stylesheet" href="{{.config.SiteWebfolder}}css/{{.config.DefaultStyle}}" />
|
||||
<link rel="shortcut icon" href="{{.config.SiteWebfolder}}favicon.png">
|
||||
</head>
|
||||
<body>
|
||||
<div id="topbar">{{range $i, $board := .boards}}
|
||||
<a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" class="topbar-item">/{{$board.Dir}}/</a>{{end}}
|
||||
</div>
|
||||
{{template "img_header.html" .}}
|
||||
<div id="top-pane">
|
||||
<span id="site-title">{{.config.SiteName}}</span><br />
|
||||
<span id="site-slogan">{{.config.SiteSlogan}}</span>
|
||||
</div><br />
|
||||
<div id="frontpage">
|
||||
<div class="section-block" style="margin: 16px 64px 16px 64px;">
|
||||
<div class="section-body">
|
||||
{{template "front_intro.html" .}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-block">
|
||||
<div class="section-title-block"><b>Boards</b></div>
|
||||
<div class="section-body">
|
||||
{{range $_, $section := .sections}}{{if not $section.Hidden}}<ul style="float:left; list-style: none">
|
||||
<li style="text-align: center; font-weight: bold"><b><u>{{$section.Name}}</u></b></li>
|
||||
{{range $_, $board := $.boards}}{{if and (eq $board.Section $section.ID) (ne $board.Dir $.config.Modboard)}}
|
||||
<li><a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" title="{{$board.Description}}">/{{$board.Dir}}/</a> — {{$board.Title}}</li>
|
||||
{{end}}{{end}}
|
||||
</ul>{{end}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if gt .config.MaxRecentPosts 0}}
|
||||
<div class="section-block">
|
||||
<div class="section-title-block"><b>Recent Posts</b></div>
|
||||
<div class="section-body">
|
||||
<div id="recent-posts">
|
||||
{{range $i, $post := $.recent_posts}}{{$postURL := getPostURL $post "recent" false}}
|
||||
<div class="recent-post">
|
||||
{{if and (ne $post.Filename "deleted") (ne $post.Filename "")}}<a href="{{$postURL}}" class="front-reply" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a><br />
|
||||
{{else}}<div class="file-deleted-box" style="text-align:center; float:none;"><a href="{{$.postURL}}" class="front-reply" target="_blank">No file</a></div>{{end}}<br />
|
||||
<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/">/{{$post.BoardName}}/</a>
|
||||
<hr />
|
||||
{{truncateMessage (stripHTML $post.Message) 40 4}}</div>{{end}}</div>
|
||||
</div>{{end}}</div>
|
||||
</div>
|
||||
<div id="main">
|
||||
<table style="width:100%" cellspacing="10">
|
||||
<colgroup>
|
||||
<col id="sections" />
|
||||
<col id="recent" />
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<ul id="tab-bar">
|
||||
<li id="current-tab" class="tab">
|
||||
<a href="#">News</a>
|
||||
</li>
|
||||
<li class="tab">
|
||||
<a href="#boards">Boards</a>
|
||||
</li>
|
||||
<li class="tab">
|
||||
<a href="#rules">Rules</a>
|
||||
</li>
|
||||
<li class="tab">
|
||||
<a href="#faq">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="first-page" class="page">{{range $ii, $page := .page_arr}}{{if eq $page.Page 0}}
|
||||
<div class="section-block">
|
||||
<div class="section-title-block" id="first-page0">
|
||||
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
{{$page.Message}}
|
||||
</div>
|
||||
</div>{{end}}{{end}}
|
||||
</div>
|
||||
<div id="boards-page" class="page">
|
||||
<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<b>Boards</b>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<ul>{{range $_, $board := .boards}}{{if eq $board.Dir $.config.Modboard}}{{else}}
|
||||
<li><b>/{{$board.Dir}}/</b> {{$board.Description}}</li>{{end}}{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rules-page" class="page">{{range $ii, $page := .page_arr}}{{if eq $page.Page 1}}
|
||||
<div class="section-block">
|
||||
<div class="section-title-block" id="first-page0">
|
||||
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
{{$page.Message}}
|
||||
</div>
|
||||
</div>{{end}}{{end}}
|
||||
</div>
|
||||
<div id="faq-page" class="page">{{range $ii, $page := .page_arr.Data}}{{if eq $page.Page 2}}
|
||||
<div class="section-block">
|
||||
<div class="section-title-block" id="first-page0">
|
||||
<b>{{$page.Subject}}</b> by <a href="mailto:{{$page.Email}}" >{{$page.Poster}}</a><a href="{{.config.SiteWebfolder}}#first-page{{$ii}}" class="permalink">#</a>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
{{$page.Message}}
|
||||
</div>
|
||||
</div>{{end}}{{end}}
|
||||
</div>
|
||||
</td>
|
||||
{{if gt .config.MaxRecentPosts 0}}<td>
|
||||
<div id="recent-posts-header" class="section-title-block"><b>Recent Posts</b></div>
|
||||
{{range $i, $post := $.recent_posts}}<div class="section-block">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><a href="{{$post.BoardName}}/res/{{if eq $post.ParentID 0}}{{intToString $post.PostID}}.html{{else}}{{intToString $post.ParentID}}.html#{{intToString $post.PostID}}{{end}}">/{{$post.BoardName}}/</a></span> - {{$appended := stringAppend $post.Name $post.Tripcode}}{{if eq $appended ""}}<b>Anonymous</b>{{else}}<b>{{$post.Name}}</b>{{if ne $post.Tripcode ""}}!{{$post.Tripcode}}{{end}}{{end}}
|
||||
</div>
|
||||
<div class="section-body">
|
||||
{{if ne $post.Filename ""}}<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/src/{{$post.Filename}}" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a>{{end}}
|
||||
{{truncateMessage $post.Message 225 12}}
|
||||
</div>
|
||||
</div>{{end}}{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{{template "global_footer.html" .}}
|
||||
{{template "global_footer.html" .}}
|
||||
|
|
1
templates/front_intro.html
Normal file
1
templates/front_intro.html
Normal file
|
@ -0,0 +1 @@
|
|||
Welcome to Gochan!
|
|
@ -3,13 +3,10 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{{with $.op.Subject}}
|
||||
{{if ne $.op.Subject ""}}
|
||||
<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
|
||||
{{else if ne $.op.MessageHTML ""}}
|
||||
<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
|
||||
{{end}}
|
||||
{{else}}<title>/{{.board.Dir}}/ - {{.board.Title}}</title>{{end}}
|
||||
{{with $.op.Subject}}{{if ne $.op.Subject ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
|
||||
{{else if ne $.op.MessageHTML ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
|
||||
{{end}}{{else}}{{with $.recent_posts}}<title>{{$.config.SiteName}}</title>
|
||||
{{else}}<title>/{{.board.Dir}}/ - {{.board.Title}}</title>{{end}}{{end}}
|
||||
<script type="text/javascript" src="{{$.config.SiteWebfolder}}javascript/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var styles = [{{range $ii, $style := .config.Styles}}{{if gt $ii 0}}, {{end}}{Name: "{{$style.Name}}", Filename: "{{$style.Filename}}"}{{end}}];
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
<table id="board-options">
|
||||
<tr><th class="option-column">Option</th><th class="value-column">Value</th></tr>
|
||||
<tr><td>Directory</td><td><input type="text" name="dir" value="" /></td></tr>
|
||||
<tr><td>Section</td><td><select name="section" selected="0">
|
||||
<option value="none">Select section...</option>{{range $_, $section := .section_arr}}
|
||||
<tr><td>Section</td><td><select name="section" selected="0">{{range $_, $section := .section_arr}}
|
||||
<option value="{{$section.ID}}">{{$section.Name}}</option>{{end}}
|
||||
</select></td></tr>
|
||||
<tr><td>Order</td><td><input type="text" name="order" value="0" /></td></tr>
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
2.5.0
|
||||
2.6.0
|
Loading…
Add table
Add a link
Reference in a new issue