getConstants(); } } // Defining the different types of elements available. abstract class ComposerElementTypes { const UNSET = "unset"; const RAW = "raw"; const H1 = "h1"; const H2 = "h2"; const H3 = "h3"; const PARAGRAPH = "paragraph"; const BUTTON = "button"; const CODE = "code"; const HR = "hr"; const CONTAINER = "container"; const COLLAPSE = "collapse"; const SPACER = "spacer"; const IMAGE = "image"; const TABLE = "table"; const GRID = "grid"; const GALLERY = "gallery"; const VIDEO = "video"; /** * Returns all the constants present in the class. * @return array All the constants in as "[[k, v], [k, v], ...]". * @see https://www.php.net/manual/en/reflectionclass.getconstants.php */ static function getConstants(): array { $oClass = new ReflectionClass(__CLASS__); return $oClass->getConstants(); } } // Defining modifiers. abstract class ComposerElementModifiers { // Generic > Margin const GENERIC_MARGIN_NO_TOP = ["mt-0", "mt-0"]; const GENERIC_MARGIN_NO_BOTTOM = ["mb-0", "mb-0"]; const GENERIC_MARGIN_NO_LEFT = ["ml-0", "ml-0"]; const GENERIC_MARGIN_NO_RIGHT = ["mr-0", "mr-0"]; const GENERIC_MARGIN_NO_X = ["mx-0", "mx-0"]; const GENERIC_MARGIN_NO_Y = ["my-0", "my-0"]; const GENERIC_MARGIN_NONE = ["m-0", "m-0" ]; // Generic > Padding const GENERIC_PADDING_NO_TOP = ["pt-0", "pt-0"]; const GENERIC_PADDING_NO_BOTTOM = ["pb-0", "pb-0"]; const GENERIC_PADDING_NO_LEFT = ["pl-0", "pl-0"]; const GENERIC_PADDING_NO_RIGHT = ["pr-0", "pr-0"]; const GENERIC_PADDING_NO_X = ["px-0", "px-0"]; const GENERIC_PADDING_NO_Y = ["py-0", "py-0"]; const GENERIC_PADDING_NONE = ["p-0" , "p-0" ]; // Generic > Others const GENERIC_FULL_WIDTH = ["w-full", "w-full"]; const GENERIC_BOLD = ["bold", "f-w-500"]; // Containers const CONTAINER_SCROLL_HORIZONTAL = ["horizontal-scroll", "overflow-x-scroll hide-scrollbar"]; const CONTAINER_SCROLL_HORIZONTAL_AUTO = ["horizontal-scroll-auto", "overflow-x-auto"]; const CONTAINER_CARD = ["card", "card"]; // Buttons const BUTTON_THIN = ["thin", ""]; const BUTTON_THICK = ["thick", ""]; const BUTTON_ROUNDED = ["rounded", ""]; const BUTTON_CIRCLE = ["circle", ""]; const BUTTON_DOWNLOAD_PRIMARY = ["download-primary", "primary"]; // Horizontal ruler const HR_SUBTLE = ["subtle", "subtle"]; // Collapse const DETAILS_NO_ROUNDING = ["no-rounding", ""]; const DETAILS_CLOSED = ["closed", ""]; // Tables const TABLE_NO_OUTER_PADDING = ["no-outer-padding", "table-no-outer-padding"]; const TABLE_STRIPED = ["striped", "table-striped"]; const TABLE_HOVER = ["hover", "table-hover"]; const TABLE_INNER_BORDER = ["inner-bordered", "table-inner-bordered"]; const TABLE_OUTER_BORDER = ["outer-bordered", "table-outer-bordered"]; const TABLE_V2_STYLISH = ["stylish", "stylish r-s border o-hidden"]; const TABLE_V2_CELL_PADDING = ["auto-cell-padding", "table-p-xs table-h-p-s"]; const TABLE_V2_VERTICAL_ALIGN = ["v-center-cells", "table-v-center"]; // Code const CODE_BLOCK = ["code-block", "w-full d-inline-block"]; // Other internal constants const _INDEX_KEY = 0; const _INDEX_CLASSES = 1; /** * Returns all the constants present in the class. * @return array All the constants in as "[[k, v], [k, v], ...]". * @see https://www.php.net/manual/en/reflectionclass.getconstants.php */ static function getConstants(): array { $oClass = new ReflectionClass(__CLASS__); return $oClass->getConstants(); } /** * Returns the given modifier's constant's key * @param array $modifier_data A modifier constant defined in "ComposerElementModifiers". * @return string The modifier's key or an empty string if an error was encountered. */ static function get_modifier_key(array $modifier_data) : string { return sizeof($modifier_data) >= 1 ? $modifier_data[ComposerElementModifiers::_INDEX_KEY] : ''; } /** * Returns the given modifier's constant's classes * @param array $modifier_data A modifier constant defined in "ComposerElementModifiers". * @return string The modifier's classes or an empty string if an error was encountered. */ static function get_modifier_classes(array $modifier_data) : string { return sizeof($modifier_data) >= 2 ? $modifier_data[ComposerElementModifiers::_INDEX_CLASSES] : ''; } /** * @param string $modifier_key * @return string The resolved DOM classes, or an empty string if the given modifier is unknown. */ static function get_classes_from_key(string $modifier_key) : string { foreach(ComposerElementModifiers::getConstants() as $constant_values) { if(!is_array($constant_values)) { continue; } if($modifier_key == $constant_values[ComposerElementModifiers::_INDEX_KEY]) { return $constant_values[ComposerElementModifiers::_INDEX_CLASSES]; } } return ""; } static function is_modifier_in_modifiers(array $modifier_data, array $modifiers) : bool { foreach($modifiers as $modifier) { if($modifier_data[ComposerElementModifiers::_INDEX_KEY] == $modifier) { return true; } } return false; } } // Data classes class ComposerContent { public array $strings; public ComposerContentMetadata $metadata; public array $elements; function __construct(array $strings, ComposerContentMetadata $metadata, array $elements) { $this->strings = $strings; $this->metadata = $metadata; $this->elements = $elements; } static function from_json(array $json_data) : ComposerContent { global $default_language; return new ComposerContent( key_exists("strings", $json_data) ? $json_data["strings"] : array($default_language=>[]), ComposerContentMetadata::from_json( key_exists("metadata", $json_data) ? $json_data["metadata"] : array() ), key_exists("elements", $json_data) ? ComposerElement::from_json_array($json_data["elements"]) : array() ); } public function get_html() : string { $htmlCode = ""; // FIXME: Check for the template after the loop - Isn't it done already ? foreach($this->elements as $element) { /** @var ComposerElement $element */ $htmlCode .= $element->get_html($this); } return $this->metadata->apply_template($this, $htmlCode); } public function get_head_title() : string { if(!is_null($this->metadata->head->title)) { return localize_private($this->metadata->head->title, $this->strings, false); } return localize("content.default.head.title"); } public function get_head_description() : string { if(!is_null($this->metadata->head->title)) { return localize_private($this->metadata->head->description, $this->strings, false); } return localize("content.default.head.description"); } public function get_opengraph_tags(?string $title_prefix, ?string $type_override, ?string $url_override, ?string $image_url_override, ?string $image_url_fallback) : string { global $host_uri; $final_image_uri = (is_null($image_url_override) ? (is_null($this->metadata->opengraph->image) ? $image_url_fallback : $this->metadata->opengraph->image) : $image_url_override); return 'metadata->opengraph->title, $this->strings, false)) . '" />metadata->opengraph->description, $this->strings, false)) . '" />metadata->opengraph->type) : $type_override) . '" />'; // } } class ComposerContentMetadata { public string $title; public string $description; public string $template; public ComposerContentMetadataHead $head; public ComposerContentMetadataOpengraph $opengraph; public ?ComposerContentMetadataArticle $article; function __construct(string $title, string $description, string $template, ComposerContentMetadataHead $head, ComposerContentMetadataOpengraph $opengraph, ?ComposerContentMetadataArticle $article) { $this->title = $title; $this->description = $description; $this->template = $template; $this->head = $head; $this->opengraph = $opengraph; $this->article = $article; // Safety checks. if($this->template == ComposerTemplates::ARTICLE_LEGACY && is_null($this->article)) { $this->article = ComposerContentMetadataArticle::from_json([]); } } static function from_json(array $json_data) : ComposerContentMetadata { return new ComposerContentMetadata( key_exists("title", $json_data) ? $json_data["title"] : "", key_exists("description", $json_data) ? $json_data["description"] : "", key_exists("template", $json_data) ? $json_data["template"] : "", ComposerContentMetadataHead::from_json( key_exists("head", $json_data) ? $json_data["head"] : array() ), ComposerContentMetadataOpengraph::from_json( key_exists("opengraph", $json_data) ? $json_data["opengraph"] : array() ), key_exists("article", $json_data) ? ComposerContentMetadataArticle::from_json($json_data["article"]) : null, ); } function apply_template(ComposerContent $content_root, string $inner_html) : string { switch($this->template) { case ComposerTemplates::ARTICLE_LEGACY: // FIXME: Is this even used anymore ?!? $inner_html = '
' . '

' . '  ' . localize_private($this->article->title, $content_root->strings, false) . '' . localize_private($this->article->subtitle, $content_root->strings, false) . '

' . '
' . $inner_html . '
' . '
' . '
'; break; case ComposerTemplates::GENERIC_PROJECT_README: // Prepending the heading $inner_html = getMainHeader( localize_private($this->article->title, $content_root->strings, false), $this->article->icon, localize_private($this->article->subtitle, $content_root->strings, false), null, false, null, 3, false, true ) . '
' . $inner_html . '
'; // Grabbing the DOM for inside the tags bar $_template_gpr_tags_dom = ''; if(sizeof($this->article->tags) > 0) { foreach($this->article->tags as $tag) { $_template_gpr_tags_dom .= '#' . $tag . ''); } } else { $_template_gpr_tags_dom .= '' . localize("content.error.message.data.no.tags") . ''; } // Printing the tags bar $inner_html .= getMainHeader( $_template_gpr_tags_dom, null, null, null, true, null, 6, false, false, true ); break; case ComposerTemplates::RAW: default: break; } return $inner_html; } } class ComposerContentMetadataHead { public ?string $title; public ?string $description; function __construct(?string $title, ?string $description) { $this->title = $title; $this->description = $description; } static function from_json(array $json_data) : ComposerContentMetadataHead { return new ComposerContentMetadataHead( key_exists("title", $json_data) ? $json_data["title"] : null, key_exists("description", $json_data) ? $json_data["description"] : null ); } } class ComposerContentMetadataOpengraph { public ?string $title; public ?string $description; public ?string $type; public ?string $url; public ?string $image; public ?string $image_type; function __construct(?string $title, ?string $description, ?string $type, ?string $url, ?string $image, ?string $image_type) { $this->title = $title; $this->description = $description; $this->type = $type; $this->url = $url; $this->image = $image; $this->image_type = $image_type; } static function from_json(array $json_data) : ComposerContentMetadataOpengraph { return new ComposerContentMetadataOpengraph( key_exists("title", $json_data) ? $json_data["title"] : null, key_exists("description", $json_data) ? $json_data["description"] : null, key_exists("type", $json_data) ? $json_data["type"] : null, key_exists("url", $json_data) ? $json_data["url"] : null, key_exists("image", $json_data) ? $json_data["image"] : null, key_exists("image_type", $json_data) ? $json_data["image_type"] : null, ); } } class ComposerContentMetadataArticle { public string $icon; public string $title; public string $subtitle; public array $tags; function __construct(string $icon, string $title, string $subtitle, array $tags) { $this->icon = $icon; $this->title = $title; $this->subtitle = $subtitle; $this->tags = $tags; } static function from_json(array $json_data) : ComposerContentMetadataArticle { return new ComposerContentMetadataArticle( key_exists("icon", $json_data) ? $json_data["icon"] : "fad fa-question", key_exists("title", $json_data) ? $json_data["title"] : ''.localize("content.error.message.data.no.title").'', key_exists("subtitle", $json_data) ? $json_data["subtitle"] : '', key_exists("tags", $json_data) ? $json_data["tags"] : [], ); } public function __get($property) { return is_null($this->$property) ? "" : $this->$property; } } class ComposerElement { // Global parameters private string $type; private ?array $modifiers; private ?string $link; // Any direct element-container private ?array $parts; // Any direct text-container private ?string $content; private bool $localize; // Generic modifier values private ?int $padding; private ?int $margin; // Spacer's size private ?int $size; // Table's parameters private ?array $head; private ?array $body; private int $colspan; private int $rowspan; // Paragraph and code's parameters private ?int $indent; // Code's parameters private ?array $code; private ?string $codeLanguage; private bool $codeCopyable; // Button's parameters private ?string $color; // Image and video's parameters private ?string $source; private ?string $thumbnail; // Galleries parameters private array $images; // Screen readers parameters private ?string $srTitle; function __construct(string $type, ?array $modifiers, ?string $link, ?array $parts, ?string $content, bool $localize, ?int $padding, ?int $margin, ?int $size, ?array $head, ?array $body, int $colspan, int $rowspan, ?int $indent, ?array $code, ?string $codeLanguage, bool $codeCopyable, ?string $color, ?string $source, ?string $thumbnail, ?array $images, ?string $srTitle) { $this->type = $type; $this->modifiers = $modifiers; $this->link = $link; $this->parts = $parts; $this->content = $content; $this->localize = $localize; $this->padding = $padding; $this->margin = $margin; $this->size = $size; $this->head = ComposerElement::from_json_array($head); if(is_null($body)) { $this->body = array(); } else { $this->body = array_fill(0, sizeof($body), []); for($body_row_index = 0; $body_row_index < sizeof($body); $body_row_index++) { $this->body[$body_row_index] = ComposerElement::from_json_array($body[$body_row_index]); } } $this->colspan = $colspan; $this->rowspan = $rowspan; $this->indent = $indent; $this->code = $code; $this->codeLanguage = $codeLanguage; $this->codeCopyable = $codeCopyable; $this->color = $color; $this->source = $source; $this->thumbnail = $thumbnail; if(is_null($images)) { $this->images = array(); } else { $this->images = $images; } $this->srTitle = $srTitle; } static function from_json_array(?array $json_dataArray) : array { $parts = array(); if(!is_null($json_dataArray)) { foreach($json_dataArray as $part) { $parts[] = ComposerElement::from_json($part); } } return $parts; } static function from_json(array $json_data) : ComposerElement { return new ComposerElement( key_exists("type", $json_data) ? $json_data["type"] : ComposerElementTypes::UNSET, key_exists("modifiers", $json_data) ? $json_data["modifiers"] : [], key_exists("link", $json_data) ? $json_data["link"] : null, key_exists("parts", $json_data) ? ComposerElement::from_json_array($json_data["parts"]) : null, key_exists("content", $json_data) ? $json_data["content"] : null, key_exists("localize", $json_data) ? $json_data["localize"] : true, key_exists("padding", $json_data) ? $json_data["padding"] : null, key_exists("margin", $json_data) ? $json_data["margin"] : null, key_exists("size", $json_data) ? $json_data["size"] : null, key_exists("head", $json_data) ? $json_data["head"] : null, key_exists("body", $json_data) ? $json_data["body"] : null, key_exists("colspan", $json_data) ? $json_data["colspan"] : 1, key_exists("rowspan", $json_data) ? $json_data["rowspan"] : 1, key_exists("indent", $json_data) ? $json_data["indent"] : null, key_exists("code", $json_data) ? $json_data["code"] : null, key_exists("language", $json_data) ? $json_data["language"] : null, key_exists("copyable", $json_data) ? $json_data["copyable"] : false, key_exists("color", $json_data) ? $json_data["color"] : null, key_exists("source", $json_data) ? $json_data["source"] : null, key_exists("thumbnail", $json_data) ? $json_data["thumbnail"] : null, key_exists("images", $json_data) ? $json_data["images"] : null, key_exists("sr_title", $json_data) ? $json_data["sr_title"] : null, ); } /** * Processes the "content" and "parts" class' variables and returns their interpreted content as HTML. * @param ComposerContent $content_root The content in which this element is contained. * @param bool $doLocalization Whether the "content" variable should be processed to return localized text. * @param bool $doSubElements Whether the "parts" variable should be processed to return localized text. * @param bool $stopIfLocalized Whether the process should return if some text was in the "content" variable. * @return string The interpreted content as HTML. */ private function get_inner_html(ComposerContent $content_root, bool $doLocalization = true, bool $doSubElements = true, bool $stopIfLocalized = true) : string { global $LANG_FALLBACK_KEY_PREFIX; $htmlCode = ""; $wasTextLocalized = false; if($doLocalization) { // Checking if "content" was declared. if(is_null($this->content) && !$doSubElements) { return "

error.no.inner.content

"; } // Checking if there is something to process. if(!empty($this->content)) { $wasTextLocalized = true; if(!$this->localize) { $htmlCode .= $this->content; } else { // We can now localize the content key. $htmlCode .= localize_private($this->content, $content_root->strings, true, $LANG_FALLBACK_KEY_PREFIX); } } // Checking for early stop. if($wasTextLocalized && $stopIfLocalized) { return $htmlCode; } } if($doSubElements) { // Checking if "parts" was declared. if(is_null($this->parts)) { if(!$wasTextLocalized) { $htmlCode = "

error.no.inner.parts

"; } return $htmlCode; } // Appending each sub-element. foreach($this->parts as $subElement) { /** @var ComposerElement $subElement */ $htmlCode .= $subElement->get_html($content_root); } } return $htmlCode; } private function get_inner_html_elements(ComposerContent $content_root) : string { return $this->get_inner_html($content_root, false, true, false); } private function get_inner_html_text(ComposerContent $content_root) : string { return $this->get_inner_html($content_root, true, false, false); } private function get_modifiers_classes() : string { if(!is_null($this->modifiers)) { $classes = ""; // Combining classes. foreach($this->modifiers as $modifier) { /** @var string $modifier */ $classes .= ComposerElementModifiers::get_classes_from_key($modifier) . ' '; } // Removing redundant and useless spaces. return preg_replace('/\s+/', ' ', trim($classes)); } return ""; } /** * Processes the element and returns its interpreted form as HTML. * @param ComposerContent $content_root The content in which this element is contained. * @return string The interpreted element as HTML. */ public function get_html(ComposerContent $content_root) : string { $htmlCode = ""; // Setting up the link and its title if needed. if(!is_null($this->link)) { $htmlCode .= 'type == ComposerElementTypes::BUTTON ? 'class="bland-link button-link"' : '') .'>'; } switch($this->type) { case ComposerElementTypes::UNSET: $htmlCode .= "

error.element.type.unset !

"; break; case ComposerElementTypes::RAW: $htmlCode .= $this->get_inner_html($content_root); break; case ComposerElementTypes::H1: $htmlCode .= getMainHeader( $this->get_inner_html($content_root), null, null, null, !ComposerElementModifiers::is_modifier_in_modifiers( ComposerElementModifiers::GENERIC_MARGIN_NO_TOP, $this->modifiers), "bkgd-math", // heading-dyn-width-1 3, false, false, true ); break; case ComposerElementTypes::H2: case ComposerElementTypes::H3: // Defining the text's indent level. $_paragraph_ident_level = is_null($this->indent) ? 0 : $this->indent; // Defining the text's size. $_headingFontSize = ($this->type == ComposerElementTypes::H3 ? '18' : ( $this->type == ComposerElementTypes::H2 ? '20' : '22' )); // Composing heading. $htmlCode .= '<' . strtolower($this->type) . ' class="font-weight-semi-bold font-size-' . $_headingFontSize . ' m-0 ml-md-' . ($_paragraph_ident_level * 5) . '">' . $this->get_inner_html($content_root) . 'type) . '>'; break; case ComposerElementTypes::PARAGRAPH: // Defining the text's indent level. // TODO: Join with others $_paragraph_ident_level = is_null($this->indent) ? 0 : $this->indent; $_paragraph_ident_level = $_paragraph_ident_level < 0 ? 0 : $_paragraph_ident_level; $_paragraph_ident_level = $_paragraph_ident_level > 5 ? 5 : $_paragraph_ident_level; $_paragraph_ident_level = (["", "ml-xs", "ml-s", "ml-m", "ml-l", "ml-xl"])[$_paragraph_ident_level]; // Calculating the vertical margin modifiers $_paragraph_no_margin_top = ComposerElementModifiers::is_modifier_in_modifiers( ComposerElementModifiers::GENERIC_MARGIN_NO_TOP, $this->modifiers); if($_paragraph_no_margin_top) { $_paragraph_margin_modifier = ''; } else { $_paragraph_margin_modifier = 'mt-xs '; } // Adding other tags manually // FIXME: Use the standard functions FFS... $_paragraph_margin_modifier .= ( ComposerElementModifiers::is_modifier_in_modifiers( ComposerElementModifiers::GENERIC_BOLD, $this->modifiers) ) ? "t-w-500 " : ""; // Fixes some "overflowing" issue when indent is bigger than 2. $_paragraph_margin_modifier .= "mr-s "; // Composing the paragraph $htmlCode .= '

' . $this->get_inner_html($content_root) . '

'; break; case ComposerElementTypes::BUTTON: // Composing the button. $htmlCode .= ''; break; case ComposerElementTypes::CODE: // Defining the code's indent level. $_paragraph_ident_level = is_null($this->indent) ? 0 : $this->indent; // Defining the highlight language. $_language_class = is_null($this->codeLanguage) ? "nohighlight" : "language-" . $this->codeLanguage; // Parent container with a relative position to handle the wedge when the code itself is // horizontally scrollable. $htmlCode .= '
'; // Opening the code element. // Note: The "mt-10" may have to be removed if it clashes with 'no-margin-top' ! $htmlCode .= '
'; // Adding code lines. if(!is_null($this->code)) { foreach($this->code as $code_line) { //$htmlCode .= htmlspecialchars($code_line) . '
'; // Old method (Not compatible with hljs) $htmlCode .= '' . str_replace(" ", " ", htmlspecialchars($code_line)) . '
'; } } if($this->codeCopyable) { //border-t-0 border-r-0 $htmlCode .= ''; } // Closing code element. $htmlCode .= '
'; // Closing super container. $htmlCode .= '
'; break; case ComposerElementTypes::HR: // Getting the modifiers' classes $_hr_classes = $this->get_modifiers_classes(); // Composing the element. if(empty($_hr_classes)) { $htmlCode .= ''; } else { $htmlCode .= '
'; } break; case ComposerElementTypes::CONTAINER: // Defining the padding's size. $_container_padding = is_null($this->padding) ? 0 : $this->padding; $_container_padding = $_container_padding < 0 ? 0 : $_container_padding; $_container_padding = $_container_padding > 5 ? 5 : $_container_padding; $_container_padding = (["", "p-xs ", "p-s ", "p-m ", "p-l ", "p-xl "])[$_container_padding]; // Composing the container. $htmlCode .= '
' . $this->get_inner_html($content_root) . '
'; break; case ComposerElementTypes::COLLAPSE: // Composing collapse. $htmlCode .= '
modifiers ) ? "closed" : "open") . '>'; $htmlCode .= ''; $_title = "title"; $_subtitle = "subtitle"; $htmlCode .= '

' . '' . '' . '  '.$_title. ''.$_subtitle.'

'; $htmlCode .= '
modifiers ) ? " p-0 py-01" : "") . (ComposerElementModifiers::is_modifier_in_modifiers( ComposerElementModifiers::DETAILS_NO_ROUNDING, $this->modifiers ) ? " rounded-0" : "") . ' border-0 border-bottom">' . $this->get_inner_html($content_root) . '
'; break; case ComposerElementTypes::SPACER: // Defining the spacer's size. $_spacer_size = is_null($this->size) ? 1 : $this->size; // Composing spacer. $htmlCode .= '
'; break; case ComposerElementTypes::IMAGE: break; case ComposerElementTypes::TABLE: // Composing table. $htmlCode .= '
'; $htmlCode .= ''; if(!is_null($this->head)) { $htmlCode .= ''; foreach($this->head as $head_element) { /** @var ComposerElement $head_element */ $htmlCode .= ''; } $htmlCode .= ''; } if(!is_null($this->body)) { $htmlCode .= ''; for($body_row_index = 0; $body_row_index < sizeof($this->body); $body_row_index++) { $htmlCode .= ''; foreach($this->body[$body_row_index] as $body_cell) { /** @var ComposerElement $body_cell */ $htmlCode .= 'colspan > 1 ? ' colspan="' . $body_cell->colspan . '"' : '') . ($body_cell->rowspan > 1 ? ' rowspan="' . $body_cell->rowspan . '"' : '') . '>' . $body_cell->get_html($content_root) . ''; } $htmlCode .= ''; } $htmlCode .= ''; } $htmlCode .= '
' . $head_element->get_html($content_root) . '
'; $htmlCode .= "
"; break; case ComposerElementTypes::GRID: break; case ComposerElementTypes::GALLERY: if(!is_null($this->srTitle)) { $htmlCode .= '
'; $htmlCode .= ''; } else { $htmlCode .= '
'; } $htmlCode .= '
'; $htmlCode .= '
    '; foreach($this->images as $galleryImageUrl) { $htmlCode .= '
  • '; } $htmlCode .= '
'; break; case ComposerElementTypes::VIDEO: // Composing the video element $htmlCode .= ''; break; default: $htmlCode .= "

error.unknown !

"; break; } if(!is_null($this->link)) { $htmlCode .= '
'; } return $htmlCode; } } // Generic functions function get_content_error(string $error_title_key, string $error_description_key) : ?ComposerContent { // FIXME: Make this non-nullable !!! return null; } function load_content_by_file_path(string $file_path) : ?ComposerContent { $content_json_data = json_decode(file_get_contents($file_path), true); if(is_null($content_json_data)) { return null; } return ComposerContent::from_json($content_json_data); } function load_content_by_id(string $content_id) : ?ComposerContent { // FIXME: Find another way to get `$config_dir_content` here ! global $config_dir_content; $content_file_path = get_content_file_path($config_dir_content, $content_id); if(is_null($content_file_path)) { return null; } else { return load_content_by_file_path($content_file_path); } } ?>