diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..d61b873
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,30 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## v1.0.1 - 2019-09-17
+
+### Added
+
+* Dark mode for default theme (hint: there's an option in `index.php`)
+* Media endpoint URL in HTML head section (in addition to micropub query)
+
+### Fixed
+
+* Uses current time if `published` value is an empty string on micropub API
+* Properly escape values for meta tags in HTML head
+* Prevent errors from occurring when trying to determine non-existent
+ Content-Type
+* Wrap long words and links in default theme
+* Save user configuration propertly if note and links are empty
+
+### Changed
+
+* Resize profile to always be square
+
+## v1.0.0 Initial Release - 2019-09-14
+
+No changes were made. It was the first release, after all!
diff --git a/includes/api.include.php b/includes/api.include.php
index 81b1628..215752a 100644
--- a/includes/api.include.php
+++ b/includes/api.include.php
@@ -29,8 +29,18 @@ function ml_api_method () {
* @return string
*/
function ml_api_content_type () {
- $content_type = $_SERVER['CONTENT_TYPE'];
- if (empty($content_type)) $content_type = $_SERVER['HTTP_CONTENT_TYPE'];
+ $content_type = '';
+
+ if (isset($_SERVER['CONTENT_TYPE'])) {
+ $content_type = $_SERVER['CONTENT_TYPE'];
+ }
+
+ if (empty($content_type) && isset($_SERVER['HTTP_CONTENT_TYPE'])) {
+ $content_type = $_SERVER['HTTP_CONTENT_TYPE'];
+ }
+
+ // Default to form data if no value was provided.
+ if (empty($content_type)) $content_type = HTTPContentType::FORM_DATA;
return $content_type;
}
@@ -43,7 +53,7 @@ function ml_api_content_type () {
function ml_api_post_decode () {
global $post;
- if (ml_api_content_type() === 'application/json') {
+ if (ml_api_content_type() === HTTPContentType::JSON) {
$post = json_decode(file_get_contents('php://input'), true);
} else {
$post = $_POST;
@@ -81,6 +91,7 @@ function ml_api_post_json ($post, $key, $is_single = false) {
if (!is_array($post)) return null;
if (!isset($post[$key])) return null;
if (empty($post[$key])) return null;
+ if (!is_array($post[$key])) return $post[$key];
// A lot of microformats2 items are intentionally single element arrays.
// I'm not sure why, but if we know it's supposed to, parse it here.
@@ -110,10 +121,12 @@ function ml_api_get ($key) {
* @return null|string
*/
function ml_api_access_token () {
+ global $post;
+
// Don't allow user in without a valid bearer token
$bearer = ml_http_bearer();
- if ($bearer === false) {
+ if ($bearer === false && $post !== null) {
$bearer = ml_api_post('access_token');
}
diff --git a/includes/functions.include.php b/includes/functions.include.php
index f297804..9c8841b 100644
--- a/includes/functions.include.php
+++ b/includes/functions.include.php
@@ -244,7 +244,7 @@ function ml_get_title () {
$str = '';
if ($showing === Show::POST || $showing === Show::PAGE) {
- $str .= $posts['name'] !== ''
+ $str .= $posts['name'] !== '' && $posts['name'] !== null
? $posts['name']
: $posts['summary'];
$str .= Config::TITLE_SEPARATOR;
@@ -395,6 +395,9 @@ function ml_page_headers () {
$description = User::NOTE;
$image = ml_icon_url();
}
+
+ $description = htmlspecialchars($description, ENT_QUOTES);
+ $title = htmlspecialchars(ml_get_title(), ENT_QUOTES);
?>
@@ -404,7 +407,7 @@ function ml_page_headers () {
-
+
@@ -415,6 +418,7 @@ function ml_page_headers () {
' />
+ ' />
diff --git a/includes/lib/media.php b/includes/lib/media.php
index 27c7ff4..6ecce57 100644
--- a/includes/lib/media.php
+++ b/includes/lib/media.php
@@ -64,6 +64,11 @@ abstract class ImageType extends BasicEnum {
const GIF = 'image/gif'; // jif
}
+abstract class ImageResizeMethod extends BasicEnum {
+ const KEEP_ASPECT_RATIO = 0;
+ const SQUARE = 1;
+}
+
class ImageResizer {
private $image;
private $type;
@@ -72,6 +77,7 @@ class ImageResizer {
private $width_src;
private $height_src;
private $filename;
+ private $resize_method;
private $filename_override;
private $mimetype_override;
@@ -81,9 +87,16 @@ class ImageResizer {
* @param array $file
* @param string $filename_override If set, the image will be forcibly saved here
* @param string $mimetype_override If set, the image will be forcibly saved with this type
+ * @param ImageResizeMethod $resize_method If set, the image will be resized differently
* @return ImageResizer
+ * @throws Exception
*/
- function __construct ($file, $filename_override = null, $mimetype_override = null) {
+ function __construct (
+ $file,
+ $filename_override = null,
+ $mimetype_override = null,
+ $resize_method = ImageResizeMethod::KEEP_ASPECT_RATIO
+ ) {
if ($file['error'] !== UPLOAD_ERR_OK) throw new UploadException($file);
if (empty($file['tmp_name'])) {
@@ -99,6 +112,13 @@ function __construct ($file, $filename_override = null, $mimetype_override = nul
throw new Exception('Image was not provided');
}
+ // Make sure resize method is an acceptable value
+ if (!ImageResizeMethod::isValidValue($resize_method)) {
+ throw new Exception('Invalid resize method');
+ }
+
+ $this->resize_method = $resize_method;
+
// Calculate new image size
if (!$this->dimensions($file)) {
throw new Exception('Image dimensions could not be determined');
@@ -224,11 +244,29 @@ private function load ($file) {
}
private function resize () {
+ // Determine resize coordinates
+ $scale = $this->width_src / $this->width;
+
+ $source_x = 0;
+ $source_y = 0;
+
+ if ($this->resize_method === ImageResizeMethod::SQUARE) {
+ if ($this->width_src > $this->height_src) {
+ $source_x = ceil(($this->width_src - $this->height_src) / 2.0);
+ $this->width_src = $this->height_src;
+ $this->width = $this->height;
+ } else if ($this->width_src < $this->height_src) {
+ $source_y = ceil(($this->height_src - $this->width_src) / 2.0);
+ $this->height_src = $this->width_src;
+ $this->height = $this->width;
+ }
+ }
+
$destination = imagecreatetruecolor($this->width, $this->height);
$success = imagecopyresampled(
- $destination, // New image
+ $destination, // New image
$this->image, // Old image
- 0, 0, 0, 0, // Image origin coords
+ 0, 0, $source_x, $source_y, // Image origin coords
$this->width, $this->height, // New image size
$this->width_src, $this->height_src // Old image size
);
diff --git a/index.php b/index.php
index 54dfd30..5957edc 100644
--- a/index.php
+++ b/index.php
@@ -1,7 +1,7 @@
\'\', \'url\' => \'\' ],';
+ $contents .= ' // [ \'name\' => \'\', \'url\' => \'\' ],
+';
}
// Close identities section
@@ -148,7 +147,12 @@ class User {
// Attempt to upload/resize profile picture
if (isset($_FILES['photo'])) {
- $image = new ImageResizer($_FILES['photo'], 'me', 'image/jpg');
+ $image = new ImageResizer(
+ $_FILES['photo'],
+ 'me',
+ ImageType::JPG,
+ ImageResizeMethod::SQUARE
+ );
}
if (count($errors) === 0) {
diff --git a/media/index.php b/media/index.php
index 770f94e..8676104 100644
--- a/media/index.php
+++ b/media/index.php
@@ -1,6 +1,6 @@
div {
+ padding: 10px 16px;
+ border: 1px solid #333;
+ border-radius: 6px;
+ margin-top: 10px;
+}
+
+#entry-interactions .p-name {
+ font-weight: 700;
+}
+
+.entry-interaction-emoji, #entry-interactions .u-photo {
+ float: left;
+ line-height: 40px;
+ width: 40px;
+ height: 40px;
+ font-size: 40px;
+ margin-right: 10px;
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+@media (max-width: 500px) {
+ header .u-photo {
+ float: none;
+ display: block;
+ width: 100%;
+ max-width: 240px;
+ margin: 0 auto 16px auto;
+ }
+
+ header {
+ text-align: center;
+ }
+
+ .tags {
+ text-align: left;
+ float: none;
+ display: block;
+ margin-bottom: 10px;
+ max-width: 100%;
+ }
+ .tags a {
+ display: inline-block;
+ margin: 0 5px 0 0;
+ padding: 0 0 5px 0;
+ }
+}
diff --git a/themes/microlight-default/css/style.css b/themes/microlight-default/css/style.css
index a7b36b1..e1037fd 100644
--- a/themes/microlight-default/css/style.css
+++ b/themes/microlight-default/css/style.css
@@ -57,6 +57,11 @@ h2.p-name {
font-size: 24px;
}
+h2.p-name, h2.p-name a {
+ word-break: normal;
+ overflow-wrap: break-word;
+}
+
.p-name-emoji {
margin-right: 12px;
line-height: 20px;
diff --git a/themes/microlight-default/elements.php b/themes/microlight-default/elements.php
index 61f3db8..47c95fd 100644
--- a/themes/microlight-default/elements.php
+++ b/themes/microlight-default/elements.php
@@ -5,18 +5,24 @@
if (!defined('MICROLIGHT')) die();
function html_head () {
+ global $dark_mode;
+
echo "";
echo "";
- echo "";
+ echo "";
echo "";
// Add pre-generated headers
ml_page_headers();
+ $css = isset($dark_mode) && $dark_mode === true
+ ? '/css/style-dark.css'
+ : '/css/style.css';
+
// Add this theme's stylesheet
echo "";
+ echo $css . "' />";
echo "";
}
diff --git a/themes/microlight-default/index.php b/themes/microlight-default/index.php
index a1d18a2..2ebfc30 100644
--- a/themes/microlight-default/index.php
+++ b/themes/microlight-default/index.php
@@ -4,6 +4,9 @@
// file from within microlight itself.
if (!defined('MICROLIGHT')) die();
+// Should this theme be dark or light? You decide!
+$dark_mode = false;
+
// Contains various elements for this page
require_once('elements.php');
diff --git a/webmention/index.php b/webmention/index.php
index 3245b2a..d89fac4 100644
--- a/webmention/index.php
+++ b/webmention/index.php
@@ -1,6 +1,6 @@