@@ -0,0 +1,191 @@ | |||
<!doctype html> | |||
<html> | |||
<head> | |||
<link rel="stylesheet" media="screen" href="/stylesheets/style.css"> | |||
<meta charset="utf-8"> | |||
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %} | |||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"> | |||
<link rel='stylesheet' href='/stylesheets/fullcalendar.min.css' /> | |||
<script type='text/javascript'> | |||
var active_page = "news"; | |||
</script> | |||
<title>{{ settings.title }}</title> | |||
{% include 'header.html' %} | |||
<script src='/js/moment.min.js'></script> | |||
<script src='/js/fullcalendar.min.js'></script> | |||
</head> | |||
<body class="8chan vichan {% if mod %}is-moderator{% else %}is-not-moderator{% endif %}" data-stylesheet="{% if config.default_stylesheet.1 != '' %}{{ config.default_stylesheet.1 }}{% else %}default{% endif %}"> | |||
<div class="bar top"> | |||
{{ boardlist.top }} | |||
</div> | |||
<header> | |||
<h1 class="glitch" data-text="{{ settings.title }}"> {{ settings.title }}</h1> | |||
<div class="subtitle">{{ settings.subtitle }}</div> | |||
</header> | |||
<div class="ban"> | |||
<div id='calendar'></div> | |||
</div> | |||
<hr/> | |||
<footer> | |||
<p class="unimportant" style="margin-top:20px;text-align:center;">- <a href="http://tinyboard.org/">Tinyboard</a> + | |||
<a href='https://int.vichan.net/devel/'>vichan</a> + | |||
<a href='https://github.com/lainchan/lainchan'>lainchan</a> {{ config.version }} - | |||
<br><a href="http://tinyboard.org/">Tinyboard</a> Copyright © 2010-2014 Tinyboard Development Group | |||
<br><a href="https://engine.vichan.net/">vichan</a> Copyright © 2012-2016 vichan-devel | |||
<br><a href="https://github.com/lainchan/lainchan">lainchan</a> Copyright © 2014-2017 lainchan Administration</p> | |||
</footer> | |||
<div class="pages"></div> | |||
<script type='text/javascript'> | |||
$(document).ready(function() { | |||
var calendar = $('#calendar').fullCalendar({ | |||
editable: true, | |||
header: { | |||
left: 'prev,next today', | |||
center: 'title', | |||
right: 'month,agendaWeek,agendaDay' | |||
}, | |||
events: "calendarpost.php", | |||
eventRender: function(event, element, view) { | |||
if (event.allDay === 'true') { | |||
event.allDay = true; | |||
} else { | |||
event.allDay = false; | |||
} | |||
element.find('.fc-title').append("<br/>" + event.description); | |||
element.css('background-color',event.color); | |||
}, | |||
selectable: true, | |||
selectHelper: true, | |||
select: function(start, end, allDay) { | |||
var title = prompt('Event Title:'); | |||
var description = prompt('Event Description:'); | |||
var url = prompt("Event URL"); | |||
var color = prompt("Event Color"); | |||
var starttime = prompt("Event Start Time"); | |||
var endtime = prompt("Event End Time"); | |||
if (title) { | |||
var startmoment = moment(start); | |||
var endmoment = moment(end); | |||
var start = startmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
var end = endmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
if (starttime && endtime){ | |||
var starttimemoment = moment(starttime,'HH:mm'); | |||
var endtimemoment = moment(endtime,'HH:mm'); | |||
startmoment.hour(starttimemoment.hour()); | |||
startmoment.minute(starttimemoment.minute()); | |||
endmoment.hour(endtimemoment.hour()); | |||
endmoment.minute(endtimemoment.minute()); | |||
endmoment.subtract(1, "days"); | |||
allday = false; | |||
start = startmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
end = endmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
} | |||
$.ajax({ | |||
url: 'calendarpost.php', | |||
data: 'type=add&title='+ title+'&description='+ description +'&start='+ start +'&end='+ end + '&url='+url+'&color='+color, | |||
type: "POST", | |||
success: function(json) { | |||
alert('Added Successfully'); | |||
} | |||
}); | |||
calendar.fullCalendar('renderEvent', | |||
{ | |||
title: title, | |||
description: description, | |||
start: start, | |||
end: end, | |||
allDay: allDay, | |||
url: url, | |||
color:color, | |||
}, | |||
true | |||
); | |||
} | |||
calendar.fullCalendar('unselect'); | |||
}, | |||
editable: true, | |||
eventDrop: function(event, delta) { | |||
var startmoment = moment(start); | |||
var endmoment = moment(end); | |||
var start = startmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
var end = endmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
var starttime = prompt("Event Start Time"); | |||
var endtime = prompt("Event End Time"); | |||
if (starttime && endtime){ | |||
var starttimemoment = moment(starttime,'HH:mm'); | |||
var endtimemoment = moment(endtime,'HH:mm'); | |||
startmoment.hour(starttimemoment.hour()); | |||
startmoment.minute(starttimemoment.minute()); | |||
endmoment.hour(endtimemoment.hour()); | |||
endmoment.minute(endtimemoment.minute()); | |||
allday = false; | |||
endmoment.subtract(1, "days"); | |||
start = startmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
end = endmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
} | |||
$.ajax({ | |||
url: 'calendarpost.php', | |||
data: 'type=update&title='+ event.title+'&description='+ event.description + '&start='+ start +'&end='+ end +'&id='+ event.id , | |||
type: "POST", | |||
success: function(json) { | |||
alert("Updated Successfully"); | |||
} | |||
}); | |||
}, | |||
eventClick: function(event) { | |||
var decision = confirm("Do you really want to do that?"); | |||
if (decision) { | |||
$.ajax({ | |||
type: "POST", | |||
url: 'calendarpost.php', | |||
data: "type=delete&id=" + event.id, | |||
success: function(json) { | |||
$('#calendar').fullCalendar('removeEvents', event.id); | |||
alert("Updated Successfully");} | |||
}); | |||
} | |||
}, | |||
eventResize: function(event) { | |||
var startmoment = moment(start); | |||
var endmoment = moment(end); | |||
var start = moment(start).format('YYYY-MM-DD HH:mm:ss'); | |||
var end = moment(end).format('YYYY-MM-DD HH:mm:ss'); | |||
var starttime = prompt("Event Start Time"); | |||
var endtime = prompt("Event End Time"); | |||
if (starttime && endtime){ | |||
var starttimemoment = moment(starttime,'HH:mm'); | |||
var endtimemoment = moment(endtime,'HH:mm'); | |||
startmoment.hour(starttimemoment.hour()); | |||
startmoment.minute(starttimemoment.minute()); | |||
endmoment.hour(endtimemoment.hour()); | |||
endmoment.minute(endtimemoment.minute()); | |||
allday = false; | |||
endmoment.subtract(1, "days"); | |||
start = startmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
end = endmoment.format('YYYY-MM-DD HH:mm:ss'); | |||
} | |||
$.ajax({ | |||
url: 'calendarpost.php', | |||
data: 'type=update&title='+ event.title+ '&description='+ event.description + '&start='+ start +'&end='+ end +'&id='+ event.id , | |||
type: "POST", | |||
success: function(json) { | |||
alert("Updated Successfully"); | |||
} | |||
}); | |||
} | |||
}); | |||
}); | |||
</script> | |||
<script type="text/javascript">{% raw %} | |||
ready(); | |||
{% endraw %}</script> | |||
</body> | |||
</html> |
@@ -0,0 +1,53 @@ | |||
<?php | |||
require '/var/www/html/inc/functions.php'; | |||
$method = $_SERVER['REQUEST_METHOD']; | |||
if ($method == 'POST') { | |||
// Method is POST | |||
$type = $_POST['type']; | |||
switch ($type) { | |||
case "add": | |||
$title = $_POST['title']; | |||
$description = $_POST['description']; | |||
$start = $_POST['start']; | |||
$end = $_POST['end']; | |||
$url = $_POST['url']; | |||
$color = $_POST['color']; | |||
$query = prepare("INSERT INTO calendar_events (title, description, start, end,url,color) VALUES (:title,:description, :start, :end,:url, :color )"); | |||
$query->bindValue(':title', $title); | |||
$query->bindValue(':description', $description); | |||
$query->bindValue(':start', $start); | |||
$query->bindValue(':end', $end); | |||
$query->bindValue(':url', $url); | |||
$query->bindValue(':color', $color); | |||
$query->execute() or error(db_error($query)); | |||
break; | |||
case "delete": | |||
$id = $_POST['id']; | |||
$query = query("DELETE from calendar_events WHERE id = :id") or error(db_error()); | |||
break; | |||
case "update": | |||
$id = $_POST['id']; | |||
$title = $_POST['title']; | |||
$description = $_POST['description']; | |||
$start = $_POST['start']; | |||
$end = $_POST['end']; | |||
$query = prepare(" UPDATE calendar_events SET title = :title, description = :description, start = :start, end = :end, url = :url, color =:color WHERE id = :id"); | |||
$query->bindValue(':id', $id); | |||
$query->bindValue(':title', $title); | |||
$query->bindValue(':description', $description); | |||
$query->bindValue(':start', $start); | |||
$query->bindValue(':end', $end); | |||
$query->bindValue(':url', $url); | |||
$query->bindValue(':color', $color); | |||
$query->execute() or error(db_error($query)); | |||
break; | |||
default: | |||
} | |||
} elseif ($method == 'GET') { | |||
// Method is GET | |||
$query = query("SELECT * FROM calendar_events ORDER BY id") or error(db_error()); | |||
echo json_encode($query->fetchAll(PDO::FETCH_ASSOC)); | |||
} | |||
?> |
@@ -0,0 +1,36 @@ | |||
<?php | |||
$theme = Array(); | |||
// Theme name | |||
$theme['name'] = 'Calendar'; | |||
// Description (you can use Tinyboard markup here) | |||
$theme['description'] = 'Calendar theme.'; | |||
$theme['version'] = 'v0.0.1'; | |||
// Theme configuration | |||
$theme['config'] = Array(); | |||
$theme['config'][] = Array( | |||
'title' => 'Site title', | |||
'name' => 'title', | |||
'type' => 'text' | |||
); | |||
$theme['config'][] = Array( | |||
'title' => 'Slogan', | |||
'name' => 'subtitle', | |||
'type' => 'text', | |||
'comment' => '(optional)' | |||
); | |||
$theme['config'][] = Array( | |||
'title' => 'File', | |||
'name' => 'file', | |||
'type' => 'text', | |||
'default' => $config['file_index'], | |||
'comment' => '(eg. "index.html")' | |||
); | |||
// Unique function name for building everything | |||
$theme['build_function'] = 'calendar_build'; | |||
@@ -0,0 +1,40 @@ | |||
<?php | |||
require 'info.php'; | |||
function calendar_build($action, $settings, $board) { | |||
// Possible values for $action: | |||
// - all (rebuild everything, initialization) | |||
// - news (news has been updated) | |||
// - boards (board list changed) | |||
Calendar::build($action, $settings); | |||
} | |||
// Wrap functions in a class so they don't interfere with normal Tinyboard operations | |||
class Calendar { | |||
public static function build($action, $settings) { | |||
global $config; | |||
if ($action == 'all' || $action == 'news') | |||
file_write($config['dir']['home'] . $settings['file'], Calendar::htmlpage($settings)); | |||
file_write($config['dir']['home'] . "calendarpost.php", Calendar::phppage($settings)); | |||
} | |||
// Build staff application page | |||
public static function htmlpage($settings) { | |||
global $config; | |||
return Element('themes/calendar/calendar.html', Array( | |||
'settings' => $settings, | |||
'config' => $config, | |||
'boardlist' => createBoardlist() | |||
)); | |||
} | |||
public static function phppage($settings) { | |||
global $config; | |||
$page = file_get_contents('templates/themes/calendar/calendarpost.php'); | |||
return $page; | |||
} | |||
}; | |||
?> |
@@ -0,0 +1,36 @@ | |||
<?php | |||
$theme = Array(); | |||
// Theme name | |||
$theme['name'] = 'StaffApplication'; | |||
// Description (you can use Tinyboard markup here) | |||
$theme['description'] = 'Staff Application theme.'; | |||
$theme['version'] = 'v0.0.1'; | |||
// Theme configuration | |||
$theme['config'] = Array(); | |||
$theme['config'][] = Array( | |||
'title' => 'Site title', | |||
'name' => 'title', | |||
'type' => 'text' | |||
); | |||
$theme['config'][] = Array( | |||
'title' => 'Slogan', | |||
'name' => 'subtitle', | |||
'type' => 'text', | |||
'comment' => '(optional)' | |||
); | |||
$theme['config'][] = Array( | |||
'title' => 'File', | |||
'name' => 'file', | |||
'type' => 'text', | |||
'default' => $config['file_index'], | |||
'comment' => '(eg. "index.html")' | |||
); | |||
// Unique function name for building everything | |||
$theme['build_function'] = 'staffapplication_build'; | |||
@@ -0,0 +1,80 @@ | |||
{% filter remove_whitespace %} | |||
<!doctype html> | |||
<html> | |||
<head> | |||
<link rel="stylesheet" media="screen" href="/stylesheets/style.css"> | |||
<meta charset="utf-8"> | |||
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %} | |||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"> | |||
<script type='text/javascript'> | |||
var active_page = "news"; | |||
</script> | |||
<title>{{ settings.title }}</title> | |||
{% include 'header.html' %} | |||
</head> | |||
<body class="8chan vichan {% if mod %}is-moderator{% else %}is-not-moderator{% endif %}" data-stylesheet="{% if config.default_stylesheet.1 != '' %}{{ config.default_stylesheet.1 }}{% else %}default{% endif %}"> | |||
<div class="bar top"> | |||
{{ boardlist.top }} | |||
</div> | |||
<header> | |||
<h1 class="glitch" data-text="{{ settings.title }}"> {{ settings.title }}</h1> | |||
<div class="subtitle">{{ settings.subtitle }}</div> | |||
</header> | |||
<center> | |||
<img src="static/lain_is_cute_datass_small_teal.png" alt="mascot"/> | |||
</center> | |||
<div class="ban"> | |||
<p> | |||
Please use to the form below to apply to be staff.</br> | |||
If you don't want to use this form you can also email admin@lainchan.org or ask in #questions on the Lainchan IRC channel. | |||
In the rest of your application section, please specify the following information: </br> | |||
Do you have to specify all the requested information below ? </br> | |||
No of course not, but the more you specify the more likely your application will be approved, because applications | |||
that demostrate that you can put effort in things, tell us that you can be bothered putting effort into things.</br> | |||
What position you wanted to apply for ? E.g. Chan staff ? IRC staff ? Sysadmin ? Developer ? All of the above ? | |||
None of the above ? Special snowflake role invented just for you ?</br> | |||
Your reasons for applying ? </br> | |||
Your existing qualifications for the position </br> | |||
A summary of your strengths, weaknesses and interesting points / quirks </br> | |||
If chan staff , then please specify which boards you are interested in and your experience with their subject matter. | |||
</br> | |||
Things to not include on your application. </br> | |||
1. NSFW pictures </br> | |||
2. Anything that is against the rules on the Rules page.</br> | |||
3. Short stories about ducks and ribbons and that guy Jimmy and other off topic things.</br> | |||
4. Your entire life story. </br> | |||
5. Your passport number or SSN and / or other identifying information. </br> | |||
6. Your rant about XYZ and how much all ABC need to suffer DEF because of it. </br> | |||
</p> | |||
<form action="staffapplication.php" method="post"> | |||
<p><label for="name">Name: </label><input type="text" name="name" size="50"></p> | |||
<p><label for="contactmethod">Preferred Contact Method: </label><select name="contactmethod"> | |||
<option value="email" selected>Email</option> | |||
<option value="irc">IRC</option> | |||
<option value="chan">Lainchan</option> | |||
</select></p> | |||
<p><label for="email">Email: </label><input type="email" name="email" size="50"></p> | |||
<p> | |||
<label for="application">The rest of your application.</label><textarea name="application" rows="30" cols="50"></textarea> | |||
</p> | |||
<p><label for="anitspam">Antispam: (What is Cyberpunk , answer in all CAPS, single word, no spaces) </label><input type="text" name="antispam" size="50"></p> | |||
<input type="submit" value="Send"> | |||
</form> | |||
</div> | |||
<hr/> | |||
<footer> | |||
<p class="unimportant" style="margin-top:20px;text-align:center;">- <a href="http://tinyboard.org/">Tinyboard</a> + | |||
<a href='https://int.vichan.net/devel/'>vichan</a> + | |||
<a href='https://github.com/lainchan/lainchan'>lainchan</a> {{ config.version }} - | |||
<br><a href="http://tinyboard.org/">Tinyboard</a> Copyright © 2010-2014 Tinyboard Development Group | |||
<br><a href="https://engine.vichan.net/">vichan</a> Copyright © 2012-2016 vichan-devel | |||
<br><a href="https://github.com/lainchan/lainchan">lainchan</a> Copyright © 2014-2017 lainchan Administration</p> | |||
</footer> | |||
<div class="pages"></div> | |||
<script type="text/javascript">{% raw %} | |||
ready(); | |||
{% endraw %}</script> | |||
</body> | |||
</html> | |||
{% endfilter %} |
@@ -0,0 +1,54 @@ | |||
<?php | |||
$name = $contactmethod = $email = $application = $antispam = $displaymessage = ""; | |||
require '/var/www/html/inc/functions.php'; | |||
if (isset ($_POST["antispam"])){ | |||
if ($_POST["antispam"] == "DUCK"){ | |||
$namecheck = ! empty($_POST["name"]); | |||
$contactmethodcheck = $_POST["contactmethod"] == "email"; | |||
$emailcheck = ! empty($_POST["email"]); | |||
$emailischecked = $contactmethodcheck ? $emailcheck : true; | |||
if ($emailischecked && $namecheck){ | |||
$name = $_POST["name"]; | |||
$contactmethod = $_POST["contactmethod"]; | |||
$email = $_POST["email"]; | |||
$application = $_POST["application"]; | |||
$antispam = $_POST["antispam"]; | |||
$to = "admin@lainchan.org"; | |||
$subject = "Lainchan.org Staff Application for " . $name; | |||
$message = "Name: " . $name . "\r\n"; | |||
$message .= "Contact method: " . $contactmethod . "\r\n"; | |||
$message .= $application; | |||
$message = wordwrap($message, 70, "\r\n"); | |||
$source = $emailcheck ? $email : $to; | |||
$headers = 'From: ' . $source . "\r\n" . | |||
'Reply-To: ' . $source . "\r\n" . | |||
'X-Mailer: PHP/' . phpversion(); | |||
$sent = mail($to, $subject, $message, $headers); | |||
$sentmessage = $sent ? "was submitted successfully.</p>\r\n" : "was unable to be submitted.</p>\r\n"; | |||
$displaymessage = "<p style=\"text-align:center;\"> Your staff application " . $sentmessage; | |||
} | |||
} | |||
else | |||
{ | |||
$displaymessage = "<p style=\"text-align:center;\">ANTISPAM VALUE INCORRECT</p>\r\n"; | |||
} | |||
} | |||
else { | |||
$displaymessage = "<p style=\"text-align:center;\">ANTISPAM NOT SET</p>\r\n"; | |||
} | |||
$displaymessage .= '<span style="text-align:center; display: block;" >[ <a href="https://lainchan.org/"> Return Home </a> ]</span>'; | |||
echo Element('page.html', array( | |||
'index' => $config['root'], | |||
'title' => _('Staff Application'), | |||
'config' => $config, | |||
'boardlist' => createBoardlist(isset($mod) ? $mod : false), | |||
'body' => $displaymessage, | |||
) | |||
); | |||
?> |
@@ -0,0 +1,40 @@ | |||
<?php | |||
require 'info.php'; | |||
function staffapplication_build($action, $settings, $board) { | |||
// Possible values for $action: | |||
// - all (rebuild everything, initialization) | |||
// - news (news has been updated) | |||
// - boards (board list changed) | |||
StaffApplication::build($action, $settings); | |||
} | |||
// Wrap functions in a class so they don't interfere with normal Tinyboard operations | |||
class StaffApplication { | |||
public static function build($action, $settings) { | |||
global $config; | |||
if ($action == 'all' || $action == 'news') | |||
file_write($config['dir']['home'] . $settings['file'], StaffApplication::htmlpage($settings)); | |||
file_write($config['dir']['home'] . "staffapplication.php", StaffApplication::phppage($settings)); | |||
} | |||
// Build staff application page | |||
public static function htmlpage($settings) { | |||
global $config; | |||
return Element('themes/staffapplication/staffapplication.html', Array( | |||
'settings' => $settings, | |||
'config' => $config, | |||
'boardlist' => createBoardlist() | |||
)); | |||
} | |||
public static function phppage($settings) { | |||
global $config; | |||
$page = file_get_contents('templates/themes/staffapplication/staffapplicationpost.php'); | |||
return $page; | |||
} | |||
}; | |||
?> |
@@ -0,0 +1,55 @@ | |||
<?php | |||
$theme = array(); | |||
// Theme name | |||
$theme['name'] = 'Overboard (Ukko) 4'; | |||
// Description (you can use Tinyboard markup here) | |||
$theme['description'] = 'Board with threads and messages from all boards'; | |||
$theme['version'] = 'v0.2'; | |||
// Theme configuration | |||
$theme['config'] = array(); | |||
$theme['config'][] = array( | |||
'title' => 'Board name', | |||
'name' => 'title', | |||
'type' => 'text', | |||
'default' => 'Ukko' | |||
); | |||
$theme['config'][] = array( | |||
'title' => 'Board URI', | |||
'name' => 'uri', | |||
'type' => 'text', | |||
'default' => '*', | |||
'comment' => '(ukko for example)' | |||
); | |||
$theme['config'][] = array( | |||
'title' => 'Subtitle', | |||
'name' => 'subtitle', | |||
'type' => 'text', | |||
'comment' => '(%s = thread limit. for example "%s freshly bumped threads")' | |||
); | |||
$theme['config'][] = array( | |||
'title' => 'Excluded boards', | |||
'name' => 'exclude', | |||
'type' => 'text', | |||
'comment' => '(space seperated)' | |||
); | |||
$theme['config'][] = array( | |||
'title' => 'Number of threads', | |||
'name' => 'thread_limit', | |||
'type' => 'text', | |||
'default' => '15', | |||
); | |||
// Unique function name for building everything | |||
$theme['build_function'] = 'ukko4_build'; | |||
$theme['install_callback'] = 'ukko4_install'; | |||
if(!function_exists('ukko4_install')) { | |||
function ukko4_install($settings) { | |||
if (!file_exists($settings['uri'])) | |||
@mkdir($settings['uri'], 0777) or error("Couldn't create " . $settings['uri'] . ". Check permissions.", true); | |||
file_write($settings['uri'] . '/ukko.js', Element('themes/ukko/ukko.js', array())); | |||
} | |||
} | |||
@@ -0,0 +1,162 @@ | |||
<?php | |||
require 'info.php'; | |||
function ukko4_build($action, $settings) { | |||
global $config; | |||
$ukko = new ukko(); | |||
$ukko->settings = $settings; | |||
if (! ($action == 'all' || $action == 'post' || $action == 'post-thread' || $action == 'post-delete')) { | |||
return; | |||
} | |||
$action = generation_strategy('sb_ukko', array()); | |||
if ($action == 'delete') { | |||
file_unlink($settings['uri'] . '/index.html'); | |||
if ($config['api']['enabled']) { | |||
$jsonFilename = $settings['uri'] . '/0.json'; | |||
file_unlink($jsonFilename); | |||
$jsonFilename = $settings['uri'] . '/catalog.json'; | |||
file_unlink($jsonFilename); | |||
$jsonFilename = $settings['uri'] . '/threads.json'; | |||
file_unlink($jsonFilename); | |||
} | |||
} | |||
elseif ($action == 'rebuild') { | |||
file_write($settings['uri'] . '/index.html', $ukko->build()); | |||
} | |||
} | |||
class ukko4 { | |||
public $settings; | |||
public function build($mod = false) { | |||
global $config; | |||
$boards = listBoards(); | |||
$body = ''; | |||
$overflow = array(); | |||
$board = array( | |||
'dir' => $this->settings['uri'] . "/", | |||
'url' => $this->settings['uri'], | |||
'uri' => $this->settings['uri'], | |||
'name' => $this->settings['title'], | |||
'title' => sprintf($this->settings['subtitle'], $this->settings['thread_limit']) | |||
); | |||
$boardsforukko = array(); | |||
$query = ''; | |||
foreach($boards as &$_board) { | |||
if(in_array($_board['uri'], explode(' ', $this->settings['exclude']))) | |||
continue; | |||
$query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `thread` IS NULL UNION ALL ", $_board['uri'], $_board['uri']); | |||
array_push($boardsforukko,$_board); | |||
} | |||
$query = preg_replace('/UNION ALL $/', 'ORDER BY `bump` DESC', $query); | |||
$query = query($query) or error(db_error()); | |||
$count = 0; | |||
$threads = array(); | |||
if ($config['api']['enabled']) { | |||
$apithreads = array(); | |||
} | |||
while($post = $query->fetch()) { | |||
if(!isset($threads[$post['board']])) { | |||
$threads[$post['board']] = 1; | |||
} else { | |||
$threads[$post['board']] += 1; | |||
} | |||
if($count < $this->settings['thread_limit']) { | |||
openBoard($post['board']); | |||
$thread = new Thread($post, $mod ? '?/' : $config['root'], $mod); | |||
$posts = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `sticky` DESC, `id` DESC LIMIT :limit", $post['board'])); | |||
$posts->bindValue(':id', $post['id']); | |||
$posts->bindValue(':limit', ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']), PDO::PARAM_INT); | |||
$posts->execute() or error(db_error($posts)); | |||
$num_images = 0; | |||
while ($po = $posts->fetch()) { | |||
if ($po['files']) | |||
$num_images++; | |||
$post2 = new Post($po, $mod ? '?/' : $config['root'], $mod); | |||
$thread->add($post2); | |||
} | |||
if ($posts->rowCount() == ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) { | |||
$ct = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM ``posts_%s`` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `files` IS NOT NULL AND `thread` = :thread", $post['board'], $post['board'])); | |||
$ct->bindValue(':thread', $post['id'], PDO::PARAM_INT); | |||
$ct->execute() or error(db_error($count)); | |||
$c = $ct->fetch(); | |||
$thread->omitted = $c['num'] - ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']); | |||
$c = $ct->fetch(); | |||
$thread->omitted_images = $c['num'] - $num_images; | |||
} | |||
$thread->posts = array_reverse($thread->posts); | |||
$body .= '<h2><a href="' . $config['root'] . $post['board'] . '">/' . $post['board'] . '/</a></h2>'; | |||
$body .= $thread->build(true); | |||
if ($config['api']['enabled']) { | |||
array_push($apithreads,$thread); | |||
} | |||
} else { | |||
$page = 'index'; | |||
if(floor($threads[$post['board']] / $config['threads_per_page']) > 0) { | |||
$page = floor($threads[$post['board']] / $config['threads_per_page']) + 1; | |||
} | |||
$overflow[] = array('id' => $post['id'], 'board' => $post['board'], 'page' => $page . '.html'); | |||
} | |||
$count += 1; | |||
} | |||
$body .= '<script> var overflow = ' . json_encode($overflow) . '</script>'; | |||
$body .= '<script type="text/javascript" src="/'.$this->settings['uri'].'/ukko.js"></script>'; | |||
// json api | |||
if ($config['api']['enabled']) { | |||
require_once __DIR__. '/../../../inc/api.php'; | |||
$api = new Api(); | |||
$jsonFilename = $board['dir'] . '0.json'; | |||
$json = json_encode($api->translatePage($apithreads)); | |||
file_write($jsonFilename, $json); | |||
$catalog = array(); | |||
$catalog[0] = $apithreads; | |||
$json = json_encode($api->translateCatalog($catalog)); | |||
$jsonFilename = $board['dir'] . 'catalog.json'; | |||
file_write($jsonFilename, $json); | |||
$json = json_encode($api->translateCatalog($catalog, true)); | |||
$jsonFilename = $board['dir'] . 'threads.json'; | |||
file_write($jsonFilename, $json); | |||
} | |||
$antibot = null; | |||
if (!$antibot) { | |||
$antibot = create_antibot($board['uri']); | |||
} | |||
$antibot->reset(); | |||
return Element('index.html', array( | |||
'config' => $config, | |||
'board' => $board, | |||
'no_post_form' => $config['overboard_post_form'] ? false : true, | |||
'body' => $body, | |||
'mod' => $mod, | |||
'boardlist' => createBoardlist($mod), | |||
'boards' => $boardsforukko, | |||
'antibot' => $antibot ) | |||
); | |||
} | |||
}; | |||
?> |
@@ -0,0 +1,116 @@ | |||
(function(){ | |||
var cache = new Array(), | |||
thread = false, | |||
loading = false, | |||
ukkotimer = false; | |||
if (localStorage.hiddenboards === undefined) { | |||
localStorage.hiddenboards = "{}"; | |||
} | |||
// Load data from HTML5 localStorage | |||
var hiddenboards = JSON.parse(localStorage.hiddenboards); | |||
var storeboards = function() { | |||
localStorage.hiddenboards = JSON.stringify(hiddenboards); | |||
}; | |||
$(document).ready(function() { | |||
var addukkohide = function() { | |||
var ukkohide = $('<a href="javascript:void(0);" class="unimportant ukkohide"></a>'); | |||
var board = $(this).next().data("board"); | |||
var hr = $("<hr />"); | |||
$(this).append(ukkohide); | |||
$(this).append(hr); | |||
if (hiddenboards[board] !== true) { | |||
ukkohide.html(_("(hide threads from this board)")); | |||
hr.hide(); | |||
} | |||
else { | |||
ukkohide.html(_("(show threads from this board)")); | |||
$(this).next().hide(); | |||
} | |||
ukkohide.click(function() { | |||
hiddenboards[board] = (hiddenboards[board] !== true); | |||
if (hiddenboards[board] !== true) { | |||
$('[data-board="'+board+'"]:not([data-cached="yes"])').show().prev(). | |||
find('.ukkohide').html(_("(hide threads from this board)")). | |||
parent().find('hr').hide(); | |||
} | |||
else { | |||
$('[data-board="'+board+'"]:not([data-cached="yes"])').hide().prev(). | |||
find('.ukkohide').html(_("(show threads from this board)")) | |||
.parent().find('hr').show(); | |||
} | |||
storeboards(); | |||
return false; | |||
}); | |||
}; | |||
$("h2").each(addukkohide); | |||
$('.pages').hide(); | |||
var loadnext = function() { | |||
if (overflow.length == 0) { | |||
$('.pages').show().html(_("No more threads to display")); | |||
} | |||
while($(window).scrollTop() + $(window).height() + 1000 > $(document).height() && !loading && overflow.length > 0) { | |||
var page = modRoot + overflow[0].board + '/' + overflow[0].page; | |||
thread = $('div#thread_' + overflow[0].id + '[data-board="' + overflow[0].board + '"]'); | |||
if (thread.length > 0 && thread.attr("data-cached") !== 'yes') { // already present | |||
overflow.shift(); | |||
continue; | |||
} | |||
var boardheader = $('<h2><a href="/' + overflow[0].board + '/">/' + overflow[0].board + '/</a> </h2>'); | |||
if($.inArray(page, cache) != -1) { | |||
if (thread.length > 0) { | |||
$('div[id*="thread_"]').last().after(thread.attr('data-board', overflow[0].board).attr("data-cached", "no").css('display', 'block')); | |||
boardheader.insertBefore(thread); | |||
addukkohide.call(boardheader); | |||
$(document).trigger('new_post', thread); | |||
} | |||
overflow.shift(); | |||
} else { | |||
loading = true; | |||
$('.pages').show().html(_("Loading...")); | |||
$.get(page, function(data) { | |||
cache.push(page); | |||
$(data).find('div[id*="thread_"]').each(function() { | |||
var checkout = $(this).attr('id').replace('thread_', ''); | |||
if ($('div#thread_' + checkout + '[data-board="' + overflow[0].board + '"]').length == 0) { | |||
$('form[name="postcontrols"]').prepend($(this).css('display', 'none').attr("data-cached", "yes").attr('data-board', overflow[0].board)); | |||
} | |||
}); | |||
thread = $('div#thread_' + overflow[0].id + '[data-board="' + overflow[0].board + '"][data-cached="yes"]'); | |||
if(thread.length > 0) { | |||
$('div[id*="thread_"]').last().after(thread.attr('data-board', overflow[0].board).attr("data-cached", "no").css('display', 'block')); | |||
boardheader.insertBefore(thread); | |||
addukkohide.call(boardheader); | |||
$(document).trigger('new_post', thread); | |||
} | |||
overflow.shift(); | |||
loading = false; | |||
$('.pages').hide().html(""); | |||
}); | |||
break; | |||
} | |||
} | |||
clearTimeout(ukkotimer); | |||
ukkotimer = setTimeout(loadnext, 1000); | |||
}; | |||
$(window).on('scroll', loadnext); | |||
ukkotimer = setTimeout(loadnext, 1000); | |||
}); | |||
})(); |