Skip to content

Commit 31a96a2

Browse files
committed
Merge branch 'develop/bespoke' into feature/TD-5575-Display-SCORM-content-inline-with-full-screen-option
2 parents bf83abd + ddfdb6e commit 31a96a2

File tree

13 files changed

+431
-72
lines changed

13 files changed

+431
-72
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
node_modules/
22
vendor/
3-
/.vs
3+
/.vs
4+
5+
# Compiled CSS files
6+
css/*.min.css
7+
css/*.min.css.map

classes/output/core_renderer.php

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,199 @@
3636
*/
3737
class core_renderer extends \theme_boost\output\core_renderer
3838
{
39+
40+
/**
41+
* Returns the data context for the global theme header, fetching from API.
42+
* This method is called by {{# output.get_global_header_data }} in Mustache.
43+
*
44+
* @return \stdClass An object containing data for the header.
45+
*/
46+
public function get_global_header_data() {
47+
global $PAGE; // Keep $PAGE just in case for future use/context, though not strictly needed for this API call
48+
global $DB, $USER; // Declare $DB and $USER as global
49+
global $SESSION;
50+
51+
$context = new \stdClass();
52+
$context->customnavigation = []; // Default to empty array in case of API issues
53+
54+
// Fetch token for current user
55+
$token = null; // Initialize to null
56+
$tokenNew = null; // Initialize to null
57+
$accesstoken = null; // Initialize to null
58+
$response_content = false; // Initialize to false
59+
60+
// --- NEW: Get the configured .NET application base URL ---
61+
$dotnet_base_url = get_config('theme_nhse', 'dotnet_base_url');
62+
63+
if (!empty($dotnet_base_url) && substr($dotnet_base_url, -1) !== '/') {
64+
$dotnet_base_url .= '/';
65+
}
66+
67+
// --- NEW: Add dotnet_base_url to the context for Mustache template ---
68+
$context->dotnet_base_url = $dotnet_base_url;
69+
70+
// --- NEW: Get the configured API Base URL ---
71+
$api_base_url = get_config('theme_nhse', 'api_base_url');
72+
// Ensure the API base URL ends with a slash if it's not empty
73+
if (!empty($api_base_url) && substr($api_base_url, -1) !== '/') {
74+
$api_base_url .= '/';
75+
}
76+
77+
if (empty($api_base_url)) {
78+
// Log an error and return early if the API URL is not configured
79+
error_log("theme_nhse: ERROR: LH OpenAPI Base URL is not configured in theme settings. Cannot fetch navigation data.");
80+
return $context; // Return empty context if API URL is missing
81+
}
82+
83+
// --- NEW: Add login status to the context ---
84+
// isloggedin() is a Moodle core function that returns true if a user is logged in.
85+
$context->is_user_logged_in = isloggedin();
86+
87+
// --- NEW: Add 'Site Administration' link if user is an admin ---
88+
// Check if the user has the capability to configure the site (i.e., is an admin)
89+
if (has_capability('moodle/site:config', \context_system::instance())) {
90+
$admin_link = new \stdClass();
91+
$admin_link->title = "Site administration";
92+
$admin_link->url = new \moodle_url('/admin/search.php'); // Use the observed URL
93+
$admin_link->hasnotification = false;
94+
$admin_link->notificationcount = 0;
95+
$admin_link->openInNewTab = false; // Or true, if you prefer it opens in a new tab
96+
97+
// Add this admin link to your customnavigation array
98+
// This ensures it gets rendered by your {{#customnavigation}} block in Mustache
99+
$context->customnavigation[] = $admin_link;
100+
error_log("theme_nhse: Added Site Administration link to custom navigation.");
101+
}
102+
103+
104+
if (isloggedin()) { // Only try to fetch token if a user is logged in
105+
$token = $DB->get_record('auth_oidc_token', ['username' => $USER->username]);
106+
if ($token) {
107+
error_log("theme_nhse: Found OIDC token for user {$USER->username}.");
108+
// You would then use $token->accesstoken to construct your bearer token
109+
$accesstoken = $token->token;
110+
error_log("theme_nhse: accesstoken {$accesstoken}");
111+
112+
} else {
113+
error_log("theme_nhse: No OIDC token found for user {$USER->username}.");
114+
}
115+
} else {
116+
error_log("theme_nhse: User not logged in, skipping OIDC token fetch.");
117+
}
118+
119+
// --- The rest of your existing API call logic ---
120+
$api_endpoint_path = 'User/GetLHUserNavigation';
121+
$url = $api_base_url . $api_endpoint_path;
122+
123+
124+
125+
try
126+
{
127+
$curl = new \curl();
128+
// Set Authorization header
129+
$options = [
130+
'HTTPHEADER' => [
131+
'Authorization: Bearer ' . $accesstoken,
132+
'Accept: application/json'
133+
]
134+
];
135+
$response = $curl->get($url, null, $options);
136+
$result = json_decode($response, true);
137+
// Log the raw response and the decoded result
138+
error_log("theme_nhse: API Response (raw): " . $response);
139+
error_log("theme_nhse: API Response (decoded): " . print_r($result, true));
140+
// Check for JSON decoding errors
141+
if (json_last_error() !== JSON_ERROR_NONE) {
142+
error_log("theme_nhse: JSON decoding error: " . json_last_error_msg());
143+
}
144+
} catch (Exception $e)
145+
{
146+
debugging('CURL error: ' . $e->getMessage(), DEBUG_DEVELOPER);
147+
error_log("theme_nhse: CURL Exception caught for URL: " . $url . " Message: " . $e->getMessage());
148+
}
149+
150+
// --- Conditional Block for Processing Response (after try-catch) ---
151+
// We use $result here, which will be null if there was an API error or JSON decoding issue.
152+
if (is_array($result) && !empty($result)) {
153+
// JSON decoded successfully and is an array with content
154+
error_log("theme_nhse: JSON decoded successfully. Processing " . count($result) . " items.");
155+
$processed_links = [];
156+
foreach ($result as $item) {
157+
// Check 'visible' property from API (only include if true or not set)
158+
// Assuming 'visible' being absent or true means it should be shown
159+
160+
// --- NEW: Skip item if title is "Sign Out" ---
161+
// We use trim() to handle any potential leading/trailing whitespace.
162+
if (isset($item['title']) && trim($item['title']) === 'Sign Out') {
163+
error_log("theme_nhse: Skipping 'Sign Out' link from API response.");
164+
continue; // Skip to the next item in the loop
165+
}
166+
167+
168+
if (!isset($item['visible']) || $item['visible'] === true) {
169+
$processed_item = new \stdClass();
170+
$processed_item->title = $item['title'] ?? 'Untitled'; // Default title if missing
171+
// Handle URLs - convert to moodle_url if internal, keep as string if external
172+
if (isset($item['url']) && !empty($item['url'])) {
173+
$item_url_path = $item['url']; // Store the raw URL from the API
174+
175+
// Check if it's an absolute URL (starts with http/s or //)
176+
if (strpos($item_url_path, 'http') === 0 || strpos($item_url_path, '//') === 0) {
177+
$processed_item->url = $item_url_path; // Use the absolute URL as is
178+
error_log("theme_nhse: Processing absolute URL: {$processed_item->url}");
179+
}
180+
// If it's a relative URL AND we have a configured .NET base URL, prepend it
181+
else if (!empty($dotnet_base_url)) {
182+
// Prepend .NET base URL, ensuring no double slashes by trimming leading slash from item_url_path
183+
$processed_item->url = $dotnet_base_url . ltrim($item_url_path, '/');
184+
error_log("theme_nhse: Redirecting relative link '{$item_url_path}' to .NET domain: {$processed_item->url}");
185+
}
186+
// Fallback: If it's a relative URL but no .NET base URL is configured,
187+
// treat it as a Moodle internal URL.
188+
else {
189+
$processed_item->url = new \moodle_url($item_url_path);
190+
error_log("theme_nhse: .NET base URL not configured, processing relative link '{$item_url_path}' as Moodle internal.");
191+
}
192+
} else {
193+
// Default to Moodle home if URL is missing or empty
194+
$processed_item->url = new \moodle_url('/');
195+
error_log("theme_nhse: Item has empty or missing URL, defaulting to Moodle home.");
196+
}
197+
$processed_item->hasnotification = $item['hasNotification'] ?? false;
198+
$processed_item->notificationcount = $item['notificationCount'] ?? 0;
199+
$processed_item->openInNewTab = $item['openInNewTab'] ?? false;
200+
201+
$processed_links[] = $processed_item;
202+
} else {
203+
// Log items that are not visible
204+
error_log("theme_nhse: Item not visible and filtered out: " . ($item['title'] ?? 'N/A') . " (visible: " . ($item['visible'] ? 'true' : 'false') . ")");
205+
}
206+
}
207+
208+
// Add API processed links AFTER the static admin link, so it appears first if you want.
209+
// If you want admin link to appear last, change this to array_unshift or prepend it.
210+
$context->customnavigation = array_merge($context->customnavigation, $processed_links);
211+
//$context->customnavigation = array_unshift($context->customnavigation, $processed_links);
212+
213+
error_log("theme_nhse: Processed links for display: " . print_r($context->customnavigation, true));
214+
215+
216+
// Log the final processed links (for debugging)
217+
error_log("theme_nhse: Processed links for display: " . print_r($processed_links, true));
218+
} else {
219+
// This block handles cases where:
220+
// 1. $result is null (due to JSON decoding error or CURL exception)
221+
// 2. $result is not an array (e.g., API returned a non-array JSON like a string or object)
222+
// 3. $result is an empty array
223+
$json_error_msg = (json_last_error() !== JSON_ERROR_NONE) ? json_last_error_msg() : 'N/A';
224+
error_log("theme_nhse: Failed to process API response. Response was empty, not an array, or an error occurred. JSON Error: " . $json_error_msg);
225+
error_log("theme_nhse: Raw API response (if available): " . ($response ?: 'No response content'));
226+
}
227+
228+
return $context;
229+
}
230+
231+
39232
/**
40233
* Wrapper for header elements.
41234
*

css/nhse.min.css

Lines changed: 0 additions & 26 deletions
This file was deleted.

css/nhse.min.css.map

Lines changed: 0 additions & 1 deletion
This file was deleted.

lang/en/theme_nhse.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
defined('MOODLE_INTERNAL') || die();
2626

2727
$string['advancedsettings'] = 'Advanced settings';
28+
$string['api_base_url_setting'] = 'LH OpenAPI Base URL';
29+
$string['api_base_url_setting_desc'] = 'The base URL for the Learning Hub OpenAPI (e.g., https://lh-openapi.dev.local). This will be used to fetch user navigation data.';
2830
$string['backgroundimage'] = 'Background image';
2931
$string['backgroundimage_desc'] = 'The image to display as a background of the site. The background image you upload here will override the background image in your theme preset files.';
3032
$string['bcsettings'] = 'Breadcrumb settings';
@@ -44,6 +46,8 @@
4446
$string['cookiesnotice'] = 'Read our cookies notice';
4547
$string['cookiesenabled'] = 'Cookies must be enabled in your browser';
4648
$string['currentinparentheses'] = '(current)';
49+
$string['dotnet_base_url_setting'] = '.NET Application Base URL';
50+
$string['dotnet_base_url_setting_desc'] = 'The base URL for your .NET application (e.g., https://lh-web.dev.local). Relative links received from the API will be prepended with this URL if they are not absolute.';
4751
$string['fontsize'] = 'Theme base fontsize';
4852
$string['fontsize_desc'] = 'Enter a fontsize in %';
4953
$string['footersettings'] = 'Footer settings';

scss/nhse.scss

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ body {
186186
#page {
187187
&.drawers {
188188
.main-inner {
189-
max-width: 990px;
189+
/* max-width: 990px; */
190190
}
191191
}
192192
}
@@ -213,13 +213,6 @@ body {
213213
}
214214
}
215215

216-
/**
217-
* Increase max container width
218-
*/
219-
.nhsuk-width-container {
220-
max-width: 990px;
221-
}
222-
223216
/**
224217
* Cards and box styles
225218
*/
@@ -338,27 +331,69 @@ body {
338331
}
339332

340333
.nhsuk-header__container {
341-
padding: 16px 0;
342-
max-width: 990px;
334+
padding: 16px 0;
343335
}
344336

345337
.nhsuk-header__search-form {
346338
margin: 0;
347339
}
348340

349-
@media (max-width: 40.0525em) {
350-
.nhsuk-header__container {
351-
display: flex !important;
352-
.nhsuk-header__logo {
353-
padding-right: 12px;
341+
.nhsuk-header__rhscontent {
342+
343+
// Styles specifically for the nhsuk-header__rhscontent element
344+
display: flex;
345+
align-items: center;
346+
justify-content: flex-end; // Example: Align content to the right
347+
// Add other styles as needed (padding, etc.)
348+
349+
.border-left, .border-start {
350+
border-left: none !important;
351+
}
352+
353+
.custom-control-input:checked~.custom-control-label::before {
354+
color: $btn-primary-text;
355+
background-color: $btn-default-background;
356+
border-color: $btn-default-background;
357+
}
358+
359+
.custom-control-input:checked~.custom-control-label::after {
360+
background-color: $btn-primary-background;
361+
}
362+
363+
.text-primary {
364+
color: $btn-secondary-text!important;
365+
}
366+
.nhsuk-header__content {
367+
padding-right: 1.5rem;
368+
}
369+
370+
.nhsuk-account__login {
371+
font-size: 0.875rem;
372+
float: right;
373+
position: relative;
374+
z-index: 2;
375+
display: flex;
376+
justify-content: space-between;
377+
align-items: center;
378+
gap: 1.5rem;
379+
}
380+
381+
.nhsuk-account__login--link {
382+
color: #fff;
354383
}
355-
}
356-
}
357384

358-
.header-maxwidth {
359-
max-width: 990px;
360385
}
361386

387+
// @media (max-width: 40.0525em) {
388+
// .nhsuk-header__container {
389+
// display: flex !important;
390+
// .nhsuk-header__logo {
391+
// padding-right: 12px;
392+
// }
393+
// }
394+
// }
395+
396+
362397
@media (min-width: 768px) {
363398
.header-maxwidth {
364399
padding-left: 0;
@@ -395,9 +430,9 @@ body {
395430
#page {
396431
margin: 0 auto;
397432
width: 100%;
398-
max-width: 1440px;
433+
max-width: 1200px;
399434
&.nhsuk-width-container {
400-
max-width: 990px;
435+
max-width: 1200px;
401436
}
402437
.main-inner {
403438
padding: 1.5rem 1.5rem;
@@ -570,6 +605,7 @@ body {
570605
color: $color_nhsuk-black;
571606
border-bottom: 4px solid $color_nhsuk-black;
572607
}
608+
573609
}
574610
}
575611

@@ -645,9 +681,25 @@ body {
645681
color: $color_nhsuk-white;
646682
border-bottom: 4px solid $color_nhsuk-white;
647683
}
684+
648685
}
649686
}
650687

688+
.nhsuk-tag {
689+
top: 0.5rem;
690+
right: -0.625rem;
691+
font-size: 0.6875rem;
692+
line-height: 1.125rem;
693+
font-weight: 900;
694+
background: #d5281b;
695+
color: #fff;
696+
min-width: 1.125rem;
697+
text-align: center;
698+
border-radius: 0.5625rem;
699+
padding: 0.0625rem 0.1875rem 0;
700+
}
701+
702+
651703
.nhsuk-breadcrumb__list {
652704
.nhsuk-breadcrumb__item {
653705
.nhsuk-breadcrumb__link {
@@ -911,7 +963,7 @@ body {
911963

912964
@media (min-width: 48.0625em) {
913965
.nhsuk-search__input {
914-
width: 180px;
966+
width: 16.25rem;
915967
}
916968

917969
.nhsuk-search__submit {

0 commit comments

Comments
 (0)