summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--data/docs/912
-rw-r--r--data/global.pl4
-rw-r--r--data/skingen/style.css (renamed from static/f/style.css)181
-rw-r--r--lib/ChangeLog16
-rw-r--r--lib/VNDB/DB/Releases.pm3
-rw-r--r--lib/VNDB/DB/Users.pm2
-rw-r--r--lib/VNDB/Func.pm35
-rw-r--r--lib/VNDB/Handler/Discussions.pm2
-rw-r--r--lib/VNDB/Handler/ULists.pm3
-rw-r--r--lib/VNDB/Handler/Users.pm7
-rw-r--r--lib/VNDB/Handler/VNPage.pm6
-rw-r--r--lib/VNDB/Util/FormHTML.pm3
-rw-r--r--lib/VNDB/Util/LayoutHTML.pm4
-rw-r--r--static/f/boxbg.pngbin83 -> 0 bytes
-rw-r--r--static/f/forms.js26
-rw-r--r--static/f/script.js83
-rw-r--r--static/s/angel/bg.jpg (renamed from static/f/bg.jpg)bin36419 -> 36419 bytes
-rw-r--r--static/s/angel/bgright.jpg (renamed from static/f/bgright.jpg)bin4366 -> 4366 bytes
-rw-r--r--static/s/angel/conf39
-rw-r--r--static/s/grey/bg.jpgbin0 -> 33434 bytes
-rw-r--r--static/s/grey/bgright.jpgbin0 -> 3062 bytes
-rw-r--r--static/s/grey/conf39
-rw-r--r--static/s/lb/bg.jpgbin0 -> 37246 bytes
-rw-r--r--static/s/lb/conf39
-rw-r--r--util/dump.sql3
-rwxr-xr-xutil/skingen.pl93
-rw-r--r--util/updates/update_2.1.sql4
-rwxr-xr-xutil/vndb.pl30
29 files changed, 521 insertions, 115 deletions
diff --git a/.gitignore b/.gitignore
index 4ce94ab6..59f221ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
/data/config.pl
/data/log/
+/static/s/*/style.css
+/static/s/*/boxbg.png
/static/cv/
/static/rg/
/static/sf/
diff --git a/data/docs/9 b/data/docs/9
index 6029ef1b..fd6da75e 100644
--- a/data/docs/9
+++ b/data/docs/9
@@ -1,11 +1,13 @@
:TITLE:Discussion board
-:INC:notfinished
:INC:index
:SUB:Introduction
<p>
- <i>todo...</i>
+ VNDB has a nicely integrated discussion board which can be used for, well,
+ discussions. As we're not using any popular and freely available forum software
+ and have instead written something by ourselves, this discussion board has a
+ few slight differences with the popular boards you're used to.
</p>
@@ -53,6 +55,12 @@
</dd><dt>[spoiler]</dt><dd>
The [spoiler]-tag should be used to hide information that could spoil the enjoyment of playing the
visual novel for people who haven't done so yet.
+ </dd><dt>[quote]</dt><dd>
+ When quoting other people, put the quoted message inside a [quote] .. [/quote] block. Please
+ note that the popular [quote=source]-syntax doesn't work on VNDB. (yet)
+ </dd><dt>[raw]</dt><dd>
+ Show off your formatting code skills by putting anything you don't want to have formatted in a [raw]
+ tag. Any of the formatting codes mentioned above are ignored within a [raw] .. [/raw] block.
</dd>
</dl>
<p>
diff --git a/data/global.pl b/data/global.pl
index bb4bfe4a..2c8a7a56 100644
--- a/data/global.pl
+++ b/data/global.pl
@@ -13,11 +13,12 @@ our %O = (
# VNDB-specific options (object_data)
-our %S = (
+our %S = (%S,
version => `cd $VNDB::ROOT; git describe` =~ /^(.+)$/ && $1,
url => 'http://vndb.org',
url_static => 'http://s.vndb.org',
site_title => 'Yet another VNDB clone',
+ skin_default => 'test',
cookie_domain => '.vndb.org',
cookie_key => 'any-private-string-here',
sharedmem_key => 'VNDB',
@@ -203,6 +204,7 @@ our %S = (
'low',
'blacklist',
],
+ # note: keep these synchronised in script.js
vn_rstat => [
'Unknown',
'Pending',
diff --git a/static/f/style.css b/data/skingen/style.css
index 92062a76..ecbba8a7 100644
--- a/static/f/style.css
+++ b/data/skingen/style.css
@@ -9,15 +9,15 @@ body, td {
font: 8pt "Tahoma";
}
body {
- background: #000 url(/f/bg.jpg) no-repeat;
- color: #ddd;
+ $_bodybg$;
+ color: $maintext$
}
a {
- color: #fff;
+ color: $maintext$;
text-decoration: none;
}
a:hover {
- border-bottom: 1px dotted #fff;
+ border-bottom: 1px dotted $maintext$;
}
table {
border-collapse: collapse;
@@ -27,7 +27,7 @@ table td {
padding: 3px;
}
table tr.odd {
- background: url(/f/boxbg.png) repeat;
+ background: url($_boxbg$) repeat;
}
img {
border: none;
@@ -37,9 +37,7 @@ img {
position: absolute;
top: 0px;
right: 0px;
- width: 433px;
- height: 140px;
- background: url(/f/bgright.jpg) no-repeat;
+ $_bgright$
}
#header {
@@ -51,7 +49,7 @@ img {
font-family: "Futura", "Century New Gothic", "Arial", Serif;
font-size: 19pt;
font-style: italic;
- color: #135;
+ color: $maintitle$;
border: none!important;
}
#header h1.debug a {
@@ -61,10 +59,10 @@ img {
#footer {
margin: 15px auto 0 auto;
text-align: center;
- color: #135;
+ color: $footer$;
}
#footer a {
- color: #135;
+ color: $footer$;
text-decoration: underline;
}
@@ -73,7 +71,7 @@ ul, ol {
}
p.locked {
float: right;
- color: #e44;
+ color: $standout$;
font-style: italic;
margin: 0!important;
}
@@ -84,14 +82,27 @@ p.locked {
p.description {
margin: 10px 100px!important;
}
-b.done { font-weight: normal; color: #0c0 }
-b.todo { font-weight: normal; color: #c00 }
+b.done { font-weight: normal; color: $statok$ }
+b.todo { font-weight: normal; color: $statnok$ }
.clearfloat {
clear: both;
height: 0;
}
+b.spoiler, b.spoiler a {
+ color: #000;
+ background-color: #000;
+ font-weight: normal;
+}
+b.spoiler_shown { font-weight: normal }
+div.quote {
+ padding: 1px 5px;
+ margin: 0px 10px;
+ color: $grayedout$;
+ border-left: 1px dotted $border$;
+}
+
@@ -105,9 +116,9 @@ legend {
display: none;
}
input.text, input.submit, select, textarea {
- background-color: #135;
- color: #ccc;
- border: 1px solid #36A;
+ background-color: $secbg$;
+ color: $maintext$;
+ border: 1px solid $secborder$;
font: 9pt "Tahoma";
margin: 1px;
}
@@ -116,7 +127,7 @@ optgroup option {
font-style: normal;
}
input.submit {
- background-color: #123;
+ background: url($_boxbg$) repeat;
padding: 1px;
}
input.text, select {
@@ -178,23 +189,23 @@ td.field label {
font-size: 11pt;
}
#maincontent h1 {
- color: #258;
+ color: $boxtitle$;
font-size: 14pt;
margin: -5px 0 15px 0;
}
#maincontent h2.alttitle {
- color: #fff;
+ color: $alttitle$;
margin: -17px 0 15px 15px;
font-weight: normal;
}
#maincontent div.mainbox {
- border: 1px solid #258;
+ border: 1px solid $border$;
margin: 21px 0 -10px 0;
padding: 5px;
- background: url(/f/boxbg.png) repeat;
+ background: url($_boxbg$) repeat;
}
#maincontent div.mainbox a {
- color: #7bd;
+ color: $link$;
}
#maincontent p {
margin: 3px 20px;
@@ -212,7 +223,7 @@ p.center {
}
b.future {
font-weight: normal;
- color: #e44;
+ color: $standout$;
}
@@ -228,20 +239,20 @@ b.future {
}
#menulist div.menubox {
margin: 0 0 10px 0;
- border: 1px solid #258;
- background: url(boxbg.png) repeat;
+ border: 1px solid $border$;
+ background: url($_boxbg$) repeat;
}
#menulist div.menubox div {
padding: 2px 7px;
}
#menulist h2 {
- border-bottom: 1px solid #258;
- background-color: #234;
+ border-bottom: 1px solid $border$;
+ background: url($_boxbg$) repeat;
padding: 1px 3px;
}
#menulist h2, #menulist h2 a {
font-size: 8pt;
- color: #fff;
+ color: $maintext$;
}
#menulist dt {
display: block;
@@ -295,18 +306,18 @@ b.future {
float: right;
display: block;
height: 14px;
- border: 1px solid #258;
+ border: 1px solid $border$;
border-bottom: none;
padding: 1px 7px 5px 7px;
margin: 0 0 0 10px;
- background-color: #012;
+ background-color: $tabbg$;
}
#maincontent ul.maintabs.notfirst li a {
margin-top: 20px;
}
#maincontent ul.maintabs.bottom li a {
margin-top: 10px;
- border-bottom: 1px solid #258;
+ border-bottom: 1px solid $border$;
border-top: none;
padding: 4px 7px 2px 7px;
}
@@ -317,7 +328,7 @@ b.future {
}
#maincontent ul.maintabs li.tabselected a,
#maincontent ul.maintabs li a:hover {
- background-color: #0c1925;
+ background-color: $_blendbg$;
padding-bottom: 6px;
}
#maincontent ul.maintabs.bottom li.tabselected a,
@@ -380,13 +391,14 @@ p.browseopts {
text-align: center;
padding: 2px;
}
-p.browseopts a {
+#maincontent p.browseopts a {
padding: 1px 3px;
- color: #fff!important;
- border: 1px solid #258;
+ color: $maintext$;
+ border: 1px solid $border$;
margin: 0 2px;
}
-p.browseopts a.optselected, p.browseopts a:hover {
+#maincontent p.browseopts a.optselected,
+#maincontent p.browseopts a:hover {
border: 0;
padding: 2px 4px;
}
@@ -401,7 +413,7 @@ div.mainbox.browse table td.tc1 {
}
table thead td {
font-weight: bold;
- background-color: #135;
+ background-color: $secbg$;
}
form.search {
display: block;
@@ -428,7 +440,7 @@ div.mainbox.history td.tc1_2 {
div.mainbox.history td.tc2 { width: 65px; }
div.mainbox.history td.tc3 { width: 90px }
div.mainbox.history td.editsum {
- color: #258;
+ color: $grayedout$;
padding-top: 0;
text-align: right;
}
@@ -448,12 +460,12 @@ div.thread table {
width: 100%;
}
div.thread td {
- border-bottom: 1px solid #258;
+ border-bottom: 1px solid $border$;
}
div.thread td.tc1 {
width: 150px;
padding: 5px 10px;
- border-right: 1px solid #258;
+ border-right: 1px solid $border$;
}
div.thread td.tc2 {
padding: 10px 20px 10px 10px;
@@ -463,17 +475,17 @@ div.thread tr.deleted td {
}
div.thread i.deleted {
font-style: normal;
- color: #258;
+ color: $grayedout$;
}
div.thread i.lastmod {
float: right;
font-size: 7pt;
- color: #258;
+ color: $grayedout$;
margin: 0 -10px -5px 0;
}
div.thread i.edit {
float: right;
- color: #258;
+ color: $grayedout$;
font-style: normal;
margin: -10px -10px 0 0;
}
@@ -490,7 +502,7 @@ div.mainbox.discussions td.tags {
padding-left: 60px;
}
div.mainbox.discussions td.tags a {
- color: #258!important
+ color: $grayedout$!important
}
div.discussions td.tc2 { width: 50px; }
div.discussions td.tc3 { width: 90px; }
@@ -499,7 +511,7 @@ div.discussions td.tc4 { width: 170px; }
font-family: "Futura", "Century New Gothic", "Arial", Serif;
font-weight: bold;
font-style: italic;
- color: #258;
+ color: $grayedout$;
font-size: 13pt;
margin: 20px 0 -20px 0;
}
@@ -549,9 +561,10 @@ div.vndetails table dd {
margin-left: 90px;
}
.catlvl_0, .catlvl_1, .catlvl_2, .catlvl_3 { font-style: normal; }
-.catlvl_1 { color: #444!important }
-.catlvl_2 { color: #777 }
-.catlvl_3 { color: #fff }
+.catlvl_1 { color: $catlevel1$!important }
+.catlvl_2 { color: $catlevel2$!important }
+.catlvl_3 { color: $catlevel3$!important }
+
div.vndetails td.relations dt {
float: none;
font-style: normal;
@@ -570,7 +583,7 @@ div.vndescription {
}
div.vndescription h2 {
margin: 0 30px!important;
- border-top: 1px solid #258;
+ border-top: 1px solid $border$;
padding: 3px 70px;
font-weight: bold!important;
}
@@ -582,7 +595,7 @@ div.vndescription p {
width: 100%;
}
.releases tr.lang td, #screenshots tr.rel td {
- background: url(/f/boxbg.png) repeat;
+ background: url($_boxbg$) repeat;
font-weight: bold;
}
.releases td.tc1 {
@@ -599,10 +612,10 @@ div.vndescription p {
width: 90px;
}
.releases td.tc5 {
- text-align: right;
+ width: 140px;
}
.releases td.tc5 a {
- color: #ddd!important;
+ color: $maintext$!important;
border: 0;
}
.releases td.tc6 {
@@ -625,8 +638,8 @@ a.addnew {
}
#screenshots td.scr div i { font-size: 7pt; }
#screenshots td.scr img { border: 3px solid transparent; }
-#screenshots td.scr div.nsfw img { border: 3px solid #C00; }
-#screenshots td.scr a:hover img { border: 3px solid #258; }
+#screenshots td.scr div.nsfw img { border: 3px solid $statnok$; }
+#screenshots td.scr a:hover img { border: 3px solid $border$; }
#screenshots td.scr a { border: none; }
#screenshots div.hidden { display: none }
#screenshots #nsfwshown { font-style: normal }
@@ -635,6 +648,14 @@ a.addnew {
margin: 0;
}
+#vldd { position: absolute; left: -500px; border: 1px solid $border$; background-color: $secbg$; width: 180px; }
+#vldd ul { float: left; width: 90px; list-style-type: none; margin: 0; padding: 0 }
+#vldd li b { display: block; font-weight: normal; padding-left: 5px; }
+#vldd li i { display: block; font-style: normal; padding-left: 10px; }
+#vldd li a { display: block; padding-left: 10px; color: $link$; border: 0; }
+#vldd li a:hover { background: url($_boxbg$) repeat }
+#vldd ul.full { width: 180px; text-align: center; }
+#vldd ul.full li a { padding: 0 }
@@ -645,7 +666,7 @@ a.addnew {
.votegraph { float: left; margin-right: 20px }
.votegraph td { padding: 0 2px; }
.votegraph td.number { text-align: right }
-.votegraph td div { float: left; height: 14px; background-color: #258; margin-right: 2px; }
+.votegraph td div { float: left; height: 14px; background-color: $border$; margin-right: 2px; }
.votestats thead td { background: transparent; text-align: center; padding: 2px; }
.votestats tfoot td { text-align: right }
@@ -680,6 +701,9 @@ a.addnew {
list-style-type: none;
padding: 0;
}
+#maincontent #jt_box_categories li li a {
+ color: $grayedout$;
+}
a.help {
vertical-align: super;
font-size: 6pt;
@@ -688,7 +712,6 @@ a.help {
padding-left: 1px;
}
#maincontent #jt_box_categories li li a {
- color: #ccc;
text-decoration: none;
display: block;
width: 160px;
@@ -706,15 +729,16 @@ a.help {
#jt_box_relations td.tc2 select { width: 130px; }
#ds_box {
- border: 1px solid #258;
+ border: 1px solid $border$;
border-top: none;
- background-color: #13273a;
+ background-color: $secbg$;
+ cursor: pointer;
}
#ds_box b {
padding: 2px 0 0 10px;
}
#ds_box tr.selected {
- background: url(/f/boxbg.png) repeat;
+ background: url($_boxbg$) repeat;
}
#ds_box table {
width: 100%;
@@ -754,7 +778,7 @@ a.help {
width: 90%;
padding: 0 30px 5px 30px;
margin: 0 auto;
- border-top: 1px solid #258;
+ border-top: 1px solid $border$;
}
#advoptions.hidden { display: none }
#advoptions h2 {
@@ -797,8 +821,8 @@ ul#catselect li li {
list-style-type: none;
background: url(/f/select.png) no-repeat;
}
-ul#catselect li li.inc { background-position: 0px -16px; color: #0c0; }
-ul#catselect li li.exc { background-position: 0px -33px; color: #c00; }
+ul#catselect li li.inc { background-position: 0px -16px; color: $statok$; }
+ul#catselect li li.exc { background-position: 0px -33px; color: $statnok$; }
@@ -866,7 +890,7 @@ ul#catselect li li.exc { background-position: 0px -33px; color: #c00; }
#jt_box_visual_novels div, #jt_box_producers div { padding-left: 20px }
#jt_box_visual_novels input, #jt_box_producers input { margin-right: 10px; width: 300px }
#jt_box_visual_novels span, #jt_box_producers span { clear: left; display: block; padding: 2px; }
-#jt_box_visual_novels span.odd, #jt_box_producers span.odd { background: url(/f/boxbg.png) repeat; }
+#jt_box_visual_novels span.odd, #jt_box_producers span.odd { background: url($_boxbg$) repeat; }
#jt_box_visual_novels i, #jt_box_producers i { font-style: normal; display: block; float: left; width: 310px }
#jt_box_visual_novels b, #jt_box_producers b { font-weight: normal; }
@@ -879,11 +903,11 @@ ul#catselect li li.exc { background-position: 0px -33px; color: #c00; }
.docs h3 { margin-top: 25px; }
.docs dd { padding-bottom: 5px; margin-left: 120px; }
.docs dt { float: left }
-.docs ul.index { display: block; float: right; width: 150px; padding: 2px; margin: 0 0 10px 5px; background: url(/f/boxbg.png) repeat; border: 1px solid #258; }
+.docs ul.index { display: block; float: right; width: 150px; padding: 2px; margin: 0 0 10px 5px; background: url($_boxbg$) repeat; border: 1px solid $border$; }
.docs ul.index li { list-style-type: none; }
.docs ul.index li a { margin: 0 0 0 10px; }
.docs .retired { text-decoration: line-through; }
-.docs dt b { color: #258; font-weight: normal; font-style: normal; font-size: 12px; }
+.docs dt b { color: $grayedout$; font-weight: normal; font-style: normal; font-size: 12px; }
@@ -930,12 +954,12 @@ ul#catselect li li.exc { background-position: 0px -33px; color: #c00; }
div.warning, div.notice {
margin: 5px 10%;
padding: 15px;
- background-color: #534;
- border: 1px solid #C00;
+ background-color: $warnbg$;
+ border: 1px solid $warnborder$;
}
div.notice {
- background-color: #354;
- border: 1px solid #0C0;
+ background-color: $noticebg$;
+ border: 1px solid $noticeborder$;
}
div.warning ul, div.notice ul {
margin-left: 0;
@@ -958,11 +982,10 @@ div.revision {
padding-bottom: 10px!important;
}
div.revision div, div.revision table {
- border: 1px solid #258;
+ border: 1px solid $border$;
margin: 0 auto;
width: 90%;
- /*background: url(/f/boxbg.png) repeat;*/
- background-color: #13273a;
+ background-color: $secbg$;
clear: both;
}
div.revision table thead tr td {
@@ -971,7 +994,7 @@ div.revision table thead tr td {
font-weight: normal;
}
div.revision table td {
- border-right: 1px solid #258;
+ border-right: 1px solid $border$;
padding: 5px;
}
div.revision td.tcval {
@@ -983,11 +1006,11 @@ div.revision div {
}
.diff_add {
font-weight: normal;
- background-color: #354;
+ background-color: $diffadd$;
}
.diff_del {
font-weight: normal;
- background-color: #534;
+ background-color: $diffdel$;
}
div.revision .next {
float: right;
@@ -1010,8 +1033,8 @@ div#iv_view {
display: none;
top: -5000px;
left: -5000px;
- background: url(/f/boxbg.png) repeat;
- border: 1px solid #258;
+ background: url($_boxbg$) repeat;
+ border: 1px solid $border$;
padding: 5px;
text-align: center;
}
@@ -1028,7 +1051,7 @@ div#iv_view {
top: -50px;
width: 100px;
padding: 3px;
- background-color: #f5f5f5;
+ background-color: #f5f5f5; /* no real need to skin this */
text-align: center;
border: 1px solid #ccc;
color: #000;
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 5eb214ff..92532247 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,10 +1,12 @@
-TODO:
- + The current implementation of the hidden flag *SUCKS*, seriously needs
- some revising:
- + Add a 'change' when hiding/unhiding an item
- + Remove all references to an item when it's hidden
- (preferably with the option to re-add them when unhiding)
- + Add a link for the hidden 'h' option at /hist
+2.1 - 2008-12-29
+ - Skin support
+ - 'show all items' tab to large forms
+ - Allow items to be selected using the mouse on the dropdown search
+ - [spoiler] tag produces mouseover-style spoilers instead of ROT13
+ - Fixed tiny timezone-related bug
+ - Re-added release list dropdown on VN pages
+ - Added [quote] tag to bb2html
+ - fixed URL parser in bb2html
2.0 - 2008-12-20
- New layout
diff --git a/lib/VNDB/DB/Releases.pm b/lib/VNDB/DB/Releases.pm
index b2c78d5e..6af2f736 100644
--- a/lib/VNDB/DB/Releases.pm
+++ b/lib/VNDB/DB/Releases.pm
@@ -3,6 +3,7 @@ package VNDB::DB::Releases;
use strict;
use warnings;
+use POSIX 'strftime';
use Exporter 'import';
our @EXPORT = qw|dbReleaseGet dbReleaseAdd dbReleaseEdit|;
@@ -27,7 +28,7 @@ sub dbReleaseGet {
$o{vid} ? (
'rv.vid = ?' => $o{vid} ) : (),
defined $o{unreleased} ? (
- q|rr.released !s TO_CHAR('today'::timestamp, 'YYYYMMDD')::integer| => $o{unreleased} ? '>' : '<=' ) : (),
+ q|rr.released !s ?| => [ $o{unreleased} ? '>' : '<=', strftime('%Y%m%d', gmtime) ] ) : (),
);
my @join = (
diff --git a/lib/VNDB/DB/Users.pm b/lib/VNDB/DB/Users.pm
index 501bb8bb..6f1a13c6 100644
--- a/lib/VNDB/DB/Users.pm
+++ b/lib/VNDB/DB/Users.pm
@@ -64,7 +64,7 @@ sub dbUserEdit {
my %h;
defined $o{$_} && ($h{$_.' = ?'} = $o{$_})
- for (qw| username mail rank show_nsfw show_list |);
+ for (qw| username mail rank show_nsfw show_list skin |);
$h{'passwd = decode(?, \'hex\')'} = $o{passwd}
if defined $o{passwd};
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 9abacad0..330dad7d 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -86,6 +86,7 @@ sub userstr {
# [url=..] [/url]
# [raw] .. [/raw]
# [spoiler] .. [/spoiler]
+# [quote] .. [/quote]
# v+, v+.+
# http://../
sub bb2html {
@@ -94,11 +95,10 @@ sub bb2html {
$raw =~ s/\r//g;
return '' if !$raw && $raw ne "0";
- my($result, $length, @open) = ('', 0, 'first');
+ my($result, $length, $rmnewline, @open) = ('', 0, 0, 'first');
my $e = sub {
local $_ = shift;
- tr/A-Za-z/N-ZA-Mn-za-m/ if !@_ && grep /spoiler/, @open;
s/&/&amp;/g;
s/>/&gt;/g;
s/</&lt;/g;
@@ -109,13 +109,34 @@ sub bb2html {
for (split /(\s|\n|\[[^\]]+\])/, $raw) {
next if !defined $_;
+ next if $_ eq '';
+
+ $rmnewline = s/\n//g if $rmnewline;
+ next if $_ eq '';
my $lit = $_;
if($open[$#open] ne 'raw') {
if ($_ eq '[raw]') { push @open, 'raw'; next }
- elsif ($_ eq '[spoiler]') { push @open, 'spoiler'; next }
- elsif ($_ eq '[/spoiler]') { pop @open if $open[$#open] eq 'spoiler'; next }
- elsif ($_ eq '[/url]') {
+ elsif ($_ eq '[spoiler]') { push @open, 'spoiler'; $result .= '<b class="spoiler">'; next }
+ elsif ($_ eq '[quote]') {
+ push @open, 'quote';
+ $result .= '<div class="quote">' if !$maxlength;
+ $rmnewline++;
+ next
+ } elsif ($_ eq '[/spoiler]') {
+ if($open[$#open] eq 'spoiler') {
+ $result .= '</b>';
+ pop @open;
+ }
+ next;
+ } elsif ($_ eq '[/quote]') {
+ if($open[$#open] eq 'quote') {
+ $result .= '</div>' if !$maxlength;
+ $rmnewline++;
+ pop @open;
+ }
+ next;
+ } elsif($_ eq '[/url]') {
if($open[$#open] eq 'url') {
$result .= '</a>';
pop @open;
@@ -126,7 +147,7 @@ sub bb2html {
push @open, 'url';
next;
} elsif(!grep(/url/, @open) &&
- s{(.*)(http|https)://(.+[0-9a-zA-Z=/])(.*)}
+ s{(.*)(http|https)://(.+[\d\w=/-])(.*)}
{$e->($1).qq|<a href="$2://|.$e->($3, 1).'" rel="nofollow">'.$e->('link').'</a>'.$e->($4)}e) {
$length += 4;
last if $maxlength && $length > $maxlength;
@@ -151,7 +172,7 @@ sub bb2html {
$result .= $e->($_);
}
- $result .= '</a>'
+ $result .= $_ eq 'url' ? '</a>' : $_ eq 'quote' ? '</div>' : '</b>'
while((local $_ = pop @open) ne 'first');
$result .= '...' if $maxlength && $length > $maxlength;
diff --git a/lib/VNDB/Handler/Discussions.pm b/lib/VNDB/Handler/Discussions.pm
index 286e3ee5..06693590 100644
--- a/lib/VNDB/Handler/Discussions.pm
+++ b/lib/VNDB/Handler/Discussions.pm
@@ -54,7 +54,7 @@ sub thread {
table;
for my $i (0..$#$p) {
local $_ = $p->[$i];
- my $class = $i % 2 == 0 ? 'odd ' : '';
+ my $class = $i % 2 ? 'odd ' : '';
$class .= 'deleted' if $_->{hidden};
Tr class => $class;
td class => 'tc1';
diff --git a/lib/VNDB/Handler/ULists.pm b/lib/VNDB/Handler/ULists.pm
index 5353dbc9..f86cba83 100644
--- a/lib/VNDB/Handler/ULists.pm
+++ b/lib/VNDB/Handler/ULists.pm
@@ -70,7 +70,8 @@ sub rlist {
$f->{e} =~ /^([rv])(\d+)$/ && $1 eq 'r' ? (rstat => $2) : (vstat => $2)
) if $f->{e} ne 'del';
- $self->resRedirect('/r'.$id, 'temp');
+ (my $ref = $self->reqHeader('Referer')||"/r$id") =~ s/^\Q$self->{url}//;
+ $self->resRedirect($ref, 'temp');
}
diff --git a/lib/VNDB/Handler/Users.pm b/lib/VNDB/Handler/Users.pm
index daba59e6..f2bb0fa6 100644
--- a/lib/VNDB/Handler/Users.pm
+++ b/lib/VNDB/Handler/Users.pm
@@ -299,6 +299,7 @@ sub edit {
{ name => 'mail', template => 'mail' },
{ name => 'usrpass', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
{ name => 'usrpass2', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
+ { name => 'skin', enum => [ '', keys %{$self->{skins}} ], required => 0, default => '' },
{ name => 'flags_list', required => 0, default => 0 },
{ name => 'flags_nsfw', required => 0, default => 0 },
);
@@ -308,6 +309,7 @@ sub edit {
$o{username} = $frm->{usrname} if $frm->{usrname};
$o{rank} = $frm->{rank} if $frm->{rank};
$o{mail} = $frm->{mail};
+ $o{skin} = $frm->{skin};
$o{passwd} = md5_hex($frm->{usrpass}) if $frm->{usrpass};
$o{show_list} = $frm->{flags_list} ? 1 : 0;
$o{show_nsfw} = $frm->{flags_nsfw} ? 1 : 0;
@@ -321,6 +323,7 @@ sub edit {
$frm->{usrname} ||= $u->{username};
$frm->{rank} ||= $u->{rank};
$frm->{mail} ||= $u->{mail};
+ $frm->{skin} ||= $u->{skin};
$frm->{flags_list} = $u->{show_list} if !defined $frm->{flags_list};
$frm->{flags_nsfw} = $u->{show_nsfw} if !defined $frm->{flags_nsfw};
@@ -341,7 +344,7 @@ sub edit {
$self->authCan('usermod') ? (
[ input => short => 'usrname', name => 'Username' ],
[ select => short => 'rank', name => 'Rank', options => [
- map [ $_, $self->{user_ranks}[$_][0] ], 1..$#{$self->{user_ranks}} ] ],
+ map [ $_, $self->{user_ranks}[$_][0] ], 1..$#{$self->{user_ranks}} ] ],
) : (
[ static => label => 'Username', content => $frm->{usrname} ],
),
@@ -353,6 +356,8 @@ sub edit {
[ passwd => short => 'usrpass2', name => 'Confirm pass.' ],
[ part => title => 'Options' ],
+ [ select => short => 'skin', name => 'Prefered skin', options => [
+ map [ $_ eq $self->{skin_default} ? '' : $_, $self->{skins}{$_} ], sort { $self->{skins}{$a} cmp $self->{skins}{$b} } keys %{$self->{skins}} ] ],
[ check => short => 'flags_list', name =>
qq|Allow other people to see my visual novel list (<a href="/u$uid/list">/u$uid/list</a>) |.
qq|and wishlist (<a href="/u$uid/wish">/u$uid/wish</a>)| ],
diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm
index 35a9ac8c..b53b60ee 100644
--- a/lib/VNDB/Handler/VNPage.pm
+++ b/lib/VNDB/Handler/VNPage.pm
@@ -397,9 +397,9 @@ sub _releases {
a href => "/r$rel->{id}", title => $rel->{original}||$rel->{title}, $rel->{title};
end;
td class => 'tc5';
- if($rel->{ulist}) {
- a href => "/r$rel->{id}";
- lit liststat $rel->{ulist};
+ if($self->authInfo->{id}) {
+ a href => "/r$rel->{id}", id => "rlsel_$rel->{id}";
+ lit $rel->{ulist} ? liststat $rel->{ulist} : '--';
end;
} else {
txt ' ';
diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm
index 80b8c4f3..ff23682d 100644
--- a/lib/VNDB/Util/FormHTML.pm
+++ b/lib/VNDB/Util/FormHTML.pm
@@ -216,6 +216,9 @@ sub htmlForm {
a href => "#$short", id => "jt_sel_$short", $subs[$_*2];
end;
}
+ li class => 'left';
+ a href => '#all', id => 'jt_sel_all', 'All items';
+ end;
end;
}
diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm
index e5ced8f6..30a10ce3 100644
--- a/lib/VNDB/Util/LayoutHTML.pm
+++ b/lib/VNDB/Util/LayoutHTML.pm
@@ -12,13 +12,15 @@ our @EXPORT = qw|htmlHeader htmlFooter|;
sub htmlHeader { # %options->{ title, js, noindex, search }
my($self, %o) = @_;
+ my $skin = $self->authInfo->{skin} || $self->{skin_default};
+ $skin = $self->{skin_default} if !-d "$VNDB::ROOT/static/s/$skin";
# heading
html;
head;
title $o{title};
Link rel => 'shortcut icon', href => '/favicon.ico', type => 'image/x-icon';
- Link rel => 'stylesheet', href => $self->{url_static}.'/f/style.css', type => 'text/css', media => 'all';
+ Link rel => 'stylesheet', href => $self->{url_static}.'/s/'.$skin.'/style.css', type => 'text/css', media => 'all';
if($o{js}) {
script type => 'text/javascript', src => $self->{url_static}.'/f/forms.js'; end;
}
diff --git a/static/f/boxbg.png b/static/f/boxbg.png
deleted file mode 100644
index 43b546b5..00000000
--- a/static/f/boxbg.png
+++ /dev/null
Binary files differ
diff --git a/static/f/forms.js b/static/f/forms.js
index 2408dd2e..cd65058d 100644
--- a/static/f/forms.js
+++ b/static/f/forms.js
@@ -75,12 +75,7 @@ function catLoad() {
}
function catSet(id, rnk) {
- // doesn't work very nice with skins...
- var c = rnk == 0 ? '' :
- rnk == 1 ? '#0c0' :
- rnk == 2 ? '#cc0' : '#c00';
- x('b_'+id).style.color = c;
- x('cat_'+id).style.color = c;
+ x('cat_'+id).className = 'catlvl_'+rnk;
x('b_'+id).innerHTML = rnk;
}
@@ -97,8 +92,11 @@ function catSet(id, rnk) {
function dsInit(obj, url, trfunc, serfunc, retfunc) {
obj.onkeydown = dsKeyDown;
obj.onblur = function() {
- if(x('ds_box'))
- x('ds_box').style.top = '-500px';
+ // timeout to make sure the tr.onclick event is called before we've hidden the object
+ setTimeout(function () {
+ if(x('ds_box'))
+ x('ds_box').style.top = '-500px';
+ }, 500)
};
// all local data is stored in the DOM input object
obj.returnFunc = retfunc;
@@ -228,6 +226,18 @@ function dsResults(hr, obj) {
tr.itemData = l[i];
if(obj.selectedId == id)
tr.setAttribute('class', 'selected');
+ tr.onmouseover = function() {
+ obj.selectedId = this.id.substr(7);
+ var l = x('ds_box').getElementsByTagName('tr');
+ for(var i=0;i<l.length;i++)
+ l[i].className = l[i].id == 'ds_box_'+obj.selectedId ? 'selected' : '';
+ };
+ tr.onclick = function() {
+ obj.value = obj.serFunc(this.itemData);
+ if(x('ds_box'))
+ x('ds_box').style.top = '-500px';
+ obj.selectedId = 0;
+ };
obj.trFunc(l[i], tr);
tb.appendChild(tr);
}
diff --git a/static/f/script.js b/static/f/script.js
index 8ff2fe7f..68d40f75 100644
--- a/static/f/script.js
+++ b/static/f/script.js
@@ -15,6 +15,10 @@ clearInterval(t);f()}},10);window.onload=f;}
+
+
+/* A D V A N C E D S E A R C H */
+
function searchInit() {
cl('advselect', function() {
var e = x('advoptions');
@@ -184,6 +188,66 @@ function ivClose() {
+
+/* V N L I S T D R O P D O W N */
+
+var rstat = [ 'Unknown', 'Pending', 'Obtained', 'On loan', 'Deleted' ];
+var vstat = [ 'Unknown', 'Playing', 'Finished', 'Stalled', 'Dropped' ];
+function vlDropDown(e) {
+ e = e || window.event;
+ var tg = e.target || e.srcElement;
+ while(tg && (tg.nodeType == 3 || tg.nodeName.toLowerCase() != 'a'))
+ tg = tg.parentNode;
+
+ var o = x('vldd');
+ if(!o && (!tg || tg.id.substr(0,6) != 'rlsel_'))
+ return;
+
+ if(o) {
+ var mouseX = e.pageX || (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft);
+ var mouseY = e.pageY || (e.clientY + document.body.scrollTop + document.documentElement.scrollTop);
+ if((mouseX < ddx-5 || mouseX > ddx+o.offsetWidth+100 || mouseY < ddy-5 || mouseY > ddy+o.offsetHeight+5)
+ || (tg && tg.id.substr(0,6) == 'rlsel_' && tg.id != 'rlsel_'+o.relId)) {
+ document.body.removeChild(o);
+ o = null;
+ }
+ }
+ if(!o && tg) {
+ o = tg;
+ ddx = ddy = 0;
+ do {
+ ddx += o.offsetLeft;
+ ddy += o.offsetTop;
+ } while(o = o.offsetParent);
+ ddx -= 185;
+
+ var cu = '/r'+tg.id.substr(6)+'/list?e=';
+ var st = tg.innerHTML.split(' / ');
+ var r = '<ul><li><b>Release status</b></li>';
+ for(var i=0;i<rstat.length;i++)
+ r += st[0] && st[0].indexOf(rstat[i]) >= 0 ? '<li><i>'+rstat[i]+'</i></li>' : '<li><a href="'+cu+'r'+i+'">'+rstat[i]+'</a></li>';
+ r += '</ul><ul><li><b>Play status</b></li>';
+ for(var i=0;i<vstat.length;i++)
+ r += st[1] && st[1].indexOf(vstat[i]) >= 0 ? '<li><i>'+vstat[i]+'</i></li>' : '<li><a href="'+cu+'v'+i+'">'+vstat[i]+'</a></li>';
+ r += '</ul>';
+ if(tg.innerHTML != '--')
+ r += '<ul class="full"><li><a href="'+cu+'del">Remove from VN list</a></li></ul>';
+
+ o = document.createElement('div');
+ o.id = 'vldd';
+ o.relId = tg.id.substr(6);
+ o.style.left = ddx+'px';
+ o.style.top = ddy+'px';
+ o.innerHTML = r;
+ document.body.appendChild(o);
+ }
+}
+
+
+
+
+
+
/* J A V A S C R I P T T A B S */
function jtInit() {
@@ -213,7 +277,8 @@ function jtSel(which, nolink) {
for(var i=0;i<l.length;i++)
if(l[i].id.substr(0,7) == 'jt_sel_') {
var name = l[i].id.substr(7);
- x('jt_box_'+name).style.display = name == which ? 'block' : 'none';
+ if(name != 'all')
+ x('jt_box_'+name).style.display = name == which || which == 'all' ? 'block' : 'none';
var o = x('jt_sel_'+name).parentNode;
if(o.className.indexOf('tabselected') >= 0) {
if(name != which)
@@ -370,10 +435,26 @@ DOMLoad(function() {
// initialize image viewer
ivInit();
+ // vnlist dropdown
+ var l = document.getElementsByTagName('a');
+ for(var i=0;i<l.length;i++)
+ if(l[i].id.substr(0,6) == 'rlsel_') {
+ document.onmousemove = vlDropDown;
+ break;
+ }
+
// Javascript tabs
if(x('jt_select'))
jtInit();
+ // spoiler tags
+ l = document.getElementsByTagName('b');
+ for(i=0;i<l.length;i++)
+ if(l[i].className == 'spoiler') {
+ l[i].onmouseover = function() { this.className = 'spoiler_shown' };
+ l[i].onmouseout = function() { this.className = 'spoiler' };
+ }
+
// forms.js
if(x('categories'))
catLoad();
diff --git a/static/f/bg.jpg b/static/s/angel/bg.jpg
index f91e414e..f91e414e 100644
--- a/static/f/bg.jpg
+++ b/static/s/angel/bg.jpg
Binary files differ
diff --git a/static/f/bgright.jpg b/static/s/angel/bgright.jpg
index e1dff0cd..e1dff0cd 100644
--- a/static/f/bgright.jpg
+++ b/static/s/angel/bgright.jpg
Binary files differ
diff --git a/static/s/angel/conf b/static/s/angel/conf
new file mode 100644
index 00000000..72df41b0
--- /dev/null
+++ b/static/s/angel/conf
@@ -0,0 +1,39 @@
+name Angelic Serenade (dark blue)
+
+// text
+maintext #ddd // primary text color (also used for the menu links)
+grayedout #258 // color used for grayed-out/non-important things
+standout #e44 // color of 'stand-out' text
+link #7bd // primary link color (not used for the menu links)
+statok #0c0 // generic 'ok' text color (used for vnlist statuses & category browser)
+statnok #c00 // generoc 'not ok' text color (used for above, and as border for NSFW screenshots)
+footer #135 // text color of the footer
+
+// titles
+maintitle #135 // text color of the site title
+boxtitle #258 // box titles
+alttitle #fff // alternative title
+
+// bg colors
+bodybg #000 // main background color
+tabbg #012 // background color of inactive tabs
+secbg #0d2741 // secondary background color (used on input fields and table headers)
+secborder #35A // secondary border color (used on input fields)
+border #258 // primary border color
+boxbg #112233BC // RGBA, background color of the boxes, stacked for menu box titles and odd row numers
+
+// images (0 = no image)
+imglefttop bg.jpg
+imgrighttop bgright.jpg
+
+// misc colors
+catlevel1 #444 // category levels
+catlevel2 #777
+catlevel3 #fff
+diffadd #354 // background color of changes in the diff viewer
+diffdel #534
+warnbg #534 // background color of a warning box
+warnborder #c00 // ..border
+noticebg #354 // notice box
+noticeborder #0c0 // ...and border
+
diff --git a/static/s/grey/bg.jpg b/static/s/grey/bg.jpg
new file mode 100644
index 00000000..8d61ac55
--- /dev/null
+++ b/static/s/grey/bg.jpg
Binary files differ
diff --git a/static/s/grey/bgright.jpg b/static/s/grey/bgright.jpg
new file mode 100644
index 00000000..c52499ea
--- /dev/null
+++ b/static/s/grey/bgright.jpg
Binary files differ
diff --git a/static/s/grey/conf b/static/s/grey/conf
new file mode 100644
index 00000000..10675446
--- /dev/null
+++ b/static/s/grey/conf
@@ -0,0 +1,39 @@
+name Touhou (grey)
+
+// text
+maintext #222
+grayedout #666
+standout #500
+link #005
+statok #050
+statnok #500
+footer #bbb
+
+// titles
+maintitle #ccc
+boxtitle #444
+alttitle #000
+
+// bg colors
+bodybg #fff
+tabbg #ddd
+secbg #bbb
+secborder #000
+border #666
+boxbg #dddddddd
+
+// images (0 = no image)
+imglefttop bg.jpg
+imgrighttop bgright.jpg
+
+// misc colors
+catlevel1 #555
+catlevel2 #333
+catlevel3 #000
+diffadd #cfc
+diffdel #fcc
+warnbg #fcc
+warnborder #c00
+noticebg #cfc
+noticeborder #0c0
+
diff --git a/static/s/lb/bg.jpg b/static/s/lb/bg.jpg
new file mode 100644
index 00000000..94a7874d
--- /dev/null
+++ b/static/s/lb/bg.jpg
Binary files differ
diff --git a/static/s/lb/conf b/static/s/lb/conf
new file mode 100644
index 00000000..7cdcd16a
--- /dev/null
+++ b/static/s/lb/conf
@@ -0,0 +1,39 @@
+name Little Busters! (pink)
+
+// text
+maintext #408
+grayedout #670159
+standout #e44
+link #a2d
+statok #0c0
+statnok #c00
+footer #f78de7
+
+// titles
+maintitle #f78de7
+boxtitle #670159
+alttitle #5328a7
+
+// bg colors
+bodybg #fff
+tabbg #f78de7
+secbg #f78de7
+secborder #670159
+border #f76ee2
+boxbg #f7b6edcc
+
+// images (0 = no image)
+imglefttop bg.jpg
+imgrighttop 0
+
+// misc colors
+catlevel1 #444
+catlevel2 #d28
+catlevel3 #999
+diffadd #cfc
+diffdel #fcc
+warnbg #fff
+warnborder #c00
+noticebg #f7b6ed
+noticeborder #670159
+
diff --git a/util/dump.sql b/util/dump.sql
index 848ddd34..719f0f75 100644
--- a/util/dump.sql
+++ b/util/dump.sql
@@ -184,7 +184,8 @@ CREATE TABLE users (
show_nsfw boolean NOT NULL DEFAULT FALSE,
show_list boolean NOT NULL DEFAULT TRUE,
c_votes integer NOT NULL DEFAULT 0,
- c_changes integer NOT NULL DEFAULT 0
+ c_changes integer NOT NULL DEFAULT 0,
+ skin varchar(128) NOT NULL DEFAULT ''
);
-- vn
diff --git a/util/skingen.pl b/util/skingen.pl
new file mode 100755
index 00000000..9c06b077
--- /dev/null
+++ b/util/skingen.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+
+package VNDB;
+
+use strict;
+use warnings;
+use Cwd 'abs_path';
+use Data::Dumper 'Dumper';
+use Image::Magick;
+
+
+our($ROOT, %O);
+BEGIN { ($ROOT = abs_path $0) =~ s{/util/skingen\.pl$}{}; }
+require $ROOT.'/data/global.pl';
+
+
+if(@ARGV) {
+ writeskin(readskin($_)) for (@ARGV);
+} else {
+ /([^\/]+)$/ && writeskin(readskin($1)) for (glob($ROOT.'/static/s/*'));
+}
+
+
+sub readskin { # skin name
+ my $name = shift;
+ my %o;
+ open my $F, '<', $ROOT.'/static/s/'.$name.'/conf' or die $!;
+ while(<$F>) {
+ chomp;
+ s{[\t\s]*//.+$}{};
+ next if !/^([a-z0-9]+)[\t\s]+(.+)$/;
+ $o{$1} = $2;
+ }
+ close $F;
+ $o{_name} = $name;
+ return \%o;
+}
+
+
+sub writeskin { # $obj
+ my $o = shift;
+
+ # fix image locations
+ $o->{$_} && ($o->{$_} = '/s/'.$o->{_name}.'/'.$o->{$_}) for (qw|imglefttop imgrighttop|);
+
+ # get the right top image
+ if($o->{imgrighttop}) {
+ my $img = Image::Magick->new;
+ $img->Read($ROOT.'/static'.$o->{imgrighttop});
+ $o->{_bgright} = sprintf 'background: url(%s) no-repeat; width: %dpx; height: %dpx',
+ $o->{imgrighttop}, $img->Get('width'), $img->Get('height');
+ } else {
+ $o->{_bgright} = 'display: none';
+ }
+
+ # body background
+ if(!$o->{imglefttop}) {
+ $o->{_bodybg} = "background-color: $o->{bodybg}";
+ } else {
+ $o->{_bodybg} = "background: $o->{bodybg} url($o->{imglefttop}) no-repeat";
+ }
+
+
+ # create boxbg.png
+ my $img = Image::Magick->new(size => '1x1');
+ $img->Read('xc:'.$o->{boxbg});
+ $img->Write(filename => $ROOT.'/static/s/'.$o->{_name}.'/boxbg.png');
+ $o->{_boxbg} = '/s/'.$o->{_name}.'/boxbg.png';
+
+ # get the blend color
+ $img = Image::Magick->new(size => '1x1');
+ $img->Read('xc:'.$o->{bodybg}, 'xc:'.$o->{boxbg});
+ $img = $img->Flatten();
+ $o->{_blendbg} = '#'.join '', map sprintf('%02x', $_*255), $img->GetPixel(x=>1,y=>1);
+
+ # write the CSS
+ open my $CSS, '<', "$ROOT/data/skingen/style.css" or die $!;
+ open my $SKIN, '>', "$ROOT/static/s/$o->{_name}/style.css" or die $!;
+ while((my $d = <$CSS>)) {
+ if($O{debug}) {
+ chomp $d;
+ $d =~ s/^\s*/ /;
+ $d =~ s{/\*.+\*/}{}; # NOTE: multiline comments or multiple comments per line won't work
+ next if $d !~ /[^\s\t]/;
+ }
+ $d =~ s/\$$_\$/$o->{$_}/g for (keys %$o);
+ print $SKIN $d;
+ }
+ close $SKIN;
+ close $CSS;
+}
+
+
diff --git a/util/updates/update_2.1.sql b/util/updates/update_2.1.sql
new file mode 100644
index 00000000..7ae8fecf
--- /dev/null
+++ b/util/updates/update_2.1.sql
@@ -0,0 +1,4 @@
+
+-- skin selector
+ALTER TABLE users ADD COLUMN skin varchar(128) NOT NULL DEFAULT '';
+
diff --git a/util/vndb.pl b/util/vndb.pl
index 5ef0bf40..a9ac36b4 100755
--- a/util/vndb.pl
+++ b/util/vndb.pl
@@ -22,6 +22,11 @@ use YAWF ':html';
our(%O, %S);
+# load and (if required) regenerate the skins
+# NOTE: $S{skins} can be modified in data/config.pl, allowing deletion of skins or forcing only one skin
+$S{skins} = readskins();
+
+
# load settings from global.pl
require $ROOT.'/data/global.pl';
@@ -73,3 +78,28 @@ sub handle404 {
}
+sub readskins {
+ my %skins; # dirname => skin name
+ my $regen = 0;
+ my $lasttemplate = [stat "$ROOT/data/skingen/style.css"]->[9];
+ for my $f (glob "$ROOT/static/s/*") {
+ my $n = $1 if $f =~ m{([^/]+)$};
+ open my $F, '<', "$f/conf" or die $!;
+ while(<$F>) {
+ chomp;
+ s{[\t\s]*//.*$}{};
+ next if !/^name[\t\s]+(.+)$/;
+ $skins{$n} = $1;
+ last;
+ }
+ close $F;
+
+ my $lastgen = [stat "$f/style.css"]->[9];
+ $regen = 1 if (!-f "$f/style.css" && -x $f)
+ || ([stat "$f/conf"]->[9] > $lastgen || $lasttemplate > $lastgen) && -w "$f/style.css";
+ }
+ # note: this only works if the current process has write access to the skins
+ `$ROOT/util/skingen.pl` if $regen;
+ return \%skins;
+}
+