xref: /plugin/combo/syntax/webcode.php (revision 21913ab3235d516e2fa19c7e3929b555b3a2bda1)
15f891b7eSNickeau<?php
25f891b7eSNickeau/**
35f891b7eSNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved.
45f891b7eSNickeau *
55f891b7eSNickeau * This source code is licensed under the GPL license found in the
65f891b7eSNickeau * COPYING  file in the root directory of this source tree.
75f891b7eSNickeau *
85f891b7eSNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
95f891b7eSNickeau * @author   ComboStrap <support@combostrap.com>
105f891b7eSNickeau *
115f891b7eSNickeau */
125f891b7eSNickeau
135f891b7eSNickeau/**
145f891b7eSNickeau * Plugin Webcode: Show webcode (Css, HTML) in a iframe
155f891b7eSNickeau *
165f891b7eSNickeau */
175f891b7eSNickeau
185f891b7eSNickeau// must be run within Dokuwiki
195f891b7eSNickeauuse ComboStrap\LogUtility;
205f891b7eSNickeauuse ComboStrap\PluginUtility;
215f891b7eSNickeauuse ComboStrap\Tag;
22*21913ab3SNickeauuse ComboStrap\TagAttributes;
235f891b7eSNickeau
245f891b7eSNickeauif (!defined('DOKU_INC')) die();
255f891b7eSNickeau
265f891b7eSNickeau/**
275f891b7eSNickeau * Webcode
285f891b7eSNickeau */
295f891b7eSNickeauclass syntax_plugin_combo_webcode extends DokuWiki_Syntax_Plugin
305f891b7eSNickeau{
315f891b7eSNickeau
325f891b7eSNickeau    const EXTERNAL_RESOURCES_ATTRIBUTE_DISPLAY = 'externalResources'; // In the action bar
335f891b7eSNickeau    const EXTERNAL_RESOURCES_ATTRIBUTE_KEY = 'externalresources'; // In the code
345f891b7eSNickeau
355f891b7eSNickeau    // Simple cache bursting implementation for the webCodeConsole.(js|css) file
365f891b7eSNickeau    // They must be incremented manually when they changed
375f891b7eSNickeau    const WEB_CSS_VERSION = 1.1;
385f891b7eSNickeau    const WEB_CONSOLE_JS_VERSION = 2.1;
395f891b7eSNickeau
405f891b7eSNickeau    const TAG = 'webcode';
415f891b7eSNickeau
425f891b7eSNickeau    /**
435f891b7eSNickeau     * The tag that have codes
445f891b7eSNickeau     */
455f891b7eSNickeau    const CODE_TAGS = array("code", "plugin_combo_code");
465f891b7eSNickeau
475f891b7eSNickeau    /**
485f891b7eSNickeau     * The attribute names in the array
495f891b7eSNickeau     */
505f891b7eSNickeau    const CODES_ATTRIBUTE = "codes";
515f891b7eSNickeau    const USE_CONSOLE_ATTRIBUTE = "useConsole";
52*21913ab3SNickeau    const RENDERINGMODE_ATTRIBUTE = 'renderingmode';
53*21913ab3SNickeau    const RENDERING_ONLY_RESULT = "onlyresult";
545f891b7eSNickeau
555f891b7eSNickeau    /**
565f891b7eSNickeau     * @var array that holds the iframe attributes
575f891b7eSNickeau     */
585f891b7eSNickeau    private $attributes = array();
595f891b7eSNickeau
605f891b7eSNickeau
615f891b7eSNickeau    /**
625f891b7eSNickeau     * Syntax Type.
635f891b7eSNickeau     *
645f891b7eSNickeau     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
655f891b7eSNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
665f891b7eSNickeau     *
675f891b7eSNickeau     * container because it may contain header in case of how to
685f891b7eSNickeau     */
695f891b7eSNickeau    public function getType()
705f891b7eSNickeau    {
715f891b7eSNickeau        return 'container';
725f891b7eSNickeau    }
735f891b7eSNickeau
745f891b7eSNickeau    /**
755f891b7eSNickeau     * @return array
765f891b7eSNickeau     * Allow which kind of plugin inside
775f891b7eSNickeau     *
785f891b7eSNickeau     * array('container', 'baseonly','formatting', 'substition', 'protected', 'disabled', 'paragraphs')
795f891b7eSNickeau     *
805f891b7eSNickeau     */
815f891b7eSNickeau    public function getAllowedTypes()
825f891b7eSNickeau    {
835f891b7eSNickeau        return array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
845f891b7eSNickeau    }
855f891b7eSNickeau
865f891b7eSNickeau
875f891b7eSNickeau    public function accepts($mode)
885f891b7eSNickeau    {
89*21913ab3SNickeau
90*21913ab3SNickeau        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
91*21913ab3SNickeau
925f891b7eSNickeau    }
935f891b7eSNickeau
945f891b7eSNickeau    /**
955f891b7eSNickeau     * @see Doku_Parser_Mode::getSort()
965f891b7eSNickeau     * The mode (plugin) with the lowest sort number will win out
975f891b7eSNickeau     *
985f891b7eSNickeau     * See {@link Doku_Parser_Mode_code}
995f891b7eSNickeau     */
1005f891b7eSNickeau    public function getSort()
1015f891b7eSNickeau    {
1025f891b7eSNickeau        return 99;
1035f891b7eSNickeau    }
1045f891b7eSNickeau
1055f891b7eSNickeau    /**
1065f891b7eSNickeau     * Called before any calls to ConnectTo
1075f891b7eSNickeau     * @return void
1085f891b7eSNickeau     */
1095f891b7eSNickeau    function preConnect()
1105f891b7eSNickeau    {
1115f891b7eSNickeau    }
1125f891b7eSNickeau
1135f891b7eSNickeau    /**
1145f891b7eSNickeau     * Create a pattern that will called this plugin
1155f891b7eSNickeau     *
1165f891b7eSNickeau     * @param string $mode
1175f891b7eSNickeau     *
1185f891b7eSNickeau     * All dokuwiki mode can be seen in the parser.php file
1195f891b7eSNickeau     * @see Doku_Parser_Mode::connectTo()
1205f891b7eSNickeau     */
1215f891b7eSNickeau    public function connectTo($mode)
1225f891b7eSNickeau    {
1235f891b7eSNickeau
1245f891b7eSNickeau        $pattern = PluginUtility::getContainerTagPattern(self::TAG);
1255f891b7eSNickeau        $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeForComponent($this->getPluginComponent()));
1265f891b7eSNickeau
1275f891b7eSNickeau    }
1285f891b7eSNickeau
1295f891b7eSNickeau
1305f891b7eSNickeau    // This where the addPattern and addExitPattern are defined
1315f891b7eSNickeau    public function postConnect()
1325f891b7eSNickeau    {
1335f891b7eSNickeau        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeForComponent($this->getPluginComponent()));
1345f891b7eSNickeau    }
1355f891b7eSNickeau
1365f891b7eSNickeau
1375f891b7eSNickeau    /**
1385f891b7eSNickeau     * Handle the match
1395f891b7eSNickeau     * You get the match for each pattern in the $match variable
1405f891b7eSNickeau     * $state says if it's an entry, exit or match pattern
1415f891b7eSNickeau     *
1425f891b7eSNickeau     * This is an instruction block and is cached apart from the rendering output
1435f891b7eSNickeau     * There is two caches levels
1445f891b7eSNickeau     * This cache may be suppressed with the url parameters ?purge=true
1455f891b7eSNickeau     *
1465f891b7eSNickeau     * The returned values are cached in an array that will be passed to the render method
1475f891b7eSNickeau     * The handle function goal is to parse the matched syntax through the pattern function
1485f891b7eSNickeau     * and to return the result for use in the renderer
1495f891b7eSNickeau     * This result is always cached until the page is modified.
1505f891b7eSNickeau     * @param string $match
1515f891b7eSNickeau     * @param int $state
1525f891b7eSNickeau     * @param int $pos
1535f891b7eSNickeau     * @param Doku_Handler $handler
1545f891b7eSNickeau     * @return array|bool
1555f891b7eSNickeau     * @throws Exception
1565f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::handle()
1575f891b7eSNickeau     *
1585f891b7eSNickeau     */
1595f891b7eSNickeau    public function handle($match, $state, $pos, Doku_Handler $handler)
1605f891b7eSNickeau    {
1615f891b7eSNickeau        switch ($state) {
1625f891b7eSNickeau
1635f891b7eSNickeau            case DOKU_LEXER_ENTER :
1645f891b7eSNickeau
1655f891b7eSNickeau                // We got the first webcode tag and its attributes
1665f891b7eSNickeau
1675f891b7eSNickeau                $match = substr($match, 8, -1); //9 = strlen("<webcode")
1685f891b7eSNickeau
1695f891b7eSNickeau                // Reset of the attributes
1705f891b7eSNickeau                // With some framework the php object may be still persisted in memory
1715f891b7eSNickeau                // And you may get some attributes from other page
1725f891b7eSNickeau                $attributes = array();
1735f891b7eSNickeau                $attributes['frameborder'] = 1;
1745f891b7eSNickeau                $attributes['width'] = '100%';
1755f891b7eSNickeau
176*21913ab3SNickeau                $renderingModeKey = self::RENDERINGMODE_ATTRIBUTE;
1775f891b7eSNickeau                $attributes[$renderingModeKey] = 'story';
1785f891b7eSNickeau
1795f891b7eSNickeau                // config Parameters will get their value in lowercase
1805f891b7eSNickeau                $configAttributes = [$renderingModeKey];
1815f891b7eSNickeau
1825f891b7eSNickeau                // /i not case sensitive
1835f891b7eSNickeau                $attributePattern = "\s*(\w+)\s*=\s*\"?([^\"\s]+)\"?\\s*";
1845f891b7eSNickeau                $result = preg_match_all('/' . $attributePattern . '/i', $match, $matches);
1855f891b7eSNickeau
1865f891b7eSNickeau
1875f891b7eSNickeau                if ($result != 0) {
1885f891b7eSNickeau                    foreach ($matches[1] as $key => $lang) {
1895f891b7eSNickeau                        $attributeKey = strtolower($lang);
1905f891b7eSNickeau                        $attributeValue = $matches[2][$key];
1915f891b7eSNickeau                        if (in_array($attributeKey, $configAttributes)) {
1925f891b7eSNickeau                            $attributeValue = strtolower($attributeValue);
1935f891b7eSNickeau                        }
1945f891b7eSNickeau                        $attributes[$attributeKey] = $attributeValue;
1955f891b7eSNickeau                    }
1965f891b7eSNickeau                }
1975f891b7eSNickeau
1985f891b7eSNickeau                // We set the attributes on a class scope
1995f891b7eSNickeau                // to be used in the DOKU_LEXER_UNMATCHED step
2005f891b7eSNickeau                $this->attributes = $attributes;
2015f891b7eSNickeau
2025f891b7eSNickeau                // Cache the values to be used by the render method
2035f891b7eSNickeau                return array(
2045f891b7eSNickeau                    PluginUtility::STATE => $state,
2055f891b7eSNickeau                    PluginUtility::ATTRIBUTES => $attributes
2065f891b7eSNickeau                );
2075f891b7eSNickeau
2085f891b7eSNickeau
2095f891b7eSNickeau            case DOKU_LEXER_UNMATCHED :
2105f891b7eSNickeau
21132b85071SNickeau                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
21232b85071SNickeau
2135f891b7eSNickeau
2145f891b7eSNickeau            case DOKU_LEXER_EXIT:
2155f891b7eSNickeau
2165f891b7eSNickeau                /**
2175f891b7eSNickeau                 * Capture all codes
2185f891b7eSNickeau                 */
2195f891b7eSNickeau                $codes = array();
2205f891b7eSNickeau                /**
2215f891b7eSNickeau                 * Does the javascript contains a console statement
2225f891b7eSNickeau                 */
2235f891b7eSNickeau                $useConsole = false;
2245f891b7eSNickeau                $exitTag = new Tag(self::TAG, array(), $state, $handler);
2255f891b7eSNickeau                $openingTag = $exitTag->getOpeningTag();
226*21913ab3SNickeau                $renderingMode = strtolower($openingTag->getAttribute(self::RENDERINGMODE_ATTRIBUTE));
2275f891b7eSNickeau                if ($openingTag->hasDescendants()) {
2285f891b7eSNickeau                    $tags = $openingTag->getDescendants();
2295f891b7eSNickeau                    /**
2305f891b7eSNickeau                     * Mime and code content are in two differents
2315f891b7eSNickeau                     * tag. To be able to set the content to the good type
2325f891b7eSNickeau                     * we keep a trace of it
2335f891b7eSNickeau                     */
2345f891b7eSNickeau                    $actualCodeType = "";
2355f891b7eSNickeau                    foreach ($tags as $tag) {
2365f891b7eSNickeau                        if (in_array($tag->getName(), self::CODE_TAGS)) {
2375f891b7eSNickeau
238*21913ab3SNickeau                            /**
239*21913ab3SNickeau                             * Only rendering mode
240*21913ab3SNickeau                             * on all node (unmatched also)
241*21913ab3SNickeau                             */
242*21913ab3SNickeau                            if ($renderingMode == self::RENDERING_ONLY_RESULT) {
243*21913ab3SNickeau                                $tag->addAttribute(TagAttributes::DISPLAY, "none");
244*21913ab3SNickeau                            }
245*21913ab3SNickeau
2465f891b7eSNickeau                            if ($tag->getState() == DOKU_LEXER_ENTER) {
2475f891b7eSNickeau                                // Get the code (The content between the code nodes)
2485f891b7eSNickeau                                // We ltrim because the match gives us the \n at the beginning and at the end
2495f891b7eSNickeau                                $actualCodeType = strtolower(trim($tag->getType()));
2505f891b7eSNickeau
2515f891b7eSNickeau                                // Xml is html
2525f891b7eSNickeau                                if ($actualCodeType == 'xml') {
2535f891b7eSNickeau                                    $actualCodeType = 'html';
2545f891b7eSNickeau                                }
255*21913ab3SNickeau                                // The code for a language may be scattered in multiple block
2565f891b7eSNickeau                                if (!isset($codes[$actualCodeType])) {
2575f891b7eSNickeau                                    $codes[$actualCodeType] = "";
2585f891b7eSNickeau                                }
259*21913ab3SNickeau
2605f891b7eSNickeau                                continue;
2615f891b7eSNickeau                            }
2625f891b7eSNickeau
2635f891b7eSNickeau                            if ($tag->getState() == DOKU_LEXER_UNMATCHED) {
2645f891b7eSNickeau
2655f891b7eSNickeau                                $codeContent = $tag->getData()[PluginUtility::PAYLOAD];
2665f891b7eSNickeau
2675f891b7eSNickeau                                if (empty($actualCodeType)) {
2685f891b7eSNickeau                                    LogUtility::msg("The type of the code should not be null for the code content " . $codeContent, LogUtility::LVL_MSG_WARNING, self::TAG);
2695f891b7eSNickeau                                    continue;
2705f891b7eSNickeau                                }
2715f891b7eSNickeau
2725f891b7eSNickeau                                // Append it
2735f891b7eSNickeau                                $codes[$actualCodeType] = $codes[$actualCodeType] . $codeContent;
2745f891b7eSNickeau
2755f891b7eSNickeau                                // Check if a javascript console function is used, only if the flag is not set to true
2765f891b7eSNickeau                                if (!$useConsole == true) {
2775f891b7eSNickeau                                    if (in_array($actualCodeType, array('babel', 'javascript', 'html', 'xml'))) {
2785f891b7eSNickeau                                        // if the code contains 'console.'
2795f891b7eSNickeau                                        $result = preg_match('/' . 'console\.' . '/is', $codeContent);
2805f891b7eSNickeau                                        if ($result) {
2815f891b7eSNickeau                                            $useConsole = true;
2825f891b7eSNickeau                                        }
2835f891b7eSNickeau                                    }
2845f891b7eSNickeau                                }
2855f891b7eSNickeau                                // Reset
2865f891b7eSNickeau                                $actualCodeType = "";
2875f891b7eSNickeau                            }
2885f891b7eSNickeau                        }
2895f891b7eSNickeau                    }
2905f891b7eSNickeau                }
291*21913ab3SNickeau//                if(isset($codes["dw"])){
292*21913ab3SNickeau//                    // http://php.net/manual/en/function.stream-context-create.php
293*21913ab3SNickeau//                    $dw = $codes["dw"];
294*21913ab3SNickeau//
295*21913ab3SNickeau//                    $url = Site::getAjaxUrl();
296*21913ab3SNickeau//                    $data = array(
297*21913ab3SNickeau//                        action_plugin_combo_webcode::DW_PARAM => $dw,
298*21913ab3SNickeau//                        action_plugin_combo_webcode::CALL_PARAM => action_plugin_combo_webcode::CALL_ID
299*21913ab3SNickeau//                    );
300*21913ab3SNickeau//
301*21913ab3SNickeau//                    // use key 'http' even if you send the request to https://...
302*21913ab3SNickeau//                    $options = array(
303*21913ab3SNickeau//                        'http' => array(
304*21913ab3SNickeau//                            'method'  => 'POST',
305*21913ab3SNickeau//                            'content' => http_build_query($data)
306*21913ab3SNickeau//                        )
307*21913ab3SNickeau//                    );
308*21913ab3SNickeau//                    $context  = stream_context_create($options);
309*21913ab3SNickeau//                    $result = file_get_contents($url, false, $context);
310*21913ab3SNickeau//                    if ($result === FALSE) { /* Handle error */ }
311*21913ab3SNickeau//
312*21913ab3SNickeau//                }
3135f891b7eSNickeau                return array(
3145f891b7eSNickeau                    PluginUtility::STATE => $state,
3155f891b7eSNickeau                    self::CODES_ATTRIBUTE => $codes,
3165f891b7eSNickeau                    self::USE_CONSOLE_ATTRIBUTE => $useConsole
3175f891b7eSNickeau                );
3185f891b7eSNickeau
3195f891b7eSNickeau        }
3205f891b7eSNickeau        return false;
3215f891b7eSNickeau
3225f891b7eSNickeau    }
3235f891b7eSNickeau
3245f891b7eSNickeau    /**
3255f891b7eSNickeau     * Render the output
3265f891b7eSNickeau     * @param string $mode
3275f891b7eSNickeau     * @param Doku_Renderer $renderer
3285f891b7eSNickeau     * @param array $data - what the function handle() return'ed
3295f891b7eSNickeau     * @return bool - rendered correctly (not used)
3305f891b7eSNickeau     *
3315f891b7eSNickeau     * The rendering process
3325f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::render()
3335f891b7eSNickeau     *
3345f891b7eSNickeau     */
3355f891b7eSNickeau    public function render($mode, Doku_Renderer $renderer, $data)
3365f891b7eSNickeau    {
3375f891b7eSNickeau        // The $data variable comes from the handle() function
3385f891b7eSNickeau        //
3395f891b7eSNickeau        // $mode = 'xhtml' means that we output html
3405f891b7eSNickeau        // There is other mode such as metadata where you can output data for the headers (Not 100% sure)
3415f891b7eSNickeau        if ($mode == 'xhtml') {
3425f891b7eSNickeau
3435f891b7eSNickeau
3445f891b7eSNickeau            /** @var Doku_Renderer_xhtml $renderer */
3455f891b7eSNickeau
3465f891b7eSNickeau            $state = $data[PluginUtility::STATE];
3475f891b7eSNickeau            switch ($state) {
3485f891b7eSNickeau
3495f891b7eSNickeau                case DOKU_LEXER_ENTER :
3505f891b7eSNickeau
3518aa9d0e6Sgerardnico                    PluginUtility::getSnippetManager()->upsertJavascriptForBar(self::TAG);
3525f891b7eSNickeau
3535f891b7eSNickeau                    // The extracted data are the attribute of the webcode tag
3545f891b7eSNickeau                    // We put in a class variable so that we can use in the last step (DOKU_LEXER_EXIT)
3555f891b7eSNickeau                    $this->attributes = $data[PluginUtility::ATTRIBUTES];
3565f891b7eSNickeau
3575f891b7eSNickeau                    break;
3585f891b7eSNickeau
3595f891b7eSNickeau                case DOKU_LEXER_UNMATCHED :
3605f891b7eSNickeau
36132b85071SNickeau                    $renderer->doc .= PluginUtility::renderUnmatched($data);
3625f891b7eSNickeau                    break;
3635f891b7eSNickeau
3645f891b7eSNickeau                case DOKU_LEXER_EXIT :
3655f891b7eSNickeau                    $codes = $data[self::CODES_ATTRIBUTE];
3665f891b7eSNickeau                    // Create the real output of webcode
3675f891b7eSNickeau                    if (sizeof($codes) == 0) {
3685f891b7eSNickeau                        return false;
3695f891b7eSNickeau                    }
3705f891b7eSNickeau
3718aa9d0e6Sgerardnico                    PluginUtility::getSnippetManager()->upsertCssSnippetForBar(self::TAG);
3725f891b7eSNickeau
3735f891b7eSNickeau                    // Dokuwiki Code ?
3745f891b7eSNickeau                    if (array_key_exists('dw', $codes)) {
3755f891b7eSNickeau
3765f891b7eSNickeau                        $renderer->doc .= PluginUtility::render($codes['dw']);
3775f891b7eSNickeau
3785f891b7eSNickeau                    } else {
3795f891b7eSNickeau
3805f891b7eSNickeau
3815f891b7eSNickeau                        // Js, Html, Css
3825f891b7eSNickeau                        $iframeHtml = '<html><head>';
3835f891b7eSNickeau                        $iframeHtml .= '<meta http-equiv="content-type" content="text/html; charset=UTF-8">';
3845f891b7eSNickeau                        $iframeHtml .= '<title>Made by Webcode</title>';
3855f891b7eSNickeau                        $iframeHtml .= '<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">';
3865f891b7eSNickeau
3875f891b7eSNickeau
3885f891b7eSNickeau                        // External Resources such as css stylesheet or js
3895f891b7eSNickeau                        $externalResources = array();
3905f891b7eSNickeau                        if (array_key_exists(self::EXTERNAL_RESOURCES_ATTRIBUTE_KEY, $this->attributes)) {
3915f891b7eSNickeau                            $externalResources = explode(",", $this->attributes[self::EXTERNAL_RESOURCES_ATTRIBUTE_KEY]);
3925f891b7eSNickeau                        }
3935f891b7eSNickeau
3945f891b7eSNickeau                        // Babel Preprocessor, if babel is used, add it to the external resources
3955f891b7eSNickeau                        if (array_key_exists('babel', $codes)) {
3965f891b7eSNickeau                            $babelMin = "https://unpkg.com/babel-standalone@6/babel.min.js";
3975f891b7eSNickeau                            // a load of babel invoke it (be sure to not have it twice
3985f891b7eSNickeau                            if (!(array_key_exists($babelMin, $externalResources))) {
3995f891b7eSNickeau                                $externalResources[] = $babelMin;
4005f891b7eSNickeau                            }
4015f891b7eSNickeau                        }
4025f891b7eSNickeau
4035f891b7eSNickeau                        // Add the external resources
4045f891b7eSNickeau                        foreach ($externalResources as $externalResource) {
4055f891b7eSNickeau                            $pathInfo = pathinfo($externalResource);
4065f891b7eSNickeau                            $fileExtension = $pathInfo['extension'];
4075f891b7eSNickeau                            switch ($fileExtension) {
4085f891b7eSNickeau                                case 'css':
4095f891b7eSNickeau                                    $iframeHtml .= '<link rel="stylesheet" type="text/css" href="' . $externalResource . '">';
4105f891b7eSNickeau                                    break;
4115f891b7eSNickeau                                case 'js':
4125f891b7eSNickeau                                    $iframeHtml .= '<script type="text/javascript" src="' . $externalResource . '"></script>';
4135f891b7eSNickeau                                    break;
4145f891b7eSNickeau                            }
4155f891b7eSNickeau                        }
4165f891b7eSNickeau
4175f891b7eSNickeau
4185f891b7eSNickeau                        // WebConsole style sheet
4195f891b7eSNickeau                        $iframeHtml .= '<link rel="stylesheet" type="text/css" href="' . PluginUtility::getResourceBaseUrl() . '/webcode/webcode-iframe.css?ver=' . self::WEB_CSS_VERSION . '"/>';
4205f891b7eSNickeau
421*21913ab3SNickeau                        // A little margin to make it neater
422*21913ab3SNickeau                        // that can be overwritten via cascade
423*21913ab3SNickeau                        $iframeHtml .= '<style>body { margin:10px } /* default margin */</style>';
424*21913ab3SNickeau
425*21913ab3SNickeau                        // The css
4265f891b7eSNickeau                        if (array_key_exists('css', $codes)) {
4275f891b7eSNickeau                            $iframeHtml .= '<!-- The CSS code -->';
4285f891b7eSNickeau                            $iframeHtml .= '<style>' . $codes['css'] . '</style>';
4295f891b7eSNickeau                        };
430*21913ab3SNickeau                        $iframeHtml .= '</head><body>';
4315f891b7eSNickeau                        if (array_key_exists('html', $codes)) {
4325f891b7eSNickeau                            $iframeHtml .= '<!-- The HTML code -->';
4335f891b7eSNickeau                            $iframeHtml .= $codes['html'];
4345f891b7eSNickeau                        }
4355f891b7eSNickeau                        // The javascript console area is based at the end of the HTML document
4365f891b7eSNickeau                        $useConsole = $data[self::USE_CONSOLE_ATTRIBUTE];
4375f891b7eSNickeau                        if ($useConsole) {
4385f891b7eSNickeau                            $iframeHtml .= '<!-- WebCode Console -->';
4395f891b7eSNickeau                            $iframeHtml .= '<div><p class=\'webConsoleTitle\'>Console Output:</p>';
4405f891b7eSNickeau                            $iframeHtml .= '<div id=\'webCodeConsole\'></div>';
4415f891b7eSNickeau                            $iframeHtml .= '<script type=\'text/javascript\' src=\'' . PluginUtility::getResourceBaseUrl() . '/webcode/webcode-console.js?ver=' . self::WEB_CONSOLE_JS_VERSION . '\'></script>';
4425f891b7eSNickeau                            $iframeHtml .= '</div>';
4435f891b7eSNickeau                        }
4445f891b7eSNickeau                        // The javascript comes at the end because it may want to be applied on previous HTML element
4455f891b7eSNickeau                        // as the page load in the IO order, javascript must be placed at the end
4465f891b7eSNickeau                        if (array_key_exists('javascript', $codes)) {
4475f891b7eSNickeau                            $iframeHtml .= '<!-- The Javascript code -->';
4485f891b7eSNickeau                            $iframeHtml .= '<script type="text/javascript">' . $codes['javascript'] . '</script>';
4495f891b7eSNickeau                        }
4505f891b7eSNickeau                        if (array_key_exists('babel', $codes)) {
4515f891b7eSNickeau                            $iframeHtml .= '<!-- The Babel code -->';
4525f891b7eSNickeau                            $iframeHtml .= '<script type="text/babel">' . $codes['babel'] . '</script>';
4535f891b7eSNickeau                        }
4545f891b7eSNickeau                        $iframeHtml .= '</body></html>';
4555f891b7eSNickeau
4565f891b7eSNickeau                        // Here the magic from the plugin happens
4575f891b7eSNickeau                        // We add the Iframe and the JsFiddleButton
4585f891b7eSNickeau                        $iFrameHtml = '<iframe ';
4595f891b7eSNickeau
4605f891b7eSNickeau                        // We add the name HTML attribute
4615f891b7eSNickeau                        $name = "WebCode iFrame";
4625f891b7eSNickeau                        if (array_key_exists('name', $this->attributes)) {
4635f891b7eSNickeau                            $name .= ' ' . $this->attributes['name'];
4645f891b7eSNickeau                        }
4655f891b7eSNickeau                        $iFrameHtml .= ' name="' . $name . '" ';
4665f891b7eSNickeau
4675f891b7eSNickeau                        // The class to be able to select them
4685f891b7eSNickeau                        $iFrameHtml .= ' class="webCode" ';
4695f891b7eSNickeau
4705f891b7eSNickeau                        // We add the others HTML attributes
4715f891b7eSNickeau                        $iFrameHtmlAttributes = array('width', 'height', 'frameborder', 'scrolling');
4725f891b7eSNickeau                        foreach ($this->attributes as $attribute => $value) {
4735f891b7eSNickeau                            if (in_array($attribute, $iFrameHtmlAttributes)) {
4745f891b7eSNickeau                                $iFrameHtml .= ' ' . $attribute . '=' . $value;
4755f891b7eSNickeau                            }
4765f891b7eSNickeau                        }
4775f891b7eSNickeau                        $iFrameHtml .= ' srcdoc="' . htmlentities($iframeHtml) . '" ></iframe>';//
4785f891b7eSNickeau
4795f891b7eSNickeau                        // Credits bar
4805f891b7eSNickeau                        $bar = '<div class="webcode-bar">';
4815f891b7eSNickeau                        $bar .= '<div class="webcode-bar-item">' . PluginUtility::getUrl(self::TAG, "Rendered by Webcode", false) . '</div>';
4825f891b7eSNickeau                        $bar .= '<div class="webcode-bar-item">' . $this->addJsFiddleButton($codes, $this->attributes) . '</div>';
4835f891b7eSNickeau                        $bar .= '</div>';
4845f891b7eSNickeau                        $renderer->doc .= '<div class="webcode">' . $iFrameHtml . $bar . '</div>';
4855f891b7eSNickeau                    }
4865f891b7eSNickeau
4875f891b7eSNickeau                    break;
4885f891b7eSNickeau            }
4895f891b7eSNickeau
4905f891b7eSNickeau            return true;
4915f891b7eSNickeau        }
4925f891b7eSNickeau        return false;
4935f891b7eSNickeau    }
4945f891b7eSNickeau
4955f891b7eSNickeau    /**
4965f891b7eSNickeau     * @param array $codes the array containing the codes
4975f891b7eSNickeau     * @param array $attributes the attributes of a call (for now the externalResources)
4985f891b7eSNickeau     * @return string the HTML form code
4995f891b7eSNickeau     *
5005f891b7eSNickeau     * Specification, see http://doc.jsfiddle.net/api/post.html
5015f891b7eSNickeau     */
5025f891b7eSNickeau    public function addJsFiddleButton($codes, $attributes)
5035f891b7eSNickeau    {
5045f891b7eSNickeau
5055f891b7eSNickeau        $postURL = "https://jsfiddle.net/api/post/library/pure/"; //No Framework
5065f891b7eSNickeau
5075f891b7eSNickeau        $externalResources = array();
5085f891b7eSNickeau        if (array_key_exists(self::EXTERNAL_RESOURCES_ATTRIBUTE_KEY, $attributes)) {
5095f891b7eSNickeau            $externalResources = explode(",", $attributes[self::EXTERNAL_RESOURCES_ATTRIBUTE_KEY]);
5105f891b7eSNickeau        }
5115f891b7eSNickeau
5125f891b7eSNickeau
5135f891b7eSNickeau        if ($this->useConsole) {
5145f891b7eSNickeau            // If their is a console.log function, add the Firebug Lite support of JsFiddle
5155f891b7eSNickeau            // Seems to work only with the Edge version of jQuery
5165f891b7eSNickeau            // $postURL .= "edge/dependencies/Lite/";
5175f891b7eSNickeau            // The firebug logging is not working anymore because of 404
5185f891b7eSNickeau            // Adding them here
5195f891b7eSNickeau            $externalResources[] = 'The firebug resources for the console.log features';
5205f891b7eSNickeau            $externalResources[] = PluginUtility::getResourceBaseUrl() . '/firebug/firebug-lite.css';
5215f891b7eSNickeau            $externalResources[] = PluginUtility::getResourceBaseUrl() . '/firebug/firebug-lite-1.2.js';
5225f891b7eSNickeau        }
5235f891b7eSNickeau
5245f891b7eSNickeau        // The below code is to prevent this JsFiddle bug: https://github.com/jsfiddle/jsfiddle-issues/issues/726
5255f891b7eSNickeau        // The order of the resources is not guaranteed
5265f891b7eSNickeau        // We pass then the resources only if their is one resources
5275f891b7eSNickeau        // Otherwise we pass them as a script element in the HTML.
5285f891b7eSNickeau        if (count($externalResources) <= 1) {
5295f891b7eSNickeau            $externalResourcesInput = '<input type="hidden" name="resources" value="' . implode(",", $externalResources) . '">';
5305f891b7eSNickeau        } else {
5315f891b7eSNickeau            $codes['html'] .= "\n\n\n\n\n<!-- The resources -->\n";
5325f891b7eSNickeau            $codes['html'] .= "<!-- They have been added here because their order is not guarantee through the API. -->\n";
5335f891b7eSNickeau            $codes['html'] .= "<!-- See: https://github.com/jsfiddle/jsfiddle-issues/issues/726 -->\n";
5345f891b7eSNickeau            foreach ($externalResources as $externalResource) {
5355f891b7eSNickeau                if ($externalResource != "") {
5365f891b7eSNickeau                    $extension = pathinfo($externalResource)['extension'];
5375f891b7eSNickeau                    switch ($extension) {
5385f891b7eSNickeau                        case "css":
5395f891b7eSNickeau                            $codes['html'] .= "<link href=\"" . $externalResource . "\" rel=\"stylesheet\">\n";
5405f891b7eSNickeau                            break;
5415f891b7eSNickeau                        case "js":
5425f891b7eSNickeau                            $codes['html'] .= "<script src=\"" . $externalResource . "\"></script>\n";
5435f891b7eSNickeau                            break;
5445f891b7eSNickeau                        default:
5455f891b7eSNickeau                            $codes['html'] .= "<!-- " . $externalResource . " -->\n";
5465f891b7eSNickeau                    }
5475f891b7eSNickeau                }
5485f891b7eSNickeau            }
5495f891b7eSNickeau        }
5505f891b7eSNickeau
5515f891b7eSNickeau        $jsCode = $codes['javascript'];
5525f891b7eSNickeau        $jsPanel = 0; // language for the js specific panel (0 = JavaScript)
5535f891b7eSNickeau        if (array_key_exists('babel', $codes)) {
5545f891b7eSNickeau            $jsCode = $codes['babel'];
5555f891b7eSNickeau            $jsPanel = 3; // 3 = Babel
5565f891b7eSNickeau        }
5575f891b7eSNickeau
5585f891b7eSNickeau        // Title and description
5595f891b7eSNickeau        global $ID;
5605f891b7eSNickeau        $title = $attributes['name'];
5615f891b7eSNickeau        $pageTitle = tpl_pagetitle($ID, true);
5625f891b7eSNickeau        if (!$title) {
5635f891b7eSNickeau
5645f891b7eSNickeau            $title = "Code from " . $pageTitle;
5655f891b7eSNickeau        }
5665f891b7eSNickeau        $description = "Code from the page '" . $pageTitle . "' \n" . wl($ID, $absolute = true);
5675f891b7eSNickeau        return '<form  method="post" action="' . $postURL . '" target="_blank">' .
5685f891b7eSNickeau            '<input type="hidden" name="title" value="' . htmlentities($title) . '">' .
5695f891b7eSNickeau            '<input type="hidden" name="description" value="' . htmlentities($description) . '">' .
5705f891b7eSNickeau            '<input type="hidden" name="css" value="' . htmlentities($codes['css']) . '">' .
5715f891b7eSNickeau            '<input type="hidden" name="html" value="' . htmlentities("<!-- The HTML -->" . $codes['html']) . '">' .
5725f891b7eSNickeau            '<input type="hidden" name="js" value="' . htmlentities($jsCode) . '">' .
5735f891b7eSNickeau            '<input type="hidden" name="panel_js" value="' . htmlentities($jsPanel) . '">' .
5745f891b7eSNickeau            '<input type="hidden" name="wrap" value="b">' .  //javascript no wrap in body
5755f891b7eSNickeau            $externalResourcesInput .
5765f891b7eSNickeau            '<button>Try the code</button>' .
5775f891b7eSNickeau            '</form>';
5785f891b7eSNickeau
5795f891b7eSNickeau    }
5805f891b7eSNickeau
5815f891b7eSNickeau    /**
5825f891b7eSNickeau     * @param $codes the array containing the codes
5835f891b7eSNickeau     * @param $attributes the attributes of a call (for now the externalResources)
5845f891b7eSNickeau     * @return string the HTML form code
5855f891b7eSNickeau     */
5865f891b7eSNickeau    public function addCodePenButton($codes, $attributes)
5875f891b7eSNickeau    {
5885f891b7eSNickeau        // TODO
5895f891b7eSNickeau        // http://blog.codepen.io/documentation/api/prefill/
5905f891b7eSNickeau    }
5915f891b7eSNickeau
5925f891b7eSNickeau
5935f891b7eSNickeau}
594