diff --git a/hubzilla/addon/cry01/Widget/Cry01.php b/hubzilla/addon/cry01/Widget/Cry01.php new file mode 100644 index 0000000..7f10744 --- /dev/null +++ b/hubzilla/addon/cry01/Widget/Cry01.php @@ -0,0 +1,133 @@ +load_listings($path); + return $this->render_directory($listings, $config); + } + + private function load_listings($path) { + // Loads listings.json from the operator-configured path. + if (!$path) return ['core' => [], 'tier1' => [], 'tier2' => [], 'other' => []]; + $raw = @file_get_contents($path); + if ($raw === false) return ['core' => [], 'tier1' => [], 'tier2' => [], 'other' => []]; + $data = json_decode($raw, true); + return (json_last_error() === JSON_ERROR_NONE) + ? $data + : ['core' => [], 'tier1' => [], 'tier2' => [], 'other' => []]; + } + + private function render_directory($listings, $config) { + // Renders the four-tab Bootstrap directory widget. + $default_tab = $config['directory_default_tab'] ?? 'core'; + $uid = 'cry01-dir-' . substr(md5(uniqid()), 0, 6); + + $tabs = [ + 'core' => 'Core', + 'tier1' => 'Tier-I', + 'tier2' => 'Tier-II', + 'other' => 'Other', + ]; + + $out = '
'; + $out .= ''; + + $out .= '
'; + foreach ($tabs as $key => $label) { + $active = ($key === $default_tab) ? 'show active' : ''; + $out .= '
'; + $out .= ($key === 'core') + ? $this->render_core_tab($listings['core'] ?? []) + : $this->render_tier_tab($listings[$key] ?? [], $label); + $out .= '
'; + } + $out .= '
'; + return $out; + } + + private function render_core_tab($core) { + // Renders the three permanent Core slots. Pending slots show invitation text. + $slots = [ + 'taxonomy-authority' => ['role' => 'Taxonomy Authority', 'desc' => 'The institutional source of the case law categories this diagnostic record is organized by.'], + 'methodology-certifier' => ['role' => 'Methodology Certifier', 'desc' => 'The law firm whose professional association with this project certifies the diagnostic record meets a standard the legal community can use.'], + 'peer-operator' => ['role' => 'Peer Operator', 'desc' => 'The cooperating Civic Infrastructure host who can independently verify, support, and if necessary continue this diagnostic record.'], + ]; + + $indexed = []; + foreach ($core as $entry) { + $indexed[$entry['slot'] ?? ''] = $entry; + } + + $out = ''; + foreach ($slots as $slot_id => $slot_def) { + $entry = $indexed[$slot_id] ?? []; + $status = $entry['status'] ?? 'pending'; + $out .= '
'; + if ($status === 'pending' || empty($entry['name'])) { + $out .= '
' . $this->h($slot_def['role']) . '
'; + $out .= '
' . $this->h($slot_def['desc']) . '
'; + $out .= '
Invitation pending
'; + } else { + $url = $entry['url'] ?? ''; + $name = $this->h($entry['name']); + $out .= '
'; + $out .= $url ? '' . $name . '' : $name; + $out .= '
'; + $out .= '
' . $this->h($slot_def['role']) . '
'; + } + $out .= '
'; + } + return $out; + } + + private function render_tier_tab($entries, $label) { + // Renders a tier tab. Shows placeholder text if no entries. + if (empty($entries)) { + return '

No ' . $this->h($label) . ' listings yet.

'; + } + $out = ''; + foreach ($entries as $entry) { + $name = $this->h($entry['name'] ?? ''); + $role = $this->h($entry['role'] ?? ''); + $url = $entry['url'] ?? ''; + $desc = $this->h($entry['description'] ?? ''); + $out .= '
'; + $out .= '
'; + $out .= $url ? '' . $name . '' : $name; + $out .= '
'; + if ($role) $out .= '
' . $role . '
'; + if ($desc) $out .= '
' . $desc . '
'; + $out .= '
'; + } + return $out; + } + + private function h($value) { + // HTML-escapes a value for safe output. + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); + } +}