moveToPreviousCorrespondingOpeningCall();
$type = $openingTag->getType();
$renderingMode = $openingTag->getAttribute(WebCodeTag::RENDERING_MODE_ATTRIBUTE);
if ($renderingMode !== null) {
LogUtility::warning("The `renderingmode` attribute has been deprecated for the webcode `type` attribute.");
if ($type === null) {
$type = strtolower($renderingMode);
}
}
if ($type === WebCodeTag::RENDERING_ONLY_RESULT_DEPRECATED) {
LogUtility::warning("The `type` value (" . self::RENDERING_ONLY_RESULT_DEPRECATED . ") should be replaced by (" . self::RESULT_TYPE . ")");
$type = WebCodeTag::RESULT_TYPE;
}
/**
* The mime (ie xml,html, ...) and code content are in two differents
* call. To be able to set the content to the good type
* we keep a trace of it
*/
$actualCodeType = "";
/**
* Loop
*/
while ($actualTag = $callStack->next()) {
$tagName = $actualTag->getTagName();
if (in_array($tagName, WebCodeTag::CODE_TAGS)) {
/**
* Only result or inject mode, we don't display the code
* on all node (enter, exit and unmatched)
*/
if (in_array($type, [WebCodeTag::RESULT_TYPE, self::INJECT_TYPE])) {
$actualTag->addAttribute(Display::DISPLAY, Display::DISPLAY_NONE_VALUE);
}
switch ($actualTag->getState()) {
case DOKU_LEXER_ENTER:
// Get the code (The content between the code nodes)
// We ltrim because the match gives us the \n at the beginning and at the end
$actualCodeType = strtolower(trim($actualTag->getType()));
// Xml is html
if ($actualCodeType === 'xml') {
$actualCodeType = 'html';
}
// markdown, dokuwiki is marki
if (in_array($actualCodeType, ['md', 'markdown', 'dw'])) {
$actualCodeType = WebCodeTag::MARKI_LANG;
}
// The code for a language may be scattered in multiple block
if (!isset($codes[$actualCodeType])) {
$codes[$actualCodeType] = "";
}
continue 2;
case DOKU_LEXER_UNMATCHED:
$codeContent = $actualTag->getPluginData()[PluginUtility::PAYLOAD];
if (empty($actualCodeType)) {
LogUtility::msg("The type of the code should not be null for the code content " . $codeContent, LogUtility::LVL_MSG_WARNING, WebCodeTag::TAG);
continue 2;
}
// Append it
$codes[$actualCodeType] = $codes[$actualCodeType] . $codeContent;
// Check if a javascript console function is used, only if the flag is not set to true
if (!$useConsole) {
if (in_array($actualCodeType, array('babel', 'javascript', 'html', 'xml'))) {
// if the code contains 'console.'
$result = preg_match('/' . 'console\.' . '/is', $codeContent);
if ($result) {
$useConsole = true;
}
}
}
// Reset
$actualCodeType = "";
break;
}
}
}
/**
* By default, markup code
* is rendered inside the page
* We got less problem such as iframe overflow
* due to lazy loading, such as relative link, ...
*/
if (
array_key_exists(WebCodeTag::MARKI_LANG, $codes)
&& count($codes) === 1
&& $openingTag->getAttribute(WebCodeTag::IFRAME_BOOLEAN_ATTRIBUTE) === null
&& $openingTag->getType() === null
) {
$openingTag->setType(self::INJECT_TYPE);
}
return [
WebCodeTag::CODES_ATTRIBUTE => $codes,
WebCodeTag::USE_CONSOLE_ATTRIBUTE => $useConsole,
PluginUtility::ATTRIBUTES => $openingTag->getAttributes()
];
}
/**
* Tag is of an iframe (Web code) or a div (wiki markup)
*/
public static function renderExit(TagAttributes $tagAttributes, array $data)
{
$codes = $data[WebCodeTag::CODES_ATTRIBUTE];
$type = $tagAttributes->getType();
if ($type === null) {
$type = self::STORY_TYPE;
}
/**
* Rendering mode is used in handle exit, we delete it
* to not get it in the HTML output
*/
$tagAttributes->removeComponentAttributeIfPresent(WebCodeTag::RENDERING_MODE_ATTRIBUTE);
// Create the real output of webcode
if (sizeof($codes) == 0) {
return false;
}
// Css
$snippetSystem = PluginUtility::getSnippetManager();
$snippetSystem->attachCssInternalStyleSheet(WebCodeTag::TAG);
$snippetSystem->attachJavascriptFromComponentId(WebCodeTag::TAG);
// Mermaid code ?
if (array_key_exists(MermaidTag::MERMAID_CODE, $codes)) {
$mermaidCode = "";
foreach ($codes as $codeKey => $code) {
if ($codeKey !== MermaidTag::MERMAID_CODE) {
LogUtility::error("The code type ($codeKey) was mixed with mermaid code in a webcode and this is not yet supported. The code was skipped");
continue;
}
$mermaidCode .= $code;
}
$tagAttributes->addComponentAttributeValue(MermaidTag::MARKUP_CONTENT_ATTRIBUTE, $mermaidCode);
return MermaidTag::renderEnter($tagAttributes);
}
/**
* Dokuwiki Code
* (Just HTML)
*/
if (array_key_exists(WebCodeTag::MARKI_LANG, $codes)) {
$markupCode = $codes[WebCodeTag::MARKI_LANG];
if ($type === self::INJECT_TYPE) {
/**
* the div is to be able to apply some CSS
* such as don't show editbutton on webcode
*/
$html = $tagAttributes->toHtmlEnterTag("div");
try {
$contextPath = ExecutionContext::getActualOrCreateFromEnv()
->getContextPath();
$html .= FetcherMarkup::confChild()
->setRequestedMarkupString($markupCode)
->setDeleteRootBlockElement(false)
->setIsDocument(false)
->setRequestedContextPath($contextPath)
->setRequestedMimeToXhtml()
->build()
->getFetchString();
} catch (ExceptionCompile $e) {
$html .= $e->getMessage();
LogUtility::log2file("Error while rendering webcode", LogUtility::LVL_MSG_ERROR, WebCodeTag::CANONICAL, $e);
}
$html .= "";
return $html;
}
/**
* Iframe output
*/
$tagAttributes->removeComponentAttribute(WebCodeTag::IFRAME_BOOLEAN_ATTRIBUTE);
if (!$tagAttributes->hasAttribute(TagAttributes::NAME_ATTRIBUTE)) {
$tagAttributes->addOutputAttributeValueIfNotEmpty(TagAttributes::NAME_ATTRIBUTE, "WebCode iFrame");
}
try {
$url = FetcherMarkupWebcode::createFetcherMarkup($markupCode)
->getFetchUrl()
->toString();
$tagAttributes->addOutputAttributeValue("src", $url);
} catch (ExceptionBadState $e) {
// The markup is provided, we shouldn't have a bad state
LogUtility::internalError("We were unable to set the iframe URL. Error:{$e->getMessage()}", WebCodeTag::CANONICAL);
}
return self::finishIframe($tagAttributes);
}
/**
* Js Html Css language
*/
if ($type === self::INJECT_TYPE) {
$htmlToInject = self::getCss($codes);
return $htmlToInject . self::getBodyHtmlAndJavascript($codes, false);
}
/** @noinspection JSUnresolvedLibraryURL */
$headIFrame = <<
EOF;
// External Resources such as css stylesheet or js
$externalResources = [];
if ($tagAttributes->hasComponentAttribute(WebCodeTag::EXTERNAL_RESOURCES_ATTRIBUTE_KEY)) {
LogUtility::warning("The (" . WebCodeTag::EXTERNAL_RESOURCES_ATTRIBUTE_KEY . ") has been deprecated. You should put your script/link in a code block with the `display` attribute set to `none`.");
$resources = $tagAttributes->getValueAndRemove(WebCodeTag::EXTERNAL_RESOURCES_ATTRIBUTE_KEY);
$externalResources = explode(",", $resources);
}
// Jsx / Babel Preprocessor, if babel is used, add it to the external resources
if (array_key_exists('babel', $codes)) {
$babelMin = "https://unpkg.com/babel-standalone@6/babel.min.js";
// a load of babel invoke it (be sure to not have it twice
if (!(array_key_exists($babelMin, $externalResources))) {
$externalResources[] = $babelMin;
}
}
// Add the external resources
foreach ($externalResources as $externalResource) {
$pathInfo = pathinfo($externalResource);
$fileExtension = $pathInfo['extension'];
switch ($fileExtension) {
case 'css':
$headIFrame .= "";
break;
case 'js':
$headIFrame .= "";
break;
}
}
// WebConsole style sheet
$webcodeClass = WebCodeTag::getClass();
$cssUrl = FetcherRawLocalPath::createFromPath(WikiPath::createComboResource("webcode:webcode-iframe.css"))->getFetchUrl()->toHtmlString();
$headIFrame .= "";
// A little margin to make it neater
// that can be overwritten via cascade
$headIFrame .= "";
// The css
$headIFrame .= self::getCss($codes);
// The javascript console script should be first to handle console.log in the content
$useConsole = $data[WebCodeTag::USE_CONSOLE_ATTRIBUTE];
if ($useConsole) {
$url = FetcherRawLocalPath::createFromPath(WikiPath::createComboResource("webcode:webcode-console.js"))->getFetchUrl()->toHtmlString();
$headIFrame .= <<
EOF;
}
$body = self::getBodyHtmlAndJavascript($codes, $useConsole);
$iframeSrcValue = <<Made by WebCode
$headIFrame
$body