Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions system/core/pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,72 @@ abstract class HyphaSystemPage extends HyphaPage {
abstract class for a page backed by datatype and xml file.
*/
abstract class HyphaDatatypePage extends HyphaPage {
const INDEX_TABLE_COLUMNS_TITLE = 'index_table_column_title';
const INDEX_TABLE_COLUMNS_AUTHOR = 'index_table_column_author';
const INDEX_TABLE_COLUMNS_DATE = 'index_table_column_date';
const INDEX_TABLE_COLUMNS_STATUS = 'index_table_column_status';

public $pageListNode, $language, $pagename, $privateFlag;

function __construct(HyphaDomElement $node, RequestContext $O_O) {
parent::__construct($O_O);
$this->replacePageListNode($node);
}

/**
* @return string
*/
public static function getDatatypeName() {
return str_replace('_', ' ', get_called_class());
}

/**
* @return array
*/
public static function getIndexTableColumns() {
return [
__(self::INDEX_TABLE_COLUMNS_TITLE),
__(self::INDEX_TABLE_COLUMNS_AUTHOR),
__(self::INDEX_TABLE_COLUMNS_DATE),
];
}

/**
* @return array
*/
public function getIndexData() {
$id = $this->pageListNode->getAttribute('id');
$date = $this->getSortDateTime();
$data = [
__(self::INDEX_TABLE_COLUMNS_TITLE) => [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if using the translated titles as array indices here is the best approach? I would tend to use some kind of (untranslated) name as the index, and then put the translated title in a field next to class/sort/value?

'class' => 'type_'.get_class($this).' '.($this->privateFlag ? 'is-private' : 'is-public'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These things (datatype and private flag) seem to be unrelated to the title, so I wonder if these are appropriate here? Conceptually, they would be a column of their own, but you probably do not want to display them as such.

Maybe these would be more appropriate as classes on the <tr> instead of an individual column? Maybe returned as a special column in this array?

'sort' => preg_replace("/[^A-Za-z0-9]/", '', $this->getTitle()).'_'.$id,
'value' => '<a href="'.$this->language.'/'.$this->pagename.'">'.$this->getTitle().'</a>',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be html_value to distinguish between html and text value? Alternatively, the non-HTML values should be htmlspecialchars'd? Alternatively, this could maybe build a DomNode to indicate that it is already HTML (combined with my other suggestion to build a DOM tree instead of an HTML string), and then any strings can be treated as text (and thus encoded).

],
__(self::INDEX_TABLE_COLUMNS_AUTHOR) => $this->getAuthor(),
__(self::INDEX_TABLE_COLUMNS_DATE) => [
'sort' => $date ? $date->format('YmdHis') : '',
'value' => $date ? $date->format('Y-m-d') : '',
],
];
return $this->filterIndexData($data);
}

/**
* @param array $data
*
* @return array
*/
protected function filterIndexData(array $data) {
$availableColumns = self::getIndexTableColumns();
foreach ($data as $column => $dataPerColumn) {
if (!in_array($column, $availableColumns)) {
unset($data[$column]);
}
}
return $data;
}

protected function deletePage() {
global $hyphaXml, $hyphaUser;
$id = $this->pageListNode->getAttribute('id');
Expand Down Expand Up @@ -92,6 +147,32 @@ public function getTitle() {
return showPagename($this->pagename);
}

/**
* @return null|string
*/
public function getAuthor() {
$v = $this->getLatestVersion();
return $v ? $v->getAttribute('author') : null;
}

/**
* @return null|string
*/
public function getLatestVersion() {
if ($this->xml->hasVersions() && $this->xml->getElementById($this->language)) {
$history = [];
foreach($this->xml->getElementById($this->language)->getElementsByTagName('version') as $v) {
$timestamp = $v->getAttribute('xml:id');
$history[$timestamp] = $v;
}
if (!empty($history)) {
krsort($history);
return reset($history);
}
}
return null;
}

public function renderSingleLine(HyphaDomElement $container) {
$h2 = $container->document()->createElement('h2');
$h2->setText($this->getTitle());
Expand Down
126 changes: 100 additions & 26 deletions system/datatypes/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,116 @@ public function pageIndexView(HyphaRequest $request) {
$languageName = $isoLangList[$language];
$languageName = substr($languageName, 0, strpos($languageName, ' ('));

$this->html->linkScript('//cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js');
$this->html->linkStyle('//cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css');

$html = <<<TABLE
<table class="page_index">
<thead>
<tr>
[[headerItems]]
</tr>
</thead>
<tbody>
[[tbody]]
</tbody>
</table>
TABLE;

$tRowTpl = <<<ROW
<tr>
[[recordItems]]
</tr>
ROW;
$tRowItemTpl = <<<ROWITEM
<td class="index-item [[name]] [[class]]" data-sort="[[sort]]">[[value]]</td>
ROWITEM;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I like using these HTML templates like this. They are easy to read, but building HTML from text also seems prone to typos, encoding errors, etc. For forms, we're using this approach because those are complex and very diverse, but here the structure is very repetitive and simple, which means it could be feasible to just build up the DOM in memory like we do elsewhere. This has the advantage that all encoding is done automatically, you can't break the DOM with a typo, you can easily make changes to earlier sections of the DOM, etc.


$dataTypes = hypha_getDataTypes();

// get list of available pages and sort alphabetically
$pageList = [];
foreach(hypha_getPageList() as $page) {
foreach(hypha_getPageList() as $index => $page) {
$lang = hypha_pageGetLanguage($page, $language);
if ($lang) if ($this->O_O->isUser() || ($page->getAttribute('private')!='on')) {
$pageList[] = $lang->getAttribute('name').($page->getAttribute('private')=='on' ? '&#;' : '');
$pageListDatatype[$lang->getAttribute('name')] = $page->getAttribute('type');
$isPrivateOrUser = $this->O_O->isUser() || ($page->getAttribute('private') != 'on');
$isInDataType = array_key_exists($page->getAttribute('type'), $dataTypes);
if ($lang && $isPrivateOrUser && $isInDataType) {
/** @var HyphaDatatypePage $hyphaPage */
$hyphaPage = createPageInstance($this->O_O, $page);
$titleSort = preg_replace("/[^A-Za-z0-9]/", '', $hyphaPage->getTitle());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the sort return in the column data, could the default sorting maybe reuse that (i.e. by using a user-defined sorting function after collecting all index data that looks at title->sort?

$titleSort .= '_'.$index;
$pageList[$titleSort] = $hyphaPage;
}
}
if ($pageList) array_multisort(array_map('strtolower', $pageList), $pageList);

// add capitals
$capital = 'A';
$first = true;
$htmlList = [];
if ($pageList) foreach($pageList as $pagename) {
while($capital < strtoupper($pagename[0])) $capital++;
if (strtoupper($pagename[0]) == $capital) {
if (!$first) {
$htmlList[] = '</div>';
ksort($pageList);

$columns = [];
foreach ($dataTypes as $class => $name) {
$cols = call_user_func($class . '::getIndexTableColumns');
$columns += array_combine($cols, $cols);
}

$tbody = '';
// iterate over page list
foreach($pageList as $titleSort => $hyphaPage) {
$recordItems = '';
$items = $hyphaPage->getIndexData();
foreach ($columns as $name) {
if (array_key_exists($name, $items)) {
$item = $items[$name];
} else {
$item = '';
}
if (!is_array($item)) {
$item = ['value' => $item];
}

$vars = ['name' => $name];
foreach (['value', 'sort', 'class'] as $key) {
if (array_key_exists($key, $item)) {
$vars[$key] = $item[$key];
}
}
$htmlList[] = '<div class="letter-wrapper">';
$htmlList[] = '<div class="letter">'.$capital.'</div>';
$capital++;
$first = false;
$recordItems .= hypha_substitute($tRowItemTpl, $vars);
}
$privatePos = strpos($pagename, '&#;');
if ($privatePos) $pagename = substr($pagename, 0, $privatePos);
$htmlList[] = '<div class="index-item type_'.$pageListDatatype[$pagename].' '.($privatePos ? 'is-private' : 'is-public').'"><a href="'.$language.'/'.$pagename.'">'.showPagename($pagename).'</a></div>';

$vars = [
'recordItems' => $recordItems,
];

$tbody .= hypha_substitute($tRowTpl, $vars);
}

$headerItems = '';
foreach ($columns as $column) {
$headerItems .= '<th>'.$column.'</th>';
}

$html = '<div class="index">';
foreach($htmlList as $htmlLine) $html.= $htmlLine;
$html.= '</div>';
$vars = [
'headerItems' => $headerItems,
'tbody' => $tbody,
];

$html = hypha_substitute($html, $vars);

// initialize datatable
$js = <<<EOD
$(document).ready(function () {
$('.page_index').DataTable({
order: [[ [[sortIndex]], "desc" ]],
paging: false,
});
});
EOD;

$dateIndex = array_search(__(HyphaDatatypePage::INDEX_TABLE_COLUMNS_DATE), array_values($columns));
$vars = [
'sortIndex' => $dateIndex,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this sortIndex mean exactly? Is this the default sorting (if so, then why sort the HTML at all)? Or the only option for interactive sorting? This could probably use a comment.

];
$js = hypha_substitute($js, $vars);
$this->html->writeScript($js);

$this->html->writeToElement('pagename', __('page-index').': '.$languageName);
$this->html->writeToElement('main', $html);
}
}
}
31 changes: 31 additions & 0 deletions system/datatypes/peer_reviewed_article.php
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,30 @@ protected function sendMail($receivers, $subject, $message) {
sendMail($receivers, hypha_getTitle() . ': '. $subject, $message, hypha_getEmail(), hypha_getTitle(), $style);
}

/**
* @return array
*/
public static function getIndexTableColumns() {
$columns = parent::getIndexTableColumns();
if (isUser()) {
$columns[] = __(self::INDEX_TABLE_COLUMNS_STATUS);
}
return $columns;
}

/**
* @return array
*/
public function getIndexData() {
$data = [
__(self::INDEX_TABLE_COLUMNS_STATUS) => [
'value' => $this->getStatus(),
'sort' => $this->getStatus(),
],
] + parent::getIndexData();
return $this->filterIndexData($data);
}

/**
* Gets the article title.
*
Expand All @@ -2047,6 +2071,13 @@ public function getTitle() {
return $title;
}

/**
* @return string
*/
public function getAuthor() {
return $this->xml->find(self::FIELD_NAME_ARTICLE)->getAttribute(self::FIELD_NAME_AUTHOR);
}

/**
* Gets the article excerpt.
*
Expand Down
8 changes: 7 additions & 1 deletion system/languages/en.php
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,13 @@
"art-date-format-date" => "%B %e, %Y", // see for format: https://www.php.net/manual/en/function.date.php
"art-date-format-time" => "at %l:%M%p", // see for format: https://www.php.net/manual/en/function.date.php
"art-read-more" => "Read more",


// index
"index_table_column_title" => "title",
"index_table_column_author" => "author",
"index_table_column_date" => "date",
"index_table_column_status" => "status",

// sharing links
"share-email-subject" => "See '[[title]]' at [[domain]]",
"share-email-body" => "I came across '[[title]]' at [[domain]]: [[url]]",
Expand Down
6 changes: 6 additions & 0 deletions system/languages/nl.php
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,12 @@
"art-date-format-time" => "om %k:%Mu", // see for format: https://www.php.net/manual/en/function.date.php
"art-read-more" => "Lees meer",

// index
"index_table_column_title" => "title",
"index_table_column_author" => "author",
"index_table_column_date" => "date",
"index_table_column_status" => "status",

// sharing links
"share-email-subject" => "Zie '[[title]]' op [[domain]]",
"share-email-body" => "Ik kwam '[[title]]' tegen op [[domain]]: [[url]]",
Expand Down