pull/11/head
Squidly271 2022-12-03 17:21:30 -05:00
parent 6d061a1c11
commit f2f1abfb22
4 changed files with 112 additions and 83 deletions

View File

@ -2,8 +2,8 @@
4e55f7483b661af21a25b677179baffe ./CA_notices.page
4c5d4598e1bafa46bd90c27cbe302122 ./ca_settings.page
e8d29607ec792ddf9f6832b10ee70fdc ./default.cfg
9a5b45bd22ee24f7a7eed98e377a8501 ./include/exec.php
ec64fc40aa10ccf2b98907e3081053f5 ./include/helpers.php
2ea430441b1f4e63a6e7eab4dd39ba9b ./include/exec.php
9441e82a241d88d6cdbee4e910a5cdda ./include/helpers.php
116042a918060278e77379b0dd73482c ./include/paths.php
532fffdf939594c143e679da02bd841e ./javascript/libraries.js
71f911a818d88d3d567f8a2898094ee2 ./README.md
@ -22,4 +22,4 @@ da3b4f9b73c5c3bf65be6c42d68b51f9 ./scripts/showStatistics.php
34554a56611dfe625889c82afd5138de ./scripts/updatePluginSupport.php
25bdaed6f62ac73f9ef7c3ce0c125ef7 ./skins/Narrow/css.php
7eb021a105e2f7a15675ec8a14e6f05e ./skins/Narrow/skin.html
c0061be734e2f9896c4f981958da0354 ./skins/Narrow/skin.php
614f249640c329d4167a72a3f6fda0c5 ./skins/Narrow/skin.php

View File

@ -662,7 +662,7 @@ function displayRepositories() {
$fav['RepoName'] = $repoName;
$fav['SortName'] = $repoName;
} else {
if ( $repositories[$repoName]['bio'] ) {
if ( isset($repositories[$repoName]['bio']) ) {
$bio[$repoName] = $repositories[$repoName];
$bio[$repoName] = $repositories[$repoName];
$bio[$repoName]['RepositoryTemplate'] = true;
@ -679,9 +679,9 @@ function displayRepositories() {
usort($bio,"mySort");
usort($allRepos,"mySort");
$allRepos = array_merge($bio,$allRepos);
if ( $fav )
if ( isset($fav) )
array_unshift($allRepos,$fav);
$file['community'] = $allRepos;
$file['community'] = addMissingVars($allRepos);
writeJsonFile($caPaths['repositoriesDisplayed'],$file);
}
@ -924,7 +924,7 @@ function get_content() {
$display[] = $template;
}
if ( $filter ) {
if ( is_array($searchResults['nameHit']) ) {
if ( isset($searchResults['nameHit']) ) {
usort($searchResults['nameHit'],"mySort");
if ( ! strpos($filter," Repository") ) {
if ( $caSettings['favourite'] && $caSettings['favourite'] !== "none" ) {
@ -1394,7 +1394,10 @@ function pinApp() {
$repository = getPost("repository","oops");
$name = getPost("name","oops");
$pinnedApps = readJsonFile($caPaths['pinnedV2']);
$pinnedApps["$repository&$name"] = $pinnedApps["$repository&$name"] ? false : "$repository&$name";
if (isset($pinnedApps["$repository&$name"]) )
$pinnedApps["$repository&$name"] = false;
else
$pinnedApps["$repository&$name"] = "$repository&$name";
$pinnedApps = array_filter($pinnedApps);
writeJsonFile($caPaths['pinnedV2'],$pinnedApps);
postReturn(['status' => in_array(true,$pinnedApps)]);
@ -1457,7 +1460,7 @@ function pinnedApps() {
$displayedApplications['community'] = $displayed;
$displayedApplications['pinnedFlag'] = true;
writeJsonFile($caPaths['community-templates-displayed'],$displayedApplications);
postReturn(["status"=>"ok","script"=>$script]);
postReturn(["status"=>"ok","script"=>$script ?? ""]);
}
################################################
@ -1915,14 +1918,18 @@ function createXML() {
if ( is_array($config['@attributes']) ) {
if ( $config['@attributes']['Type'] == "Path" ) {
$defaultReferenced = array_values(array_filter(explode("/",$config['@attributes']['Default'])));
if ( $defaultReferenced[0] == "mnt" && $defaultReferenced[1] && ! in_array($defaultReferenced[1],$disksPresent) )
$config['@attributes']['Default'] = str_replace("/mnt/{$defaultReferenced[1]}/","/mnt/{$disksPresent[0]}/",$config['@attributes']['Default']);
if ( isset($defaultReferenced[0]) && isset($defaultReferenced[1]) ) {
if ( $defaultReferenced[0] == "mnt" && $defaultReferenced[1] && ! in_array($defaultReferenced[1],$disksPresent) )
$config['@attributes']['Default'] = str_replace("/mnt/{$defaultReferenced[1]}/","/mnt/{$disksPresent[0]}/",$config['@attributes']['Default']);
}
$valueReferenced = array_values(array_filter(explode("/",$config['value'])));
if ( $valueReferenced[0] == "mnt" && $valueReferenced[1] && ! in_array($valueReferenced[1],$disksPresent) )
$config['value'] = str_replace("/mnt/{$valueReferenced[1]}/","/mnt/{$disksPresent[0]}/",$config['value']);
if ( isset($valueReferenced[0]) && isset($valueReferenced[1]) ) {
if ( $valueReferenced[0] == "mnt" && $valueReferenced[1] && ! in_array($valueReferenced[1],$disksPresent) )
$config['value'] = str_replace("/mnt/{$valueReferenced[1]}/","/mnt/{$disksPresent[0]}/",$config['value']);
}
// Check for pre-existing folders only differing by "case" and adjust accordingly
// Default path
@ -1993,7 +2000,7 @@ function createXML() {
@mkdir(dirname($xmlFile));
file_put_contents($xmlFile,$xml);
}
postReturn(["status"=>"ok","cache"=>$cacheVolume]);
postReturn(["status"=>"ok","cache"=>$cacheVolume ?? ""]);
}
########################
@ -2248,7 +2255,7 @@ function search_dockerhub() {
$searchName = str_replace("docker-","",$o['Name']);
$searchName = str_replace("-docker","",$searchName);
$dockerResults[$i] = $o;
$dockerResults[$i] = addMissingVars($o);
$i=++$i;
}
$dockerFile['num_pages'] = $num_pages;
@ -2265,6 +2272,7 @@ function getLastUpdate($ID) {
global $caPaths;
$count = 0;
$registry_json = null;
while ( $count < 5 ) {
$templates = &$GLOBALS['templates'];
if ( $templates ) break;
@ -2306,7 +2314,7 @@ function getLastUpdate($ID) {
return;
}
$registry_json['last_updated'] = $registry_json['last_updated'] ?? false;
$lastUpdated = $registry_json['last_updated'] ? tr(date("M j, Y",strtotime($registry_json['last_updated'])),0) : "Unknown";
return $lastUpdated;

View File

@ -251,7 +251,7 @@ function fixTemplates($template) {
###############################################
function makeXML($template) {
# ensure its a v2 template if the Config entries exist
if ( $template['Config'] && ! $template['@attributes'] )
if ( isset($template['Config']) && ! isset($template['@attributes']) )
$template['@attributes'] = ["version"=>2];
if ($template['Overview']) $template['Description'] = $template['Overview'];
@ -260,8 +260,10 @@ function makeXML($template) {
fixAttributes($template,"Config");
# Sanitize the Requires entry if there is any CA links within it
preg_match_all("/\/\/(.*?)&#92;/m",$template['Requires'],$searchMatches);
if ( count($searchMatches[1]) ) {
if ($template['Requires'] && $searchMatches)
preg_match_all("/\/\/(.*?)&#92;/m",$template['Requires'],$searchMatches);
if ( isset($searchMatches[1]) && count($searchMatches[1]) ) {
foreach ($searchMatches[1] as $searchResult) {
$template['Requires'] = str_replace("//$searchResult\\\\",$searchResult,$template['Requires']);
}
@ -275,7 +277,7 @@ function makeXML($template) {
#################################################################################
function fixAttributes(&$template,$attribute) {
if ( ! is_array($template[$attribute]) ) return;
if ( $template[$attribute]['@attributes'] ) {
if ( isset($template[$attribute]['@attributes']) ) {
$template[$attribute][0]['@attributes'] = $template[$attribute]['@attributes'];
if ( $template[$attribute]['value'])
$template[$attribute][0]['value'] = $template[$attribute]['value'];
@ -318,7 +320,7 @@ function versionCheck($template) {
function readXmlFile($xmlfile,$generic=false,$stats=true) {
global $statistics;
if ( ! is_file($xmlfile) ) return false;
if ( $xmlfile && ! is_file($xmlfile) ) return false;
$xml = file_get_contents($xmlfile);
$o = TypeConverter::xmlToArray($xml,TypeConverter::XML_GROUP);
$o = addMissingVars($o);
@ -670,14 +672,15 @@ function debug($str) {
# Gets the default ports in a template #
########################################
function portsUsed($template) {
if ( $template['Network'] !== "bridge")
if ( ($template['Network'] ?? "whatever") !== "bridge")
return;
$portsUsed = [];
if ( $template['Config']['@attributes'] )
if ( isset($template['Config']['@attributes']) )
$template['Config'] = ['@attributes'=>$template['Config']];
if ( is_array($template['Config']) ) {
foreach ($template['Config'] as $config) {
if ( $config['@attributes']['Type'] !== "Port" ) continue;
if ( $config['@attributes']['Type'] !== "Port" )
continue;
$portsUsed[] = $config['value'] ?: $config['@attributes']['Default'];
}
}
@ -688,7 +691,6 @@ function portsUsed($template) {
# Get the ports in use #
########################
function getPortsInUse() {
return [];
global $var, $caPaths;
$addr = null;
@ -812,7 +814,11 @@ function addMissingVars($o) {
'stars',
'LanguageURL',
'LastUpdate',
'RecommendedWho'
'RecommendedWho',
'RepoName',
'SortName',
'ca_fav',
'Pinned'
];
@ -1435,7 +1441,7 @@ class Array2XML {
// after we are done with all the keys in the array (if it is one)
// we check if it has any text value, if yes, append it.
if(!is_array($arr)) {
$node->appendChild($xml->createTextNode(self::bool2str($arr)));
$node->appendChild($xml->createTextNode(self::bool2str($arr ?? "")));
}
return $node;
}

View File

@ -86,19 +86,20 @@ function my_display_apps($file,$pageNumber=1,$selectedApps=false,$startup=false)
# Create entries for skins.
foreach ($displayedTemplates as $template) {
if ( ! $template['Blacklist'] ) {
if ( isset($extraBlacklist[$template['Repository']]) ) {
$template['Blacklist'] = true;
$template['ModeratorComment'] = $extraBlacklist[$template['Repository']];
if ( ! $template['RepositoryTemplate'] ) {
if ( ! $template['Blacklist'] ) {
if ( isset($extraBlacklist[$template['Repository']]) ) {
$template['Blacklist'] = true;
$template['ModeratorComment'] = $extraBlacklist[$template['Repository']];
}
}
if ( ! $template['Deprecated'] && isset($extraDeprecated[$template['Repository']]) ) {
$template['Deprecated'] = true;
$template['ModeratorComment'] = $extraDeprecated[$template['Repository']];
}
}
if ( ! $template['Deprecated'] && isset($extraDeprecated[$template['Repository']]) ) {
$template['Deprecated'] = true;
$template['ModeratorComment'] = $extraDeprecated[$template['Repository']];
}
if ( $template['RepositoryTemplate'] ) {
$template['Icon'] = $template['icon'] ?: "/plugins/dynamix.docker.manager/images/question.png";
$template['Icon'] = $template['icon'] ?? "/plugins/dynamix.docker.manager/images/question.png";
if ( ! $template['bio'] )
$template['CardDescription'] = tr("No description present");
@ -187,7 +188,7 @@ function my_display_apps($file,$pageNumber=1,$selectedApps=false,$startup=false)
}
$actionsContext[] = ["icon"=>"ca_fa-delete","text"=>tr("Remove from Previous Apps"),"alternate"=>tr("Remove"),"action"=>"removeApp('{$template['InstallPath']}','{$template['Name']}');"];
} else {
if ( ! $template['BranchID'] ) {
if ( ! ($template['BranchID'] ?? null) ) {
if ( is_file("{$caPaths['dockerManTemplates']}/my-{$template['Name']}.xml") ) {
$test = readXmlFile("{$caPaths['dockerManTemplates']}/my-{$template['Name']}.xml",true);
if ( $template['Repository'] == $test['Repository'] ) {
@ -453,6 +454,7 @@ function getPopupDescriptionSkin($appNumber) {
$extraBlacklist = readJsonFile($caPaths['extraBlacklist']);
$extraDeprecated = readJsonFile($caPaths['extraDeprecated']);
$templateDescription = "";
$selected = null;
$pinnedApps = readJsonFile($caPaths['pinnedV2']);
@ -664,7 +666,7 @@ function getPopupDescriptionSkin($appNumber) {
if ( ! $template['Blacklist'] ) {
if ( ( $template['Compatible'] || $caSettings['hideIncompatible'] !== "true" ) ) {
if ( !$template['Deprecated'] || $caSettings['hideDeprecated'] !== "true" ) {
if ( ! $template['BranchID'] ) {
if ( ! isset($template['BranchID']) ) {
$actionsContext[] = ["icon"=>"ca_fa-install","text"=>tr("Install"),"action"=>"popupInstallXML('".addslashes($template['Path'])."','default','','".portsUsed($template)."');"];
} else {
$actionsContext[] = ["icon"=>"ca_fa-install","text"=>tr("Install"),"action"=>"displayTags('{$template['ID']}',false,'','".portsUsed($template)."');"];
@ -852,10 +854,10 @@ function getRepoDescriptionSkin($repository) {
$repo['bio'] = $repo['bio'] ? markdown($repo['bio']) : "<br><center>".tr("No description present");
$favRepoClass = ($caSettings['favourite'] == $repository) ? "fav" : "nonfav";
$totalApps = $totalPlugins = $totalDocker = $totalDownloads = 0;
$totalApps = $totalLanguage = $totalPlugins = $totalDocker = $totalDownloads = $downloadDockerCount = 0;
foreach ($templates as $template) {
if ( $template['RepoName'] !== $repository ) continue;
if ( $template['BranchID'] ) continue;
if ( isset($template['BranchID']) ) continue;
if ( $template['Blacklist'] ) continue;
if ( $template['Deprecated'] && $caSettings['hideDeprecated'] !== "false" ) continue;
@ -893,7 +895,7 @@ function getRepoDescriptionSkin($repository) {
</div>
<div class='popupRepoDescription'><br>".strip_tags($repo['bio'])."</div>
";
if ( $repo['DonateLink'] ) {
if ( isset($repo['DonateLink']) ) {
$t .= "
<div class='donateArea'>
<div class='repoDonateText'>{$repo['DonateText']}</div>
@ -901,9 +903,9 @@ function getRepoDescriptionSkin($repository) {
</div>
";
}
if ( $repo['Photo'] || $repo['Video']) {
if ( isset($repo['Photo']) || isset($repo['Video']) ) {
$t .= "<div>";
if ( $repo['Photo'] ) {
if ( isset($repo['Photo']) ) {
$photos = is_array($repo['Photo']) ? $repo['Photo'] : [$repo['Photo']];
$t .= "<div>";
foreach ($photos as $shot) {
@ -911,8 +913,8 @@ function getRepoDescriptionSkin($repository) {
}
$t .= "</div>";
}
if ( $repo['Video'] ) {
if ( $repo['Photo'] )
if ( isset($repo['Video']) ) {
if ( isset($repo['Photo']) )
$t .= "<div><hr></div>";
$videos = is_array($repo['Video']) ? $repo['Video'] : [$repo['Video']];
@ -935,19 +937,19 @@ function getRepoDescriptionSkin($repository) {
$t .= "<div class='repoLinkArea'>";
if ( $repo['WebPage'] )
if ( isset($repo['WebPage']) )
$t .= "<a class='appIconsPopUp ca_webpage' href='{$repo['WebPage']}' target='_blank'> ".tr("Web Page")."</a>";
if ( $repo['Forum'] )
if ( isset($repo['Forum']) )
$t .= "<a class='appIconsPopUp ca_forum' href='{$repo['Forum']}' target='_blank'> ".tr("Forum")."</a>";
if ( $repo['profile'] )
if ( isset($repo['profile']) )
$t .= "<a class='appIconsPopUp ca_profile' href='{$repo['profile']}' target='_blank'> ".tr("Forum Profile")."</a>";
if ( $repo['Facebook'] )
if ( isset($repo['Facebook']) )
$t .= "<a class='appIconsPopUp ca_facebook' href='{$repo['Facebook']}' target='_blank'> ".tr("Facebook")."</a>";
if ( $repo['Reddit'] )
if ( isset($repo['Reddit']) )
$t .= "<a class='appIconsPopUp ca_reddit' href='{$repo['Reddit']}' target='_blank'> ".tr("Reddit")."</a>";
if ( $repo['Twitter'] )
if ( isset($repo['Twitter']) )
$t .= "<a class='appIconsPopUp ca_twitter' href='{$repo['Twitter']}' target='_blank'> ".tr("Twitter")."</a>";
if ( $repo['Discord'] )
if ( isset($repo['Discord']) )
$t .= "<a class='appIconsPopUp ca_discord_popup' target='_blank' href='{$repo['Discord']}' target='_blank'> ".tr("Discord")."</a>";
$t .= "
@ -962,7 +964,7 @@ function getRepoDescriptionSkin($repository) {
<tr><td class='repoLeft'>".tr("Total Docker Applications")."</td><td class='repoRight'>$totalDocker</td></tr>
<tr><td class='repoLeft'>".tr("Total Plugin Applications")."</td><td class='repoRight'>$totalPlugins</td></tr>
";
if ( $totalLanguage )
if ( isset($totalLanguage) )
$t .= "
<tr><td class='repoLeft''>".tr("Total Languages")."</td><td class='repoRight'>$totalLanguage</td></tr>
";
@ -1003,9 +1005,9 @@ function displaySearchResults($pageNumber) {
$tempFile = readJsonFile($caPaths['dockerSearchResults']);
$num_pages = $tempFile['num_pages'];
$file = $tempFile['results'];
// $templates = readJsonFile($caPaths['community-templates-info']);
$templates = &$GLOBALS['templates'];
$count = 0;
$ct = "<div>".tr("NOTE You must visit the dockerHub page to gather the information required to install correctly")."<span class='templateSearch' style='float:right'>Show CA templates</span></div><br><br>";
$ct .= "<div class='ca_templatesDisplay'>";
@ -1045,25 +1047,33 @@ function displayCard($template) {
$appName = str_replace("-"," ",$template['display_dockerName'] ?? "");
$holderClass = "";
$card = "";
$popupType = $template['RepositoryTemplate'] ? "ca_repoPopup" : "ca_appPopup";
if ( $template['RepositoryTemplate'] )
$template['DockerHub'] = false;
if ( $template['DockerHub'] )
$popupType = null;
else {
$popupType = $template['RepositoryTemplate'] ? "ca_repoPopup" : "ca_appPopup";
if ($template['Language']) {
$language = "{$template['Language']}";
$language .= $template['LanguageLocal'] ? " - {$template['LanguageLocal']}" : "";
$template['Category'] = "";
if (! $template['RepositoryTemplate'] && $template['Language']) {
$language = "{$template['Language']}";
$language .= $template['LanguageLocal'] ? " - {$template['LanguageLocal']}" : "";
$template['Category'] = "";
}
}
extract($template);
$class = "spotlightHome";
$appType = $Plugin ? "appPlugin" : "appDocker";
$appType = $Language ? "appLanguage": $appType;
$appType = (strpos($Category,"Drivers") !== false) && $Plugin ? "appDriver" : $appType;
$appType = $RepositoryTemplate ? "appRepository" : $appType;
if ( $RepositoryTemplate )
$appType = "appRepository";
else {
$appType = $Plugin ? "appPlugin" : "appDocker";
$appType = $Language ? "appLanguage": $appType;
$appType = (strpos($Category,"Drivers") !== false) && $Plugin ? "appDriver" : $appType;
}
switch ($appType) {
case "appPlugin":
$typeTitle = tr("This application is a plugin");
@ -1077,10 +1087,14 @@ function displayCard($template) {
case "appDriver":
$typeTitle = tr("This application is a driver (plugin)");
break;
default:
$typeTitle = "";
break;
}
if ($InstallPath ?? false)
$Path = $InstallPath;
$Category = $Category ?? "";
$Category = explode(" ",$Category)[0];
$Category = explode(":",$Category)[0];
@ -1109,29 +1123,29 @@ function displayCard($template) {
$supportContext[] = ["icon"=>"ca_discord","link"=>$Discord,"text"=>tr("Discord")];
if ( $Support )
$supportContext[] = ["icon"=>"ca_fa-support","link"=>$Support,"text"=> $SupportLanguage ?: tr("Support Forum")];
} else {
$holderClass='repositoryCard';
$cardClass = "ca_repoinfo";
$ID = str_replace(" ","",$RepoName);
$supportContext = [];
if ( $profile )
if ( $profile ?? false )
$supportContext[] = ["icon"=>"ca_profile","link"=>$profile,"text"=>tr("Profile")];
if ( $Forum )
if ( $Forum ?? false)
$supportContext[] = ["icon"=>"ca_forum","link"=>$Forum,"text"=>tr("Forum")];
if ( $Twitter )
if ( $Twitter ?? false)
$supportContext[] = ["icon"=>"ca_twitter","link"=>$Twitter,"text"=>tr("Twitter")];
if ( $Reddit )
if ( $Reddit ?? false)
$supportContext[] = ["icon"=>"ca_reddit","link"=>$Reddit,"text"=>tr("Reddit")];
if ( $Facebook )
if ( $Facebook ?? false)
$supportContext[] = ["icon"=>"ca_facebook","link"=>$Facebook,"text"=>tr("Facebook")];
if ( $WebPage )
if ( $WebPage ?? false)
$supportContext[] = ["icon"=>"ca_webpage","link"=>$WebPage,"text"=>tr("Web Page")];
$Name = str_replace(["' Repository","'s Repository"," Repository"],"",html_entity_decode($author,ENT_QUOTES));
$Name = str_replace(["&apos;s","'s"],"",$Name);
$author = "";
$Path = $Repository = $Plugin = $IconFA = $ModeratorComment = $RecommendedDate = $UpdateAvailable = $Blacklist = $Official = $Trusted = $Pinned = $actionsContext = $Deprecated = $Removable = $CAComment = $Installed = $Uninstalled = $Uninstall = $fav = $Beta = $Requires = $caTemplateExists = $actionCentre = $Overview = $imageNoClick = "";
}
$bottomClass = "ca_bottomLineSpotLight";
@ -1142,7 +1156,7 @@ function displayCard($template) {
<div class='ca_bottomLine $bottomClass'>
<div class='infoButton_docker dockerPopup' data-dockerHub='$DockerHub'>".tr("Docker Hub")."</div>";
} else {
if ( $PluginURL ) {
if ( $PluginURL ?? false) {
$dataPluginURL = "data-pluginurl='$PluginURL'";
} else {
$dataPluginURL = "";
@ -1176,8 +1190,8 @@ function displayCard($template) {
$card .= "<span class='favCardBackground' title='".htmlentities($favText)."'></span>";
} else
$card .= "<span class='favCardBackground' style='display:none;'></span>";
if ( ! $Pinned )
$pinStyle = "display:none;";
$pinStyle = $Pinned ? "" : "display:none;";
$pindata = (strpos($Repository,"/") !== false) ? $Repository : "library/$Repository";
$card .= "<span class='pinnedCard' title='".htmlentities(tr("This application is pinned for later viewing"))."' data-pindata='$pindata$SortName' style='$pinStyle'></span>";
@ -1197,7 +1211,8 @@ function displayCard($template) {
$type = 'plugin';
break;
}
if ($Removable && !$DockerInfo && ! $Installed && ! $Blacklist) {
$checked = $checked ?? "";
if ($Removable && !($DockerInfo ?? false) && ! $Installed && ! $Blacklist) {
$card .= "<input class='ca_multiselect ca_tooltip' title='".tr("Check off to select multiple reinstalls")."' type='checkbox' data-name='$previousAppName' data-humanName='$Name' data-type='$type' data-deletepath='$InstallPath' $checked>";
} elseif ( $actionCentre && $UpdateAvailable ) {
$card .= "<input class='ca_multiselect ca_tooltip' title='".tr("Check off to select multiple updates")."' type='checkbox' data-name='$previousAppName' data-humanName='$Name' data-type='$type' data-language='$LanguagePack' $checked>";
@ -1250,7 +1265,7 @@ function displayCard($template) {
</div>
";
$Overview = $Overview ?: $Description;
$Overview = $Overview ?: ($Description ?? "");
if ( ! $Overview )
$Overview = tr("No description present");
@ -1398,7 +1413,7 @@ function displayPopup($template) {
</div>
<div class='popupDescription popup_readmore'>$display_ovr</div>
";
if ( $Requires && ! is_file($RequiresFile) )
if ( $Requires && ! is_file($RequiresFile ?? "") )
$card .= "<div class='additionalRequirementsHeader'>".tr("Additional Requirements")."</div><div class='additionalRequirements'>{$template['Requires']}</div>";
if ( $Deprecated )