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 () { <?php echo ml_get_title(); ?> ' /> + ' /> 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 @@