first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
@@ -0,0 +1,65 @@
<?php
/**
* @file classes/controllers/grid/feature/CollapsibleGridFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class CollapsibleGridFeature
*
* @ingroup controllers_grid_feature
*
* @brief Add collapse and expand functionality to grids.
*
*/
namespace PKP\controllers\grid\feature;
use APP\template\TemplateManager;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\NullAction;
class CollapsibleGridFeature extends GridFeature
{
/**
* @copydoc GridFeature::GridFeature()
* Constructor.
*/
public function __construct($id = 'collapsible')
{
parent::__construct($id);
}
/**
* @copyDoc GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.CollapsibleGridFeature';
}
/**
* @copyDoc GridFeature::fetchUIElement()
*/
public function fetchUIElements($request, $grid)
{
$controlLink = new LinkAction(
'expandGridControlLink',
new NullAction(),
null,
'expand_all'
);
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('controlLink', $controlLink);
$markup = $templateMgr->fetch('controllers/grid/feature/collapsibleGridFeature.tpl');
return ['collapsibleLink' => $markup];
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\CollapsibleGridFeature', '\CollapsibleGridFeature');
}
@@ -0,0 +1,195 @@
<?php
/**
* @file classes/controllers/grid/feature/GeneralPagingFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class GeneralPagingFeature
*
* @ingroup controllers_grid_feature
*
* @brief Base class that implements common functionality for
* paging features.
*
*/
namespace PKP\controllers\grid\feature;
use APP\core\Application;
use PKP\controllers\grid\GridHandler;
use PKP\core\ArrayItemIterator;
use PKP\core\ItemIterator;
use PKP\handler\PKPHandler;
class GeneralPagingFeature extends GridFeature
{
/** @var ItemIterator */
private $_itemIterator;
/** @var int itemsPerPage */
private $_itemsPerPage;
/**
* @see GridFeature::GridFeature()
*
* @param string $id Feature identifier.
* @param null|int $itemsPerPage Optional Number of items to show at
* the first time.
* Constructor.
*/
public function __construct($id, $itemsPerPage = null)
{
$this->_itemsPerPage = $itemsPerPage;
parent::__construct($id);
}
//
// Getters and setters.
//
/**
* Get item iterator.
*
* @return ItemIterator
*/
public function getItemIterator()
{
return $this->_itemIterator;
}
//
// Extended GridFeature methods.
//
/**
* @copydoc GridFeature::setOptions()
*/
public function setOptions($request, $grid)
{
// Get the default items per page setting value.
$rangeInfo = PKPHandler::getRangeInfo($request, $grid->getId());
$iterator = $this->getItemIterator();
$defaultItemsPerPage = $rangeInfo->getCount();
// Check for a component level items per page setting.
$componentItemsPerPage = $request->getUserVar($this->_getItemsPerPageParamName($grid->getId()));
if (!$componentItemsPerPage) {
$componentItemsPerPage = $this->_itemsPerPage;
}
if ($componentItemsPerPage) {
$currentItemsPerPage = $componentItemsPerPage;
} else {
$currentItemsPerPage = $defaultItemsPerPage;
}
$this->addOptions([
'itemsPerPageParamName' => $this->_getItemsPerPageParamName($grid->getId()),
'defaultItemsPerPage' => $defaultItemsPerPage,
'currentItemsPerPage' => $currentItemsPerPage,
'itemsTotal' => $iterator->getCount(),
'pageParamName' => PKPHandler::getPageParamName($grid->getId()),
'currentPage' => $iterator->getPage()
]);
parent::setOptions($request, $grid);
}
//
// Hooks implementation.
//
/**
* @copydoc GridFeature::gridInitialize()
* The feature will know about the current filter
* value so it can request grid refreshes keeping
* the filter.
*/
public function getGridDataElements($args)
{
$filter = $args['filter'];
if (is_array($filter) && !empty($filter)) {
$this->addOptions(['filter' => json_encode($filter)]);
}
}
/**
* @copydoc GridFeature::setGridDataElements()
*/
public function setGridDataElements($args)
{
$grid = & $args['grid'];
$data = & $args['data'];
if (is_array($data)) {
$request = Application::get()->getRequest();
$rangeInfo = $grid->getGridRangeInfo($request, $grid->getId());
$itemIterator = new ArrayItemIterator($data, $rangeInfo->getPage(), $rangeInfo->getCount());
$this->_itemIterator = $itemIterator;
$data = $itemIterator->toArray();
} elseif ($data instanceof ItemIterator) {
$this->_itemIterator = $data;
}
}
/**
* @copydoc GridFeature::getRequestArgs()
*/
public function getRequestArgs($args)
{
$grid = $args['grid'];
$requestArgs = & $args['requestArgs'];
// Add paging info so grid actions will not lose paging context.
// Only works if grid link actions use the getRequestArgs
// returned content.
$request = Application::get()->getRequest();
$rangeInfo = $grid->getGridRangeInfo($request, $grid->getId());
$requestArgs[GridHandler::getPageParamName($grid->getId())] = $rangeInfo->getPage();
$requestArgs[$this->_getItemsPerPageParamName($grid->getId())] = $rangeInfo->getCount();
}
/**
* @copydoc GridFeature::getGridRangeInfo()
*/
public function getGridRangeInfo($args)
{
$request = $args['request'];
$grid = $args['grid'];
$rangeInfo = $args['rangeInfo'];
// Add grid level items per page setting, if any.
$itemsPerPage = $request->getUserVar($this->_getItemsPerPageParamName($grid->getId()));
if ($this->_itemsPerPage) {
$itemsPerPage = $this->_itemsPerPage;
} // Feature config overrides.
if ($itemsPerPage) {
$rangeInfo->setCount($itemsPerPage);
}
}
//
// Private helper methods.
//
/**
* Get the range info items per page parameter name.
*
* @param string $rangeName
*
* @return string
*/
private function _getItemsPerPageParamName($rangeName)
{
return $rangeName . 'ItemsPerPage';
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\GeneralPagingFeature', '\GeneralPagingFeature');
}
@@ -0,0 +1,301 @@
<?php
/**
* @file classes/controllers/grid/feature/GridFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class GridFeature
*
* @ingroup controllers_grid_feature
*
* @brief Base grid feature class. A feature is a type of plugin specific
* to the grid widgets. It provides several hooks to allow injection of
* additional grid functionality. This class implements template methods
* to be extended by subclasses.
*
*/
namespace PKP\controllers\grid\feature;
use PKP\controllers\grid\GridHandler;
use PKP\core\PKPRequest;
class GridFeature
{
/** @var string */
public $_id;
/** @var array */
public $_options;
/**
* Constructor.
*
* @param string $id Feature id.
*/
public function __construct($id)
{
$this->setId($id);
}
//
// Getters and setters.
//
/**
* Get feature id.
*
* @return string
*/
public function getId()
{
return $this->_id;
}
/**
* Set feature id.
*
* @param string $id
*/
public function setId($id)
{
$this->_id = $id;
}
/**
* Get feature js class options.
*
* @return array
*/
public function getOptions()
{
return $this->_options;
}
/**
* Add feature js class options.
*
* @param array $options $optionId => $optionValue
*/
public function addOptions($options)
{
assert(is_array($options));
$this->_options = array_merge((array) $this->getOptions(), $options);
}
//
// Protected methods to be used or extended by subclasses.
//
/**
* Set feature js class options. Extend this method to
* define more feature js class options.
*
* @param PKPRequest $request
* @param GridHandler $grid
*/
public function setOptions($request, $grid)
{
$renderedElements = $this->fetchUIElements($request, $grid);
if ($renderedElements) {
foreach ($renderedElements as $id => $markup) {
$this->addOptions([$id => $markup]);
}
}
}
/**
* Fetch any user interface elements that
* this feature needs to add its functionality
* into the grid. Use this only for ui elements
* that grid will not fetch itself.
*
* @param PKPRequest $request
* @param GridHandler $grid The grid that this
* feature is attached to.
*
* @return array It is expected that the array
* returns data in this format:
* $elementId => $elementMarkup
*/
public function fetchUIElements($request, $grid)
{
return [];
}
/**
* Return the java script feature class.
*
* @return string|null
*/
public function getJSClass()
{
return null;
}
//
// Public hooks to be implemented in subclasses.
//
/**
* Hook called every time grid request args are
* required. Note that if the specific grid implementation
* extends the getRequestArgs method, this hook will only
* be called if the extending method call its parent.
*
* @param array $args
* 'grid' => GridHandler
* 'requestArgs' => array
*/
public function getRequestArgs($args)
{
return null;
}
/**
* Hook called every time the grid range info is
* retrieved.
*
* @param array $args
* 'request' => PKPRequest
* 'grid' => GridHandler
* 'rangeInfo' => DBResultRange
*/
public function getGridRangeInfo($args)
{
return null;
}
/**
* Hook called when grid data is retrieved.
*
* @param array $args
* 'request' => PKPRequest
* 'grid' => GridHandler
* 'gridData' => mixed (array or ItemIterator)
* 'filter' => array
*/
public function getGridDataElements($args)
{
return null;
}
/**
* Hook called before grid data is setted.
*
* @param array $args
* 'grid' => GridHandler
* 'data' => mixed (array or ItemIterator)
*/
public function setGridDataElements($args)
{
return null;
}
/**
* Hook called every time grid initialize a row object.
*
* @param array $args
* 'grid' => GridHandler,
* 'row' => GridRow
*/
public function getInitializedRowInstance($args)
{
return null;
}
/**
* Hook called on grid category row initialization.
*
* @param array $args 'request' => PKPRequest
* 'grid' => CategoryGridHandler
* 'categoryId' => int
* 'row' => GridCategoryRow
*/
public function getInitializedCategoryRowInstance($args)
{
return null;
}
/**
* Hook called on grid's initialization.
*
* @param array $args Contains the grid handler referenced object
* in 'grid' array index.
*/
public function gridInitialize($args)
{
return null;
}
/**
* Hook called on grid's data loading.
*
* @param array $args
* 'request' => PKPRequest,
* 'grid' => GridHandler,
* 'gridData' => array
*/
public function loadData($args)
{
return null;
}
/**
* Hook called on grid fetching.
*
* @param array $args 'grid' => GridHandler
*/
public function fetchGrid($args)
{
$grid = & $args['grid'];
$request = & $args['request'];
$this->setOptions($request, $grid);
}
/**
* Hook called after a group of rows is fetched.
*
* @param array $args
* 'request' => PKPRequest
* 'grid' => GridHandler
* 'jsonMessage' => JSONMessage
*/
public function fetchRows($args)
{
return null;
}
/**
* Hook called after a row is fetched.
*
* @param array $args
* 'request' => PKPRequest
* 'grid' => GridHandler
* 'row' => mixed GridRow or null
* 'jsonMessage' => JSONMessage
*/
public function fetchRow($args)
{
return null;
}
/**
* Hook called when save grid items sequence
* is requested.
*
* @param array $args 'request' => PKPRequest,
* 'grid' => GridHandler
*/
public function saveSequence($args)
{
return null;
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\GridFeature', '\GridFeature');
}
@@ -0,0 +1,161 @@
<?php
/**
* @file classes/controllers/grid/feature/InfiniteScrollingFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class InfiniteScrollingFeature
*
* @ingroup controllers_grid_feature
*
* @brief Add infinite scrolling functionality to grids. It doesn't support
* category grids.
*
*/
namespace PKP\controllers\grid\feature;
use APP\template\TemplateManager;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\NullAction;
class InfiniteScrollingFeature extends GeneralPagingFeature
{
/**
* @copydoc GeneralPagingFeature::GeneralPagingFeature()
* Constructor.
*
* @param null|mixed $itemsPerPage
*/
public function __construct($id = 'infiniteScrolling', $itemsPerPage = null)
{
parent::__construct($id, $itemsPerPage);
}
//
// Extended methods from GridFeature.
//
/**
* @copydoc GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.InfiniteScrollingFeature';
}
/**
* @copydoc GridFeature::fetchUIElements()
*/
public function fetchUIElements($request, $grid)
{
$options = $this->getOptions();
$shown = $options['currentItemsPerPage'] * $options['currentPage'];
if ($shown > $options['itemsTotal']) {
$shown = $options['itemsTotal'];
}
$moreItemsLinkAction = false;
if ($shown < $options['itemsTotal']) {
$moreItemsLinkAction = new LinkAction(
'moreItems',
new NullAction(),
__('grid.action.moreItems'),
'more_items'
);
}
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'iterator' => $this->getItemIterator(),
'shown' => $shown,
'grid' => $grid,
'moreItemsLinkAction' => $moreItemsLinkAction,
]);
return [
'pagingMarkup' => $templateMgr->fetch('controllers/grid/feature/infiniteScrolling.tpl'),
];
}
//
// Hooks implementation.
//
/**
* @copydoc GridFeature::fetchRows()
*/
public function fetchRows($args)
{
$request = $args['request'];
$grid = $args['grid'];
$jsonMessage = $args['jsonMessage'];
// Render the paging options, including updated markup.
$this->setOptions($request, $grid);
$pagingAttributes = ['pagingInfo' => $this->getOptions()];
// Add paging attributes to json so grid can update UI.
$additionalAttributes = (array) $jsonMessage->getAdditionalAttributes();
$jsonMessage->setAdditionalAttributes(
array_merge(
$pagingAttributes,
$additionalAttributes
)
);
}
/**
* @copydoc GridFeature::fetchRow()
* Check if user really deleted a row and fetch the last one from
* the current page.
*/
public function fetchRow($args)
{
$request = $args['request'];
$grid = $args['grid'];
$row = $args['row'];
$jsonMessage = $args['jsonMessage'];
$pagingAttributes = [];
// Render the paging options, including updated markup.
$this->setOptions($request, $grid);
$pagingAttributes['pagingInfo'] = $this->getOptions();
if (is_null($row)) {
$gridData = $grid->getGridDataElements($request);
// Get the last data element id of the current page.
end($gridData);
$lastRowId = key($gridData);
// Get the row and render it.
$args = ['rowId' => $lastRowId];
$row = $grid->getRequestedRow($request, $args);
$pagingAttributes['deletedRowReplacement'] = $grid->renderRow($request, $row);
} else {
// No need for paging markup.
unset($pagingAttributes['pagingInfo']['pagingMarkup']);
}
// Add paging attributes to json so grid can update UI.
$additionalAttributes = $jsonMessage->getAdditionalAttributes();
// Unset sequence map until we support that.
unset($additionalAttributes['sequenceMap']);
$jsonMessage->setAdditionalAttributes(
array_merge(
$pagingAttributes,
$additionalAttributes
)
);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\InfiniteScrollingFeature', '\InfiniteScrollingFeature');
}
@@ -0,0 +1,191 @@
<?php
/**
* @file classes/controllers/grid/feature/OrderCategoryGridItemsFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OrderCategoryGridItemsFeature
*
* @ingroup controllers_grid_feature
*
* @brief Implements category grid ordering functionality.
*
*/
namespace PKP\controllers\grid\feature;
use PKP\controllers\grid\GridHandler;
use PKP\core\PKPRequest;
class OrderCategoryGridItemsFeature extends OrderItemsFeature
{
public const ORDER_CATEGORY_GRID_CATEGORIES_ONLY = 1;
public const ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY = 2;
public const ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS = 3;
/**
* Constructor.
*
* @param int $typeOption Defines which grid elements will
* be orderable (categories and/or rows).
* @param bool $overrideRowTemplate This feature uses row
* actions and it will force the usage of the gridRow.tpl.
* If you want to use a different grid row template file, set this flag to
* false and make sure to use a template file that adds row actions.
* @param GridHandler $grid The grid this feature is to be part of
*/
public function __construct($typeOption = self::ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS, $overrideRowTemplate = true, $grid = null)
{
parent::__construct($overrideRowTemplate);
if ($grid) {
$grid->_constants['ORDER_CATEGORY_GRID_CATEGORIES_ONLY'] = self::ORDER_CATEGORY_GRID_CATEGORIES_ONLY;
$grid->_constants['ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY'] = self::ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY;
$grid->_constants['ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS'] = self::ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS;
}
$this->addOptions(['type' => $typeOption]);
}
//
// Getters and setters.
//
/**
* Return this feature type.
*
* @return int One of the ORDER_CATEGORY_GRID_... constants
*/
public function getType()
{
$options = $this->getOptions();
return $options['type'];
}
//
// Extended methods from GridFeature.
//
/**
* @see GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.OrderCategoryGridItemsFeature';
}
//
// Hooks implementation.
//
/**
* @see OrderItemsFeature::getInitializedRowInstance()
*/
public function getInitializedRowInstance($args)
{
if ($this->getType() != self::ORDER_CATEGORY_GRID_CATEGORIES_ONLY) {
parent::getInitializedRowInstance($args);
}
}
/**
* @see GridFeature::getInitializedCategoryRowInstance()
*/
public function getInitializedCategoryRowInstance($args)
{
if ($this->getType() != self::ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY) {
$row = & $args['row'];
$this->addRowOrderAction($row);
}
}
/**
* @see GridFeature::saveSequence()
*/
public function saveSequence($args)
{
$request = & $args['request'];
$grid = & $args['grid'];
$data = json_decode($request->getUserVar('data'));
$gridCategoryElements = $grid->getGridDataElements($request);
if ($this->getType() != self::ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY) {
$categoriesData = [];
foreach ($data as $categoryData) {
$categoriesData[] = $categoryData->categoryId;
}
// Save categories sequence.
$firstSeqValue = $grid->getDataElementSequence(reset($gridCategoryElements));
foreach ($gridCategoryElements as $rowId => $element) {
$rowPosition = array_search($rowId, $categoriesData);
$newSequence = $firstSeqValue + $rowPosition;
$currentSequence = $grid->getDataElementSequence($element);
if ($newSequence != $currentSequence) {
$grid->setDataElementSequence($request, $rowId, $element, $newSequence);
}
}
}
// Save rows sequence, if this grid has also orderable rows inside each category.
$this->_saveRowsInCategoriesSequence($request, $grid, $gridCategoryElements, $data);
}
//
// Private helper methods.
//
/**
* Save row elements sequence inside categories.
*
* @param PKPRequest $request
* @param GridHandler $grid
* @param array $gridCategoryElements
*/
public function _saveRowsInCategoriesSequence($request, &$grid, $gridCategoryElements, $data)
{
if ($this->getType() != self::ORDER_CATEGORY_GRID_CATEGORIES_ONLY) {
foreach ($gridCategoryElements as $categoryId => $element) {
$gridRowElements = $grid->getGridCategoryDataElements($request, $element);
if (!$gridRowElements) {
continue;
}
// Get the correct rows sequence data.
/** @var ?array */
$rowsData = null;
foreach ($data as $categoryData) {
if ($categoryData->categoryId == $categoryId) {
$rowsData = $categoryData->rowsId;
break;
}
}
unset($rowsData[0]); // remove the first element, it is always the parent category ID
$gridRowElement = reset($gridRowElements);
$firstSeqValue = $grid->getDataElementInCategorySequence($categoryId, $gridRowElement);
foreach ($gridRowElements as $rowId => $element) {
$newSequence = array_search($rowId, $rowsData);
$currentSequence = $grid->getDataElementInCategorySequence($categoryId, $element);
if ($newSequence != $currentSequence) {
$grid->setDataElementInCategorySequence($categoryId, $element, $newSequence);
}
}
}
}
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\OrderCategoryGridItemsFeature', '\OrderCategoryGridItemsFeature');
foreach ([
'ORDER_CATEGORY_GRID_CATEGORIES_ONLY',
'ORDER_CATEGORY_GRID_CATEGORIES_ROWS_ONLY',
'ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS',
] as $constantName) {
define($constantName, constant('\OrderCategoryGridItemsFeature::' . $constantName));
}
}
@@ -0,0 +1,80 @@
<?php
/**
* @file classes/controllers/grid/feature/OrderGridItemsFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OrderGridItemsFeature
*
* @ingroup controllers_grid_feature
*
* @brief Implements grid ordering functionality.
*
*/
namespace PKP\controllers\grid\feature;
class OrderGridItemsFeature extends OrderItemsFeature
{
/**
* Constructor.
*
* @copydoc OrderItemsFeature::OrderItemsFeature()
*
* @param null|mixed $nonOrderableItemsMessage
*/
public function __construct($overrideRowTemplate = true, $nonOrderableItemsMessage = null)
{
parent::__construct($overrideRowTemplate, $nonOrderableItemsMessage);
}
//
// Extended methods from GridFeature.
//
/**
* @see GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.OrderGridItemsFeature';
}
//
// Hooks implementation.
//
/**
* @see GridFeature::saveSequence()
*
* @param array $args
*/
public function saveSequence($args)
{
$request = & $args['request'];
$grid = & $args['grid'];
$data = json_decode($request->getUserVar('data'));
$gridElements = $grid->getGridDataElements($request);
if (empty($gridElements)) {
return;
}
$firstSeqValue = $grid->getDataElementSequence(reset($gridElements));
foreach ($gridElements as $rowId => $element) {
$rowPosition = array_search($rowId, $data);
$newSequence = $firstSeqValue + $rowPosition;
$currentSequence = $grid->getDataElementSequence($element);
if ($newSequence != $currentSequence) {
$grid->setDataElementSequence($request, $rowId, $element, $newSequence);
}
}
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\OrderGridItemsFeature', '\OrderGridItemsFeature');
}
@@ -0,0 +1,217 @@
<?php
/**
* @file classes/controllers/grid/feature/OrderItemsFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OrderItemsFeature
*
* @ingroup controllers_grid_feature
*
* @brief Base class for grid widgets ordering functionality.
*
*/
namespace PKP\controllers\grid\feature;
use APP\template\TemplateManager;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\NullAction;
class OrderItemsFeature extends GridFeature
{
/** @var bool */
public $_overrideRowTemplate;
/** @var string */
public $_nonOrderableItemMessage;
/**
* Constructor.
*
* @param bool $overrideRowTemplate This feature uses row
* actions and it will force the usage of the gridRow.tpl.
* If you want to use a different grid row template file, set this flag to
* false and make sure to use a template file that adds row actions.
* @param string $nonOrderableItemMessage optional A translated message to be used
* when user tries to move a non orderable grid item.
*/
public function __construct($overrideRowTemplate, $nonOrderableItemMessage = null)
{
parent::__construct('orderItems');
$this->setOverrideRowTemplate($overrideRowTemplate);
$this->setNonOrderableItemMessage($nonOrderableItemMessage);
}
//
// Getters and setters.
//
/**
* Set override row template flag.
*/
public function setOverrideRowTemplate($overrideRowTemplate)
{
$this->_overrideRowTemplate = $overrideRowTemplate;
}
/**
* Get override row template flag.
*
* @param GridRow $gridRow
*
* @return bool
*/
public function getOverrideRowTemplate(&$gridRow)
{
// Make sure we don't return the override row template
// flag to objects that are not instances of GridRow class.
if ($gridRow instanceof GridRow) {
return $this->_overrideRowTemplate;
} else {
return false;
}
}
/**
* Set non orderable item message.
*
* @param string $nonOrderableItemMessage Message already translated.
*/
public function setNonOrderableItemMessage($nonOrderableItemMessage)
{
$this->_nonOrderableItemMessage = $nonOrderableItemMessage;
}
/**
* Get non orderable item message.
*
* @return string Message already translated.
*/
public function getNonOrderableItemMessage()
{
return $this->_nonOrderableItemMessage;
}
//
// Extended methods from GridFeature.
//
/**
* @see GridFeature::setOptions()
*/
public function setOptions($request, $grid)
{
parent::setOptions($request, $grid);
$router = $request->getRouter();
$this->addOptions([
'saveItemsSequenceUrl' => $router->url($request, null, null, 'saveSequence', null, $grid->getRequestArgs()),
'csrfToken' => $request->getSession()->getCsrfToken(),
]);
}
/**
* @see GridFeature::fetchUIElements()
*/
public function fetchUIElements($request, $grid)
{
$templateMgr = TemplateManager::getManager($request);
$UIElements = [];
if ($this->isOrderActionNecessary()) {
$templateMgr->assign('gridId', $grid->getId());
$UIElements['orderFinishControls'] = $templateMgr->fetch('controllers/grid/feature/gridOrderFinishControls.tpl');
}
$nonOrderableItemMessage = $this->getNonOrderableItemMessage();
if ($nonOrderableItemMessage) {
$templateMgr->assign('orderMessage', $nonOrderableItemMessage);
$UIElements['orderMessage'] = $templateMgr->fetch('controllers/grid/feature/gridOrderNonOrderableMessage.tpl');
}
return $UIElements;
}
//
// Hooks implementation.
//
/**
* @see GridFeature::getInitializedRowInstance()
*/
public function getInitializedRowInstance($args)
{
$row = & $args['row'];
if ($args['grid']->getDataElementSequence($row->getData()) !== false) {
$this->addRowOrderAction($row);
}
}
/**
* @see GridFeature::gridInitialize()
*/
public function gridInitialize($args)
{
$grid = & $args['grid'];
if ($this->isOrderActionNecessary()) {
$grid->addAction(
new LinkAction(
'orderItems',
new NullAction(),
__('grid.action.order'),
'order_items'
)
);
}
}
//
// Protected methods.
//
/**
* Add grid row order action.
*
* @param GridRow $row
*/
public function addRowOrderAction($row)
{
if ($this->getOverrideRowTemplate($row)) {
$row->setTemplate('controllers/grid/gridRow.tpl');
}
$row->addAction(
new LinkAction(
'moveItem',
new NullAction(),
'',
'order_items'
),
GridRow::GRID_ACTION_POSITION_ROW_LEFT
);
}
//
// Protected template methods.
//
/**
* Return if this feature will use
* a grid level order action. Default is
* true, override it if needed.
*
* @return bool
*/
public function isOrderActionNecessary()
{
return true;
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\OrderItemsFeature', '\OrderItemsFeature');
}
@@ -0,0 +1,45 @@
<?php
/**
* @file classes/controllers/grid/feature/OrderListbuilderItemsFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OrderListbuilderItemsFeature
*
* @ingroup controllers_grid_feature
*
* @brief Implements listbuilder ordering functionality.
*
*/
namespace PKP\controllers\grid\feature;
class OrderListbuilderItemsFeature extends OrderItemsFeature
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct(false);
}
//
// Extended methods from GridFeature.
//
/**
* @see GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.OrderListbuilderItemsFeature';
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\OrderListbuilderItemsFeature', '\OrderListbuilderItemsFeature');
}
@@ -0,0 +1,165 @@
<?php
/**
* @file classes/controllers/grid/feature/PagingFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PagingFeature
*
* @ingroup controllers_grid_feature
*
* @brief Add paging functionality to grids.
*
*/
namespace PKP\controllers\grid\feature;
use APP\template\TemplateManager;
class PagingFeature extends GeneralPagingFeature
{
/**
* @see GridFeature::GridFeature()
* Constructor.
*
* @param string $id Feature identifier.
*/
public function __construct($id = 'paging')
{
parent::__construct($id);
}
//
// Extended methods from GridFeature.
//
/**
* @copydoc GridFeature::getJSClass()
*/
public function getJSClass()
{
return '$.pkp.classes.features.PagingFeature';
}
/**
* @copydoc GridFeature::fetchUIElements()
*/
public function fetchUIElements($request, $grid)
{
$options = $this->getOptions();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'iterator' => $this->getItemIterator(),
'currentItemsPerPage' => $options['currentItemsPerPage'],
'grid' => $grid,
]);
return ['pagingMarkup' => $templateMgr->fetch('controllers/grid/feature/gridPaging.tpl')];
}
//
// Hooks implementation.
//
/**
* @copydoc GridFeature::fetchRow()
* Check if user really deleted a row. Handle following cases:
* 1 - recently added requested row is on previous pages and its
* addition changes the current requested page items;
* 2 - deleted a row from a page that's not the last one;
* 3 - deleted the last row from a page that's not the last one;
*
* The solution is:
* 1 - fetch the first grid data row;
* 2 - fetch the last grid data row;
* 3 - send a request to refresh the entire grid usign the previous
* page.
*/
public function fetchRow($args)
{
$request = $args['request'];
$grid = $args['grid'];
$row = $args['row'];
$jsonMessage = $args['jsonMessage'];
$pagingAttributes = [];
if (is_null($row)) {
$gridData = $grid->getGridDataElements($request);
$iterator = $this->getItemIterator();
$rangeInfo = $grid->getGridRangeInfo($request, $grid->getId());
// Check if row was really deleted or if the requested row is
// just not inside the requested range.
$deleted = true;
$topLimitRowId = (int) $request->getUserVar('topLimitRowId');
$bottomLimitRowId = (int) $request->getUserVar('bottomLimitRowId');
reset($gridData);
$firstDataId = key($gridData);
next($gridData);
$secondDataId = key($gridData);
end($gridData);
$lastDataId = key($gridData);
if ($secondDataId == $topLimitRowId) {
$deleted = false;
// Case 1.
// Row was added but it's on previous pages, so the first
// item of the grid was moved to the second place by the added
// row. Render the first one that's currently not visible yet in
// grid.
$args = ['rowId' => $firstDataId];
$row = $grid->getRequestedRow($request, $args);
$pagingAttributes['newTopRow'] = $grid->renderRow($request, $row);
}
if ($firstDataId == $topLimitRowId && $lastDataId == $bottomLimitRowId) {
$deleted = false;
}
if ($deleted) {
if ((empty($gridData) ||
// When DAOResultFactory, it seems that if no items were found for the current
// range information, the last page is fetched, which give us grid data even if
// the current page is empty. So we check for iterator and rangeInfo current pages.
$iterator->getPage() != $rangeInfo->getPage())
&& $iterator->getPageCount() >= 1) {
// Case 3.
$pagingAttributes['loadLastPage'] = true;
} else {
if (count($gridData) >= $rangeInfo->getCount()) {
// Case 2.
// Get the last data element id of the current page.
end($gridData);
$firstRowId = key($gridData);
// Get the row and render it.
$args = ['rowId' => $firstRowId];
$row = $grid->getRequestedRow($request, $args);
$pagingAttributes['deletedRowReplacement'] = $grid->renderRow($request, $row);
}
}
}
}
// Render the paging options, including updated markup.
$this->setOptions($request, $grid);
$pagingAttributes['pagingInfo'] = $this->getOptions();
// Add paging attributes to json so grid can update UI.
$additionalAttributes = $jsonMessage->getAdditionalAttributes();
$jsonMessage->setAdditionalAttributes(
array_merge(
$pagingAttributes,
$additionalAttributes
)
);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\PagingFeature', '\PagingFeature');
}
@@ -0,0 +1,85 @@
<?php
/**
* @file classes/controllers/grid/feature/selectableItems/ItemSelectionGridColumn.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ItemSelectionGridColumn
*
* @ingroup classes_controllers_grid_feature_selectableItems
*
* @brief Implements a column with checkboxes to select grid items.
*/
namespace PKP\controllers\grid\feature\selectableItems;
use PKP\controllers\grid\ColumnBasedGridCellProvider;
use PKP\controllers\grid\GridColumn;
class ItemSelectionGridColumn extends GridColumn
{
/** @var string */
public $_selectName;
/**
* Constructor
*
* @param string $selectName The name of the form parameter
* to which the selected files will be posted.
*/
public function __construct($selectName)
{
assert(is_string($selectName) && !empty($selectName));
$this->_selectName = $selectName;
$cellProvider = new ColumnBasedGridCellProvider();
parent::__construct(
'select',
'common.select',
null,
'controllers/grid/gridRowSelectInput.tpl',
$cellProvider,
['width' => 3]
);
}
//
// Getters and Setters
//
/**
* Get the select name.
*
* @return string
*/
public function getSelectName()
{
return $this->_selectName;
}
//
// Public methods
//
/**
* Method expected by ColumnBasedGridCellProvider
* to render a cell in this column.
*
* @see ColumnBasedGridCellProvider::getTemplateVarsFromRowColumn()
*/
public function getTemplateVarsFromRow($row)
{
// Return the data expected by the column's cell template.
return [
'elementId' => $row->getId(),
'selectName' => $this->getSelectName(),
'selected' => $row->getFlag('selected')];
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\selectableItems\ItemSelectionGridColumn', '\ItemSelectionGridColumn');
}
@@ -0,0 +1,68 @@
<?php
/**
* @file classes/controllers/grid/feature/selectableItems/SelectableItemsFeature.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class SelectableItemsFeature
*
* @ingroup controllers_grid_feature_selectableItems
*
* @brief Implements grid widgets selectable items functionality.
*
*/
namespace PKP\controllers\grid\feature\selectableItems;
use PKP\controllers\grid\feature\GridFeature;
class SelectableItemsFeature extends GridFeature
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct('selectableItems');
}
//
// Hooks implementation.
//
/**
* @see GridFeature::gridInitialize()
*/
public function gridInitialize($args)
{
$grid = $args['grid'];
// Add checkbox column to the grid.
$grid->addColumn(new ItemSelectionGridColumn($grid->getSelectName()));
}
/**
* @see GridFeature::getInitializedRowInstance()
*/
public function getInitializedRowInstance($args)
{
/** @var \PKP\controllers\grid\CategoryGridHandler|\PKP\controllers\grid\GridHandler */
$grid = $args['grid'];
/** @var \PKP\controllers\grid\GridRow */
$row = $args['row'];
if ($grid instanceof \PKP\controllers\grid\CategoryGridHandler) {
$categoryId = $grid->getCurrentCategoryId();
$row->addFlag('selected', (bool) $grid->isDataElementInCategorySelected($categoryId, $row->getData()));
} else {
$row->addFlag('selected', (bool) $grid->isDataElementSelected($row->getData()));
}
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\controllers\grid\feature\selectableItems\SelectableItemsFeature', '\SelectableItemsFeature');
}