diff --git a/_build/data/transport.core.system_settings.php b/_build/data/transport.core.system_settings.php index a34f938f995..7a54d35138d 100644 --- a/_build/data/transport.core.system_settings.php +++ b/_build/data/transport.core.system_settings.php @@ -993,6 +993,24 @@ 'area' => 'manager', 'editedon' => null, ], '', true, true); +$settings['manager_datetime_separator'] = $xpdo->newObject(modSystemSetting::class); +$settings['manager_datetime_separator']->fromArray([ + 'key' => 'manager_datetime_separator', + 'value' => ', ', + 'xtype' => 'textfield', + 'namespace' => 'core', + 'area' => 'manager', + 'editedon' => null, +], '', true, true); +$settings['manager_datetime_empty_value'] = $xpdo->newObject(modSystemSetting::class); +$settings['manager_datetime_empty_value']->fromArray([ + 'key' => 'manager_datetime_empty_value', + 'value' => '—', + 'xtype' => 'textfield', + 'namespace' => 'core', + 'area' => 'manager', + 'editedon' => null, +], '', true, true); $settings['manager_direction'] = $xpdo->newObject(modSystemSetting::class); $settings['manager_direction']->fromArray([ 'key' => 'manager_direction', diff --git a/core/lexicon/en/default.inc.php b/core/lexicon/en/default.inc.php index 58145332f7f..93a8896ba0b 100644 --- a/core/lexicon/en/default.inc.php +++ b/core/lexicon/en/default.inc.php @@ -97,6 +97,7 @@ $_lang['data_err_load'] = 'Error loading data.'; $_lang['date'] = 'Date'; $_lang['datechanged'] = 'Date changed'; +$_lang['datetime_conversion_err_invalid_mysql_format'] = 'Attempted to convert the value “[[+value]]” to a timestamp, but the the value is not in the required mysql format (Y-m-d H:i:s).'; $_lang['db_header'] = 'Database tables'; $_lang['db_info_mysql'] = 'If a table has an overhead, you may optimize it by clicking on the link in the Overhead column.'; $_lang['delete'] = 'Delete'; @@ -510,6 +511,7 @@ $_lang['untitled_tv'] = 'Untitled tv'; $_lang['untitled_weblink'] = 'Untitled weblink'; $_lang['untitled_symlink'] = 'Untitled symlink'; +$_lang['unedited'] = 'Unedited'; $_lang['unknown'] = 'Unknown'; $_lang['unsaved_changes'] = 'There are unsaved changes. Are you sure you want to leave this page?'; $_lang['update'] = 'Update'; diff --git a/core/lexicon/en/setting.inc.php b/core/lexicon/en/setting.inc.php index 03cf9c14fa8..3045ee95c88 100644 --- a/core/lexicon/en/setting.inc.php +++ b/core/lexicon/en/setting.inc.php @@ -219,6 +219,12 @@ $_lang['setting_date_timezone'] = 'Default Time Zone'; $_lang['setting_date_timezone_desc'] = 'Controls the default timezone setting for PHP date functions, if not empty. If empty and the PHP date.timezone ini setting is not set in your environment, UTC will be assumed.'; +$_lang['manager_datetime_empty_value'] = 'Datetime Empty Value'; +$_lang['manager_datetime_empty_value_desc'] = 'The text (if any) that will show in grids and forms when a datetime field’s value has not been set. (Default: “–” [a single en dash])'; + +$_lang['manager_datetime_separator'] = 'Datetime Separator'; +$_lang['manager_datetime_separator_desc'] = 'When the date and time are shown as a combined element, these characters will be used to visually seapate them. (Default: “, ” [comma and space])'; + $_lang['setting_debug'] = 'Debug'; $_lang['setting_debug_desc'] = 'Controls turning debugging on/off in MODX and/or sets the PHP error_reporting level. \'\' = use current error_reporting, \'0\' = false (error_reporting = 0), \'1\' = true (error_reporting = -1), or any valid error_reporting value (as an integer).'; diff --git a/core/lexicon/en/workspace.inc.php b/core/lexicon/en/workspace.inc.php index 324f3477390..96a314c9489 100644 --- a/core/lexicon/en/workspace.inc.php +++ b/core/lexicon/en/workspace.inc.php @@ -60,6 +60,7 @@ $_lang['newest_additions'] = 'Newest Additions'; $_lang['no_preview'] = 'No Preview'; $_lang['not_installed'] = 'Not Installed'; +$_lang['not_updated'] = 'Not Updated'; $_lang['package'] = 'Package'; $_lang['package_add'] = 'New Package'; $_lang['package_already_downloaded'] = 'Package already downloaded'; diff --git a/core/src/Revolution/Formatter/modManagerDateFormatter.php b/core/src/Revolution/Formatter/modManagerDateFormatter.php new file mode 100644 index 00000000000..b89a0fa421a --- /dev/null +++ b/core/src/Revolution/Formatter/modManagerDateFormatter.php @@ -0,0 +1,244 @@ +modx =& $modx; + $this->managerDateFormat = $this->modx->getOption('manager_date_format', null, 'Y-m-d', true); + $this->managerTimeFormat = $this->modx->getOption('manager_time_format', null, 'H:i', true); + $this->managerDateEmptyDisplay = $this->modx->getOption('manager_datetime_empty_value', null, '–', true); + } + + public function isEmpty($value): bool + { + return in_array($value, $this->managerDateEmptyValues); + } + + /** + * Calculates the Unix timestamp for a valid date/time-related value, + * applying the system-specified server offset if applicable + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @return int|null The calculated timestamp + */ + protected function parseValue($value, bool $useOffset = false): ?int + { + if ($this->isEmpty($value)) { + return null; + } + + if (!modX::isValidTimestamp($value)) { + // If not a timestamp integer, expecting mysql-formatted value + $dateTime = \DateTimeImmutable::createFromFormat($this->managerDateHiddenFormat, $value); + if ($dateTime === false) { + $msg = $this->modx->lexicon('datetime_conversion_err_invalid_mysql_format', ['value' => $value]); + $this->modx->log(modX::LOG_LEVEL_WARN, $msg); + return 0; + } + $value = $dateTime->getTimestamp(); + } + + $value = (int)$value; + + if (!$useOffset) { + return $value; + } + + $offset = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; + + return $value + $offset; + } + + /** + * Transforms a date/time-related value using the specified DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param string $format The custom format to use when formatting the $value + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function format($value, string $format, bool $useOffset = false, ?string $emptyValue = null): string + { + $value = $this->parseValue($value, $useOffset); + + if ($value === null) { + return $emptyValue === null ? $this->managerDateEmptyDisplay : $emptyValue; + } + + return date($format, $value); + } + + /** + * Transforms a date/time-related value according to the DateTime system format used for hidden values + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @return string The formatted date + */ + public function formatHidden($value): string + { + return $this->format($value, $this->managerDateHiddenFormat, false, ''); + } + + /** + * Transforms a date/time-related value into the specified date-only DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatDate($value, bool $useOffset = false, ?string $emptyValue = null): string + { + return $this->format($value, $this->managerDateFormat, $useOffset, $emptyValue); + } + + /** + * Transforms a date/time-related value into the specified time-only DateTime format + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatTime($value, bool $useOffset = false, ?string $emptyValue = null): string + { + return $this->format($value, $this->managerTimeFormat, $useOffset, $emptyValue); + } + + /** + * Transforms a date/time-related value into the specified DateTime format showing + * both date and time, including an optional system-specified separator + * @param string|int $value The value to transform (a Unix timestamp or mysql-format string) + * @param bool $useOffset Whether to use the offset time (system setting) in the date calculation + * @param string|null $emptyValue The text to show when the $value passed is empty + * @return string The formatted date + */ + public function formatDateTime($value, bool $useOffset = false, ?string $emptyValue = null): string + { + $managerDateTimeSeparator = $this->modx->getOption('manager_datetime_separator', null, ', ', true); + $format = $this->managerDateFormat . $managerDateTimeSeparator . $this->managerTimeFormat; + + return $this->format($value, $format, $useOffset, $emptyValue); + } + + /** + * Formats a Resource-related date when applicable and includes localized default text to + * represent conditions where a date is not present or applicable + * + * @param string|int $value The source date value to format + * @param string $whichDate An identifier specifying the type of date being formatted + * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings + * @return string The formatted date or relevant text indicating an empty date value + */ + public function formatResourceDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + { + if ($useStandardEmptyValue) { + return $this->formatDateTime($value, true, null); + } + switch ($whichDate) { + case 'edited': + $emptyValue = $this->modx->lexicon('unedited'); + break; + case 'publish': + case 'unpublish': + $emptyValue = $this->modx->lexicon('notset'); + break; + case 'published': + $emptyValue = $this->modx->lexicon('unpublished'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); + } + $emptyValue = '(' . $emptyValue . ')'; + + return $this->formatDateTime($value, true, $emptyValue); + } + + /** + * Formats a Package-related date when applicable and includes localized default text to + * represent conditions where a date is not present or applicable + * + * @param string|int $value The source date value to format + * @param string $whichDate An identifier specifying the type of date being formatted + * @param bool $useStandardEmptyValue Whether to use the default empty value defined in the system settings + * @return string The formatted date or relevant text indicating an empty date value + */ + public function formatPackageDate($value, string $whichDate = 'created', bool $useStandardEmptyValue = true): string + { + if ($useStandardEmptyValue) { + return $this->formatDateTime($value, true, null); + } + switch ($whichDate) { + case 'installed': + $emptyValue = $this->modx->lexicon('not_installed'); + break; + case 'updated': + $emptyValue = $this->modx->lexicon('not_updated'); + break; + default: + $emptyValue = $this->modx->lexicon('unknown'); + } + $emptyValue = '(' . $emptyValue . ')'; + + return $this->formatDateTime($value, true, $emptyValue); + } +} diff --git a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php index 90a8aa692fc..2bd2550ca5b 100644 --- a/core/src/Revolution/Processors/Browser/Directory/GetFiles.php +++ b/core/src/Revolution/Processors/Browser/Directory/GetFiles.php @@ -1,4 +1,5 @@ source->getObjectsInContainer($dir); - return $this->source->hasErrors() - ? $this->failure($this->source->getErrors(), []) - : $this->outputArray($list); + if ($this->source->hasErrors()) { + return $this->failure($this->source->getErrors(), []); + } + + /** @var modManagerDateFormatter $formatter */ + $formatter = $this->modx->services->get(modManagerDateFormatter::class); + foreach ($list as $i => $file) { + $list[$i]['lastmod'] = $formatter->formatDateTime($file['lastmod']); + } + + return $this->outputArray($list); } } diff --git a/core/src/Revolution/Processors/Context/Setting/GetList.php b/core/src/Revolution/Processors/Context/Setting/GetList.php index dc8e42429f0..b0188677d6e 100644 --- a/core/src/Revolution/Processors/Context/Setting/GetList.php +++ b/core/src/Revolution/Processors/Context/Setting/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'key' => false, 'namespace' => false, 'area' => false, + 'dateFormat' => '' ]); - $this->dateFormat = $this->modx->getOption('manager_date_format') . ', ' - . $this->modx->getOption('manager_time_format'); - return $initialized; } @@ -110,8 +111,10 @@ public function prepareRow(xPDOObject $object) $k = 'setting_' . $settingArray['key']; /* if 3rd party setting, load proper text, fallback to english */ - $this->modx->lexicon->load('en:' . $object->get('namespace') . ':default', - 'en:' . $object->get('namespace') . ':setting'); + $this->modx->lexicon->load( + 'en:' . $object->get('namespace') . ':default', + 'en:' . $object->get('namespace') . ':setting' + ); $this->modx->lexicon->load($object->get('namespace') . ':default', $object->get('namespace') . ':setting'); /* get translated area text */ @@ -128,8 +131,10 @@ public function prepareRow(xPDOObject $object) $settingArray['description_trans'] = $this->modx->lexicon($k . '_desc'); $settingArray['description'] = $k . '_desc'; } else { - $this->modx->log(modX::LOG_LEVEL_DEBUG, - '[' . __METHOD__ . '] lexicon entry for ' . $k . '_desc not found'); + $this->modx->log( + modX::LOG_LEVEL_DEBUG, + '[' . __METHOD__ . '] lexicon entry for ' . $k . '_desc not found' + ); $settingArray['description_trans'] = !empty($settingArray['description']) ? $settingArray['description'] : ''; } } else { @@ -148,10 +153,12 @@ public function prepareRow(xPDOObject $object) $settingArray['oldkey'] = $settingArray['key']; - $settingArray['editedon'] = in_array( - $object->get('editedon'), - ['-001-11-30 00:00:00', '-1-11-30 00:00:00', '0000-00-00 00:00:00', null] - ) ? '' : date($this->dateFormat, strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $settingArray['editedon'] = !empty($customFormat) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) + ; return $settingArray; } diff --git a/core/src/Revolution/Processors/Processor.php b/core/src/Revolution/Processors/Processor.php index 79565241fe7..50e19f02d57 100644 --- a/core/src/Revolution/Processors/Processor.php +++ b/core/src/Revolution/Processors/Processor.php @@ -1,4 +1,5 @@ modx =& $modx; $this->setProperties($properties); } @@ -55,7 +58,8 @@ public function __construct(modX $modx,array $properties = []) { * @param string $path The absolute path * @return void */ - public function setPath($path) { + public function setPath($path) + { $this->path = $path; } @@ -66,9 +70,10 @@ public function setPath($path) { * * @return void */ - public function setProperties($properties, $merge = true) { + public function setProperties($properties, $merge = true) + { unset($properties['HTTP_MODAUTH']); - $this->properties = $merge ? array_merge($this->properties,$properties) : $properties; + $this->properties = $merge ? array_merge($this->properties, $properties) : $properties; } /** @@ -76,7 +81,8 @@ public function setProperties($properties, $merge = true) { * @param string $key * @return void */ - public function unsetProperty($key) { + public function unsetProperty($key) + { unset($this->properties[$key]); } @@ -85,7 +91,10 @@ public function unsetProperty($key) { * * @return boolean */ - public function checkPermissions() { return true; } + public function checkPermissions() + { + return true; + } /** * Can be used to provide custom methods prior to processing. Return true to tell MODX that the Processor @@ -93,14 +102,18 @@ public function checkPermissions() { return true; } * * @return boolean */ - public function initialize() { return true; } + public function initialize() + { + return true; + } /** * Load a collection of Language Topics for this processor. * Override this in your derivative class to provide the array of topics to load. * @return array */ - public function getLanguageTopics() { + public function getLanguageTopics() + { return []; } @@ -110,8 +123,9 @@ public function getLanguageTopics() { * @param mixed $object * @return array|string */ - public function success($msg = '',$object = null) { - return $this->modx->error->success($msg,$object); + public function success($msg = '', $object = null) + { + return $this->modx->error->success($msg, $object); } /** @@ -120,15 +134,17 @@ public function success($msg = '',$object = null) { * @param mixed $object * @return array|string */ - public function failure($msg = '',$object = null) { - return $this->modx->error->failure($msg,$object); + public function failure($msg = '', $object = null) + { + return $this->modx->error->failure($msg, $object); } /** * Return whether or not the processor has errors * @return boolean */ - public function hasErrors() { + public function hasErrors() + { return $this->modx->error->hasError(); } @@ -138,8 +154,9 @@ public function hasErrors() { * @param string $message * @return void */ - public function addFieldError($key,$message = '') { - $this->modx->error->addField($key,$message); + public function addFieldError($key, $message = '') + { + $this->modx->error->addField($key, $message); } /** @@ -152,9 +169,10 @@ public function addFieldError($key,$message = '') { * @param array $properties An array of properties being run with the processor * @return Processor The class specified by $className */ - public static function getInstance(modX $modx,$className,$properties = []) { + public static function getInstance(modX $modx, $className, $properties = []) + { /** @var Processor $processor */ - $processor = new $className($modx,$properties); + $processor = new $className($modx, $properties); return $processor; } @@ -170,7 +188,8 @@ abstract public function process(); * Run the processor, returning a ProcessorResponse object. * @return ProcessorResponse */ - public function run() { + public function run() + { if (!$this->checkPermissions()) { $o = $this->failure($this->modx->lexicon('permission_denied_processor', array( 'action' => preg_replace('/[^\w\-_\/]+/i', '', $this->getProperty('action')), @@ -189,7 +208,7 @@ public function run() { $o = $this->process(); } } - $response = new ProcessorResponse($this->modx,$o); + $response = new ProcessorResponse($this->modx, $o); return $response; } @@ -199,8 +218,9 @@ public function run() { * @param mixed $default * @return mixed */ - public function getProperty($k,$default = null) { - return array_key_exists($k,$this->properties) ? $this->properties[$k] : $default; + public function getProperty($k, $default = null) + { + return array_key_exists($k, $this->properties) ? $this->properties[$k] : $default; } /** @@ -210,7 +230,8 @@ public function getProperty($k,$default = null) { * @param mixed $v * @return void */ - public function setProperty($k,$v) { + public function setProperty($k, $v) + { $this->properties[$k] = $v; } @@ -222,11 +243,12 @@ public function setProperty($k,$v) { * @param boolean $force * @return int|null */ - public function setCheckbox($k,$force = false) { + public function setCheckbox($k, $force = false) + { $v = null; if ($force || isset($this->properties[$k])) { $v = empty($this->properties[$k]) || $this->properties[$k] === 'false' ? 0 : 1; - $this->setProperty($k,$v); + $this->setProperty($k, $v); } return $v; } @@ -235,7 +257,8 @@ public function setCheckbox($k,$force = false) { * Get an array of properties for this processor * @return array */ - public function getProperties() { + public function getProperties() + { return $this->properties; } @@ -245,8 +268,9 @@ public function getProperties() { * @param array $properties * @return array The newly merged properties array */ - public function setDefaultProperties(array $properties = []) { - $this->properties = array_merge($properties,$this->properties); + public function setDefaultProperties(array $properties = []) + { + $this->properties = array_merge($properties, $this->properties); return $this->properties; } @@ -261,8 +285,11 @@ public function setDefaultProperties(array $properties = []) { * @param mixed $count The total number of objects. Used for pagination. * @return string The JSON output. */ - public function outputArray(array $array,$count = false) { - if ($count === false) { $count = count($array); } + public function outputArray(array $array, $count = false) + { + if ($count === false) { + $count = count($array); + } $output = json_encode([ 'success' => true, 'total' => $count, @@ -270,7 +297,7 @@ public function outputArray(array $array,$count = false) { ], JSON_INVALID_UTF8_SUBSTITUTE); if ($output === false) { - $this->modx->log(modX::LOG_LEVEL_ERROR, 'Processor failed creating output array due to JSON error '.json_last_error()); + $this->modx->log(modX::LOG_LEVEL_ERROR, 'Processor failed creating output array due to JSON error ' . json_last_error()); return json_encode(['success' => false]); } return $output; @@ -286,7 +313,8 @@ public function outputArray(array $array,$count = false) { * @param mixed $data The PHP data to be converted. * @return string The extended JSON-encoded string. */ - public function toJSON($data) { + public function toJSON($data) + { if (is_array($data)) { array_walk_recursive($data, [&$this, '_encodeLiterals']); } @@ -300,12 +328,15 @@ public function toJSON($data) { * @param mixed &$value A reference to the value to be encoded if it is identified as a literal. * @param integer|string $key The array key corresponding to the value. */ - protected function _encodeLiterals(&$value, $key) { + protected function _encodeLiterals(&$value, $key) + { if (is_string($value)) { /* properly handle common literal structures */ - if (strpos($value, 'function(') === 0 + if ( + strpos($value, 'function(') === 0 || strpos($value, 'new Function(') === 0 - || strpos($value, 'Ext.') === 0) { + || strpos($value, 'Ext.') === 0 + ) { $value = '@@' . base64_encode($value) . '@@'; } } @@ -318,11 +349,14 @@ protected function _encodeLiterals(&$value, $key) { * @param string $string The JSON-encoded string with encoded literals. * @return string The JSON-encoded string with literals restored. */ - protected function _decodeLiterals($string) { + protected function _decodeLiterals($string) + { $pattern = '/"@@(.*?)@@"/'; $string = preg_replace_callback( $pattern, - function ($matches) { return base64_decode($matches[1]); }, + function ($matches) { + return base64_decode($matches[1]); + }, $string ); return $string; @@ -335,7 +369,8 @@ function ($matches) { return base64_decode($matches[1]); }, * @param string $separator The separator for each event response * @return string The processed response. */ - public function processEventResponse($response,$separator = "\n") { + public function processEventResponse($response, $separator = "\n") + { if (is_array($response)) { $result = false; foreach ($response as $msg) { diff --git a/core/src/Revolution/Processors/Resource/Data.php b/core/src/Revolution/Processors/Resource/Data.php index c600d2cc827..547a2e117b2 100644 --- a/core/src/Revolution/Processors/Resource/Data.php +++ b/core/src/Revolution/Processors/Resource/Data.php @@ -1,4 +1,5 @@ modx->hasPermission('view'); @@ -35,13 +39,16 @@ public function checkPermissions() public function getLanguageTopics() { - return ['resource']; + return ['resource', 'manager_log']; } public function initialize() { + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $id = $this->getProperty('id', false); - if (empty($id)) return $this->modx->lexicon('resource_err_ns'); + if (empty($id)) { + return $this->modx->lexicon('resource_err_ns'); + } $c = $this->modx->newQuery(modResource::class); $c->select([ $this->modx->getSelectColumns(modResource::class, 'modResource'), @@ -88,7 +95,7 @@ public function getCacheSource() $buffer = $this->modx->cacheManager->get($this->resource->getCacheKey(), [ xPDO::OPT_CACHE_KEY => $this->modx->getOption('cache_resource_key', null, 'resource'), xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), - xPDO::OPT_CACHE_FORMAT => (integer)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), + xPDO::OPT_CACHE_FORMAT => (int)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), ]); if ($buffer) { $buffer = $buffer['resource']['_content']; @@ -98,29 +105,46 @@ public function getCacheSource() public function getChanges(array $resourceArray) { - $emptyDate = '0000-00-00 00:00:00'; - $resourceArray['pub_date'] = !empty($resourceArray['pub_date']) && $resourceArray['pub_date'] != $emptyDate ? $resourceArray['pub_date'] : $this->modx->lexicon('none'); - $resourceArray['unpub_date'] = !empty($resourceArray['unpub_date']) && $resourceArray['unpub_date'] != $emptyDate ? $resourceArray['unpub_date'] : $this->modx->lexicon('none'); + $unknownUser = '(' . $this->modx->lexicon('unknown') . ')'; $resourceArray['status'] = $resourceArray['published'] ? $this->modx->lexicon('resource_published') : $this->modx->lexicon('resource_unpublished'); - $server_offset_time = floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600; - $format = $this->modx->getOption('manager_date_format') . ' ' . $this->modx->getOption('manager_time_format'); - $resourceArray['createdon_adjusted'] = date($format, strtotime($this->resource->get('createdon')) + $server_offset_time); - $resourceArray['createdon_by'] = $this->resource->get('creator'); - if (!empty($resourceArray['editedon']) && $resourceArray['editedon'] != $emptyDate) { - $resourceArray['editedon_adjusted'] = date($format, strtotime($this->resource->get('editedon')) + $server_offset_time); - $resourceArray['editedon_by'] = $this->resource->get('editor'); - } else { - $resourceArray['editedon_adjusted'] = $this->modx->lexicon('none'); - $resourceArray['editedon_by'] = $this->modx->lexicon('none'); - } - if (!empty($resourceArray['publishedon']) && $resourceArray['publishedon'] != $emptyDate) { - $resourceArray['publishedon_adjusted'] = date($format, strtotime($this->resource->get('publishedon')) + $server_offset_time); - $resourceArray['publishedon_by'] = $this->resource->get('publisher'); - } else { - $resourceArray['publishedon_adjusted'] = $this->modx->lexicon('none'); - $resourceArray['publishedon_by'] = $this->modx->lexicon('none'); - } + $resourceArray['createdon_by'] = $this->resource->get('creator') ?: $unknownUser; + $resourceArray['createdon_adjusted'] = $this->formatter->formatResourceDate( + $this->resource->get('createdon'), + 'created', + false + ); + $resourceArray['editedon_adjusted'] = $this->formatter->formatResourceDate( + $this->resource->get('editedon'), + 'edited', + false + ); + $resourceArray['editedon_by'] = $this->formatter->isEmpty($resourceArray['editedon']) + ? '(' . $this->modx->lexicon('unedited') . ')' + : $this->resource->get('editor') + ; + + $resourceArray['pub_date'] = $this->formatter->formatResourceDate( + $resourceArray['pub_date'], + 'publish', + false + ); + $resourceArray['unpub_date'] = $this->formatter->formatResourceDate( + $resourceArray['unpub_date'], + 'unpublish', + false + ); + $resourceArray['publishedon_adjusted'] = $this->formatter->formatResourceDate( + $this->resource->get('publishedon'), + 'published', + false + ); + $publisher = $this->resource->get('publisher') ?: $unknownUser; + $resourceArray['publishedon_by'] = $this->formatter->isEmpty($resourceArray['publishedon']) + ? '(' . $this->modx->lexicon('unpublished') . ')' + : $publisher + ; + return $resourceArray; } } diff --git a/core/src/Revolution/Processors/Resource/Event/GetList.php b/core/src/Revolution/Processors/Resource/Event/GetList.php index c89c1ea4f3b..a6c5dc0d736 100644 --- a/core/src/Revolution/Processors/Resource/Event/GetList.php +++ b/core/src/Revolution/Processors/Resource/Event/GetList.php @@ -1,4 +1,5 @@ modx->hasPermission('view_document'); @@ -38,13 +42,12 @@ public function getLanguageTopics() public function initialize() { + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, 'mode' => 'pub_date', - 'dir' => 'ASC', - 'timeFormat' => '%a %b %d, %Y %H:%M', - 'offset' => floatval($this->modx->getOption('server_offset_time', null, 0)) * 3600, + 'dir' => 'ASC' ]); return true; } @@ -55,7 +58,9 @@ public function process() $list = []; /** @var modResource $resource */ foreach ($data['results'] as $resource) { - if (!$resource->checkPolicy('view')) continue; + if (!$resource->checkPolicy('view')) { + continue; + } $resourceArray = $this->prepareRow($resource); if (!empty($resourceArray)) { $list[] = $resourceArray; @@ -94,25 +99,21 @@ public function getData() */ public function prepareRow(xPDOObject $object) { - $timeFormat = $this->getProperty('timeFormat', '%a %b %d, %Y'); - $offset = $this->getProperty('offset', 0); - $objectArray = $object->toArray(); + unset($objectArray['content']); + /* + Note that editor grids will not make use of the empty value; without doing some + refactoring of the MODx's datetime component, the field definition for this component + type must specify "date" as its field type and, by doing this, any formatting defined + below will be lost. + */ + $pubDate = $object->get('pub_date'); + $objectArray['pub_date'] = $this->formatter->formatDateTime($pubDate, true); - if (!in_array($object->get('pub_date'), ['', '1969-12-31 00:00:00'])) { - $pubDate = strtotime($object->get('pub_date')) + $offset; - $objectArray['pub_date'] = strftime($timeFormat, $pubDate); - } else { - $objectArray['pub_date'] = ''; - } + $unpubDate = $object->get('unpub_date'); + $objectArray['unpub_date'] = $this->formatter->formatDateTime($unpubDate,true); - if (!in_array($object->get('unpub_date'), ['', '1969-12-31 00:00:00'])) { - $unpubDate = strtotime($object->get('unpub_date')) + $offset; - $objectArray['unpub_date'] = strftime($timeFormat, $unpubDate); - } else { - $objectArray['unpub_date'] = ''; - } return $objectArray; } } diff --git a/core/src/Revolution/Processors/Resource/Trash/GetList.php b/core/src/Revolution/Processors/Resource/Trash/GetList.php index b53838d3da7..79234f46ac6 100644 --- a/core/src/Revolution/Processors/Resource/Trash/GetList.php +++ b/core/src/Revolution/Processors/Resource/Trash/GetList.php @@ -11,10 +11,11 @@ namespace MODX\Revolution\Processors\Resource\Trash; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modContext; -use MODX\Revolution\Processors\Model\GetListProcessor; use MODX\Revolution\modResource; use MODX\Revolution\modUser; +use MODX\Revolution\Processors\Model\GetListProcessor; use PDO; use xPDO\Om\xPDOObject; use xPDO\Om\xPDOQuery; @@ -39,6 +40,14 @@ class GetList extends GetListProcessor public $permission = 'view'; + private modManagerDateFormatter $formatter; + + public function initialize() + { + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -192,6 +201,8 @@ public function prepareRow(xPDOObject $object) $objectArray['cls'] = implode(' ', $cls); + $objectArray['deletedon'] = $this->formatter->formatDateTime($objectArray['deletedon']); + return $objectArray; } } diff --git a/core/src/Revolution/Processors/Security/Message/GetList.php b/core/src/Revolution/Processors/Security/Message/GetList.php index 4746f3e842e..19b18d93742 100644 --- a/core/src/Revolution/Processors/Security/Message/GetList.php +++ b/core/src/Revolution/Processors/Security/Message/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -78,7 +88,7 @@ public function prepareQueryAfterCount(xPDOQuery $c) 'recipient_username' => 'Recipient.username', 'recipient_fullname' => 'RecipientProfile.fullname' ]); - + return $c; } @@ -89,6 +99,11 @@ public function prepareQueryAfterCount(xPDOQuery $c) public function prepareRow(xPDOObject $object) { $objectArray = $object->toArray(); + + if (array_key_exists('date_sent', $objectArray)) { + $objectArray['date_sent'] = $this->formatter->formatDateTime($objectArray['date_sent']); + } + $objectArray['sender_name'] = $object->get('sender_fullname') . " ({$object->get('sender_username')})"; $objectArray['recipient_name'] = $object->get('recipient_fullname') . " ({$object->get('recipient_username')})"; $objectArray['read'] = $object->get('read') ? true : false; diff --git a/core/src/Revolution/Processors/Security/Profile/Get.php b/core/src/Revolution/Processors/Security/Profile/Get.php index 59775bbe45d..5ab425f6a8f 100644 --- a/core/src/Revolution/Processors/Security/Profile/Get.php +++ b/core/src/Revolution/Processors/Security/Profile/Get.php @@ -1,4 +1,5 @@ user) { return $this->modx->lexicon('user_err_not_found'); } + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return true; } @@ -67,12 +72,10 @@ public function process() $userArray = array_merge($profile->toArray(), $userArray); } - $userArray['dob'] = !empty($userArray['dob']) ? date('m/d/Y', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date('m/d/Y h:i A', - $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date('m/d/Y h:i A', - $userArray['blockedafter']) : ''; - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? date('m/d/Y', $userArray['lastlogin']) : ''; + $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; + $userArray['blockeduntil'] = $this->formatter->formatHidden($userArray['blockeduntil']); + $userArray['blockedafter'] = $this->formatter->formatHidden($userArray['blockedafter']); + $userArray['lastlogin'] = $this->formatter->formatDateTime($userArray['lastlogin'], false, ''); unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/User/Get.php b/core/src/Revolution/Processors/Security/User/Get.php index fa746b8ea94..98e86362546 100644 --- a/core/src/Revolution/Processors/Security/User/Get.php +++ b/core/src/Revolution/Processors/Security/User/Get.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); + return parent::initialize(); + } + /** * @throws \xPDO\xPDOException */ @@ -91,13 +101,11 @@ public function cleanup() $userArray = array_merge($profile->toArray(), $userArray); } - $userArray['dob'] = !empty($userArray['dob']) ? date('m/d/Y', $userArray['dob']) : ''; - $userArray['blockeduntil'] = !empty($userArray['blockeduntil']) ? date('Y-m-d H:i:s', - $userArray['blockeduntil']) : ''; - $userArray['blockedafter'] = !empty($userArray['blockedafter']) ? date('Y-m-d H:i:s', - $userArray['blockedafter']) : ''; - $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? date($this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), - $userArray['lastlogin']) : ''; + $userArray['dob'] = !empty($userArray['dob']) ? date('Y-m-d', $userArray['dob']) : ''; + $userArray['blockeduntil'] = $this->formatter->formatHidden($userArray['blockeduntil']); + $userArray['blockedafter'] = $this->formatter->formatHidden($userArray['blockedafter']); + $userArray['createdon'] = $this->formatter->formatDateTime($userArray['createdon']); + $userArray['lastlogin'] = !empty($userArray['lastlogin']) ? $this->formatter->formatDateTime($userArray['lastlogin']) : ''; unset($userArray['password'], $userArray['cachepwd'], $userArray['sessionid'], $userArray['salt']); return $this->success('', $userArray); diff --git a/core/src/Revolution/Processors/Security/User/GetOnline.php b/core/src/Revolution/Processors/Security/User/GetOnline.php index 6d0023855f9..b60d3cbd54d 100644 --- a/core/src/Revolution/Processors/Security/User/GetOnline.php +++ b/core/src/Revolution/Processors/Security/User/GetOnline.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); + return parent::initialize(); + } + /** * @param xPDOQuery $c * @return xPDOQuery @@ -70,9 +80,14 @@ public function prepareRow(xPDOObject $object) { $row = $object->toArray(); + $row['occurred_date'] = $this->formatter->formatDate($row['occurred']); + $row['occurred_time'] = $this->formatter->formatTime($row['occurred']); + $row['occurred'] = $this->formatter->formatDateTime($row['occurred']); + /** @var modUser $user */ if ($user = $object->getOne('User')) { - $row = array_merge($row, + $row = array_merge( + $row, $user->get(['username']), $user->Profile->get(['fullname', 'email']), ['photo' => $user->getPhoto(64, 64)] diff --git a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php index d1dd77078d0..f2a8955cb4e 100644 --- a/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php +++ b/core/src/Revolution/Processors/Security/User/GetRecentlyEditedResources.php @@ -1,4 +1,5 @@ setDefaultProperties(['limit' => 10]); - + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->classKeys = $this->modx->getDescendants(modResource::class); $this->classKeys[] = modResource::class; return parent::initialize(); } - /** * Filter resources by user * @param xPDOQuery $c @@ -96,27 +98,20 @@ public function prepareRow(xPDOObject $object) $resourceArray = $resource->get(['id','pagetitle','description','published','deleted','context_key', 'createdon', 'editedon']); $resourceArray['pagetitle'] = htmlspecialchars($resourceArray['pagetitle'], ENT_QUOTES, $this->modx->getOption('modx_charset', null, 'UTF-8')); - $dateFormat = $this->modx->getOption('manager_date_format'); - $timeFormat = $this->modx->getOption('manager_time_format'); - - $createdon = new \DateTimeImmutable($resourceArray['createdon']); - $resourceArray['createdon_date'] = $createdon->format($dateFormat); - $resourceArray['createdon_time'] = $createdon->format($timeFormat); - - $resourceArray['editedon_date'] = $resourceArray['createdon_date']; - $resourceArray['editedon_time'] = $resourceArray['createdon_time']; - - if (!empty($resourceArray['editedon'])) { - $editedon = new \DateTimeImmutable($resourceArray['editedon']); - $resourceArray['editedon_date'] = $editedon->format($dateFormat); - $resourceArray['editedon_time'] = $editedon->format($timeFormat); - } + $editedon = !empty($resourceArray['editedon']) ? $resourceArray['editedon'] : $resourceArray['createdon'] ; + $isUnedited = $editedon === $resourceArray['createdon']; + $resourceArray['createdon_date'] = $this->formatter->formatDate($resourceArray['createdon']); + $resourceArray['createdon_time'] = $this->formatter->formatTime($resourceArray['createdon']); + $resourceArray['editedon_date'] = $isUnedited ? $resourceArray['createdon_date'] : $this->formatter->formatDate($editedon); + $resourceArray['editedon_time'] = $isUnedited ? $resourceArray['createdon_time'] : $this->formatter->formatTime($editedon); + $row['occurred'] = $this->formatter->formatDateTime($row['occurred']); $row = array_merge($row, $resourceArray); /** @var modUser $user */ if ($user = $object->getOne('User')) { - $row = array_merge($row, + $row = array_merge( + $row, $user->get(['username']), $user->Profile->get(['fullname', 'email']), ['photo' => $user->getPhoto(64, 64)] diff --git a/core/src/Revolution/Processors/Security/User/Validation.php b/core/src/Revolution/Processors/Security/User/Validation.php index e1d27fb6bc4..bf0ac721563 100644 --- a/core/src/Revolution/Processors/Security/User/Validation.php +++ b/core/src/Revolution/Processors/Security/User/Validation.php @@ -74,8 +74,8 @@ public function alreadyExists($name) modUser::class, [ 'username' => $name, - 'id:!=' => $this->user->get('id'), - ] + 'id:!=' => $this->user->get('id') + ] ) > 0; } diff --git a/core/src/Revolution/Processors/System/ActiveResource/GetList.php b/core/src/Revolution/Processors/System/ActiveResource/GetList.php index 599b292e39b..564e405e8b1 100644 --- a/core/src/Revolution/Processors/System/ActiveResource/GetList.php +++ b/core/src/Revolution/Processors/System/ActiveResource/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ - 'dateFormat' => '%b %d, %Y %I:%M %p', + 'dateFormat' => '', ]); return $initialized; } @@ -100,7 +105,12 @@ public function prepareRow(xPDOObject $object) 'editedon', 'username', ]); - $objectArray['editedon'] = strftime($this->getProperty('dateFormat'), strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $objectArray['editedon'] = !empty($customFormat) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) + ; return $objectArray; } diff --git a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php index 8db6d363b05..d32f6acb58b 100644 --- a/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php +++ b/core/src/Revolution/Processors/System/Dashboard/Widget/Feed.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); + return parent::initialize(); + } + /** * @return array|mixed|string */ @@ -74,18 +84,21 @@ public function loadFeed($url) $feed->handle_content_type(); if ($feed->error()) { - $this->modx->log(modX::LOG_LEVEL_ERROR, - is_array($feed->error()) ? print_r($feed->error(), true) : $feed->error()); + $this->modx->log( + modX::LOG_LEVEL_ERROR, + is_array($feed->error()) ? print_r($feed->error(), true) : $feed->error() + ); } $output = []; /** @var SimplePie_Item $item */ foreach ($feed->get_items() as $item) { + $date = $item->get_date('Y-m-d H:i:s'); $output[] = $this->getFileChunk('dashboard/rssitem.tpl', [ 'title' => $item->get_title(), 'description' => $item->get_description(), 'link' => $item->get_permalink(), - 'pubdate' => $item->get_date(), + 'pubdate' => $this->formatter->formatDateTime($date) ]); } @@ -103,8 +116,7 @@ public function getFileChunk($tpl, array $placeholders = []) $file = $tpl; if (!file_exists($file)) { - $file = $this->modx->getOption('manager_path') . 'templates/' . $this->modx->getOption('manager_theme', - null, 'default') . '/' . $tpl; + $file = $this->modx->getOption('manager_path') . 'templates/' . $this->modx->getOption('manager_theme', null, 'default') . '/' . $tpl; } if (!file_exists($file)) { $file = $this->modx->getOption('manager_path') . 'templates/default/' . $tpl; @@ -126,7 +138,7 @@ public function getFileChunk($tpl, array $placeholders = []) * * @return array The proxy configuration. */ - private function buildProxyOptions() + private function buildProxyOptions() { $config = []; $proxyHost = $this->modx->getOption('proxy_host', null, ''); diff --git a/core/src/Revolution/Processors/System/Log/GetList.php b/core/src/Revolution/Processors/System/Log/GetList.php index e20a4b4d097..6558be5951b 100644 --- a/core/src/Revolution/Processors/System/Log/GetList.php +++ b/core/src/Revolution/Processors/System/Log/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'limit' => 20, 'start' => 0, @@ -61,7 +66,7 @@ public function initialize() 'actionType' => false, 'dateStart' => false, 'dateEnd' => false, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), + 'dateFormat' => '', ]); return true; } @@ -185,8 +190,8 @@ public function prepareLog(modManagerLog $log) // Action is prefixed with a namespace, assume we need to load a package $exp = explode('.', $logArray['action']); $ns = $exp[0]; - $path = $this->modx->getOption("{$ns}.core_path", null, - $this->modx->getOption('core_path') . "components/{$ns}/") . 'model/'; + $nsCorePath = $this->modx->getOption('core_path') . "components/{$ns}/"; + $path = $this->modx->getOption("{$ns}.core_path", null, $nsCorePath) . 'model/'; $this->modx->addPackage($ns, $path); } if (!empty($logArray['classKey']) && !empty($logArray['item'])) { @@ -204,7 +209,11 @@ public function prepareLog(modManagerLog $log) } else { $logArray['name'] = $log->get('item'); } - $logArray['occurred'] = date($this->getProperty('dateFormat'), strtotime($logArray['occurred'])); + $customFormat = $this->getProperty('dateFormat'); + $logArray['occurred'] = !empty($customFormat) + ? $this->formatter->format($logArray['occurred'], $customFormat) + : $this->formatter->formatDateTime($logArray['occurred']) + ; return $logArray; } @@ -245,8 +254,7 @@ public function getNameField($classKey) case modUserSetting::class: $field = 'key'; break; - default: - break; + // no default } return $field; } diff --git a/core/src/Revolution/Processors/System/Settings/GetList.php b/core/src/Revolution/Processors/System/Settings/GetList.php index 6e855d70e4b..d00ba0309dc 100644 --- a/core/src/Revolution/Processors/System/Settings/GetList.php +++ b/core/src/Revolution/Processors/System/Settings/GetList.php @@ -1,4 +1,5 @@ formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'key' => false, 'namespace' => false, 'area' => false, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), + 'dateFormat' => '' ]); return $initialized; @@ -113,9 +118,14 @@ public function prepareRow(xPDOObject $object) $k = 'setting_' . $settingArray['key']; /* if 3rd party setting, load proper text, fallback to english */ - $this->modx->lexicon->load('en:' . $object->get('namespace') . ':default', - 'en:' . $object->get('namespace') . ':setting'); - $this->modx->lexicon->load($object->get('namespace') . ':default', $object->get('namespace') . ':setting'); + $this->modx->lexicon->load( + 'en:' . $object->get('namespace') . ':default', + 'en:' . $object->get('namespace') . ':setting' + ); + $this->modx->lexicon->load( + $object->get('namespace') . ':default', + $object->get('namespace') . ':setting' + ); /* get translated area text */ if ($this->modx->lexicon->exists('area_' . $object->get('area'))) { @@ -145,19 +155,25 @@ public function prepareRow(xPDOObject $object) } else { $settingArray['name'] = $settingArray['name_trans']; } - $settingArray['key'] = htmlspecialchars($settingArray['key'], ENT_QUOTES, - $this->modx->getOption('modx_charset', null, 'UTF-8')); - $settingArray['name_trans'] = htmlspecialchars($settingArray['name_trans'], ENT_QUOTES, - $this->modx->getOption('modx_charset', null, 'UTF-8')); + $settingArray['key'] = htmlspecialchars( + $settingArray['key'], + ENT_QUOTES, + $this->modx->getOption('modx_charset', null, 'UTF-8') + ); + $settingArray['name_trans'] = htmlspecialchars( + $settingArray['name_trans'], + ENT_QUOTES, + $this->modx->getOption('modx_charset', null, 'UTF-8') + ); $settingArray['oldkey'] = $settingArray['key']; - $settingArray['editedon'] = in_array($object->get('editedon'), [ - '-001-11-30 00:00:00', - '-1-11-30 00:00:00', - '0000-00-00 00:00:00', - null - ]) ? '' : date($this->getProperty('dateFormat'), strtotime($object->get('editedon'))); + $customFormat = $this->getProperty('dateFormat'); + $editedOn = $object->get('editedon'); + $settingArray['editedon'] = !empty($customFormat) + ? $this->formatter->format($editedOn, $customFormat) + : $this->formatter->formatDateTime($editedOn) + ; return $settingArray; } diff --git a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php index f2e874e510f..39ac2efb410 100644 --- a/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Lexicon/GetList.php @@ -11,6 +11,7 @@ namespace MODX\Revolution\Processors\Workspace\Lexicon; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\modLexiconEntry; use MODX\Revolution\Processors\Processor; @@ -25,6 +26,8 @@ */ class GetList extends Processor { + private modManagerDateFormatter $formatter; + /** * @return bool */ @@ -65,6 +68,7 @@ public function initialize() if ($this->getProperty('topic') === '') { $this->setProperty('topic', 'default'); } + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return true; } @@ -137,6 +141,7 @@ function parseArray($needle, array $haystack = []) /* loop through */ $list = []; foreach ($entries as $name => $value) { + $editedOn = null; $entryArray = [ 'name' => $name, 'value' => $value, @@ -152,10 +157,10 @@ function parseArray($needle, array $haystack = []) foreach ($dbEntries[$name] as $k => $v) { $entryArray[$k] = $v; // array_merge very slow inside loop, don't use it here } - - $entryArray['editedon'] = strtotime($entryArray['editedon']) ?: strtotime($entryArray['createdon']); + $editedOn = $entryArray['editedon'] ?: $entryArray['createdon'] ; $entryArray['overridden'] = 1; } + $entryArray['editedon'] = $this->formatter->formatDateTime($editedOn); $list[] = $entryArray; } diff --git a/core/src/Revolution/Processors/Workspace/Packages/Get.php b/core/src/Revolution/Processors/Workspace/Packages/Get.php index 9243a103980..ec13fd43382 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Get.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Get.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); - $this->dateFormat = $this->getProperty('dateFormat', - $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format')); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); return parent::initialize(); } @@ -83,19 +83,17 @@ public function getMetadata() */ public function formatDates(array $packageArray) { - $updated = $this->object->get('updated'); - if ($updated !== '0000-00-00 00:00:00' && $updated !== null) { - $packageArray['updated'] = date($this->dateFormat, strtotime($updated)); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = date($this->dateFormat, strtotime($this->object->get('created'))); - $installed = $this->object->get('installed'); - if ($installed === null || $installed === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = date($this->dateFormat, strtotime($installed)); - } + $packageArray['created'] = $this->formatter->formatPackageDate($this->object->get('created')); + $packageArray['installed'] = $this->formatter->formatPackageDate( + $this->object->get('installed'), + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->formatPackageDate( + $this->object->get('updated'), + 'updated', + false + ); return $packageArray; } } diff --git a/core/src/Revolution/Processors/Workspace/Packages/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/GetList.php index a48d48c1af7..b0e040a47be 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/GetList.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'start' => 0, 'limit' => 10, 'workspace' => 1, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), 'query' => '', ]); return true; @@ -141,20 +145,18 @@ public function getVersionInfo(array $packageArray) */ public function formatDates(array $packageArray) { - if ($packageArray['updated'] !== '0000-00-00 00:00:00' && $packageArray['updated'] !== null) { - $packageArray['updated'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['updated']))); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['created']))); - if ($packageArray['installed'] === null || $packageArray['installed'] === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = utf8_encode(date($this->getProperty('dateFormat'), - strtotime($packageArray['installed']))); - } + $packageArray['created'] = $this->formatter->formatPackageDate($packageArray['created']); + $packageArray['installed'] = $this->formatter->formatPackageDate( + $packageArray['installed'], + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->formatPackageDate( + $packageArray['updated'], + 'updated', + false + ); + return $packageArray; } @@ -197,9 +199,16 @@ public function checkForUpdates(modTransportPackage $package, array $packageArra if ($package->get('provider') > 0 && $this->modx->getOption('auto_check_pkg_updates', null, false)) { $updateCacheKey = 'mgr/providers/updates/' . $package->get('provider') . '/' . $package->get('signature'); $updateCacheOptions = [ - xPDO::OPT_CACHE_KEY => $this->modx->cacheManager->getOption('cache_packages_key', null, 'packages'), - xPDO::OPT_CACHE_HANDLER => $this->modx->cacheManager->getOption('cache_packages_handler', null, - $this->modx->cacheManager->getOption(xPDO::OPT_CACHE_HANDLER)), + xPDO::OPT_CACHE_KEY => $this->modx->cacheManager->getOption( + 'cache_packages_key', + null, + 'packages' + ), + xPDO::OPT_CACHE_HANDLER => $this->modx->cacheManager->getOption( + 'cache_packages_handler', + null, + $this->modx->cacheManager->getOption(xPDO::OPT_CACHE_HANDLER) + ) ]; $updates = $this->modx->cacheManager->get($updateCacheKey, $updateCacheOptions); if (empty($updates)) { @@ -220,8 +229,7 @@ public function checkForUpdates(modTransportPackage $package, array $packageArra } else { $updates = ['count' => count($updates)]; } - $this->modx->cacheManager->set($updateCacheKey, $updates, $this->updatesCacheExpire, - $updateCacheOptions); + $this->modx->cacheManager->set($updateCacheKey, $updates, $this->updatesCacheExpire, $updateCacheOptions); } } } diff --git a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php index d8d332e233f..b32b184dff6 100644 --- a/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php +++ b/core/src/Revolution/Processors/Workspace/Packages/Version/GetList.php @@ -1,4 +1,5 @@ modx->addPackage('Revolution\Transport', MODX_CORE_PATH . 'src/'); + $this->formatter = $this->modx->services->get(modManagerDateFormatter::class); $this->setDefaultProperties([ 'limit' => 10, 'start' => 0, 'workspace' => 1, - 'dateFormat' => $this->modx->getOption('manager_date_format') . ', ' . $this->modx->getOption('manager_time_format'), 'signature' => false, ]); return parent::initialize(); @@ -57,8 +61,11 @@ public function getData() 'package_name' => urldecode($this->getProperty('package_name', $signatureArray[0])), ]; $limit = $this->getProperty('limit'); - $pkgList = $this->modx->call(modTransportPackage::class, 'listPackageVersions', - [&$this->modx, $criteria, $limit > 0 ? $limit : 0, $this->getProperty('start')]); + $pkgList = $this->modx->call( + modTransportPackage::class, + 'listPackageVersions', + [&$this->modx, $criteria, $limit > 0 ? $limit : 0, $this->getProperty('start')] + ); $data['results'] = $pkgList['collection']; $data['total'] = $pkgList['total']; return $data; @@ -110,19 +117,18 @@ public function parseVersion(modTransportPackage $package, array $packageArray) */ public function formatDates(modTransportPackage $package, array $packageArray) { - $updated = $package->get('updated'); - if ($updated !== '0000-00-00 00:00:00' && $updated !== null) { - $packageArray['updated'] = date($this->getProperty('dateFormat'), strtotime($updated)); - } else { - $packageArray['updated'] = ''; - } - $packageArray['created'] = date($this->getProperty('dateFormat'), strtotime($package->get('created'))); - $installed = $package->get('installed'); - if ($installed === null || $installed === '0000-00-00 00:00:00') { - $packageArray['installed'] = null; - } else { - $packageArray['installed'] = date($this->getProperty('dateFormat'), strtotime($installed)); - } + $packageArray['created'] = $this->formatter->formatPackageDate($package->get('created')); + $packageArray['installed'] = $this->formatter->formatPackageDate( + $package->get('installed'), + 'installed', + false + ); + $packageArray['updated'] = $this->formatter->formatPackageDate( + $package->get('updated'), + 'updated', + false + ); + return $packageArray; } @@ -137,8 +143,11 @@ public function getMetaData(modTransportPackage $package, array $packageArray) if (!empty($metadata)) { foreach ($metadata as $row) { if (!empty($row['name']) && $row['name'] === 'description') { - $packageArray['readme'] = str_replace([PHP_EOL, '

'], ['', '
'], - nl2br($row['text'])); + $packageArray['readme'] = str_replace( + [PHP_EOL, '

'], + ['', '
'], + nl2br($row['text']) + ); break; } } @@ -147,8 +156,11 @@ public function getMetaData(modTransportPackage $package, array $packageArray) $transport = $package->getTransport(); if ($transport) { $packageArray['readme'] = $transport->getAttribute('readme'); - $packageArray['readme'] = str_replace([PHP_EOL, '

'], ['', '
'], - nl2br($packageArray['readme'])); + $packageArray['readme'] = str_replace( + [PHP_EOL, '

'], + ['', '
'], + nl2br($packageArray['readme']) + ); } } unset($packageArray['attributes'], $packageArray['metadata'], $packageArray['manifest']); diff --git a/core/src/Revolution/modX.php b/core/src/Revolution/modX.php index f12942d0a93..db899c786de 100644 --- a/core/src/Revolution/modX.php +++ b/core/src/Revolution/modX.php @@ -13,6 +13,7 @@ use Exception; use GuzzleHttp\Client; use GuzzleHttp\Psr7\HttpFactory; +use MODX\Revolution\Formatter\modManagerDateFormatter; use MODX\Revolution\Services\Container; use MODX\Revolution\Error\modError; use MODX\Revolution\Error\modErrorHandler; @@ -584,6 +585,8 @@ public function initialize($contextKey= 'web', $options = null) { $this->services->add('registry', new modRegistry($this)); $this->registry = $this->services->get('registry'); + $this->services->add(modManagerDateFormatter::class, fn() => new modManagerDateFormatter($this)); + if (!$this->getOption(xPDO::OPT_SETUP)) { $this->invokeEvent( 'OnMODXInit', @@ -2987,4 +2990,28 @@ public function _postProcess() { } $this->invokeEvent('OnWebPageComplete'); } + + /** + * Determine whether the passed value is a unix timestamp and, optionally, whether it is within + * a specified range + * @param string|int $value The timestamp to test + * @param bool $limitStart Optional minimum timestamp value that will validate + * @param bool $limitEnd Optional maximum timestamp value that will validate + * @return bool + */ + public static function isValidTimestamp($value, $limitStart = false, $limitEnd = false): bool + { + // Check that value represents an integer (signed or unsigned) + if (!preg_match('/^-?[1-9][0-9]*$/', $value)) { + return false; + } + $value = (int)$value; + if (!($value <= PHP_INT_MAX && $value >= ~PHP_INT_MAX)) { + return false; + } + if (($limitStart !== false && $value < (int)$limitStart) || ($limitEnd !== false && $value > (int)$limitEnd)) { + return false; + } + return true; + } } diff --git a/manager/assets/modext/sections/system/file/edit.js b/manager/assets/modext/sections/system/file/edit.js index 80995229128..d5d994dfd43 100644 --- a/manager/assets/modext/sections/system/file/edit.js +++ b/manager/assets/modext/sections/system/file/edit.js @@ -111,14 +111,14 @@ MODx.panel.EditFile = function(config) { ,name: 'last_accessed' ,id: 'modx-file-last-accessed' ,anchor: '100%' - ,value: MODx.util.Format.dateFromTimestamp(config.record.last_accessed) + ,value: config.record.last_accessed },{ xtype: 'statictextfield' ,fieldLabel: _('file_last_modified') ,name: 'last_modified' ,id: 'modx-file-last-modified' ,anchor: '100%' - ,value: MODx.util.Format.dateFromTimestamp(config.record.last_modified) + ,value: config.record.last_modified },{ xtype: 'textarea' ,hideLabel: true diff --git a/manager/assets/modext/widgets/media/modx.browser.js b/manager/assets/modext/widgets/media/modx.browser.js index 67cb98113a0..4208711d9a8 100644 --- a/manager/assets/modext/widgets/media/modx.browser.js +++ b/manager/assets/modext/widgets/media/modx.browser.js @@ -43,7 +43,7 @@ MODx.browser.View = function(config) { {name: 'name', sortType: Ext.data.SortTypes.asUCString} ,'cls','url','relativeUrl','fullRelativeUrl','image','original_width','original_height','image_width','image_height','thumb','thumb_width','thumb_height','pathname','pathRelative','ext','disabled','preview' ,{name: 'size', type: 'float'} - ,{name: 'lastmod', type: 'date', dateFormat: 'timestamp'} + ,'lastmod' ,'menu', 'visibility' ] ,baseParams: { @@ -393,7 +393,6 @@ Ext.extend(MODx.browser.View,MODx.DataView,{ data.sizeString = data.size != 0 ? formatSize(data.size) : 0; data.imageSizeString = data.preview != 0 ? data.original_width + "x" + data.original_height + "px": 0; data.imageSizeString = data.imageSizeString === "xpx" ? 0 : data.imageSizeString; - data.dateString = !Ext.isEmpty(data.lastmod) ? new Date(data.lastmod).format(MODx.config.manager_date_format + " " + MODx.config.manager_time_format) : 0; this.lookup[data.name] = data; return data; } @@ -460,9 +459,9 @@ Ext.extend(MODx.browser.View,MODx.DataView,{ ,' '+_('image_size')+':' ,' {imageSizeString}' ,' ' - ,' ' + ,' ' ,' '+_('file_last_modified')+':' - ,' {dateString}' + ,' {lastmod}' ,' ' ,' ' ,' '+_('visibility')+':' diff --git a/manager/assets/modext/widgets/modx.panel.welcome.js b/manager/assets/modext/widgets/modx.panel.welcome.js index 5210d3e4afc..56f0d81591b 100644 --- a/manager/assets/modext/widgets/modx.panel.welcome.js +++ b/manager/assets/modext/widgets/modx.panel.welcome.js @@ -91,10 +91,6 @@ Ext.extend(MODx.panel.Welcome, MODx.Panel, { else if (response.message.length > 0) { container.innerHTML = '

' + MODx.util.safeHtml(response.message) + '

'; } - var datestamps = Ext.select(".date_stamp", container); - datestamps.each(function (el) { - el.dom.innerText = new Date(el.dom.innerText).format(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format); - }); }, scope: this } ,failure: { diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.data.js b/manager/assets/modext/widgets/resource/modx.panel.resource.data.js index ea57402aace..e9889b13e64 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.data.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.data.js @@ -2,8 +2,7 @@ MODx.panel.ResourceData = function(config) { config = config || {}; var df = { border: false - ,msgTarget: 'side' - ,width: 300 + ,anchor: '100%' }; Ext.applyIf(config,{ url: MODx.config.connector_url @@ -27,119 +26,99 @@ MODx.panel.ResourceData = function(config) { name: 'context_key' ,fieldLabel: _('context') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'alias' ,fieldLabel: _('resource_alias') ,description: _('resource_alias_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'template_name' ,fieldLabel: _('resource_template') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'pagetitle' ,fieldLabel: _('resource_pagetitle') ,description: _('resource_pagetitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'longtitle' ,fieldLabel: _('resource_longtitle') ,description: _('resource_longtitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' ,value: _('notset') },{ name: 'description' ,fieldLabel: _('resource_description') ,description: _('resource_description_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'introtext' ,fieldLabel: _('resource_summary') ,description: _('resource_summary_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content' ,fieldLabel: _('resource_content') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'published' ,fieldLabel: _('resource_published') ,description: _('resource_published_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'deleted' ,fieldLabel: _('deleted') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'publishedon' ,fieldLabel: _('resource_publishedon') ,description: _('resource_publishedon_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'pub_date' ,fieldLabel: _('resource_publishdate') ,description: _('resource_publishdate_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'unpub_date' ,fieldLabel: _('resource_unpublishdate') ,description: _('resource_unpublishdate_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'hidemenu' ,fieldLabel: _('resource_hide_from_menus') ,description: _('resource_hide_from_menus_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'menutitle' ,fieldLabel: _('resource_menutitle') ,description: _('resource_menutitle_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'menuindex' ,fieldLabel: _('resource_menuindex') ,description: _('resource_menuindex_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'link_attributes' ,fieldLabel: _('resource_link_attributes') ,description: _('resource_link_attributes_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'class_key' ,fieldLabel: _('class_key') ,description: _('resource_class_key_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content_type' ,fieldLabel: _('resource_content_type') ,description: _('resource_content_type_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'isfolder' ,fieldLabel: _('resource_folder') ,description: _('resource_folder_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'show_in_tree' ,fieldLabel: _('resource_show_in_tree') @@ -163,7 +142,6 @@ MODx.panel.ResourceData = function(config) { ,fieldLabel: _('resource_uri_override') ,description: _('resource_uri_override_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'uri' ,fieldLabel: _('resource_uri') @@ -175,31 +153,26 @@ MODx.panel.ResourceData = function(config) { ,fieldLabel: _('resource_parent') ,description: _('resource_parent_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'content_dispo' ,fieldLabel: _('resource_contentdispo') ,description: _('resource_contentdispo_help') ,xtype: 'statictextfield' - ,anchor: '100%' },{ name: 'richtext' ,fieldLabel: _('resource_richtext') ,description: _('resource_richtext_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'searchable' ,fieldLabel: _('resource_searchable') ,description: _('resource_searchable_help') ,xtype: 'staticboolean' - ,anchor: '100%' },{ name: 'cacheable' ,fieldLabel: _('resource_cacheable') ,description: _('resource_cacheable_help') ,xtype: 'staticboolean' - ,anchor: '100%' }] },{ title: _('changes') @@ -213,7 +186,6 @@ MODx.panel.ResourceData = function(config) { ,items: [{ name: 'createdon_adjusted' ,fieldLabel: _('resource_createdon') - ,anchor: '100%' },{ name: 'createdon_by' ,fieldLabel: _('resource_createdby') @@ -221,22 +193,17 @@ MODx.panel.ResourceData = function(config) { },{ name: 'publishedon_adjusted' ,fieldLabel: _('resource_publishedon') - ,anchor: '100%' },{ name: 'publishedon_by' ,fieldLabel: _('resource_publishedby') - ,anchor: '100%' },{ name: 'editedon_adjusted' ,fieldLabel: _('resource_editedon') - ,anchor: '100%' },{ name: 'editedon_by' ,fieldLabel: _('resource_editedby') - ,anchor: '100%' },{ xtype: 'modx-grid-manager-log' - ,anchor: '100%' ,preventRender: true ,formpanel: 'modx-panel-manager-log' ,baseParams: { @@ -297,8 +264,7 @@ Ext.extend(MODx.panel.ResourceData,MODx.FormPanel,{ } ,listeners: { 'success': {fn:function(r) { - if (r.object.pub_date == '0') { r.object.pub_date = ''; } - if (r.object.unpub_date == '0') { r.object.unpub_date = ''; } + r.object.publishedon = r.object.publishedon_adjusted; Ext.get('modx-resource-header').update(Ext.util.Format.htmlEncode(r.object.pagetitle)); this.getForm().setValues(r.object); this.fireEvent('ready'); diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js b/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js index 13fc9227bf5..4be9016330f 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.schedule.js @@ -57,7 +57,7 @@ MODx.grid.ResourceSchedule = function(config) { ,'pagetitle' ,'class_key' ,{name: 'pub_date', type: 'date'} - ,{name: 'unpub_date', type:'date'} + ,{name: 'unpub_date', type: 'date'} ,'menu' ] ,showActionsColumn: false @@ -88,7 +88,7 @@ MODx.grid.ResourceSchedule = function(config) { ,timeFormat: MODx.config.manager_time_format ,ctCls: 'x-datetime-inline-editor' } - ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format) + ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + MODx.config.manager_datetime_separator + MODx.config.manager_time_format) },{ header: _('unpublish_date') ,dataIndex: 'unpub_date' @@ -99,7 +99,7 @@ MODx.grid.ResourceSchedule = function(config) { ,timeFormat: MODx.config.manager_time_format ,ctCls: 'x-datetime-inline-editor' } - ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format) + ,renderer: Ext.util.Format.dateRenderer(MODx.config.manager_date_format + MODx.config.manager_datetime_separator + MODx.config.manager_time_format) }] ,tbar: [{ text: _('showing_pub') @@ -108,7 +108,7 @@ MODx.grid.ResourceSchedule = function(config) { ,enableToggle: true ,tooltip: _('click_to_change') ,id: 'btn-toggle' - ,cls:'primary-button' + ,cls: 'primary-button' }] }); MODx.grid.ResourceSchedule.superclass.constructor.call(this,config); diff --git a/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js b/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js index cb749b53652..a64f3929cde 100644 --- a/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js +++ b/manager/assets/modext/widgets/security/modx.grid.user.recent.resource.js @@ -37,7 +37,6 @@ MODx.grid.RecentlyEditedResourcesByUser = function(config) { },{ header: _('editedon') ,dataIndex: 'occurred' - ,renderer : Ext.util.Format.dateRenderer(dateFormat) },{ header: _('published') ,dataIndex: 'published' diff --git a/manager/assets/modext/widgets/system/modx.grid.manager.log.js b/manager/assets/modext/widgets/system/modx.grid.manager.log.js index 8a0b549defd..82088d5cb05 100644 --- a/manager/assets/modext/widgets/system/modx.grid.manager.log.js +++ b/manager/assets/modext/widgets/system/modx.grid.manager.log.js @@ -75,6 +75,7 @@ MODx.panel.ManagerLog = function(config) { ,name: 'dateStart' ,allowBlank: true ,anchor: '100%' + ,format: MODx.config.manager_date_format ,listeners: { 'select': {fn: this.filter, scope: this} ,'render': {fn:this._addEnterKeyHandler} @@ -85,6 +86,7 @@ MODx.panel.ManagerLog = function(config) { ,name: 'dateEnd' ,allowBlank: true ,anchor: '100%' + ,format: MODx.config.manager_date_format ,listeners: { 'select': {fn: this.filter, scope: this} ,'render': {fn:this._addEnterKeyHandler} diff --git a/manager/assets/modext/workspace/lexicon/lexicon.grid.js b/manager/assets/modext/workspace/lexicon/lexicon.grid.js index 7d7d5440d10..6b074fa3c78 100644 --- a/manager/assets/modext/workspace/lexicon/lexicon.grid.js +++ b/manager/assets/modext/workspace/lexicon/lexicon.grid.js @@ -49,7 +49,6 @@ MODx.grid.Lexicon = function(config = {}) { header: _('last_modified') ,dataIndex: 'editedon' ,width: 125 - ,renderer: this._renderLastModDate }] ,tbar: { cls: 'has-nested-filters', @@ -236,12 +235,12 @@ Ext.extend(MODx.grid.Lexicon,MODx.grid.Grid,{ } } + /** + * @deprecated since 3.0.5. To be removed in future release. Datetime formatting + * now handled in back end processors to provide uniform display across components. + */ ,_renderLastModDate: function(value) { - if (Ext.isEmpty(value)) { - return '—'; - } - - return new Date(value*1000).format(MODx.config.manager_date_format + ' ' + MODx.config.manager_time_format); + return value; } ,loadWindow2: function(btn,e,o) { diff --git a/manager/assets/modext/workspace/package.grid.js b/manager/assets/modext/workspace/package.grid.js index c25d19b2098..3914fb4080b 100644 --- a/manager/assets/modext/workspace/package.grid.js +++ b/manager/assets/modext/workspace/package.grid.js @@ -211,16 +211,11 @@ Ext.extend(MODx.grid.Package,MODx.grid.Grid,{ return this.mainColumnTpl.apply(values); } - ,dateColumnRenderer: function(d,c) { - switch(d) { - case '': - case null: - c.css = 'not-installed'; - return _('not_installed'); - default: - c.css = ''; - return _('installed_on',{'time':d}); + ,dateColumnRenderer: function(value, metaData) { + if (Ext.isEmpty(value) || value.includes(_('not_installed'))) { + metaData.css = 'not-installed'; } + return value; } ,onClick: function(e){ diff --git a/manager/assets/modext/workspace/package/package.versions.grid.js b/manager/assets/modext/workspace/package/package.versions.grid.js index 0223981dd67..eac7118d076 100644 --- a/manager/assets/modext/workspace/package/package.versions.grid.js +++ b/manager/assets/modext/workspace/package/package.versions.grid.js @@ -41,16 +41,11 @@ MODx.grid.PackageVersions = function(config) { }; Ext.extend(MODx.grid.PackageVersions,MODx.grid.Grid,{ - _rins: function(d,c) { - switch(d) { - case '': - case null: - c.css = 'not-installed'; - return _('not_installed'); - default: - c.css = ''; - return d; + _rins: function(value, metaData) { + if (Ext.isEmpty(value) || value.includes(_('not_installed'))) { + metaData.css = 'not-installed'; } + return value; } ,removePriorVersion: function(btn,e) { diff --git a/manager/controllers/default/resource/data.class.php b/manager/controllers/default/resource/data.class.php index 39614ebfb4b..887fb1965c2 100644 --- a/manager/controllers/default/resource/data.class.php +++ b/manager/controllers/default/resource/data.class.php @@ -1,4 +1,5 @@ modx->cacheManager->get($this->resource->getCacheKey(), [ xPDO::OPT_CACHE_KEY => $this->modx->getOption('cache_resource_key', null, 'resource'), xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), - xPDO::OPT_CACHE_FORMAT => (integer)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), + xPDO::OPT_CACHE_FORMAT => (int)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), ]); if ($buffer) { $placeholders['buffer'] = htmlspecialchars($buffer['resource']['_content']); @@ -115,9 +116,9 @@ public function process(array $scriptProperties = []) $placeholders['_ctx'] = $this->resource->get('context_key'); return $placeholders; + return ''; } - /** * @return string */ @@ -160,7 +161,7 @@ public function getTemplateFile() */ public function getLanguageTopics() { - return ['resource']; + return ['resource', 'manager_log']; } diff --git a/manager/controllers/default/system/file/edit.class.php b/manager/controllers/default/system/file/edit.class.php index 42ce2e85543..60de7d64891 100644 --- a/manager/controllers/default/system/file/edit.class.php +++ b/manager/controllers/default/system/file/edit.class.php @@ -1,4 +1,5 @@ modx->services->get(modManagerDateFormatter::class); + if (!empty($this->fileRecord['last_accessed'])) { + $this->fileRecord['last_accessed'] = $formatter->formatDateTime($this->fileRecord['last_accessed']); + } + if (!empty($this->fileRecord['last_modified'])) { + $this->fileRecord['last_modified'] = $formatter->formatDateTime($this->fileRecord['last_modified']); + } $this->canSave = true; $placeholders['fa'] = $this->fileRecord; diff --git a/manager/templates/default/dashboard/onlineusers.tpl b/manager/templates/default/dashboard/onlineusers.tpl index 3831a516074..1fba0446044 100644 --- a/manager/templates/default/dashboard/onlineusers.tpl +++ b/manager/templates/default/dashboard/onlineusers.tpl @@ -28,8 +28,8 @@ -
{$record.occurred|date_format:'%B %d, %Y'}
-
{$record.occurred|date_format:'%H:%M'}
+
{$record.occurred_date}
+
{$record.occurred_time}
{$record.action}