<?php final class BridgeCard { public static function render( BridgeFactory $bridgeFactory, string $bridgeClassName, ?string $token ): string { $bridge = $bridgeFactory->create($bridgeClassName); $uri = $bridge->getURI(); $name = $bridge->getName(); $icon = $bridge->getIcon(); $description = $bridge->getDescription(); $contexts = $bridge->getParameters(); // Checkbox for disabling of proxy (if enabled) if ( Configuration::getConfig('proxy', 'url') && Configuration::getConfig('proxy', 'by_bridge') ) { $proxyName = Configuration::getConfig('proxy', 'name') ?: Configuration::getConfig('proxy', 'url'); $contexts['global']['_noproxy'] = [ 'name' => sprintf('Disable proxy (%s)', $proxyName), 'type' => 'checkbox', ]; } if (Configuration::getConfig('cache', 'custom_timeout')) { $contexts['global']['_cache_timeout'] = [ 'name' => 'Cache timeout in seconds', 'type' => 'number', 'defaultValue' => $bridge->getCacheTimeout() ]; } $shortName = $bridge->getShortName(); $card = <<<CARD <section class="bridge-card" id="bridge-{$bridgeClassName}" data-ref="{$name}" data-short-name="$shortName" > <h2><a href="{$uri}">{$name}</a></h2> <p class="description">{$description}</p> <input type="checkbox" class="showmore-box" id="showmore-{$bridgeClassName}" /> <label class="showmore" for="showmore-{$bridgeClassName}">Show more</label> CARD; if (count($contexts) === 0) { // The bridge has zero parameters $card .= self::renderForm($bridgeClassName, '', [], $token); } elseif (count($contexts) === 1 && array_key_exists('global', $contexts)) { // The bridge has a single context with key 'global' $card .= self::renderForm($bridgeClassName, '', $contexts['global'], $token); } else { // The bridge has one or more contexts (named or unnamed) foreach ($contexts as $contextName => $contextParameters) { if ($contextName === 'global') { continue; } if (array_key_exists('global', $contexts)) { // Merge the global parameters into current context $contextParameters = array_merge($contextParameters, $contexts['global']); } if (!is_numeric($contextName)) { // This is a named context $card .= '<h5>' . $contextName . '</h5>' . PHP_EOL; } $card .= self::renderForm($bridgeClassName, $contextName, $contextParameters, $token); } } $card .= sprintf('<label class="showless" for="showmore-%s">Show less</label>', $bridgeClassName); if (Configuration::getConfig('admin', 'donations') && $bridge->getDonationURI()) { $card .= sprintf( '<p class="maintainer">%s ~ <a href="%s">Donate</a></p>', $bridge->getMaintainer(), $bridge->getDonationURI() ); } else { $card .= sprintf('<p class="maintainer">%s</p>', $bridge->getMaintainer()); } $card .= '</section>'; return $card; } private static function renderForm( string $bridgeClassName, string $contextName, array $contextParameters, ?string $token ) { $form = <<<EOD <form method="GET" action="?" class="bridge-form"> <input type="hidden" name="action" value="display" /> <input type="hidden" name="bridge" value="{$bridgeClassName}" /> EOD; if (Configuration::getConfig('authentication', 'token') && $token) { $form .= sprintf('<input type="hidden" name="token" value="%s" />', e($token)); } if (!empty($contextName)) { $form .= sprintf('<input type="hidden" name="context" value="%s" />', $contextName); } if (count($contextParameters) > 0) { $form .= '<div class="parameters">'; foreach ($contextParameters as $id => $inputEntry) { if (!isset($inputEntry['exampleValue'])) { $inputEntry['exampleValue'] = ''; } if (!isset($inputEntry['defaultValue'])) { $inputEntry['defaultValue'] = ''; } $idArg = 'arg-' . urlencode($bridgeClassName) . '-' . urlencode($contextName) . '-' . urlencode($id); $inputName = filter_var($inputEntry['name'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); $form .= '<label for="' . $idArg . '">' . $inputName . '</label>' . PHP_EOL; if ( !isset($inputEntry['type']) || $inputEntry['type'] === 'text' ) { $form .= self::getTextInput($inputEntry, $idArg, $id) . "\n"; } elseif ($inputEntry['type'] === 'number') { $form .= self::getNumberInput($inputEntry, $idArg, $id); } elseif ($inputEntry['type'] === 'list') { $form .= self::getListInput($inputEntry, $idArg, $id) . "\n"; } elseif ($inputEntry['type'] === 'checkbox') { $form .= self::getCheckboxInput($inputEntry, $idArg, $id); } else { $foo = 2; // oops? } $infoText = []; $infoTextScript = ''; if (isset($inputEntry['title'])) { $infoText[] = filter_var($inputEntry['title'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); } if ($inputEntry['exampleValue'] !== '') { $infoText[] = "Example (right click to use):\n" . filter_var($inputEntry['exampleValue'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); $infoTextScript = 'rssbridge_use_placeholder_value(this);'; } if (count($infoText) > 0) { $form .= '<i class="info" data-for="' . $idArg . '" title="' . implode("\n\n", $infoText) . '" oncontextmenu="' . $infoTextScript . 'return false">i</i>'; } else { $form .= '<i class="no-info"></i>'; } } $form .= '</div>'; } $form .= '<button type="submit" name="format" formtarget="_blank" value="Html">Generate feed</button>'; return $form . '</form>' . PHP_EOL; } public static function getTextInput(array $entry, string $id, string $name): string { $defaultValue = filter_var($entry['defaultValue'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); $exampleValue = filter_var($entry['exampleValue'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); $attributes = self::getInputAttributes($entry); return sprintf('<input %s id="%s" type="text" value="%s" placeholder="%s" name="%s" />', $attributes, $id, $defaultValue, $exampleValue, $name); } public static function getNumberInput(array $entry, string $id, string $name): string { $defaultValue = filter_var($entry['defaultValue'], FILTER_SANITIZE_NUMBER_INT); $exampleValue = filter_var($entry['exampleValue'], FILTER_SANITIZE_NUMBER_INT); $attributes = self::getInputAttributes($entry); return sprintf('<input %s id="%s" type="number" value="%s" placeholder="%s" name="%s" />' . "\n", $attributes, $id, $defaultValue, $exampleValue, $name); } public static function getListInput(array $entry, string $id, string $name): string { $required = $entry['required'] ?? null; if ($required) { trigger_error('The required attribute is not supported for lists'); unset($entry['required']); } $attributes = self::getInputAttributes($entry); $list = sprintf('<select %s id="%s" name="%s" >' . "\n", $attributes, $id, $name); foreach ($entry['values'] as $name => $value) { if (is_array($value)) { $list .= '<optgroup label="' . htmlentities($name) . '">'; foreach ($value as $subname => $subvalue) { if ( $entry['defaultValue'] === $subname || $entry['defaultValue'] === $subvalue ) { $list .= '<option value="' . $subvalue . '" selected>' . $subname . '</option>'; } else { $list .= '<option value="' . $subvalue . '">' . $subname . '</option>'; } } $list .= '</optgroup>'; } else { if ( $entry['defaultValue'] === $name || $entry['defaultValue'] === $value ) { $list .= '<option value="' . $value . '" selected>' . $name . '</option>' . "\n"; } else { $list .= '<option value="' . $value . '">' . $name . '</option>' . "\n"; } } } $list .= '</select>'; return $list; } public static function getCheckboxInput(array $entry, string $id, string $name): string { $required = $entry['required'] ?? null; if ($required) { trigger_error('The required attribute is not supported for checkboxes'); unset($entry['required']); } $checked = $entry['defaultValue'] === 'checked' ? 'checked' : ''; $attributes = self::getInputAttributes($entry); return sprintf('<input %s id="%s" type="checkbox" name="%s" %s />' . "\n", $attributes, $id, $name, $checked); } public static function getInputAttributes(array $entry): string { $result = ''; $required = $entry['required'] ?? null; if ($required) { $result .= ' required'; } $pattern = $entry['pattern'] ?? null; if ($pattern) { $result .= ' pattern="' . $pattern . '"'; } return $result; } }