diff --git a/admin/views/manage-posts.php b/admin/views/manage-posts.php index 3903eefc..01cf6c7b 100644 --- a/admin/views/manage-posts.php +++ b/admin/views/manage-posts.php @@ -26,7 +26,7 @@ echo ' echo ''; echo ''.($status?''.$status.'':'').($Post->title()?$Post->title():''.$Language->g('Empty title').' ').''; - echo ''.$Post->date().''; + echo ''.$Post->dateRaw().''; echo ''.$Url->filters('post').'/'.$Post->key().''; echo ''; } diff --git a/admin/views/settings-regional.php b/admin/views/settings-regional.php index d06bb019..bb84a0a3 100644 --- a/admin/views/settings-regional.php +++ b/admin/views/settings-regional.php @@ -35,6 +35,13 @@ HTML::formOpen(array('class'=>'uk-form-horizontal')); 'tip'=>$L->g('you-can-use-this-field-to-define-a-set-off') )); + HTML::formInputText(array( + 'name'=>'dateFormat', + 'label'=>$L->g('Date format'), + 'value'=>$Site->dateFormat(), + 'class'=>'uk-width-1-2 uk-form-medium' + )); + echo '
diff --git a/kernel/abstract/dbjson.class.php b/kernel/abstract/dbjson.class.php index a792164d..ccd3fa80 100644 --- a/kernel/abstract/dbjson.class.php +++ b/kernel/abstract/dbjson.class.php @@ -58,6 +58,15 @@ class dbJSON return count($this->db); } + public function getField($field) + { + if(isset($this->db[$field])) { + return $this->db[$field]; + } + + return $this->dbFields[$field]['value']; + } + // Save the JSON file. public function save() { diff --git a/kernel/boot/init.php b/kernel/boot/init.php index ccef230e..291acba0 100644 --- a/kernel/boot/init.php +++ b/kernel/boot/init.php @@ -75,7 +75,7 @@ define('CLI_STATUS', 'published'); // Database format date define('DB_DATE_FORMAT', 'Y-m-d H:i'); -// Database format date +// Date format for Dashboard schedule posts define('SCHEDULED_DATE_FORMAT', 'd M - h:i a'); // Token time to live for login via email. The offset is defined by http://php.net/manual/en/datetime.modify.php @@ -128,6 +128,7 @@ include(PATH_HELPERS.'email.class.php'); include(PATH_HELPERS.'filesystem.class.php'); include(PATH_HELPERS.'alert.class.php'); include(PATH_HELPERS.'paginator.class.php'); +include(PATH_HELPERS.'image.class.php'); // Session Session::start(); diff --git a/kernel/boot/rules/70.posts.php b/kernel/boot/rules/70.posts.php index 62f6ff9e..2294d624 100644 --- a/kernel/boot/rules/70.posts.php +++ b/kernel/boot/rules/70.posts.php @@ -68,6 +68,13 @@ function buildPost($key) $Post->setField('breakContent', $explode[0], true); $Post->setField('readMore', !empty($explode[1]), true); + // Date format + $postDate = $Post->date(); + $Post->setField('dateRaw', $postDate, true); + + $postDateFormated = $Post->dateRaw( $Site->dateFormat() ); + $Post->setField('date', $postDateFormated, true); + // Parse username for the post. if( $dbUsers->userExists( $Post->username() ) ) { diff --git a/kernel/dbsite.class.php b/kernel/dbsite.class.php index b1058d9a..7a000448 100644 --- a/kernel/dbsite.class.php +++ b/kernel/dbsite.class.php @@ -2,7 +2,7 @@ class dbSite extends dbJSON { - private $dbFields = array( + public $dbFields = array( 'title'=> array('inFile'=>false, 'value'=>'I am Guybrush Threepwood, mighty developer'), 'slogan'=> array('inFile'=>false, 'value'=>''), 'description'=> array('inFile'=>false, 'value'=>''), @@ -19,7 +19,9 @@ class dbSite extends dbJSON 'uriTag'=> array('inFile'=>false, 'value'=>'/tag/'), 'url'=> array('inFile'=>false, 'value'=>''), 'cliMode'=> array('inFile'=>false, 'value'=>true), - 'emailFrom'=> array('inFile'=>false, 'value'=>'') + 'emailFrom'=> array('inFile'=>false, 'value'=>''), + 'dateFormat'=> array('inFile'=>false, 'value'=>'F j, Y'), + 'timeFormat'=> array('inFile'=>false, 'value'=>'g:i a') ); function __construct() @@ -61,9 +63,9 @@ class dbSite extends dbJSON public function uriFilters($filter='') { $filters['admin'] = '/admin/'; - $filters['post'] = $this->db['uriPost']; - $filters['page'] = $this->db['uriPage']; - $filters['tag'] = $this->db['uriTag']; + $filters['post'] = $this->getField('uriPost'); + $filters['page'] = $this->getField('uriPage'); + $filters['tag'] = $this->getField('uriTag'); if(empty($filter)) { return $filters; @@ -74,70 +76,83 @@ class dbSite extends dbJSON public function urlPost() { - return $this->url().ltrim($this->db['uriPost'], '/'); + $filter = $this->getField('uriPost'); + return $this->url().ltrim($filter, '/'); } public function urlPage() { - return $this->url().ltrim($this->db['uriPage'], '/'); + $filter = $this->getField('uriPage'); + return $this->url().ltrim($filter, '/'); } public function urlTag() { - return $this->url().ltrim($this->db['uriTag'], '/'); + $filter = $this->getField('uriTag'); + return $this->url().ltrim($filter, '/'); } // Returns the site title. public function title() { - return $this->db['title']; + return $this->getField('title'); } public function emailFrom() { - return $this->db['emailFrom']; + return $this->getField('emailFrom'); + } + + public function dateFormat() + { + return $this->getField('dateFormat'); + } + + public function timeFormat() + { + return $this->getField('timeFormat'); } // Returns the site slogan. public function slogan() { - return $this->db['slogan']; + return $this->getField('slogan'); } // Returns the site description. public function description() { - return $this->db['description']; + return $this->getField('description'); } // Returns the site theme name. public function theme() { - return $this->db['theme']; + return $this->getField('theme'); } // Returns the admin theme name. public function adminTheme() { - return $this->db['adminTheme']; + return $this->getField('adminTheme'); } // Returns the footer text. public function footer() { - return $this->db['footer']; + return $this->getField('footer'); } // Returns the url site. public function url() { - return $this->db['url']; + return $this->getField('url'); } // Returns TRUE if the cli mode is enabled, otherwise FALSE. public function cliMode() { - return $this->db['cliMode']; + return $this->getField('cliMode'); } // Returns the relative home link @@ -149,25 +164,25 @@ class dbSite extends dbJSON // Returns the timezone. public function timezone() { - return $this->db['timezone']; + return $this->getField('timezone'); } // Returns posts per page. public function postsPerPage() { - return $this->db['postsperpage']; + return $this->getField('postsperpage'); } // Returns the current language. public function language() { - return $this->db['language']; + return $this->getField('language'); } // Returns the current locale. public function locale() { - return $this->db['locale']; + return $this->getField('locale'); } // Returns the current language in short format. @@ -183,7 +198,7 @@ class dbSite extends dbJSON // Returns the current homepage. public function homepage() { - return $this->db['homepage']; + return $this->getField('homepage'); } // Set the locale. diff --git a/kernel/helpers/image.class.php b/kernel/helpers/image.class.php new file mode 100644 index 00000000..1ee2453e --- /dev/null +++ b/kernel/helpers/image.class.php @@ -0,0 +1,232 @@ +image = $this->openImage($fileName); + + // *** Get width and height + $this->width = imagesx($this->image); + $this->height = imagesy($this->image); + + $this->resizeImage($newWidth, $newHeight, $option); + } + + public function saveImage($savePath, $imageQuality="100", $force_jpg=false) + { + $extension = strtolower(pathinfo($savePath, PATHINFO_EXTENSION)); + + // Remove the extension + $filename = substr($savePath, 0,strrpos($savePath,'.')); + + $path_complete = $filename.'.'.$extension; + + if($force_jpg) + { + imagejpeg($this->imageResized, $filename.'.jpg', $imageQuality); + } + else + { + switch($extension) + { + case 'jpg': + case 'jpeg': + if (imagetypes() & IMG_JPG) { + imagejpeg($this->imageResized, $path_complete, $imageQuality); + } + break; + + case 'gif': + if (imagetypes() & IMG_GIF) { + imagegif($this->imageResized, $path_complete); + } + break; + + case 'png': + // *** Scale quality from 0-100 to 0-9 + $scaleQuality = round(($imageQuality/100) * 9); + + // *** Invert quality setting as 0 is best, not 9 + $invertScaleQuality = 9 - $scaleQuality; + + if (imagetypes() & IMG_PNG) { + imagepng($this->imageResized, $path_complete, $invertScaleQuality); + } + break; + + default: + // *** No extension - No save. + break; + } + } + + imagedestroy($this->imageResized); + } + + private function openImage($file) + { + // *** Get extension + $extension = strtolower(strrchr($file, '.')); + + switch($extension) + { + case '.jpg': + case '.jpeg': + $img = imagecreatefromjpeg($file); + break; + case '.gif': + $img = imagecreatefromgif($file); + break; + case '.png': + $img = imagecreatefrompng($file); + break; + default: + $img = false; + break; + } + return $img; + } + + private function resizeImage($newWidth, $newHeight, $option) + { + // *** Get optimal width and height - based on $option + $optionArray = $this->getDimensions($newWidth, $newHeight, $option); + + $optimalWidth = $optionArray['optimalWidth']; + $optimalHeight = $optionArray['optimalHeight']; + + + // *** Resample - create image canvas of x, y size + $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight); + imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height); + + + // *** if option is 'crop', then crop too + if ($option == 'crop') { + $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight); + } + } + + private function getDimensions($newWidth, $newHeight, $option) + { + + if( ($this->width < $newWidth) and ($this->height < $newHeight) ) + { + return array('optimalWidth' => $this->width, 'optimalHeight' => $this->height); + } + + switch ($option) + { + case 'exact': + $optimalWidth = $newWidth; + $optimalHeight= $newHeight; + break; + case 'portrait': + $optimalWidth = $this->getSizeByFixedHeight($newHeight); + $optimalHeight= $newHeight; + break; + case 'landscape': + $optimalWidth = $newWidth; + $optimalHeight= $this->getSizeByFixedWidth($newWidth); + break; + case 'auto': + $optionArray = $this->getSizeByAuto($newWidth, $newHeight); + $optimalWidth = $optionArray['optimalWidth']; + $optimalHeight = $optionArray['optimalHeight']; + break; + case 'crop': + $optionArray = $this->getOptimalCrop($newWidth, $newHeight); + $optimalWidth = $optionArray['optimalWidth']; + $optimalHeight = $optionArray['optimalHeight']; + break; + } + + return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); + } + + private function getSizeByFixedHeight($newHeight) + { + $ratio = $this->width / $this->height; + $newWidth = $newHeight * $ratio; + return $newWidth; + } + + private function getSizeByFixedWidth($newWidth) + { + $ratio = $this->height / $this->width; + $newHeight = $newWidth * $ratio; + return $newHeight; + } + + private function getSizeByAuto($newWidth, $newHeight) + { + if ($this->height < $this->width) + // *** Image to be resized is wider (landscape) + { + $optimalWidth = $newWidth; + $optimalHeight= $this->getSizeByFixedWidth($newWidth); + } + elseif ($this->height > $this->width) + // *** Image to be resized is taller (portrait) + { + $optimalWidth = $this->getSizeByFixedHeight($newHeight); + $optimalHeight= $newHeight; + } + else + // *** Image to be resizerd is a square + { + if ($newHeight < $newWidth) { + $optimalWidth = $newWidth; + $optimalHeight= $this->getSizeByFixedWidth($newWidth); + } else if ($newHeight > $newWidth) { + $optimalWidth = $this->getSizeByFixedHeight($newHeight); + $optimalHeight= $newHeight; + } else { + // *** Sqaure being resized to a square + $optimalWidth = $newWidth; + $optimalHeight= $newHeight; + } + } + + return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); + } + + private function getOptimalCrop($newWidth, $newHeight) + { + + $heightRatio = $this->height / $newHeight; + $widthRatio = $this->width / $newWidth; + + if ($heightRatio < $widthRatio) { + $optimalRatio = $heightRatio; + } else { + $optimalRatio = $widthRatio; + } + + $optimalHeight = $this->height / $optimalRatio; + $optimalWidth = $this->width / $optimalRatio; + + return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); + } + + private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight) + { + // *** Find center - this will be used for the crop + $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 ); + $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 ); + + $crop = $this->imageResized; + //imagedestroy($this->imageResized); + + // *** Now crop from center to exact requested size + $this->imageResized = imagecreatetruecolor($newWidth , $newHeight); + imagecopyresampled($this->imageResized, $crop , 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight); + } +} diff --git a/kernel/post.class.php b/kernel/post.class.php index f2eb18eb..3abed452 100644 --- a/kernel/post.class.php +++ b/kernel/post.class.php @@ -101,7 +101,13 @@ class Post extends fileContent // Returns the post date according to locale settings and format settings. public function date($format=false) { - $date = $this->getField('date'); + return $this->getField('date'); + } + + // Returns the post date according to locale settings and format as database stored. + public function dateRaw($format=false) + { + $date = $this->getField('dateRaw'); if($format) { return Date::format($date, DB_DATE_FORMAT, $format); diff --git a/languages/en_US.json b/languages/en_US.json index e308c6f4..4334f55c 100644 --- a/languages/en_US.json +++ b/languages/en_US.json @@ -204,5 +204,7 @@ "upload-image": "Upload image", "drag-and-drop-or-click-here": "Drag and drop or click here", "insert-image": "Insert image", - "supported-image-file-types": "Supported image file types" + "supported-image-file-types": "Supported image file types", + "date-format": "Date format", + "time-format": "Time format" } \ No newline at end of file diff --git a/plugins/pages/plugin.php b/plugins/pages/plugin.php index c75636f8..324d5bda 100644 --- a/plugins/pages/plugin.php +++ b/plugins/pages/plugin.php @@ -54,24 +54,32 @@ class pluginPages extends Plugin { $parents = $pagesParents[NO_PARENT_CHAR]; foreach($parents as $parent) { - // Print the parent - $html .= '
  • '; - $html .= ''.$parent->title().''; - - // Check if the parent has children - if(isset($pagesParents[$parent->key()])) + // Check if the parent is published + if( $parent->published() ) { - $children = $pagesParents[$parent->key()]; + // Print the parent + $html .= '
  • '; + $html .= ''.$parent->title().''; - // Print children - $html .= '
      '; - foreach($children as $child) + // Check if the parent has children + if(isset($pagesParents[$parent->key()])) { - $html .= '
    • '; - $html .= ''.$child->title().''; - $html .= '
    • '; + $children = $pagesParents[$parent->key()]; + + // Print children + $html .= '
        '; + foreach($children as $child) + { + // Check if the child is published + if( $child->published() ) + { + $html .= '
      • '; + $html .= ''.$child->title().''; + $html .= '
      • '; + } + } + $html .= '
      '; } - $html .= '
    '; } } diff --git a/themes/pure/languages/de_DE.json b/themes/pure/languages/de_DE.json index aab4edba..00255464 100644 --- a/themes/pure/languages/de_DE.json +++ b/themes/pure/languages/de_DE.json @@ -2,11 +2,6 @@ "theme-data": { "name": "Pure", - "description": "Einfaches und übersichtliches Theme unter Verwendung des Frameworks Pure.css. Website: http://purecss.io.", - "author": "Bludit", - "email": "", - "website": "https://github.com/dignajar/bludit-themes", - "version": "0.3", - "releaseDate": "2015-10-02" + "description": "Einfaches und übersichtliches Theme unter Verwendung des Frameworks Pure.css." } -} +} \ No newline at end of file diff --git a/themes/pure/languages/en_US.json b/themes/pure/languages/en_US.json index 2a4c3e20..8d996c17 100644 --- a/themes/pure/languages/en_US.json +++ b/themes/pure/languages/en_US.json @@ -2,11 +2,11 @@ "theme-data": { "name": "Pure", - "description": "Simple and clean theme, based on the framework Pure.css. Website: http://purecss.io", + "description": "Simple and clean theme, based on the framework Pure.css.", "author": "Bludit", "email": "", "website": "https://github.com/dignajar/bludit-themes", - "version": "0.3", - "releaseDate": "2015-10-02" + "version": "0.6", + "releaseDate": "2015-11-13" } } \ No newline at end of file