primo commit
This commit is contained in:
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="component" method="upgrade">
|
||||
<name>com_contenthistory</name>
|
||||
<author>Joomla! Project</author>
|
||||
<creationDate>2013-05</creationDate>
|
||||
<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
|
||||
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
|
||||
<authorEmail>admin@joomla.org</authorEmail>
|
||||
<authorUrl>www.joomla.org</authorUrl>
|
||||
<version>4.0.0</version>
|
||||
<description>COM_CONTENTHISTORY_XML_DESCRIPTION</description>
|
||||
<namespace path="src">Joomla\Component\Contenthistory</namespace>
|
||||
<files folder="site">
|
||||
<folder>src</folder>
|
||||
</files>
|
||||
<media destination="com_contenthistory" folder="media">
|
||||
<folder>js</folder>
|
||||
</media>
|
||||
<administration>
|
||||
<files folder="admin">
|
||||
<filename>contenthistory.xml</filename>
|
||||
<folder>helpers</folder>
|
||||
<folder>services</folder>
|
||||
<folder>src</folder>
|
||||
<folder>tmpl</folder>
|
||||
</files>
|
||||
<languages folder="admin">
|
||||
<language tag="en-GB">language/en-GB/com_contenthistory.ini</language>
|
||||
<language tag="en-GB">language/en-GB/com_contenthistory.sys.ini</language>
|
||||
</languages>
|
||||
</administration>
|
||||
</extension>
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*
|
||||
* @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
*/
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Categories helper.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @deprecated 4.3 will be removed in 6.0
|
||||
* Use \Joomla\Component\Contenthistory\Administrator\Helper\ContenthistoryHelper instead
|
||||
*/
|
||||
class ContenthistoryHelper extends \Joomla\Component\Contenthistory\Administrator\Helper\ContenthistoryHelper
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
|
||||
use Joomla\CMS\Extension\ComponentInterface;
|
||||
use Joomla\CMS\Extension\MVCComponent;
|
||||
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
|
||||
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* The content history service provider.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
return new class () implements ServiceProviderInterface {
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Contenthistory'));
|
||||
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Contenthistory'));
|
||||
|
||||
$container->set(
|
||||
ComponentInterface::class,
|
||||
function (Container $container) {
|
||||
$component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
|
||||
|
||||
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
|
||||
|
||||
return $component;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Contenthistory Controller
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class DisplayController extends BaseController
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\AdminController;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Contenthistory list controller class.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class HistoryController extends AdminController
|
||||
{
|
||||
/**
|
||||
* Proxy for getModel.
|
||||
*
|
||||
* @param string $name The name of the model
|
||||
* @param string $prefix The prefix for the model
|
||||
* @param array $config An additional array of parameters
|
||||
*
|
||||
* @return \Joomla\CMS\MVC\Model\BaseDatabaseModel The model
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function getModel($name = 'History', $prefix = 'Administrator', $config = ['ignore_request' => true])
|
||||
{
|
||||
return parent::getModel($name, $prefix, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the keep forever value for one or more history rows. If it was Yes, changes to No. If No, changes to Yes.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function keep()
|
||||
{
|
||||
$this->checkToken();
|
||||
|
||||
// Get items to toggle keep forever from the request.
|
||||
$cid = (array) $this->input->get('cid', [], 'int');
|
||||
|
||||
// Remove zero values resulting from input filter
|
||||
$cid = array_filter($cid);
|
||||
|
||||
if (empty($cid)) {
|
||||
$this->app->enqueueMessage(Text::_('COM_CONTENTHISTORY_NO_ITEM_SELECTED'), 'warning');
|
||||
} else {
|
||||
// Get the model.
|
||||
$model = $this->getModel();
|
||||
|
||||
// Toggle keep forever status of the selected items.
|
||||
if ($model->keep($cid)) {
|
||||
$this->setMessage(Text::plural('COM_CONTENTHISTORY_N_ITEMS_KEEP_TOGGLE', \count($cid)));
|
||||
} else {
|
||||
$this->setMessage($model->getError(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_contenthistory&view=history&layout=modal&tmpl=component&item_id='
|
||||
. $this->input->getCmd('item_id') . '&' . Session::getFormToken() . '=1',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL arguments to append to a list redirect.
|
||||
*
|
||||
* @return string The arguments to append to the redirect URL.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function getRedirectToListAppend()
|
||||
{
|
||||
return '&layout=modal&tmpl=component&item_id=' . $this->input->get('item_id') . '&' . Session::getFormToken() . '=1';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Contenthistory list controller class.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class PreviewController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Proxy for getModel.
|
||||
*
|
||||
* @param string $name The name of the model
|
||||
* @param string $prefix The prefix for the model
|
||||
* @param array $config An additional array of parameters
|
||||
*
|
||||
* @return \Joomla\CMS\MVC\Model\BaseDatabaseModel The model
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function getModel($name = 'Preview', $prefix = 'Administrator', $config = ['ignore_request' => true])
|
||||
{
|
||||
return parent::getModel($name, $prefix, $config);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Dispatcher;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Dispatcher\ComponentDispatcher;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* ComponentDispatcher class for com_associations
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Dispatcher extends ComponentDispatcher
|
||||
{
|
||||
/**
|
||||
* Method to check component access permission
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Exception|NotAllowed
|
||||
*/
|
||||
protected function checkAccess()
|
||||
{
|
||||
// Check the user has permission to access this component if in the backend
|
||||
if ($this->app->getIdentity()->guest) {
|
||||
throw new NotAllowed($this->app->getLanguage()->_('JERROR_ALERTNOAUTHOR'), 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,363 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Helper;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Table\ContentHistory;
|
||||
use Joomla\CMS\Table\ContentType;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Path;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Categories helper.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class ContenthistoryHelper
|
||||
{
|
||||
/**
|
||||
* Method to put all field names, including nested ones, in a single array for easy lookup.
|
||||
*
|
||||
* @param \stdClass $object Standard class object that may contain one level of nested objects.
|
||||
*
|
||||
* @return array Associative array of all field names, including ones in a nested object.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function createObjectArray($object)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if ($object === null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($object as $name => $value) {
|
||||
$result[$name] = $value;
|
||||
|
||||
if (\is_object($value)) {
|
||||
foreach ($value as $subName => $subValue) {
|
||||
$result[$subName] = $subValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to decode JSON-encoded fields in a standard object. Used to unpack JSON strings in the content history data column.
|
||||
*
|
||||
* @param string $jsonString JSON String to convert to an object.
|
||||
*
|
||||
* @return \stdClass Object with any JSON-encoded fields unpacked.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function decodeFields($jsonString)
|
||||
{
|
||||
$object = json_decode($jsonString);
|
||||
|
||||
if (\is_object($object)) {
|
||||
foreach ($object as $name => $value) {
|
||||
if (!\is_null($value) && $subObject = json_decode($value)) {
|
||||
$object->$name = $subObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get field labels for the fields in the JSON-encoded object.
|
||||
* First we see if we can find translatable labels for the fields in the object.
|
||||
* We translate any we can find and return an array in the format object->name => label.
|
||||
*
|
||||
* @param \stdClass $object Standard class object in the format name->value.
|
||||
* @param ContentType $typesTable Table object with content history options.
|
||||
*
|
||||
* @return \stdClass Contains two associative arrays.
|
||||
* $formValues->labels in the format name => label (for example, 'id' => 'Article ID').
|
||||
* $formValues->values in the format name => value (for example, 'state' => 'Published'.
|
||||
* This translates the text from the selected option in the form.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function getFormValues($object, ContentType $typesTable)
|
||||
{
|
||||
$labels = [];
|
||||
$values = [];
|
||||
$expandedObjectArray = static::createObjectArray($object);
|
||||
static::loadLanguageFiles($typesTable->type_alias);
|
||||
|
||||
if ($formFile = static::getFormFile($typesTable)) {
|
||||
if ($xml = simplexml_load_file($formFile)) {
|
||||
// Now we need to get all of the labels from the form
|
||||
$fieldArray = $xml->xpath('//field');
|
||||
$fieldArray = array_merge($fieldArray, $xml->xpath('//fields'));
|
||||
|
||||
foreach ($fieldArray as $field) {
|
||||
if ($label = (string) $field->attributes()->label) {
|
||||
$labels[(string) $field->attributes()->name] = Text::_($label);
|
||||
}
|
||||
}
|
||||
|
||||
// Get values for any list type fields
|
||||
$listFieldArray = $xml->xpath('//field[@type="list" or @type="radio"]');
|
||||
|
||||
foreach ($listFieldArray as $field) {
|
||||
$name = (string) $field->attributes()->name;
|
||||
|
||||
if (isset($expandedObjectArray[$name])) {
|
||||
$optionFieldArray = $field->xpath('option[@value="' . $expandedObjectArray[$name] . '"]');
|
||||
|
||||
$valueText = null;
|
||||
|
||||
if (\is_array($optionFieldArray) && \count($optionFieldArray)) {
|
||||
$valueText = trim((string) $optionFieldArray[0]);
|
||||
}
|
||||
|
||||
$values[(string) $field->attributes()->name] = Text::_($valueText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = new \stdClass();
|
||||
$result->labels = $labels;
|
||||
$result->values = $values;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the XML form file for this component. Used to get translated field names for history preview.
|
||||
*
|
||||
* @param ContentType $typesTable Table object with content history options.
|
||||
*
|
||||
* @return mixed \JModel object if successful, false if no model found.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function getFormFile(ContentType $typesTable)
|
||||
{
|
||||
// First, see if we have a file name in the $typesTable
|
||||
$options = json_decode($typesTable->content_history_options);
|
||||
|
||||
if (\is_object($options) && isset($options->formFile) && is_file(JPATH_ROOT . '/' . $options->formFile)) {
|
||||
$result = JPATH_ROOT . '/' . $options->formFile;
|
||||
} else {
|
||||
$aliasArray = explode('.', $typesTable->type_alias);
|
||||
$component = ($aliasArray[1] == 'category') ? 'com_categories' : $aliasArray[0];
|
||||
$path = Folder::makeSafe(JPATH_ADMINISTRATOR . '/components/' . $component . '/models/forms/');
|
||||
array_shift($aliasArray);
|
||||
$file = File::makeSafe(implode('.', $aliasArray) . '.xml');
|
||||
$result = is_file($path . $file) ? $path . $file : false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to query the database using values from lookup objects.
|
||||
*
|
||||
* @param \stdClass $lookup The std object with the values needed to do the query.
|
||||
* @param mixed $value The value used to find the matching title or name. Typically the id.
|
||||
*
|
||||
* @return mixed Value from database (for example, name or title) on success, false on failure.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function getLookupValue($lookup, $value)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
if (isset($lookup->sourceColumn) && isset($lookup->targetTable) && isset($lookup->targetColumn) && isset($lookup->displayColumn)) {
|
||||
$db = Factory::getDbo();
|
||||
$value = (int) $value;
|
||||
$query = $db->getQuery(true);
|
||||
$query->select($db->quoteName($lookup->displayColumn))
|
||||
->from($db->quoteName($lookup->targetTable))
|
||||
->where($db->quoteName($lookup->targetColumn) . ' = :value')
|
||||
->bind(':value', $value, ParameterType::INTEGER);
|
||||
$db->setQuery($query);
|
||||
|
||||
try {
|
||||
$result = $db->loadResult();
|
||||
} catch (\Exception $e) {
|
||||
// Ignore any errors and just return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to remove fields from the object based on values entered in the #__content_types table.
|
||||
*
|
||||
* @param \stdClass $object Object to be passed to view layout file.
|
||||
* @param ContentType $typeTable Table object with content history options.
|
||||
*
|
||||
* @return \stdClass object with hidden fields removed.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function hideFields($object, ContentType $typeTable)
|
||||
{
|
||||
if ($options = json_decode($typeTable->content_history_options)) {
|
||||
if (isset($options->hideFields) && \is_array($options->hideFields)) {
|
||||
foreach ($options->hideFields as $field) {
|
||||
unset($object->$field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to load the language files for the component whose history is being viewed.
|
||||
*
|
||||
* @param string $typeAlias The type alias, for example 'com_content.article'.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function loadLanguageFiles($typeAlias)
|
||||
{
|
||||
$aliasArray = explode('.', $typeAlias);
|
||||
|
||||
if (\is_array($aliasArray) && \count($aliasArray) == 2) {
|
||||
$component = ($aliasArray[1] == 'category') ? 'com_categories' : $aliasArray[0];
|
||||
$lang = Factory::getLanguage();
|
||||
|
||||
/**
|
||||
* Loading language file from the administrator/language directory then
|
||||
* loading language file from the administrator/components/extension/language directory
|
||||
*/
|
||||
$lang->load($component, JPATH_ADMINISTRATOR)
|
||||
|| $lang->load($component, Path::clean(JPATH_ADMINISTRATOR . '/components/' . $component));
|
||||
|
||||
// Force loading of backend global language file
|
||||
$lang->load('joomla', Path::clean(JPATH_ADMINISTRATOR));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create object to pass to the layout. Format is as follows:
|
||||
* field is std object with name, value.
|
||||
*
|
||||
* Value can be a std object with name, value pairs.
|
||||
*
|
||||
* @param \stdClass $object The std object from the JSON string. Can be nested 1 level deep.
|
||||
* @param \stdClass $formValues Standard class of label and value in an associative array.
|
||||
*
|
||||
* @return \stdClass Object with translated labels where available
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function mergeLabels($object, $formValues)
|
||||
{
|
||||
$result = new \stdClass();
|
||||
|
||||
if ($object === null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$labelsArray = $formValues->labels;
|
||||
$valuesArray = $formValues->values;
|
||||
|
||||
foreach ($object as $name => $value) {
|
||||
$result->$name = new \stdClass();
|
||||
$result->$name->name = $name;
|
||||
$result->$name->value = $valuesArray[$name] ?? $value;
|
||||
$result->$name->label = $labelsArray[$name] ?? $name;
|
||||
|
||||
if (\is_object($value)) {
|
||||
$subObject = new \stdClass();
|
||||
|
||||
foreach ($value as $subName => $subValue) {
|
||||
$subObject->$subName = new \stdClass();
|
||||
$subObject->$subName->name = $subName;
|
||||
$subObject->$subName->value = $valuesArray[$subName] ?? $subValue;
|
||||
$subObject->$subName->label = $labelsArray[$subName] ?? $subName;
|
||||
$result->$name->value = $subObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to prepare the object for the preview and compare views.
|
||||
*
|
||||
* @param ContentHistory $table Table object loaded with data.
|
||||
*
|
||||
* @return \stdClass Object ready for the views.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function prepareData(ContentHistory $table)
|
||||
{
|
||||
$object = static::decodeFields($table->version_data);
|
||||
$typesTable = Table::getInstance('ContentType', 'Joomla\\CMS\\Table\\');
|
||||
$typeAlias = explode('.', $table->item_id);
|
||||
array_pop($typeAlias);
|
||||
$typesTable->load(['type_alias' => implode('.', $typeAlias)]);
|
||||
$formValues = static::getFormValues($object, $typesTable);
|
||||
$object = static::mergeLabels($object, $formValues);
|
||||
$object = static::hideFields($object, $typesTable);
|
||||
$object = static::processLookupFields($object, $typesTable);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to process any lookup values found in the content_history_options column for this table.
|
||||
* This allows category title and user name to be displayed instead of the id column.
|
||||
*
|
||||
* @param \stdClass $object The std object from the JSON string. Can be nested 1 level deep.
|
||||
* @param ContentType $typesTable Table object loaded with data.
|
||||
*
|
||||
* @return \stdClass Object with lookup values inserted.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public static function processLookupFields($object, ContentType $typesTable)
|
||||
{
|
||||
if ($options = json_decode($typesTable->content_history_options)) {
|
||||
if (isset($options->displayLookup) && \is_array($options->displayLookup)) {
|
||||
foreach ($options->displayLookup as $lookup) {
|
||||
$sourceColumn = $lookup->sourceColumn ?? false;
|
||||
$sourceValue = $object->$sourceColumn->value ?? false;
|
||||
|
||||
if ($sourceColumn && $sourceValue && ($lookupValue = static::getLookupValue($lookup, $sourceValue))) {
|
||||
$object->$sourceColumn->value = $lookupValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\CMS\Table\ContentHistory;
|
||||
use Joomla\CMS\Table\ContentType;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Component\Contenthistory\Administrator\Helper\ContenthistoryHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Methods supporting a list of contenthistory records.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class CompareModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Method to get a version history row.
|
||||
*
|
||||
* @return array|boolean On success, array of populated tables. False on failure.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @throws NotAllowed Thrown if not authorised to edit an item
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
/** @var ContentHistory $table1 */
|
||||
$table1 = $this->getTable('ContentHistory');
|
||||
|
||||
/** @var ContentHistory $table2 */
|
||||
$table2 = $this->getTable('ContentHistory');
|
||||
|
||||
$id1 = $input->getInt('id1');
|
||||
$id2 = $input->getInt('id2');
|
||||
|
||||
if (!$id1 || \is_array($id1) || !$id2 || \is_array($id2)) {
|
||||
$this->setError(Text::_('COM_CONTENTHISTORY_ERROR_INVALID_ID'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
if (!$table1->load($id1) || !$table2->load($id2)) {
|
||||
$this->setError(Text::_('COM_CONTENTHISTORY_ERROR_VERSION_NOT_FOUND'));
|
||||
|
||||
// Assume a failure to load the content means broken data, abort mission
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the first history record's content type record so we can check ACL
|
||||
/** @var ContentType $contentTypeTable */
|
||||
$contentTypeTable = $this->getTable('ContentType');
|
||||
$typeAlias = explode('.', $table1->item_id);
|
||||
array_pop($typeAlias);
|
||||
$typeAlias = implode('.', $typeAlias);
|
||||
|
||||
if (!$contentTypeTable->load(['type_alias' => $typeAlias])) {
|
||||
$this->setError(Text::_('COM_CONTENTHISTORY_ERROR_FAILED_LOADING_CONTENT_TYPE'));
|
||||
|
||||
// Assume a failure to load the content type means broken data, abort mission
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
// Access check
|
||||
if (!$user->authorise('core.edit', $table1->item_id) && !$this->canEdit($table1)) {
|
||||
throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403);
|
||||
}
|
||||
|
||||
$nullDate = $this->getDatabase()->getNullDate();
|
||||
|
||||
foreach ([$table1, $table2] as $table) {
|
||||
$object = new \stdClass();
|
||||
$object->data = ContenthistoryHelper::prepareData($table);
|
||||
$object->version_note = $table->version_note;
|
||||
|
||||
// Let's use custom calendars when present
|
||||
$object->save_date = HTMLHelper::_('date', $table->save_date, Text::_('DATE_FORMAT_LC6'));
|
||||
|
||||
$dateProperties = [
|
||||
'modified_time',
|
||||
'created_time',
|
||||
'modified',
|
||||
'created',
|
||||
'checked_out_time',
|
||||
'publish_up',
|
||||
'publish_down',
|
||||
];
|
||||
|
||||
foreach ($dateProperties as $dateProperty) {
|
||||
if (
|
||||
property_exists($object->data, $dateProperty)
|
||||
&& $object->data->$dateProperty->value !== null
|
||||
&& $object->data->$dateProperty->value !== $nullDate
|
||||
) {
|
||||
$object->data->$dateProperty->value = HTMLHelper::_(
|
||||
'date',
|
||||
$object->data->$dateProperty->value,
|
||||
Text::_('DATE_FORMAT_LC6')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $object;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $type The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $config Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function getTable($type = 'Contenthistory', $prefix = 'Joomla\\CMS\\Table\\', $config = [])
|
||||
{
|
||||
return Table::getInstance($type, $prefix, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to test whether a record is editable
|
||||
*
|
||||
* @param ContentHistory $record A Table object.
|
||||
*
|
||||
* @return boolean True if allowed to edit the record. Defaults to the permission set in the component.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
protected function canEdit($record)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
if (!empty($record->item_id)) {
|
||||
/**
|
||||
* Make sure user has edit privileges for this content item. Note that we use edit permissions
|
||||
* for the content item, not delete permissions for the content history row.
|
||||
*/
|
||||
$user = $this->getCurrentUser();
|
||||
$result = $user->authorise('core.edit', $record->item_id);
|
||||
|
||||
// Finally try session (this catches edit.own case too)
|
||||
if (!$result) {
|
||||
/** @var ContentType $contentTypeTable */
|
||||
$contentTypeTable = $this->getTable('ContentType');
|
||||
|
||||
$typeAlias = explode('.', $record->item_id);
|
||||
$id = array_pop($typeAlias);
|
||||
$typeAlias = implode('.', $typeAlias);
|
||||
$contentTypeTable->load(['type_alias' => $typeAlias]);
|
||||
$typeEditables = (array) Factory::getApplication()->getUserState(str_replace('.', '.edit.', $contentTypeTable->type_alias) . '.id');
|
||||
$result = \in_array((int) $id, $typeEditables);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,395 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Helper\CMSHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Log\Log;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\CMS\Table\ContentHistory;
|
||||
use Joomla\CMS\Table\ContentType;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Database\QueryInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Methods supporting a list of contenthistory records.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class HistoryModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
* @param ?MVCFactoryInterface $factory The factory.
|
||||
*
|
||||
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
|
||||
* @since 3.2
|
||||
*/
|
||||
public function __construct($config = [], ?MVCFactoryInterface $factory = null)
|
||||
{
|
||||
if (empty($config['filter_fields'])) {
|
||||
$config['filter_fields'] = [
|
||||
'version_id',
|
||||
'h.version_id',
|
||||
'version_note',
|
||||
'h.version_note',
|
||||
'save_date',
|
||||
'h.save_date',
|
||||
'editor_user_id',
|
||||
'h.editor_user_id',
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct($config, $factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to test whether a record is editable
|
||||
*
|
||||
* @param ContentHistory $record A Table object.
|
||||
*
|
||||
* @return boolean True if allowed to edit the record. Defaults to the permission set in the component.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function canEdit($record)
|
||||
{
|
||||
if (empty($record->item_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure user has edit privileges for this content item. Note that we use edit permissions
|
||||
* for the content item, not delete permissions for the content history row.
|
||||
*/
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
if ($user->authorise('core.edit', $record->item_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finally try session (this catches edit.own case too)
|
||||
/** @var ContentType $contentTypeTable */
|
||||
$contentTypeTable = $this->getTable('ContentType');
|
||||
|
||||
$typeAlias = explode('.', $record->item_id);
|
||||
$id = array_pop($typeAlias);
|
||||
$typeAlias = implode('.', $typeAlias);
|
||||
$contentTypeTable->load(['type_alias' => $typeAlias]);
|
||||
$typeEditables = (array) Factory::getApplication()->getUserState(str_replace('.', '.edit.', $contentTypeTable->type_alias) . '.id');
|
||||
$result = \in_array((int) $id, $typeEditables);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to test whether a history record can be deleted. Note that we check whether we have edit permissions
|
||||
* for the content item row.
|
||||
*
|
||||
* @param ContentHistory $record A Table object.
|
||||
*
|
||||
* @return boolean True if allowed to delete the record. Defaults to the permission set in the component.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
protected function canDelete($record)
|
||||
{
|
||||
return $this->canEdit($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete one or more records from content history table.
|
||||
*
|
||||
* @param array $pks An array of record primary keys.
|
||||
*
|
||||
* @return boolean True if successful, false if an error occurs.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function delete(&$pks)
|
||||
{
|
||||
$pks = (array) $pks;
|
||||
$table = $this->getTable();
|
||||
|
||||
// Iterate the items to delete each one.
|
||||
foreach ($pks as $i => $pk) {
|
||||
if ($table->load($pk)) {
|
||||
if ((int) $table->keep_forever === 1) {
|
||||
unset($pks[$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->canEdit($table)) {
|
||||
if (!$table->delete($pk)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Prune items that you can't change.
|
||||
unset($pks[$i]);
|
||||
$error = $this->getError();
|
||||
|
||||
if ($error) {
|
||||
try {
|
||||
Log::add($error, Log::WARNING, 'jerror');
|
||||
} catch (\RuntimeException $exception) {
|
||||
Factory::getApplication()->enqueueMessage($error, 'warning');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Log::add(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), Log::WARNING, 'jerror');
|
||||
} catch (\RuntimeException $exception) {
|
||||
Factory::getApplication()->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), 'warning');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the component's cache
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get an array of data items.
|
||||
*
|
||||
* @return mixed An array of data items on success, false on failure.
|
||||
*
|
||||
* @since 3.4.5
|
||||
*
|
||||
* @throws NotAllowed Thrown if not authorised to edit an item
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$items = parent::getItems();
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
if ($items === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This should be an array with at least one element
|
||||
if (!\is_array($items) || !isset($items[0])) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
// Access check
|
||||
if (!$user->authorise('core.edit', $items[0]->item_id) && !$this->canEdit($items[0])) {
|
||||
throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $type The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $config Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function getTable($type = 'ContentHistory', $prefix = 'Joomla\\CMS\\Table\\', $config = [])
|
||||
{
|
||||
return Table::getInstance($type, $prefix, $config);
|
||||
}
|
||||
/**
|
||||
* Method to toggle on and off the keep forever value for one or more records from content history table.
|
||||
*
|
||||
* @param array $pks An array of record primary keys.
|
||||
*
|
||||
* @return boolean True if successful, false if an error occurs.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function keep(&$pks)
|
||||
{
|
||||
$pks = (array) $pks;
|
||||
$table = $this->getTable();
|
||||
|
||||
// Iterate the items to delete each one.
|
||||
foreach ($pks as $i => $pk) {
|
||||
if ($table->load($pk)) {
|
||||
if ($this->canEdit($table)) {
|
||||
$table->keep_forever = $table->keep_forever ? 0 : 1;
|
||||
|
||||
if (!$table->store()) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Prune items that you can't change.
|
||||
unset($pks[$i]);
|
||||
$error = $this->getError();
|
||||
|
||||
if ($error) {
|
||||
try {
|
||||
Log::add($error, Log::WARNING, 'jerror');
|
||||
} catch (\RuntimeException $exception) {
|
||||
Factory::getApplication()->enqueueMessage($error, 'warning');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Log::add(Text::_('COM_CONTENTHISTORY_ERROR_KEEP_NOT_PERMITTED'), Log::WARNING, 'jerror');
|
||||
} catch (\RuntimeException $exception) {
|
||||
Factory::getApplication()->enqueueMessage(Text::_('COM_CONTENTHISTORY_ERROR_KEEP_NOT_PERMITTED'), 'warning');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the component's cache
|
||||
$this->cleanCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* Note. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field.
|
||||
* @param string $direction An optional direction (asc|desc).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function populateState($ordering = 'h.save_date', $direction = 'DESC')
|
||||
{
|
||||
$input = Factory::getApplication()->getInput();
|
||||
$itemId = $input->get('item_id', '', 'string');
|
||||
|
||||
$this->setState('item_id', $itemId);
|
||||
$this->setState('sha1_hash', $this->getSha1Hash());
|
||||
|
||||
// Load the parameters.
|
||||
$params = ComponentHelper::getParams('com_contenthistory');
|
||||
$this->setState('params', $params);
|
||||
|
||||
// List state information.
|
||||
parent::populateState($ordering, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an SQL query to load the list data.
|
||||
*
|
||||
* @return QueryInterface
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
// Create a new query object.
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true);
|
||||
$itemId = $this->getState('item_id');
|
||||
|
||||
// Select the required fields from the table.
|
||||
$query->select(
|
||||
$this->getState(
|
||||
'list.select',
|
||||
[
|
||||
$db->quoteName('h.version_id'),
|
||||
$db->quoteName('h.item_id'),
|
||||
$db->quoteName('h.version_note'),
|
||||
$db->quoteName('h.save_date'),
|
||||
$db->quoteName('h.editor_user_id'),
|
||||
$db->quoteName('h.character_count'),
|
||||
$db->quoteName('h.sha1_hash'),
|
||||
$db->quoteName('h.version_data'),
|
||||
$db->quoteName('h.keep_forever'),
|
||||
]
|
||||
)
|
||||
)
|
||||
->from($db->quoteName('#__history', 'h'))
|
||||
->where($db->quoteName('h.item_id') . ' = :itemid')
|
||||
->bind(':itemid', $itemId, ParameterType::STRING)
|
||||
|
||||
// Join over the users for the editor
|
||||
->select($db->quoteName('uc.name', 'editor'))
|
||||
->join(
|
||||
'LEFT',
|
||||
$db->quoteName('#__users', 'uc'),
|
||||
$db->quoteName('uc.id') . ' = ' . $db->quoteName('h.editor_user_id')
|
||||
);
|
||||
|
||||
// Add the list ordering clause.
|
||||
$orderCol = $this->state->get('list.ordering');
|
||||
$orderDirn = $this->state->get('list.direction');
|
||||
$query->order($db->quoteName($orderCol) . $orderDirn);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sha1 hash value for the current item being edited.
|
||||
*
|
||||
* @return string sha1 hash of row data
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
protected function getSha1Hash()
|
||||
{
|
||||
$result = false;
|
||||
$item_id = Factory::getApplication()->getInput()->getCmd('item_id', '');
|
||||
$typeAlias = explode('.', $item_id);
|
||||
Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/' . $typeAlias[0] . '/tables');
|
||||
$typeTable = $this->getTable('ContentType');
|
||||
$typeTable->load(['type_alias' => $typeAlias[0] . '.' . $typeAlias[1]]);
|
||||
$contentTable = $typeTable->getContentTable();
|
||||
|
||||
if ($contentTable && $contentTable->load($typeAlias[2])) {
|
||||
$helper = new CMSHelper();
|
||||
|
||||
$dataObject = $helper->getDataObject($contentTable);
|
||||
$result = $this->getTable('ContentHistory')->getSha1(json_encode($dataObject), $typeTable);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\ItemModel;
|
||||
use Joomla\CMS\Table\ContentHistory;
|
||||
use Joomla\CMS\Table\ContentType;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Component\Contenthistory\Administrator\Helper\ContenthistoryHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Methods supporting a list of contenthistory records.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class PreviewModel extends ItemModel
|
||||
{
|
||||
/**
|
||||
* Method to get a version history row.
|
||||
*
|
||||
* @param integer $pk The id of the item
|
||||
*
|
||||
* @return \stdClass|boolean On success, standard object with row data. False on failure.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @throws NotAllowed Thrown if not authorised to edit an item
|
||||
*/
|
||||
public function getItem($pk = null)
|
||||
{
|
||||
/** @var ContentHistory $table */
|
||||
$table = $this->getTable('ContentHistory');
|
||||
$versionId = Factory::getApplication()->getInput()->getInt('version_id');
|
||||
|
||||
if (!$versionId || \is_array($versionId) || !$table->load($versionId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
// Access check
|
||||
if (!$user->authorise('core.edit', $table->item_id) && !$this->canEdit($table)) {
|
||||
throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403);
|
||||
}
|
||||
|
||||
$result = new \stdClass();
|
||||
$result->version_note = $table->version_note;
|
||||
$result->data = ContenthistoryHelper::prepareData($table);
|
||||
|
||||
// Let's use custom calendars when present
|
||||
$result->save_date = HTMLHelper::_('date', $table->save_date, Text::_('DATE_FORMAT_LC6'));
|
||||
|
||||
$dateProperties = [
|
||||
'modified_time',
|
||||
'created_time',
|
||||
'modified',
|
||||
'created',
|
||||
'checked_out_time',
|
||||
'publish_up',
|
||||
'publish_down',
|
||||
];
|
||||
|
||||
$nullDate = $this->getDatabase()->getNullDate();
|
||||
|
||||
foreach ($dateProperties as $dateProperty) {
|
||||
if (
|
||||
property_exists($result->data, $dateProperty)
|
||||
&& $result->data->$dateProperty->value !== null
|
||||
&& $result->data->$dateProperty->value !== $nullDate
|
||||
) {
|
||||
$result->data->$dateProperty->value = HTMLHelper::_(
|
||||
'date',
|
||||
$result->data->$dateProperty->value,
|
||||
Text::_('DATE_FORMAT_LC6')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $type The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $config Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function getTable($type = 'ContentHistory', $prefix = 'Joomla\\CMS\\Table\\', $config = [])
|
||||
{
|
||||
return Table::getInstance($type, $prefix, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to test whether a record is editable
|
||||
*
|
||||
* @param ContentHistory $record A Table object.
|
||||
*
|
||||
* @return boolean True if allowed to edit the record. Defaults to the permission set in the component.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
protected function canEdit($record)
|
||||
{
|
||||
$result = false;
|
||||
|
||||
if (!empty($record->item_id)) {
|
||||
/**
|
||||
* Make sure user has edit privileges for this content item. Note that we use edit permissions
|
||||
* for the content item, not delete permissions for the content history row.
|
||||
*/
|
||||
$user = $this->getCurrentUser();
|
||||
$result = $user->authorise('core.edit', $record->item_id);
|
||||
|
||||
// Finally try session (this catches edit.own case too)
|
||||
if (!$result) {
|
||||
/** @var ContentType $contentTypeTable */
|
||||
$contentTypeTable = $this->getTable('ContentType');
|
||||
|
||||
$typeAlias = explode('.', $record->item_id);
|
||||
$id = array_pop($typeAlias);
|
||||
$typeAlias = implode('.', $typeAlias);
|
||||
$typeEditables = (array) Factory::getApplication()->getUserState(str_replace('.', '.edit.', $contentTypeTable->type_alias) . '.id');
|
||||
$result = \in_array((int) $id, $typeEditables);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\View\Compare;
|
||||
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View class for a list of contenthistory.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* An array of items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$this->state = $this->get('State');
|
||||
$this->items = $this->get('Items');
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\View\History;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filter\InputFilter;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
use Joomla\CMS\Toolbar\Toolbar;
|
||||
use Joomla\CMS\Toolbar\ToolbarFactoryInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View class for a list of contenthistory.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* An array of items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var Pagination
|
||||
*/
|
||||
protected $pagination;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The toolbar for the history modal. Note this is rendered inside the modal rather than using the regular module
|
||||
*
|
||||
* @var Toolbar
|
||||
*/
|
||||
protected $toolbar;
|
||||
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$this->state = $this->get('State');
|
||||
$this->items = $this->get('Items');
|
||||
$this->pagination = $this->get('Pagination');
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->toolbar = $this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page toolbar.
|
||||
*
|
||||
* @return Toolbar
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function addToolbar(): Toolbar
|
||||
{
|
||||
/** @var Toolbar $toolbar */
|
||||
$toolbar = Factory::getContainer()->get(ToolbarFactoryInterface::class)->createToolbar('toolbar');
|
||||
|
||||
// Cache a session token for reuse throughout.
|
||||
$token = Session::getFormToken();
|
||||
|
||||
// Clean up input to ensure a clean url.
|
||||
$filter = InputFilter::getInstance();
|
||||
$aliasArray = explode('.', $this->state->item_id);
|
||||
|
||||
if ($aliasArray[1] === 'category') {
|
||||
$option = 'com_categories';
|
||||
$append = '&extension=' . $filter->clean($aliasArray[0], 'cmd');
|
||||
} else {
|
||||
$option = $aliasArray[0];
|
||||
$append = '';
|
||||
}
|
||||
|
||||
$task = $filter->clean($aliasArray[1], 'cmd') . '.loadhistory';
|
||||
|
||||
// Build the final urls.
|
||||
$loadUrl = Route::_('index.php?option=' . $filter->clean($option, 'cmd') . $append . '&task=' . $task . '&' . $token . '=1');
|
||||
$previewUrl = Route::_('index.php?option=com_contenthistory&view=preview&layout=preview&tmpl=component&' . $token . '=1');
|
||||
$compareUrl = Route::_('index.php?option=com_contenthistory&view=compare&layout=compare&tmpl=component&' . $token . '=1');
|
||||
|
||||
$toolbar->basicButton('load', 'COM_CONTENTHISTORY_BUTTON_LOAD')
|
||||
->attributes(['data-url' => $loadUrl])
|
||||
->icon('icon-upload')
|
||||
->buttonClass('btn btn-success')
|
||||
->listCheck(true);
|
||||
|
||||
$toolbar->basicButton('preview', 'COM_CONTENTHISTORY_BUTTON_PREVIEW')
|
||||
->attributes(['data-url' => $previewUrl])
|
||||
->icon('icon-search')
|
||||
->listCheck(true);
|
||||
|
||||
$toolbar->basicButton('compare', 'COM_CONTENTHISTORY_BUTTON_COMPARE')
|
||||
->attributes(['data-url' => $compareUrl])
|
||||
->icon('icon-search-plus')
|
||||
->listCheck(true);
|
||||
|
||||
$toolbar->basicButton('keep', 'COM_CONTENTHISTORY_BUTTON_KEEP', 'history.keep')
|
||||
->icon('icon-lock')
|
||||
->listCheck(true);
|
||||
|
||||
$toolbar->basicButton('delete', 'COM_CONTENTHISTORY_BUTTON_DELETE', 'history.delete')
|
||||
->buttonClass('btn btn-danger')
|
||||
->icon('icon-times')
|
||||
->listCheck(true);
|
||||
|
||||
return $toolbar;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Contenthistory\Administrator\View\Preview;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* View class for a list of contenthistory.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* An array of items
|
||||
*
|
||||
* @var \stdClass|false
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* The model state
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Method to display the view.
|
||||
*
|
||||
* @param string $tpl A template file to load. [optional]
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$this->state = $this->get('State');
|
||||
$this->item = $this->get('Item');
|
||||
|
||||
if (false === $this->item) {
|
||||
$this->getLanguage()->load('com_content', JPATH_SITE, null, true);
|
||||
|
||||
throw new \Exception(Text::_('COM_CONTENT_ERROR_ARTICLE_NOT_FOUND'), 404);
|
||||
}
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
/** @var \Joomla\Component\Contenthistory\Administrator\View\Compare\HtmlView $this */
|
||||
|
||||
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
|
||||
|
||||
$version2 = $this->items[0];
|
||||
$version1 = $this->items[1];
|
||||
$object1 = $version1->data;
|
||||
$object2 = $version2->data;
|
||||
|
||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('com_contenthistory.admin-compare-compare');
|
||||
|
||||
?>
|
||||
<div role="main">
|
||||
<h1 class="mb-3"><?php echo Text::_('COM_CONTENTHISTORY_COMPARE_TITLE'); ?></h1>
|
||||
|
||||
<table id="diff" class="table">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_COMPARE_CAPTION'); ?>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-25"><?php echo Text::_('COM_CONTENTHISTORY_PREVIEW_FIELD'); ?></th>
|
||||
<th scope="col"><?php echo Text::_('COM_CONTENTHISTORY_COMPARE_OLD'); ?></th>
|
||||
<th scope="col"><?php echo Text::_('COM_CONTENTHISTORY_COMPARE_NEW'); ?></th>
|
||||
<th scope="col"><?php echo Text::_('COM_CONTENTHISTORY_COMPARE_DIFF'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($object1 as $name => $value) : ?>
|
||||
<?php if (isset($value->value) && isset($object2->$name->value) && $value->value != $object2->$name->value) : ?>
|
||||
<?php if (is_object($value->value)) : ?>
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<strong><?php echo $value->label; ?></strong>
|
||||
</td>
|
||||
</tr>
|
||||
<?php foreach ($value->value as $subName => $subValue) : ?>
|
||||
<?php $newSubValue = $object2->$name->value->$subName->value ?? ''; ?>
|
||||
<?php if ($subValue->value || $newSubValue) : ?>
|
||||
<?php if ($subValue->value != $newSubValue) : ?>
|
||||
<tr>
|
||||
<th scope="row"><em> <?php echo $subValue->label; ?></em></th>
|
||||
<td class="original"><?php echo htmlspecialchars($subValue->value, ENT_COMPAT, 'UTF-8'); ?></td>
|
||||
<td class="changed" ><?php echo htmlspecialchars($newSubValue, ENT_COMPAT, 'UTF-8'); ?></td>
|
||||
<td class="diff"> </td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<?php echo $value->label; ?>
|
||||
</th>
|
||||
<td class="original"><?php echo htmlspecialchars($value->value); ?></td>
|
||||
<?php $object2->$name->value = is_object($object2->$name->value) ? json_encode($object2->$name->value) : $object2->$name->value; ?>
|
||||
<td class="changed"><?php echo htmlspecialchars($object2->$name->value, ENT_COMPAT, 'UTF-8'); ?></td>
|
||||
<td class="diff"> </td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
/** @var \Joomla\Component\Contenthistory\Administrator\View\History\HtmlView $this */
|
||||
|
||||
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
|
||||
|
||||
$hash = $this->state->get('sha1_hash');
|
||||
$formUrl = 'index.php?option=com_contenthistory&view=history&layout=modal&tmpl=component&item_id=' . $this->state->get('item_id') . '&' . Session::getFormToken() . '=1';
|
||||
|
||||
Text::script('COM_CONTENTHISTORY_BUTTON_SELECT_ONE_VERSION', true);
|
||||
Text::script('COM_CONTENTHISTORY_BUTTON_SELECT_TWO_VERSIONS', true);
|
||||
Text::script('JLIB_HTML_PLEASE_MAKE_A_SELECTION_FROM_THE_LIST');
|
||||
|
||||
$inlineJS = <<<JS
|
||||
document.querySelectorAll('.js-link-open-window').forEach((link) => link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
window.open(link.dataset.url, 'win2', 'width=800,height=600,resizable=yes,scrollbars=yes')
|
||||
}));
|
||||
JS;
|
||||
|
||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('multiselect')
|
||||
->useScript('com_contenthistory.admin-history-modal')
|
||||
->useScript('list-view')
|
||||
->addInlineScript($inlineJS, [], ['type' => 'module']);
|
||||
?>
|
||||
<div class="container-popup">
|
||||
<div id="subhead" class="subhead noshadow mb-3">
|
||||
<?php echo $this->toolbar->render(); ?>
|
||||
</div>
|
||||
<form action="<?php echo Route::_($formUrl); ?>" method="post" name="adminForm" id="adminForm">
|
||||
<table class="table table-sm">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_VERSION_CAPTION'); ?>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="w-1 text-center">
|
||||
<input class="form-check-input" type="checkbox" name="checkall-toggle" value="" title="<?php echo Text::_('JGLOBAL_CHECK_ALL'); ?>" onclick="Joomla.checkAll(this)">
|
||||
</td>
|
||||
<th scope="col" class="w-15">
|
||||
<?php echo Text::_('JDATE'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-15 d-none d-md-table-cell">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_VERSION_NOTE'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_KEEP_VERSION'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-15 d-none d-md-table-cell">
|
||||
<?php echo Text::_('JAUTHOR'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10 text-end">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_CHARACTER_COUNT'); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $i = 0; ?>
|
||||
<?php foreach ($this->items as $item) : ?>
|
||||
<tr class="row<?php echo $i % 2; ?>">
|
||||
<td class="text-center">
|
||||
<?php echo HTMLHelper::_('grid.id', $i, $item->version_id, false, 'cid', 'cb', $item->save_date); ?>
|
||||
</td>
|
||||
<th scope="row">
|
||||
<a href="#" class="js-link-open-window save-date" data-url="<?php echo Route::_('index.php?option=com_contenthistory&view=preview&layout=preview&tmpl=component&' . Session::getFormToken() . '=1&version_id=' . $item->version_id); ?>">
|
||||
<?php echo HTMLHelper::_('date', $item->save_date, Text::_('DATE_FORMAT_LC6')); ?>
|
||||
</a>
|
||||
<?php if ($item->sha1_hash == $hash) : ?>
|
||||
<span class="icon-star" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('JCURRENT'); ?></span>
|
||||
<?php endif; ?>
|
||||
</th>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<?php echo htmlspecialchars($item->version_note); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($item->keep_forever) : ?>
|
||||
<button type="button" class="js-grid-item-action btn btn-secondary btn-sm" data-item-id="cb<?php echo $i; ?>" data-item-task="history.keep">
|
||||
<?php echo Text::_('JYES'); ?>
|
||||
<span class="icon-lock" aria-hidden="true"></span>
|
||||
</button>
|
||||
<?php else : ?>
|
||||
<button type="button" class="js-grid-item-action btn btn-secondary btn-sm" data-item-id="cb<?php echo $i; ?>" data-item-task="history.keep">
|
||||
<?php echo Text::_('JNO'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="d-none d-md-table-cell">
|
||||
<?php echo empty($item->editor) ? $item->editor_user_id : htmlspecialchars($item->editor); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php echo number_format((int) $item->character_count, 0, Text::_('DECIMALS_SEPARATOR'), Text::_('THOUSANDS_SEPARATOR')); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $i++; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php /* load the pagination. */ ?>
|
||||
<?php echo $this->pagination->getListFooter(); ?>
|
||||
|
||||
<input type="hidden" name="task" value="">
|
||||
<input type="hidden" name="boxchecked" value="0">
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_contenthistory
|
||||
*
|
||||
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
/** @var \Joomla\Component\Contenthistory\Administrator\View\Preview\HtmlView $this */
|
||||
|
||||
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
|
||||
|
||||
?>
|
||||
<div role="main">
|
||||
<h1>
|
||||
<?php echo Text::sprintf('COM_CONTENTHISTORY_PREVIEW_SUBTITLE_DATE', $this->item->save_date); ?>
|
||||
</h1>
|
||||
<?php if ($this->item->version_note) : ?>
|
||||
<h2>
|
||||
<?php echo Text::sprintf('COM_CONTENTHISTORY_PREVIEW_SUBTITLE', $this->item->version_note); ?>
|
||||
</h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="table">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_CONTENTHISTORY_PREVIEW_CAPTION'); ?>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-25" scope="col"><?php echo Text::_('COM_CONTENTHISTORY_PREVIEW_FIELD'); ?></th>
|
||||
<th scope="col"><?php echo Text::_('COM_CONTENTHISTORY_PREVIEW_VALUE'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->item->data as $name => $value) : ?>
|
||||
<?php if (is_object($value->value)) : ?>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<?php echo $value->label; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php foreach ($value->value as $subName => $subValue) : ?>
|
||||
<?php if ($subValue && isset($subValue->value)) : ?>
|
||||
<?php $subValue->value = (\is_object($subValue->value) || \is_array($subValue->value)) ? \json_encode($subValue->value, \JSON_UNESCAPED_UNICODE) : $subValue->value; ?>
|
||||
<tr>
|
||||
<th scope="row"><em> <?php echo $subValue->label; ?></em></th>
|
||||
<td><?php echo $subValue->value; ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo $value->label; ?></th>
|
||||
<td><?php echo $value->value; ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
Reference in New Issue
Block a user