From 9e568bd0c6f7dc39248bc31e301f78d378eddb54 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 1 Jun 2026 13:53:21 +0000
Subject: [PATCH 03/27] Finalize card redesign validation updates
---
view_items.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/view_items.php b/view_items.php
index 54c24615..2d183b63 100644
--- a/view_items.php
+++ b/view_items.php
@@ -1591,8 +1591,6 @@ function block_exaport_category_template_bootstrap_card($category, $courseid, $t
return $content;
}
-;
-
function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type, $categoryid, $currentcategory, $foldermode = false) {
global $CFG, $USER, $DB;
From 13d2dc4c50788e78175037375505b78bca84f7e8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 1 Jun 2026 14:05:56 +0000
Subject: [PATCH 04/27] refactor: replace PHP string-concat card rendering with
Mustache templates in view_items.php
---
.../view_items_artefact_card_flat.mustache | 83 ++++++
.../view_items_artefact_card_folder.mustache | 82 ++++++
templates/view_items_category_card.mustache | 61 ++++
view_items.php | 274 +++++++-----------
4 files changed, 329 insertions(+), 171 deletions(-)
create mode 100644 templates/view_items_artefact_card_flat.mustache
create mode 100644 templates/view_items_artefact_card_folder.mustache
create mode 100644 templates/view_items_category_card.mustache
diff --git a/templates/view_items_artefact_card_flat.mustache b/templates/view_items_artefact_card_flat.mustache
new file mode 100644
index 00000000..a576d71c
--- /dev/null
+++ b/templates/view_items_artefact_card_flat.mustache
@@ -0,0 +1,83 @@
+{{!
+ Artefact card in flat/grid mode for the bootstrap layout (moodle_bootstrap).
+ Used by block_exaport_artefact_template_bootstrap_card() in view_items.php
+ when $foldermode is false.
+
+ Context variables:
+ itemnamelower - Lowercase item name for data-item-name attribute
+ catids - Comma-separated category IDs for data-category-ids attribute
+ timemodified - Unix timestamp for data-item-date attribute
+ itemid - Integer item id
+ url - URL to the artefact detail page
+ itemname - Display name of the item (auto-escaped by mustache)
+ typeicon - Pre-rendered HTML for the type icon
+ typestring - Localised type label string
+ copytoself - Boolean: tile is in the "copy to portfolio" state (currentcategory.id == -1)
+ copytoselfurl - URL for the "make it yours" copy action (copytoself only)
+ copytoselftooltip - Localised tooltip for the copy-to-self button
+ hascomments - Boolean: item has at least one comment
+ commentcount - Integer comment count
+ commenticon - Pre-rendered HTML for the comment icon
+ projecticon - Pre-rendered HTML for the project info icon (may be empty)
+ compicon - Pre-rendered HTML for the competence icon (may be empty)
+ typemineorshared - Boolean: type is "mine" or "shared" (show edit/delete/user icons)
+ isownitem - Boolean: current user owns this item
+ editurl - URL for the edit action
+ editicon - Pre-rendered HTML for the edit icon
+ deleteurl - URL for the delete action
+ trashicon - Pre-rendered HTML for the delete icon
+ ownername - Full name of the item owner (shown in tooltip when not own item)
+ usericon - Pre-rendered HTML for the user icon
+ thumburl - URL to the item thumbnail image
+ categorybadges - Pre-rendered HTML for category badge pills (may be empty)
+ dateformatted - Human-readable date string for the card footer
+}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/view_items_artefact_card_folder.mustache b/templates/view_items_artefact_card_folder.mustache
new file mode 100644
index 00000000..335d9fec
--- /dev/null
+++ b/templates/view_items_artefact_card_folder.mustache
@@ -0,0 +1,82 @@
+{{!
+ Artefact card in folder-navigation mode for the bootstrap layout (moodle_bootstrap).
+ Used by block_exaport_artefact_template_bootstrap_card() in view_items.php
+ when $foldermode is true.
+
+ Context variables:
+ url - URL to the artefact detail page
+ itemnamelower - Lowercase item name for data-item-name attribute
+ timemodified - Unix timestamp for data-item-date attribute
+ catids - Comma-separated category IDs for data-category-ids attribute
+ itemid - Integer item id
+ typeicon - Pre-rendered HTML for the type icon (with tooltip)
+ itemname - Display name of the item (auto-escaped by mustache)
+ ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
+ viewlabel - Localised "View" label
+ viewicon - Pre-rendered HTML for the view icon
+ canedit - Boolean: show "Edit" menu entry
+ editurl - URL for the edit action
+ editicon - Pre-rendered HTML for the edit icon
+ editlabel - Localised "Edit" label
+ candelete - Boolean: show "Delete" menu entry
+ deleteurl - URL for the delete action
+ deleteicon - Pre-rendered HTML for the delete icon
+ deletelabel - Localised "Delete" label
+ introtext - Short plain-text intro excerpt (empty string when absent)
+ dateformatted - Human-readable date string for the card footer
+ compbadge - Pre-rendered HTML for the competence badge (may be empty)
+ hascomments - Boolean: item has at least one comment
+ commentcount - Integer comment count
+ commentlabel - Localised comment count tooltip string
+}}
+
+
+
+
+ {{#introtext}}
{{introtext}}
{{/introtext}}
+
+
+
+
diff --git a/templates/view_items_category_card.mustache b/templates/view_items_category_card.mustache
new file mode 100644
index 00000000..0cea8494
--- /dev/null
+++ b/templates/view_items_category_card.mustache
@@ -0,0 +1,61 @@
+{{!
+ Category card tile for the bootstrap layout (moodle_bootstrap).
+ Used by block_exaport_category_template_bootstrap_card() in view_items.php.
+
+ Context variables:
+ outerclasses - CSS class string for the outer wrapper div
+ tilenamelower - Lowercase category name for data-item-name attribute
+ isparenttile - Boolean: true when this tile links *up* to the parent category
+ tiletargetid - Integer id of the target category (for drag-drop)
+ tilefixedclass - Extra CSS class string (non-empty only for parent tile)
+ tileurl - URL the tile links to
+ tilename - Display name of the category (auto-escaped by mustache)
+ typemine - Boolean: current user owns this category (show edit/delete)
+ editurl - URL for the edit action
+ deleteurl - URL for the delete action
+ ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
+ viewicon - Pre-rendered HTML for the "view" menu item icon
+ editicon - Pre-rendered HTML for the "edit" menu item icon
+ deleteicon - Pre-rendered HTML for the "delete" menu item icon
+ viewlabel - Localised "View" label
+ editlabel - Localised "Edit" label
+ deletelabel - Localised "Delete" label
+ folderupicon - Pre-rendered HTML for the folder-open-up icon (parent tile only)
+ categorylabel - Localised "Category" tooltip text (regular tile only)
+}}
+
+
+ {{^isparenttile}}
+
+ {{/isparenttile}}
+
+
+
+
diff --git a/view_items.php b/view_items.php
index 2d183b63..a2f653a0 100644
--- a/view_items.php
+++ b/view_items.php
@@ -1540,59 +1540,44 @@ function block_exaport_artefact_list_item($item, $courseid, $type, $categoryid,
}
function block_exaport_category_template_bootstrap_card($category, $courseid, $type, $currentcategory, $parentcategory = null) {
- global $CFG;
+ global $CFG, $OUTPUT;
$isparenttile = (bool)$parentcategory;
$tiletargetid = $isparenttile ? (int)$parentcategory->id : (int)$category->id;
$tilename = $isparenttile ? $parentcategory->name : $category->name;
- $tileurl = $isparenttile ? $parentcategory->url : $category->url;
+ $tileurl = $isparenttile ? (string)$parentcategory->url : (string)$category->url;
$outerclasses = $isparenttile ? 'col mb-4 exaport-folder-category' : 'col col-card-folder mb-4 exaport-folder-category';
$tilefixedclass = $isparenttile ? 'excomdos_tile_fixed ' : '';
- $content = '
';
+ $context = [
+ 'outerclasses' => $outerclasses,
+ 'tilenamelower' => strtolower($tilename),
+ 'isparenttile' => $isparenttile,
+ 'tiletargetid' => $tiletargetid,
+ 'tilefixedclass' => $tilefixedclass,
+ 'tileurl' => $tileurl,
+ 'tilename' => $tilename,
+ 'typemine' => ($type == 'mine'),
+ 'editurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=edit',
+ 'deleteurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=delete',
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
+ 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
+ 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
+ 'viewlabel' => block_exaport_get_string('view'),
+ 'editlabel' => block_exaport_get_string('edit'),
+ 'deletelabel' => block_exaport_get_string('delete'),
+ 'folderupicon' => block_exaport_fontawesome_icon('folder-open', 'regular', 1, ['icon', 'fa-fw', 'me-1'], [],
+ ['data-bs-toggle' => 'tooltip', 'data-bs-placement' => 'top',
+ 'data-bs-title' => block_exaport_get_string('category_up')], 'up'),
+ 'categorylabel' => block_exaport_get_string('category'),
+ ];
- return $content;
+ return $OUTPUT->render_from_template('block_exaport/view_items_category_card', $context);
}
function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type, $categoryid, $currentcategory, $foldermode = false) {
- global $CFG, $USER, $DB;
+ global $CFG, $USER, $DB, $OUTPUT;
$iconTypeProps = block_exaport_item_icon_type_options($item->type);
$url = $CFG->wwwroot . '/blocks/exaport/shared_item.php?courseid=' . $courseid . '&access=portfolio/id/' . $item->userid . '&itemid=' . $item->id;
@@ -1606,7 +1591,6 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
}
if ($foldermode) {
- $itemtitle = format_string($item->name);
$typelabel = get_string($item->type, 'block_exaport');
$introtext = '';
if (!empty($item->intro)) {
@@ -1615,133 +1599,81 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
$introtext = shorten_text(trim(strip_tags($intro)), 140, true);
}
- $itemContent = '
';
-
- return $itemContent;
- }
-
- $itemContent = '
-
-
-
-
-
-
-
-
-
-
-
-
- ';
+ $cattype = ($type == 'shared') ? '&cattype=shared' : '';
+ $isownitem = ($item->userid == $USER->id);
+ $commentcount = (int)($item->comments ?? 0);
+ $commentlabel = $commentcount . ' ' . block_exaport_get_string($commentcount === 1 ? 'comment' : 'comments');
+
+ $context = [
+ 'url' => $url,
+ 'itemnamelower' => strtolower($item->name),
+ 'timemodified' => (int)$item->timemodified,
+ 'catids' => implode(',', $itemCatIds),
+ 'itemid' => (int)$item->id,
+ 'typeicon' => '
',
+ 'itemname' => $item->name,
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
+ 'viewlabel' => block_exaport_get_string('view'),
+ 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
+ 'canedit' => $isownitem,
+ 'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . $cattype,
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
+ 'editlabel' => block_exaport_get_string('edit'),
+ 'candelete' => $isownitem && block_exaport_item_is_editable($item->id),
+ 'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . $cattype,
+ 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
+ 'deletelabel' => block_exaport_get_string('delete'),
+ 'introtext' => $introtext,
+ 'dateformatted' => date('d.m.Y H:i', $item->timemodified),
+ 'compbadge' => block_exaport_get_item_comp_footer_badge($item),
+ 'hascomments' => $commentcount > 0,
+ 'commentcount' => $commentcount,
+ 'commentlabel' => $commentlabel,
+ ];
+
+ return $OUTPUT->render_from_template('block_exaport/view_items_artefact_card_folder', $context);
+ }
+
+ // Flat / grid mode.
+ $copytoself = ($currentcategory->id == -1);
+ $isownitem = ($item->userid == $USER->id);
+ $ownername = '';
+ if (!$isownitem) {
+ $itemuser = $DB->get_record('user', ['id' => $item->userid]);
+ $ownername = $itemuser ? fullname($itemuser) : '';
+ }
+
+ $context = [
+ 'itemnamelower' => strtolower($item->name),
+ 'catids' => implode(',', $itemCatIds),
+ 'timemodified' => (int)$item->timemodified,
+ 'itemid' => (int)$item->id,
+ 'url' => $url,
+ 'itemname' => $item->name,
+ 'typeicon' => block_exaport_fontawesome_icon($iconTypeProps['iconName'], $iconTypeProps['iconStyle'], 1, ['artefact_icon']),
+ 'typestring' => get_string($item->type, 'block_exaport'),
+ 'copytoself' => $copytoself,
+ 'copytoselfurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&sesskey=' . sesskey() . '&action=copytoself',
+ 'copytoselftooltip' => get_string('make_it_yours', 'block_exaport'),
+ 'hascomments' => ($item->comments > 0),
+ 'commentcount' => (int)$item->comments,
+ 'commenticon' => block_exaport_fontawesome_icon('comment', 'regular', 1, [], [], [], '', [], [], [], []),
+ 'projecticon' => block_exaport_get_item_project_icon($item),
+ 'compicon' => block_exaport_get_item_comp_icon($item),
+ 'typemineorshared' => in_array($type, ['mine', 'shared']),
+ 'isownitem' => $isownitem,
+ 'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . (($type == 'shared') ? '&cattype=shared' : ''),
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
+ 'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . (($type == 'shared') ? '&cattype=shared' : ''),
+ 'trashicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
+ 'ownername' => $ownername,
+ 'usericon' => block_exaport_fontawesome_icon('circle-user', 'solid', 1),
+ 'thumburl' => $CFG->wwwroot . '/blocks/exaport/item_thumb.php?item_id=' . $item->id,
+ 'categorybadges' => block_exaport_render_item_category_badges($item),
+ 'dateformatted' => date('d.m.Y H:i', $item->timemodified),
+ ];
- return $itemContent;
+ return $OUTPUT->render_from_template('block_exaport/view_items_artefact_card_flat', $context);
}
From f31b42112d9991046ca137053b31c80d439d8fd2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 10:18:02 +0000
Subject: [PATCH 05/27] Fix FA free icons and inline fixed icons in mustache
templates
---
templates/view_items_artefact_card_flat.mustache | 12 ++++--------
templates/view_items_artefact_card_folder.mustache | 12 ++++--------
templates/view_items_category_card.mustache | 12 ++++--------
view_items.php | 12 ------------
4 files changed, 12 insertions(+), 36 deletions(-)
diff --git a/templates/view_items_artefact_card_flat.mustache b/templates/view_items_artefact_card_flat.mustache
index a576d71c..3a80d353 100644
--- a/templates/view_items_artefact_card_flat.mustache
+++ b/templates/view_items_artefact_card_flat.mustache
@@ -17,17 +17,13 @@
copytoselftooltip - Localised tooltip for the copy-to-self button
hascomments - Boolean: item has at least one comment
commentcount - Integer comment count
- commenticon - Pre-rendered HTML for the comment icon
projecticon - Pre-rendered HTML for the project info icon (may be empty)
compicon - Pre-rendered HTML for the competence icon (may be empty)
typemineorshared - Boolean: type is "mine" or "shared" (show edit/delete/user icons)
isownitem - Boolean: current user owns this item
editurl - URL for the edit action
- editicon - Pre-rendered HTML for the edit icon
deleteurl - URL for the delete action
- trashicon - Pre-rendered HTML for the delete icon
ownername - Full name of the item owner (shown in tooltip when not own item)
- usericon - Pre-rendered HTML for the user icon
thumburl - URL to the item thumbnail image
categorybadges - Pre-rendered HTML for category badge pills (may be empty)
dateformatted - Human-readable date string for the card footer
@@ -51,17 +47,17 @@
{{/copytoself}}
{{^copytoself}}
{{#hascomments}}
-
+
{{/hascomments}}
{{{projecticon}}}
{{{compicon}}}
{{#typemineorshared}}
{{#isownitem}}
-
{{{editicon}}}
-
{{{trashicon}}}
+
+
{{/isownitem}}
{{^isownitem}}
-
{{{usericon}}}
+
{{/isownitem}}
{{/typemineorshared}}
{{/copytoself}}
diff --git a/templates/view_items_artefact_card_folder.mustache b/templates/view_items_artefact_card_folder.mustache
index 335d9fec..35ef3c89 100644
--- a/templates/view_items_artefact_card_folder.mustache
+++ b/templates/view_items_artefact_card_folder.mustache
@@ -11,16 +11,12 @@
itemid - Integer item id
typeicon - Pre-rendered HTML for the type icon (with tooltip)
itemname - Display name of the item (auto-escaped by mustache)
- ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
viewlabel - Localised "View" label
- viewicon - Pre-rendered HTML for the view icon
canedit - Boolean: show "Edit" menu entry
editurl - URL for the edit action
- editicon - Pre-rendered HTML for the edit icon
editlabel - Localised "Edit" label
candelete - Boolean: show "Delete" menu entry
deleteurl - URL for the delete action
- deleteicon - Pre-rendered HTML for the delete icon
deletelabel - Localised "Delete" label
introtext - Short plain-text intro excerpt (empty string when absent)
dateformatted - Human-readable date string for the card footer
@@ -40,20 +36,20 @@
- {{{ellipsisicon}}}
+
diff --git a/templates/view_items_category_card.mustache b/templates/view_items_category_card.mustache
index 0cea8494..71c49c3e 100644
--- a/templates/view_items_category_card.mustache
+++ b/templates/view_items_category_card.mustache
@@ -13,10 +13,6 @@
typemine - Boolean: current user owns this category (show edit/delete)
editurl - URL for the edit action
deleteurl - URL for the delete action
- ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
- viewicon - Pre-rendered HTML for the "view" menu item icon
- editicon - Pre-rendered HTML for the "edit" menu item icon
- deleteicon - Pre-rendered HTML for the "delete" menu item icon
viewlabel - Localised "View" label
editlabel - Localised "Edit" label
deletelabel - Localised "Delete" label
@@ -29,18 +25,18 @@
- {{{ellipsisicon}}}
+
diff --git a/view_items.php b/view_items.php
index a2f653a0..c11e7fc2 100644
--- a/view_items.php
+++ b/view_items.php
@@ -1560,10 +1560,6 @@ function block_exaport_category_template_bootstrap_card($category, $courseid, $t
'typemine' => ($type == 'mine'),
'editurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=edit',
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=delete',
- 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
- 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
- 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
- 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'viewlabel' => block_exaport_get_string('view'),
'editlabel' => block_exaport_get_string('edit'),
'deletelabel' => block_exaport_get_string('delete'),
@@ -1614,16 +1610,12 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
. ' data-bs-toggle="tooltip" data-bs-placement="top"'
. ' data-bs-title="' . s($typelabel) . '">',
'itemname' => $item->name,
- 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
'viewlabel' => block_exaport_get_string('view'),
- 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
'canedit' => $isownitem,
'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . $cattype,
- 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
'editlabel' => block_exaport_get_string('edit'),
'candelete' => $isownitem && block_exaport_item_is_editable($item->id),
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . $cattype,
- 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'deletelabel' => block_exaport_get_string('delete'),
'introtext' => $introtext,
'dateformatted' => date('d.m.Y H:i', $item->timemodified),
@@ -1659,17 +1651,13 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
'copytoselftooltip' => get_string('make_it_yours', 'block_exaport'),
'hascomments' => ($item->comments > 0),
'commentcount' => (int)$item->comments,
- 'commenticon' => block_exaport_fontawesome_icon('comment', 'regular', 1, [], [], [], '', [], [], [], []),
'projecticon' => block_exaport_get_item_project_icon($item),
'compicon' => block_exaport_get_item_comp_icon($item),
'typemineorshared' => in_array($type, ['mine', 'shared']),
'isownitem' => $isownitem,
'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . (($type == 'shared') ? '&cattype=shared' : ''),
- 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . (($type == 'shared') ? '&cattype=shared' : ''),
- 'trashicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'ownername' => $ownername,
- 'usericon' => block_exaport_fontawesome_icon('circle-user', 'solid', 1),
'thumburl' => $CFG->wwwroot . '/blocks/exaport/item_thumb.php?item_id=' . $item->id,
'categorybadges' => block_exaport_render_item_category_badges($item),
'dateformatted' => date('d.m.Y H:i', $item->timemodified),
From 32cb4f043fcd6dd6f017c15ce95832db553fc2e6 Mon Sep 17 00:00:00 2001
From: rwolf
Date: Tue, 2 Jun 2026 12:25:53 +0200
Subject: [PATCH 06/27] Revert "Fix FA free icons and inline fixed icons in
mustache templates"
This reverts commit f31b42112d9991046ca137053b31c80d439d8fd2.
---
templates/view_items_artefact_card_flat.mustache | 12 ++++++++----
templates/view_items_artefact_card_folder.mustache | 12 ++++++++----
templates/view_items_category_card.mustache | 12 ++++++++----
view_items.php | 12 ++++++++++++
4 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/templates/view_items_artefact_card_flat.mustache b/templates/view_items_artefact_card_flat.mustache
index 3a80d353..a576d71c 100644
--- a/templates/view_items_artefact_card_flat.mustache
+++ b/templates/view_items_artefact_card_flat.mustache
@@ -17,13 +17,17 @@
copytoselftooltip - Localised tooltip for the copy-to-self button
hascomments - Boolean: item has at least one comment
commentcount - Integer comment count
+ commenticon - Pre-rendered HTML for the comment icon
projecticon - Pre-rendered HTML for the project info icon (may be empty)
compicon - Pre-rendered HTML for the competence icon (may be empty)
typemineorshared - Boolean: type is "mine" or "shared" (show edit/delete/user icons)
isownitem - Boolean: current user owns this item
editurl - URL for the edit action
+ editicon - Pre-rendered HTML for the edit icon
deleteurl - URL for the delete action
+ trashicon - Pre-rendered HTML for the delete icon
ownername - Full name of the item owner (shown in tooltip when not own item)
+ usericon - Pre-rendered HTML for the user icon
thumburl - URL to the item thumbnail image
categorybadges - Pre-rendered HTML for category badge pills (may be empty)
dateformatted - Human-readable date string for the card footer
@@ -47,17 +51,17 @@
{{/copytoself}}
{{^copytoself}}
{{#hascomments}}
-
+
{{/hascomments}}
{{{projecticon}}}
{{{compicon}}}
{{#typemineorshared}}
{{#isownitem}}
-
-
+ {{{editicon}}}
+ {{{trashicon}}}
{{/isownitem}}
{{^isownitem}}
-
+ {{{usericon}}}
{{/isownitem}}
{{/typemineorshared}}
{{/copytoself}}
diff --git a/templates/view_items_artefact_card_folder.mustache b/templates/view_items_artefact_card_folder.mustache
index 35ef3c89..335d9fec 100644
--- a/templates/view_items_artefact_card_folder.mustache
+++ b/templates/view_items_artefact_card_folder.mustache
@@ -11,12 +11,16 @@
itemid - Integer item id
typeicon - Pre-rendered HTML for the type icon (with tooltip)
itemname - Display name of the item (auto-escaped by mustache)
+ ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
viewlabel - Localised "View" label
+ viewicon - Pre-rendered HTML for the view icon
canedit - Boolean: show "Edit" menu entry
editurl - URL for the edit action
+ editicon - Pre-rendered HTML for the edit icon
editlabel - Localised "Edit" label
candelete - Boolean: show "Delete" menu entry
deleteurl - URL for the delete action
+ deleteicon - Pre-rendered HTML for the delete icon
deletelabel - Localised "Delete" label
introtext - Short plain-text intro excerpt (empty string when absent)
dateformatted - Human-readable date string for the card footer
@@ -36,20 +40,20 @@
-
+ {{{ellipsisicon}}}
diff --git a/templates/view_items_category_card.mustache b/templates/view_items_category_card.mustache
index 71c49c3e..0cea8494 100644
--- a/templates/view_items_category_card.mustache
+++ b/templates/view_items_category_card.mustache
@@ -13,6 +13,10 @@
typemine - Boolean: current user owns this category (show edit/delete)
editurl - URL for the edit action
deleteurl - URL for the delete action
+ ellipsisicon - Pre-rendered HTML for the "⋮" dropdown toggle icon
+ viewicon - Pre-rendered HTML for the "view" menu item icon
+ editicon - Pre-rendered HTML for the "edit" menu item icon
+ deleteicon - Pre-rendered HTML for the "delete" menu item icon
viewlabel - Localised "View" label
editlabel - Localised "Edit" label
deletelabel - Localised "Delete" label
@@ -25,18 +29,18 @@
-
+ {{{ellipsisicon}}}
diff --git a/view_items.php b/view_items.php
index c11e7fc2..a2f653a0 100644
--- a/view_items.php
+++ b/view_items.php
@@ -1560,6 +1560,10 @@ function block_exaport_category_template_bootstrap_card($category, $courseid, $t
'typemine' => ($type == 'mine'),
'editurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=edit',
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=delete',
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
+ 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
+ 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'viewlabel' => block_exaport_get_string('view'),
'editlabel' => block_exaport_get_string('edit'),
'deletelabel' => block_exaport_get_string('delete'),
@@ -1610,12 +1614,16 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
. ' data-bs-toggle="tooltip" data-bs-placement="top"'
. ' data-bs-title="' . s($typelabel) . '">',
'itemname' => $item->name,
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
'viewlabel' => block_exaport_get_string('view'),
+ 'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
'canedit' => $isownitem,
'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . $cattype,
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
'editlabel' => block_exaport_get_string('edit'),
'candelete' => $isownitem && block_exaport_item_is_editable($item->id),
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . $cattype,
+ 'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'deletelabel' => block_exaport_get_string('delete'),
'introtext' => $introtext,
'dateformatted' => date('d.m.Y H:i', $item->timemodified),
@@ -1651,13 +1659,17 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
'copytoselftooltip' => get_string('make_it_yours', 'block_exaport'),
'hascomments' => ($item->comments > 0),
'commentcount' => (int)$item->comments,
+ 'commenticon' => block_exaport_fontawesome_icon('comment', 'regular', 1, [], [], [], '', [], [], [], []),
'projecticon' => block_exaport_get_item_project_icon($item),
'compicon' => block_exaport_get_item_comp_icon($item),
'typemineorshared' => in_array($type, ['mine', 'shared']),
'isownitem' => $isownitem,
'editurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=edit' . (($type == 'shared') ? '&cattype=shared' : ''),
+ 'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/item.php?courseid=' . $courseid . '&id=' . $item->id . '&action=delete&categoryid=' . $categoryid . (($type == 'shared') ? '&cattype=shared' : ''),
+ 'trashicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
'ownername' => $ownername,
+ 'usericon' => block_exaport_fontawesome_icon('circle-user', 'solid', 1),
'thumburl' => $CFG->wwwroot . '/blocks/exaport/item_thumb.php?item_id=' . $item->id,
'categorybadges' => block_exaport_render_item_category_badges($item),
'dateformatted' => date('d.m.Y H:i', $item->timemodified),
From 6a8f2273ca4d82d4a6eab7fe1b8f9909163f7f90 Mon Sep 17 00:00:00 2001
From: rwolf
Date: Tue, 2 Jun 2026 12:27:08 +0200
Subject: [PATCH 07/27] fix pro to free fontawesome
---
view_items.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/view_items.php b/view_items.php
index a2f653a0..21a3e739 100644
--- a/view_items.php
+++ b/view_items.php
@@ -1560,7 +1560,7 @@ function block_exaport_category_template_bootstrap_card($category, $courseid, $t
'typemine' => ($type == 'mine'),
'editurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=edit',
'deleteurl' => $CFG->wwwroot . '/blocks/exaport/category.php?courseid=' . $courseid . '&id=' . $category->id . '&action=delete',
- 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'solid', 1),
'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
'editicon' => block_exaport_fontawesome_icon('pen-to-square', 'regular', 1),
'deleteicon' => block_exaport_fontawesome_icon('trash-can', 'regular', 1, [], [], [], '', [], [], [], ['exaport-remove-icon']),
@@ -1614,7 +1614,7 @@ function block_exaport_artefact_template_bootstrap_card($item, $courseid, $type,
. ' data-bs-toggle="tooltip" data-bs-placement="top"'
. ' data-bs-title="' . s($typelabel) . '">',
'itemname' => $item->name,
- 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'regular', 1),
+ 'ellipsisicon' => block_exaport_fontawesome_icon('ellipsis-vertical', 'solid', 1),
'viewlabel' => block_exaport_get_string('view'),
'viewicon' => block_exaport_fontawesome_icon('eye', 'regular', 1),
'canedit' => $isownitem,
From 942c5b5224a583429f636754479f4cdd0d44ffb8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 10:31:50 +0000
Subject: [PATCH 08/27] Fix: make category card-footer consistent height with
item card-footer
---
templates/view_items_category_card.mustache | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/view_items_category_card.mustache b/templates/view_items_category_card.mustache
index 0cea8494..59755857 100644
--- a/templates/view_items_category_card.mustache
+++ b/templates/view_items_category_card.mustache
@@ -56,6 +56,6 @@
-
+
From c129a4f917993205cb81eaab1b0c03d8488bc3e1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 10:43:50 +0000
Subject: [PATCH 09/27] Refactor: extract output classes and move utility
functions to lib.php
---
classes/output/artefact_card_flat.php | 144 +++++++++++++
classes/output/artefact_card_folder.php | 144 +++++++++++++
classes/output/category_card.php | 113 ++++++++++
lib/lib.php | 121 +++++++++++
renderer.php | 40 ++++
view_items.php | 275 ++----------------------
6 files changed, 576 insertions(+), 261 deletions(-)
create mode 100644 classes/output/artefact_card_flat.php
create mode 100644 classes/output/artefact_card_folder.php
create mode 100644 classes/output/category_card.php
diff --git a/classes/output/artefact_card_flat.php b/classes/output/artefact_card_flat.php
new file mode 100644
index 00000000..572bab64
--- /dev/null
+++ b/classes/output/artefact_card_flat.php
@@ -0,0 +1,144 @@
+.
+// (c) 2016 GTN - Global Training Network GmbH