Initial commit

This commit is contained in:
nils 2020-11-23 16:33:49 +01:00 committed by Nils Otterpohl
commit ffc71865b7
15 changed files with 1228 additions and 0 deletions

119
LICENSE Normal file
View File

@ -0,0 +1,119 @@
Creative Commons Legal Code
CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES
NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE
AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION
ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE
OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS
LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION
OR WORKS PROVIDED HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer exclusive
Copyright and Related Rights (defined below) upon the creator and subsequent
owner(s) (each and all, an "owner") of an original work of authorship and/or
a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later claims
of infringement build upon, modify, incorporate in other works, reuse and
redistribute as freely as possible in any form whatsoever and for any purposes,
including without limitation commercial purposes. These owners may contribute
to the Commons to promote the ideal of a free culture and the further production
of creative, cultural and scientific works, or to gain reputation or greater
distribution for their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with
a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or
her Copyright and Related Rights in the Work and the meaning and intended
legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be protected
by copyright and related or neighboring rights ("Copyright and Related Rights").
Copyright and Related Rights include, but are not limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work, subject
to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal protection
of databases, and under any national implementation thereof, including any
amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time extensions),
(iii) in any current or future medium and for any number of copies, and (iv)
for any purpose whatsoever, including without limitation commercial, advertising
or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the
benefit of each member of the public at large and to the detriment of Affirmer's
heirs and successors, fully intending that such Waiver shall not be subject
to revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account Affirmer's
express Statement of Purpose. In addition, to the extent the Waiver is so
judged Affirmer hereby grants to each affected person a royalty-free, non
transferable, non sublicensable, non exclusive, irrevocable and unconditional
license to exercise Affirmer's Copyright and Related Rights in the Work (i)
in all territories worldwide, (ii) for the maximum duration provided by applicable
law or treaty (including future time extensions), (iii) in any current or
future medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional purposes
(the "License"). The License shall be deemed effective as of the date CC0
was applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder of
the License, and in such case Affirmer hereby affirms that he or she will
not (i) exercise any of his or her remaining Copyright and Related Rights
in the Work or (ii) assert any associated claims and causes of action with
respect to the Work, in either case contrary to Affirmer's express Statement
of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered,
licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or other
defects, accuracy, or the present or absence of errors, whether or not discoverable,
all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims
responsibility for obtaining any necessary consents, permissions or other
rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a party
to this document and has no duty or obligation with respect to this CC0 or
use of the Work.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Website
Website der Ortsfeuerwehr Braunschweig Innenstadt

45
ajax/artikel.php Normal file
View File

@ -0,0 +1,45 @@
<?php #ajax/get.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../conf.php";
$article = $_POST["article"] ?? "Empty";
$sections = array();
if ($stmt = $mysqli->prepare("select name from sections s where article = ? order by ord asc")) {
$stmt->bind_param("s", $article);
$stmt->execute();
$stmt->bind_result($name);
while ($stmt->fetch()) {
$sections[] = $name;
}
}
$name = isset($_POST["section"]) && $_POST["section"]!="" ? $_POST["section"] : ($sections[0] ?? "Empty");
$content = "Hallo";
if ($stmt = $mysqli->prepare("select content from sections s where name = ? and article = ?")) {
$stmt->bind_param("ss", $name, $article);
$stmt->execute();
$stmt->bind_result($content);
$stmt->fetch();
}
$id = preg_replace('/\s+/', '', $article."_".$name);
?>
<footer>
<h1><?=$article;?></h1>
<?php if (count($sections)>1) { ?>
<ul>
<?php foreach ($sections as $sec) { ?>
<a href='javascript:loadArticle("<?=basename(__FILE__);?>", "<?=$article;?>", "<?=$sec;?>")'<?=($sec==$name ? " class='current'" : "");?>><li><?=$sec;?></li></a>
<?php } ?>
</ul>
<?php } ?>
</footer>
<section id='<?=$id;?>'><?=$content;?></section>

170
ajax/bericht.php Normal file
View File

@ -0,0 +1,170 @@
<?php #ajax/bericht.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../conf.php";
$years = array();
$query = "select distinct year(created_time) y from `facebook_posts` order by y desc";
if ($res = $mysqli->query($query)) {
while ($row = $res->fetch_assoc()) {
$years[] = $row["y"];
}
} else {
echo $mysqli->error."<br />".$query;
}
$year = $_POST["section"]["year"] ?? ($years[0] ?? date("Y"));
$prev = array("", "", "");
$next = array("", "", "");
$article = $_POST["article"] ?? "Empty";
$title = "";
$content = "";
$additional = "";
// Get post ID
$postID = 0;
if (isset($_POST["section"]["postID"]) && $_POST["section"]["postID"]!="") {
$postID = $_POST["section"]["postID"];
} else {
$res = $mysqli->query("select ID from facebook_posts where catid=1 and year(created_time) = ".$year." order by created_time desc limit 1");
if ($res->num_rows==1) {
$postID = $res->fetch_assoc()["ID"];
}
}
// Get post content to ID
$created_time = "";
$message = "";
$query = "select created_time,title,message from facebook_posts where ID = ?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param("i", $postID);
$stmt->execute();
$stmt->bind_result($created_time, $title, $message);
$stmt->fetch();
$stmt->close();
}
$header = $title." (".$created_time.")";
$content = nl2br($message);
// Get next and previous posts
$limit = 1;
$prev = array();
$query = "select ID, created_time, year(created_time) `year`, title, '<' `dir` from facebook_posts "
."where catid=1 and created_time>'".$created_time."' order by created_time asc limit ".$limit;
$res = $mysqli->query($query);
while ($row = $res->fetch_assoc()) {
$prev[] = $row;
}
if (count($prev)>1) {
$tmp = $prev[0];
$prev[0] = $prev[1];
$prev[1] = $tmp;
$prev[0]["dir"] = "<<";
}
$query = "select ID, created_time, year(created_time) `year`, title, '>' `dir` from facebook_posts where catid=1 and created_time<'".$created_time."' order by created_time desc limit ".$limit;
$res = $mysqli->query($query);
$next = array();
$first = true;
while ($row = $res->fetch_assoc()) {
$next[] = $row;
}
if (count($next)>1) {
$next[1]["dir"] = ">>";
}
// Get all posts of selected year
$all = array();
$query = "select ID, date_format(created_time, '%d.%m.') datum, title from facebook_posts "
."where catid=1 and year(created_time)='".$year."' order by created_time desc";
$res = $mysqli->query($query);
while ($row = $res->fetch_assoc()) {
$all[] = $row;
}
// Get shared links associated with the post
$query = "select unshimmed_url,caption from facebook_links where postID = ?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param("i", $postID);
$stmt->execute();
$stmt->bind_result($unshimmed_url, $caption);
while ($stmt->fetch()) {
$additional.= "<p>Geteilter Link: <a href='".$unshimmed_url."' target='_blank'>".$caption."</a></p>";
$content = trim(str_replace($unshimmed_url, "", $content));
}
$stmt->close();
}
// Get attached images and videos
$query = "select fbid,mimetype,ext,width,height,thumbext,twidth,theight from facebook_media where postID = ?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param("i", $postID);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows>0) {
$additional.= "<div id='gallery_".preg_replace('/\s+/', '', $article)."' class='gallery'>";
while ($row = $res->fetch_assoc()) {
switch (explode("/", $row["mimetype"])[0]) {
case "youtube":
$additional.= "<iframe type='text/html' src='".$row["ext"]."'></iframe>";
break;
case "video":
$additional.= "<video height='".$row["height"]."' width='".$row["width"]."' poster='/videos/fb/of/thumbs/"
.$row["fbid"].".".$row["thumbext"]."' preload='none' muted controls><source src='/videos/fb/of/".$row["fbid"]."."
.$row["ext"]."' type='".$row["mimetype"]."'></video>";
break;
case "image":
$additional.= "<a href='/images/fb/of/".$row["fbid"].".".$row["ext"]."' target='_blank'><img src='/images/fb/of/";
if (""!=$row["thumbext"]) {
$additional.= "thumbs/".$row["fbid"].".".$row["thumbext"];
} else {
$additional.= $row["fbid"].".".$row["ext"];
}
$additional.= "'></a>";
break;
}
}
$additional.= "</div>";
}
$stmt->close();
}
$id = preg_replace('/\s+/', '', $article."_".$postID);
?>
<footer>
<h1><?=$article;?></h1>
<ul>
<select onchange="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': this.options[this.selectedIndex].value})">
<?php foreach ($years as $y) { ?>
<option<?=($year==$y ? " selected" : "");?>><?=$y;?></option>
<?php } ?>
</select>
<select onchange="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': <?=$year;?>, 'postID': this.options[this.selectedIndex].value})">
<?php foreach ($all as $a) { ?>
<option value='<?=$a["ID"];?>'<?=($postID==$a["ID"] ? " selected" : "");?>>
<?=$a["datum"].(""==$a["title"] ? "" : ": ".$a["title"]);?>
</option>
<?php } ?>
</select>
</ul>
</footer>
<section id='<?=$id;?>'>
<p><?=$content;?></p><?=$additional;?>
</section>
<footer>
<ul>
<?php foreach ($prev as $link) { ?>
<a href="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': <?=$link["year"];?>, 'postID': <?=$link["ID"];?>})"><li>
<?=$link["dir"];?> <?=(""==$link["title"] ? $link["created_time"] : $link["title"]);?>
</li></a>
<?php } ?>
<?php foreach ($next as $link) { ?>
<a href="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': <?=$link["year"];?>, 'postID': <?=$link["ID"];?>})"><li>
<?=(""==$link["title"] ? $link["created_time"] : $link["title"]);?> <?=$link["dir"];?>
</li></a>
<?php } ?>
</ul>
</footer>

85
ajax/einsaetze.php Normal file
View File

@ -0,0 +1,85 @@
<?php #ajax/einsaetze.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../../db/conf.php";
$article = $_POST["article"] ?? "Empty";
$years = array();
$query = "select distinct year(Alarmierungszeit) y from `Einsätze` order by y desc";
if ($res = $mysqli->query($query)) {
while ($row = $res->fetch_assoc()) {
$years[] = $row["y"];
}
} else {
echo $mysqli->error."<br />".$query;
}
$year = $_POST["section"]["year"] ?? ($years[0] ?? date("Y"));
$quarters = array(1, 2, 3, 4);
$quarter = $quarters[0];
if (isset($_POST["section"]["quarter"])) {
$quarter = $_POST["section"]["quarter"];
} else {
$query = "select quarter(Alarmierungszeit) q from `Einsätze` order by Alarmierungszeit desc limit 1";
if ($res = $mysqli->query($query)) {
if (1==$res->num_rows) {
$quarter = $res->fetch_row()[0];
} else {
$quarter = ceil(date("n")/3);
}
} else {
echo $mysqli->error."<br />".$query;
}
}
$query = "select date_format(b.Alarmierungszeit, '%d.%m.%Y %H:%i') Alarmierungszeit, date_format(b.Einsatzende, '%d.%m.%Y %H:%i') Einsatzende, b.Adresse, b.Zusammenfassung, a.Name aname, k.Farbe from Einsätze b "
."left join Einsatzarten a on a.ID=b.Einsatzart "
."left join Einsatzkategorien k on k.ID=a.Einsatzkategorie "
."where year(Alarmierungszeit) = ? and quarter(Alarmierungszeit) = ? "
."order by b.Alarmierungszeit desc";
$deployments = array();
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param("ii", $year, $quarter);
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$deployments[] = $row;
}
$stmt->close();
}
$id = preg_replace('/\s+/', '', $article."_".$year."-Q".$quarter);
?>
<footer>
<h1><?=$article;?></h1>
<?php if (count($years)>0) { ?>
<ul>
<select onchange="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': this.options[this.selectedIndex].value, 'quarter': <?=$quarter;?>})">
<?php foreach ($years as $y) { ?>
<option<?=($year==$y ? " selected" : "");?>><?=$y;?></option>
<?php } ?>
</select>
<select onchange="javascript:loadArticle('<?=basename(__FILE__);?>', '<?=$article;?>', {'year': <?=$year;?>, 'quarter': this.options[this.selectedIndex].value})">
<?php foreach ($quarters as $q) { ?>
<option value="<?=$q;?>"<?=($quarter==$q ? " selected" : "");?>>Q<?=$q;?></option>
<?php } ?>
</select>
</ul>
<?php } ?>
</footer>
<section id="<?=$id;?>">
<ul class="listprops">
<?php foreach ($deployments as $dep) { ?>
<li style="border-color: <?=$dep["Farbe"];?>">
<?=$dep["Alarmierungszeit"];?><?=("00.00.0000 00:00"!=$dep["Einsatzende"] ? " bis ".$dep["Einsatzende"] : "");?>: <i><?=$dep["Adresse"];?></i><br /><b><?=($dep["Zusammenfassung"]!="" ? $dep["Zusammenfassung"] : "&nbsp;");?></b>
<div class="tooltip">
<i><?=$dep["aname"];?></i>
</div>
</li>
<?php } ?>
</ul>
</section>

53
ajax/gallerie.php Normal file
View File

@ -0,0 +1,53 @@
<?php #ajax/gallerie.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../conf.php";
$article = $_POST["article"] ?? "Empty";
$galleries = array();
if ($stmt = $mysqli->prepare("select name,previewheight,previewpic from galleries g where article = ? order by ord asc")) {
$stmt->bind_param("s", $article);
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$galleries[] = $row;
}
$stmt->close();
}
$name = isset($_POST["section"]) && $_POST["section"]!="" ? $_POST["section"] : ($galleries[0]["name"] ?? "Empty");
$description = "";
$htmlcache = "";
if ($stmt = $mysqli->prepare("select description,htmlcache from galleries g where name = ? and article = ?")) {
$stmt->bind_param("ss", $name, $article);
$stmt->execute();
$stmt->bind_result($description, $htmlcache);
$stmt->fetch();
}
$id = preg_replace('/\s+/', '', $article."_".$name);
?>
<footer>
<h1><?=$article;?></h1>
<?php if (count($galleries)>1) { ?>
<ul>
<?php foreach ($galleries as $gal) { ?>
<a href='javascript:loadArticle("<?=basename(__FILE__);?>", "<?=$article;?>", "<?=$gal["name"];?>")'<?=($gal["name"]==$name ? " class='current'" : "");?>><li>
<?php if ($gal["previewheight"]>0 && $gal["previewpic"]!="") { ?>
<img src="/images/gallerien/<?=$gal["previewpic"];?>" title="<?=$gal["name"];?>" /><div><?=$gal["name"];?></div>
<?php } else { ?>
<?=$gal["name"];?>
<?php } ?>
</li></a>
<?php } ?>
</ul>
<?php } ?>
</footer>
<section id='<?=$id;?>'><?=$description.$htmlcache;?></section>

61
ajax/statistik.php Normal file
View File

@ -0,0 +1,61 @@
<?php #ajax/get.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../../db/conf.php";
$query = "select distinct year(Alarmierungszeit) sy from Einsätze order by sy desc";
$res = $mysqli->query($query);
$years = array();
while ($year = $res->fetch_assoc()) {
$years[] = $year["sy"];
}
$name = isset($_POST["section"]) && $_POST["section"]!="" ? $_POST["section"] : ($years[0] ?? 2017);
$table = "<table><tr><th>Einsatzart</th><th>Anzahl Einsätze</th></tr><tr><td colspan=2>&nbsp;</td></tr>";
$query = "select count(*) c,k.Name kn,k.Farbe,a.Name an from Einsätze b "
."left join Einsatzarten a on a.ID=b.Einsatzart "
."left join Einsatzkategorien k on k.ID=a.Einsatzkategorie "
."where year(Alarmierungszeit) = ? group by b.Einsatzart order by k.ID asc ";
$gesamt = array("Gesamt" => 0);
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param("i", $name);
$stmt->execute();
$res = $stmt->get_result();
while ($stat = $res->fetch_assoc()) {
$table.= "<tr style='background-color: ".$stat["Farbe"].";'><td>".$stat["an"]."</td><td>".$stat["c"]."</td></tr>";
$gesamt["Gesamt"]+= $stat["c"];
if (!isset($gesamt[$stat["kn"]])) {
$gesamt[$stat["kn"]] = 0;
}
$gesamt[$stat["kn"]]+= $stat["c"];
}
} else {
$table.= "<tr><td colspan=2>".$mysqli->error."</td></tr>";
}
$table.= "<tr><td colspan=2>&nbsp;</td></tr><tr><th colspan=2>Summen</th></tr><tr><td colspan=2>&nbsp;</td></tr>";
foreach ($gesamt as $k => $v) {
$table.= "<tr><td>".$k."</td><td>".$v."</td></tr>";
}
$table.= "</table>";
$article = $_POST["article"] ?? "Empty";
$id = preg_replace('/\s+/', '', $article."_".$name);
?>
<footer>
<?php if (count($years)>1) { ?>
<h1><?=$article;?></h1>
<ul>
<?php foreach ($years as $y) { ?>
<a href='javascript:loadArticle("<?=basename(__FILE__);?>", "<?=$article;?>", "<?=$y;?>")'<?=($y==$name ? " class='current'" : "");?>><li><?=$y;?></li></a>
<?php } ?>
</ul>
<?php } ?>
</footer>
<section id='<?=$id;?>'><?=$table;?></section>

51
ajax/termine.php Normal file
View File

@ -0,0 +1,51 @@
<?php #ajax/termine.php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once "../../db/conf.php";
$article = $_POST["article"] ?? "Empty";
$query = "select date_format(t.Beginn, '%d.%m.%Y %H:%i') Beginn, "
."IF(date_format(t.Beginn, '%Y-%m-%d')=date_format(t.Ende, '%Y-%m-%d'), "
." date_format(t.Ende, '%H:%i'), "
." date_format(t.Ende, '%d.%m.%Y %H:%i')"
.") Ende, IF(t.Ort is NULL or t.Ort='FWH', 'Feuerwehrhaus', t.Ort) Ort, t.Thema, "
."a.Name, a.Präfix, a.Beschreibung, a.Farbe from Termine t "
."left join Terminarten a on a.ID=t.Terminart "
."left join Dienstpläne d on d.ID=t.Dienstplan "
."left join Abteilungen b on b.ID=d.Abteilung "
."where b.Kürzel LIKE 'OF%' and IFNULL(t.Ende, t.Beginn) >= NOW() - interval 1 month and t.Beginn < NOW() + interval 2 year "
."order by t.Beginn asc";
$termine = array();
if ($stmt = $mysqli->prepare($query)) {
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$termine[] = $row;
}
$stmt->close();
}
$id = preg_replace('/\s+/', '', $article);
?>
<footer>
<h1>Dienstplan</h1>
</footer>
<section id="<?=$id;?>">
<ul class="listprops">
<?php foreach ($termine as $tmn) { ?>
<li style="border-color: <?=$tmn["Farbe"];?>">
<?=$tmn["Beginn"];?> bis <?=$tmn["Ende"];?><br />
<?=($tmn["Präfix"]!="" ? "[".$tmn["Präfix"]."] " : "");?><b><?=($tmn["Thema"]!="" ? $tmn["Thema"] : "&nbsp;");?></b><br />
<i><?=$tmn["Ort"];?></i>
<div class="tooltip">
<b><?=$tmn["Name"];?></b><br />
<i><?=$tmn["Beschreibung"];?></i>
</div>
</li>
<?php } ?>
</ul>
</section>

11
conf.php.dist Normal file
View File

@ -0,0 +1,11 @@
<?php #conf.php
$DBHOST = "localhost";
$DBUSER = "";
$DBPASS = "";
$DBNAME = "";
$mysqli = new mysqli($DBHOST, $DBUSER, $DBPASS, $DBNAME);
$mysqli->set_charset("utf8mb4");
?>

195
database_structure.sql Normal file
View File

@ -0,0 +1,195 @@
--
-- Table structure for table `articles`
--
CREATE TABLE `articles` (
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`page` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`ord` int(11) NOT NULL DEFAULT 0,
`src` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `facebook_links`
--
CREATE TABLE `facebook_links` (
`postID` int(10) UNSIGNED NOT NULL,
`unshimmed_url` varchar(250) NOT NULL,
`caption` varchar(250) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
--
-- Table structure for table `facebook_media`
--
CREATE TABLE `facebook_media` (
`fbid` bigint(20) UNSIGNED NOT NULL,
`postID` int(10) UNSIGNED DEFAULT NULL,
`mimetype` varchar(50) DEFAULT NULL,
`ext` varchar(250) DEFAULT NULL,
`width` smallint(5) UNSIGNED DEFAULT NULL,
`height` smallint(5) UNSIGNED DEFAULT NULL,
`thumbext` varchar(10) DEFAULT NULL,
`twidth` smallint(5) UNSIGNED DEFAULT NULL,
`theight` smallint(5) UNSIGNED DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
--
-- Table structure for table `facebook_posts`
--
CREATE TABLE `facebook_posts` (
`ID` int(10) UNSIGNED NOT NULL,
`fbid` bigint(20) UNSIGNED NOT NULL,
`catid` int(11) NOT NULL,
`created_time` datetime NOT NULL,
`permalink_url` varchar(250) NOT NULL,
`title` varchar(250) NOT NULL,
`message` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='id,created_time,type,status_type,permalink_url,message,link,name,picture,full_picture,object_id,parent_id,source,attachments{url,type,subattachments{type,media}}';
-- --------------------------------------------------------
--
-- Table structure for table `galleries`
--
CREATE TABLE `galleries` (
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`article` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`ord` int(11) NOT NULL,
`path` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
`description` text COLLATE utf8mb4_unicode_ci NOT NULL,
`thumbheight` smallint(5) UNSIGNED NOT NULL DEFAULT 100,
`previewheight` smallint(5) UNSIGNED NOT NULL DEFAULT 100,
`previewpic` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
`htmlcache` text COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `pages`
--
CREATE TABLE `pages` (
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`ord` int(11) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `sections`
--
CREATE TABLE `sections` (
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`article` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`ord` int(11) NOT NULL,
`content` text COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `articles`
--
ALTER TABLE `articles`
ADD PRIMARY KEY (`name`),
ADD KEY `src` (`src`),
ADD KEY `fk_sections_page` (`page`);
--
-- Indexes for table `facebook_links`
--
ALTER TABLE `facebook_links`
ADD PRIMARY KEY (`postID`,`unshimmed_url`);
--
-- Indexes for table `facebook_media`
--
ALTER TABLE `facebook_media`
ADD PRIMARY KEY (`fbid`),
ADD KEY `fk_fbmedia_post` (`postID`);
--
-- Indexes for table `facebook_posts`
--
ALTER TABLE `facebook_posts`
ADD PRIMARY KEY (`ID`);
--
-- Indexes for table `galleries`
--
ALTER TABLE `galleries`
ADD PRIMARY KEY (`name`) USING BTREE,
ADD KEY `fk_galleries_article` (`article`) USING BTREE;
--
-- Indexes for table `pages`
--
ALTER TABLE `pages`
ADD PRIMARY KEY (`name`);
--
-- Indexes for table `sections`
--
ALTER TABLE `sections`
ADD PRIMARY KEY (`name`,`article`) USING BTREE,
ADD KEY `fk_articles_section` (`article`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `facebook_posts`
--
ALTER TABLE `facebook_posts`
MODIFY `ID` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `articles`
--
ALTER TABLE `articles`
ADD CONSTRAINT `fk_sections_page` FOREIGN KEY (`page`) REFERENCES `pages` (`name`) ON UPDATE CASCADE;
--
-- Constraints for table `facebook_links`
--
ALTER TABLE `facebook_links`
ADD CONSTRAINT `fk_fblinks_post` FOREIGN KEY (`postID`) REFERENCES `facebook_posts` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `facebook_media`
--
ALTER TABLE `facebook_media`
ADD CONSTRAINT `fk_fbmedia_post` FOREIGN KEY (`postID`) REFERENCES `facebook_posts` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `galleries`
--
ALTER TABLE `galleries`
ADD CONSTRAINT `fk_galleries_article` FOREIGN KEY (`article`) REFERENCES `articles` (`name`) ON DELETE SET NULL ON UPDATE CASCADE;
--
-- Constraints for table `sections`
--
ALTER TABLE `sections`
ADD CONSTRAINT `fk_articles_section` FOREIGN KEY (`article`) REFERENCES `articles` (`name`) ON UPDATE CASCADE;
COMMIT;

6
ext/baguetteBox.min.css vendored Normal file
View File

@ -0,0 +1,6 @@
/*!
* baguetteBox.js
* @author feimosi
* @version 1.11.0
* @url https://github.com/feimosi/baguetteBox.js
*/#baguetteBox-overlay{display:none;opacity:0;position:fixed;overflow:hidden;top:0;left:0;width:100%;height:100%;z-index:1000000;background-color:#222;background-color:rgba(0,0,0,.8);-webkit-transition:opacity .5s ease;transition:opacity .5s ease}#baguetteBox-overlay.visible{opacity:1}#baguetteBox-overlay .full-image{display:inline-block;position:relative;width:100%;height:100%;text-align:center}#baguetteBox-overlay .full-image figure{display:inline;margin:0;height:100%}#baguetteBox-overlay .full-image img{display:inline-block;width:auto;height:auto;max-height:100%;max-width:100%;vertical-align:middle;-webkit-box-shadow:0 0 8px rgba(0,0,0,.6);-moz-box-shadow:0 0 8px rgba(0,0,0,.6);box-shadow:0 0 8px rgba(0,0,0,.6)}#baguetteBox-overlay .full-image figcaption{display:block;position:absolute;bottom:0;width:100%;text-align:center;line-height:1.8;white-space:normal;color:#ccc;background-color:#000;background-color:rgba(0,0,0,.6);font-family:sans-serif}#baguetteBox-overlay .full-image:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}#baguetteBox-slider{position:absolute;left:0;top:0;height:100%;width:100%;white-space:nowrap;-webkit-transition:left .4s ease,-webkit-transform .4s ease;transition:left .4s ease,-webkit-transform .4s ease;transition:left .4s ease,transform .4s ease;transition:left .4s ease,transform .4s ease,-webkit-transform .4s ease,-moz-transform .4s ease}#baguetteBox-slider.bounce-from-right{-webkit-animation:bounceFromRight .4s ease-out;animation:bounceFromRight .4s ease-out}#baguetteBox-slider.bounce-from-left{-webkit-animation:bounceFromLeft .4s ease-out;animation:bounceFromLeft .4s ease-out}@-webkit-keyframes bounceFromRight{0%,100%{margin-left:0}50%{margin-left:-30px}}@keyframes bounceFromRight{0%,100%{margin-left:0}50%{margin-left:-30px}}@-webkit-keyframes bounceFromLeft{0%,100%{margin-left:0}50%{margin-left:30px}}@keyframes bounceFromLeft{0%,100%{margin-left:0}50%{margin-left:30px}}.baguetteBox-button#next-button,.baguetteBox-button#previous-button{top:50%;top:calc(50% - 30px);width:44px;height:60px}.baguetteBox-button{position:absolute;cursor:pointer;outline:0;padding:0;margin:0;border:0;-moz-border-radius:15%;border-radius:15%;background-color:#323232;background-color:rgba(50,50,50,.5);color:#ddd;font:1.6em sans-serif;-webkit-transition:background-color .4s ease;transition:background-color .4s ease}.baguetteBox-button:focus,.baguetteBox-button:hover{background-color:rgba(50,50,50,.9)}.baguetteBox-button#next-button{right:2%}.baguetteBox-button#previous-button{left:2%}.baguetteBox-button#close-button{top:20px;right:2%;right:calc(2% + 6px);width:30px;height:30px}.baguetteBox-button svg{position:absolute;left:0;top:0}.baguetteBox-spinner{width:40px;height:40px;display:inline-block;position:absolute;top:50%;left:50%;margin-top:-20px;margin-left:-20px}.baguetteBox-double-bounce1,.baguetteBox-double-bounce2{width:100%;height:100%;-moz-border-radius:50%;border-radius:50%;background-color:#fff;opacity:.6;position:absolute;top:0;left:0;-webkit-animation:bounce 2s infinite ease-in-out;animation:bounce 2s infinite ease-in-out}.baguetteBox-double-bounce2{-webkit-animation-delay:-1s;animation-delay:-1s}@-webkit-keyframes bounce{0%,100%{-webkit-transform:scale(0);transform:scale(0)}50%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounce{0%,100%{-webkit-transform:scale(0);-moz-transform:scale(0);transform:scale(0)}50%{-webkit-transform:scale(1);-moz-transform:scale(1);transform:scale(1)}}

7
ext/baguetteBox.min.js vendored Normal file

File diff suppressed because one or more lines are too long

75
index.php Normal file
View File

@ -0,0 +1,75 @@
<!--?xml version="1.0" encoding="utf-8"?-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de-de" dir="ltr" lang="de-de">
<?php
include "conf.php";
$res = $mysqli->query("select * from pages order by ord asc");
$page = $_GET["p"] ?? "";
$nav = "";
if ($res->num_rows>1) {
$nav = "<ul>";
while ($pages = $res->fetch_assoc()) {
if (""==$page) {
$page = $pages["name"];
}
$nav.= "<a class='".($page==$pages["name"] ? "current" : "")."' href='?p=".$pages["name"]."'><li>".$pages["name"]."</li></a>";
}
$nav.= "</ul>";
}
$headerclass = isset($_GET["p"]) ? "shortened" : "full";
if ($stmt = $mysqli->prepare("select * from articles where page = ? order by ord asc")) {
$stmt->bind_param("s", $page);
$stmt->execute();
$res = $stmt->get_result();
$back_white = "white";
$articles = "";
$calls = "";
while ($article = $res->fetch_assoc()) {
$articles.= "<article class='".$back_white."' id='".$article["name"]."'></article>\n";
$section = "";
if (is_array($_GET["a"][$article["name"]])) {
foreach ($_GET["a"][$article["name"]] as $key => $val) {
if (""!=$section)
$section.= ", ";
$section.= "'".$key."': ".$val;
}
$section = "{".$section."}";
} else {
$section = "'".($_GET["a"][$article["name"]] ?? "")."'";
}
$calls.= "loadArticle('".$article["src"]."', '".$article["name"]."', ".$section.", true);\n";
$back_white = ($back_white=="white" ? "gray" : "white");
}
}
?>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="author" content="Nils Otterpohl">
<title>Ortsfeuerwehr Braunschweig Innenstadt</title>
<link href="https://www.fw-innenstadt.de/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<link rel="stylesheet" href="ext/baguetteBox.min.css">
<link rel="stylesheet" href="style.css" type="text/css">
<script src="ext/baguetteBox.min.js" async></script>
<script src="script.js"></script>
</head>
<body>
<header class="<?=$headerclass;?>">
<div id="wappen">
<a href="https://www.fw-innenstadt.de/"><img id="iwappen" src="img/wappen.svg" title="Wappen der OF Innenstadt"></a>
</div>
<div id="sitetitle">OF Innenstadt</div>
<div id="slogan">
Durch Vielfalt einzigartig!
</div>
</header>
<nav><?=$nav;?></nav>
<main id="main"><?=$articles;?></main>
</body>
</html>
<script type="text/javascript">
var urlgen = new URLGenerator("<?=$page;?>");
<?=$calls;?>
</script>

62
script.js Normal file
View File

@ -0,0 +1,62 @@
var URLGenerator = function (page) {
this._page = page;
this._articles = {};
};
URLGenerator.prototype = {
registerSection: function (article, section) {
this._articles[article] = section;
},
getCurrentUrl: function () {
var ret = this.getPageUrl();
for (var i in this._articles) {
if (typeof this._articles[i] === "object" && this._articles[i] !== null) {
for (var j in this._articles[i]) {
ret+= "&a[" + i + "][" + j + "]=" + this._articles[i][j];
}
} else /*if (this._articles[i] != "")*/ {
ret+= "&a[" + i + "]=" + this._articles[i];
}
}
return ret;
},
getPageUrl: function () {
return "index.php?p="+this._page;
}
};
function loadArticle(src, article, section, initialrun = false) {
var sectionparam = "";
if (typeof section === "object" && section !== null) {
for (var i in section) {
sectionparam+= "&section[" + i + "]=" + section[i];
}
} else if (""!=section) {
sectionparam = "&section="+section;
}
var r = new XMLHttpRequest();
r.open("POST", "ajax/"+src, true);
r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
r.onreadystatechange = function () {
if (r.readyState != 4 || r.status != 200) return;
document.getElementById(article).innerHTML = r.responseText;
urlgen.registerSection(article, section);
if (!initialrun) {
history.pushState({"main": document.getElementById("main").innerHTML, "html":r.responseText,"pageTitle":article}, "article="+article+sectionparam, urlgen.getCurrentUrl());
}
var galid = "gallery_"+article.replace(/\s+/, "");
if (r.responseText.includes("id='"+galid+"'")) {
baguetteBox.run("#"+galid, {animation: false});
}
};
r.send("article="+article+sectionparam);
}
window.onpopstate = function(e) {
if (e.state) {
document.getElementById("main").innerHTML = e.state.main;
//document.getElementById(e.state.pageTitle).innerHTML = e.state.html;
} else {
window.location.href = urlgen.getPageUrl();
}
};

285
style.css Normal file
View File

@ -0,0 +1,285 @@
/* Used colors */
.color-text { color: #000000; }
.color-links { color: #9b0000; }
.color-back-primary { background: #ffffff; }
.color-back-secondary { background: #eeeeee; }
.color-back-shade { background: #c0c0c0; }
.color-accent { color: #3914af; }
/* Generated colors */
.color-primary-0 { color: #FF0000; } /* Main Primary color (Red) */
.color-primary-1 { color: #FF6464; }
.color-primary-2 { color: #FF3939; }
.color-primary-3 { color: #C60000; }
.color-primary-4 { color: #9B0000; } /* Main Background color (Dark red) */
.color-secondary-1-0 { color: #3914AF; } /* Main Secondary color (1) */
.color-secondary-1-1 { color: #735AC4; }
.color-secondary-1-2 { color: #5639B5; }
.color-secondary-1-3 { color: #2B0F88; }
.color-secondary-1-4 { color: #20096B; }
.color-secondary-2-0 { color: #FFD300; } /* Main Secondary color (2) */
.color-secondary-2-1 { color: #FFE464; }
.color-secondary-2-2 { color: #FFDD39; }
.color-secondary-2-3 { color: #C6A400; }
.color-secondary-2-4 { color: #9B8100; }
.clr {clear: both;}
body {
font-size: 20px;
font-family: "liberation sans", arial, sans-serif;
margin: 0;
padding: 0;
}
p {
padding: 0.5em 0;
margin: 0;
text-align: left;
line-height: 1.3;
}
h1, h2, h3 {
padding: 0.5em 0;
margin: 0;
}
a {
color: #9b0000;
text-decoration: underline;
}
ul {
margin: 0;
}
/***** HEADER *****/
header {
background: #9b0000 url(img/front.jpg) center no-repeat;
background-size: cover;
height: calc(100vh - 80px);
width: calc(100% - 40px);
padding: 20px;
margin: 0;
position: relative;
}
header.shortened {
height: 250px;
}
#wappen {
position: absolute;
right: 20px;
width: 200px;
height: 200px;
}
#iwappen {
max-width: 100%;
max-height: 100%;
}
#sitetitle {
position: absolute;
bottom: 1.4em;
left: 0.2em;
max-width: 100vw;
color: #ff0000;
font-weight: bold;
font-size: 500%;
letter-spacing: 0px;
text-shadow: 0.02em 0.02em 0.02em #000000,
0.02em -0.02em 0.02em #000000,
-0.02em 0.02em 0.02em #000000,
-0.02em -0.02em 0.02em #000000;
}
#slogan {
position: absolute;
left: 0;
bottom: 1.8em;
max-width: 13.6em;
background: #ff0000;
padding: 0.1em 0.25em 0.1em 0.5em;
color: #ffffff;
font-weight: bold;
font-size: 200%;
}
/***** NAV *****/
nav {
background-color: #9b0000;
position: sticky;
top: 0;
z-index: 100;
}
nav ul {
padding: 0 0.5em;
margin: 0;
list-style: none;
}
nav a {
color: #ffffff;
}
nav li {
display: inline-block;
padding: 0.5em 0.75em;
font-weight: bold;
margin: 0;
border-top-left-radius: 0.2em;
border-top-right-radius: 0.2em;
}
nav li:hover {
background-color: #ff0000;
}
nav a.current li {
background-color: #ffffff;
color: #9b0000;
}
/***** MAIN *****/
article {
margin: 0;
padding: 2em 1em;
width: calc(100% - 2em);
}
article.gray {
background: #eeeeee;
}
article.white {
background: #ffffff;
}
footer {
font-size: 100%;
margin: 0.5em 0 0 0;
}
footer h1,footer h2,footer h3 {
margin: 0;
padding: 0;
}
footer ul {
list-style: none;
padding: 0;
margin: 0.5em 0;
}
footer li, footer select {
display: inline-block;
padding: 0.2em;
margin-bottom: 0.2em;
}
footer a li, footer select {
border: 1px solid #000;
border-radius: 0.2em;
background-color: #9b0000;
color: #ffffff;
}
footer a li:hover,footer select:hover {
background-color: #ff0000;
}
footer a.current li {
background-color: #ffffff;
color: #9b0000;
}
table {
width: 100%;
font-size: 100%;
border-collapse: collapse;
}
th {
background-color: #c0c0c0;
border: 1px solid #c0c0c0;
margin-top: 1em;
padding: 0.5em;
}
td {
border-bottom: 1px solid #c0c0c0;
}
tr.ge_eckdatum td {
background-color: rgba(255, 211, 0, 0.2);
}
tr.ge_weinsatz td {
background-color: rgba(57, 20, 175, 0.2);
}
select {
font-size: 100%;
}
footer select {
background-color: #9b0000;
color: #ffffff;
}
img.full {
margin: 0;
padding: 0;
border: 0;
width: 100%;
display: block;
}
article img {
max-width: 100%;
max-height: 24em;
}
.red {
color: #ff0000;
}
.nowrap {
white-space: nowrap;
}
.tooltip {
display: none;
background-color: #eeeeee;
border: 1px solid #000000;
border-radius: 0.15em;
}
.white .tooltip {
background-color: #ffffff;
}
video {
background-color: #000000;
height: 270px;
}
section img {
margin: 0 0.2em 0em 0;
}
ul.listprops,ul.listdepls {
padding: 0;
margin: 0;
}
ul.listprops li,ul.listdepls li {
display: inline-block;
position: relative;
padding: 0.2em;
border: 1px solid #9b0000;
background-color: #ffffff;
border-radius: 0.3em;
margin: 0.2em;
}
li:hover .tooltip {
display: block;
position: absolute;
left: 0.4em;
z-index: 999;
}
article.white ul.listprops li,article.white ul.listdepls li {
background-color: #eeeeee;
}
div.gallery {
margin: 1em 0 0 0;
}
@media only screen and (orientation: portrait) {
body {
font-size: 3.5vw;
}
header.shortened {
height: 300px;
}
nav {
font-size: 3.5vw;
}
nav li {
padding: 1em 0.35em;
}
#sitetitle {
font-size: 10vw;
/* height == 1em */
bottom: calc(300px - 0.8em); /*1.4 * 10 = 140*/
}
#slogan {
font-size: 4vw;
/* height == 1.2em */
bottom: calc(300px - 3.4em); /*1.8 * 4 = 7.2 */
}
}