| 1 | <?php |
| 2 | |
| 3 | namespace wcf\system\template\plugin; |
| 4 | |
| 5 | use wcf\system\exception\SystemException; |
| 6 | use wcf\system\request\RequestHandler; |
| 7 | use wcf\system\template\TemplateEngine; |
| 8 | use wcf\system\WCF; |
| 9 | use wcf\util\StringUtil; |
| 10 | |
| 11 | /** |
| 12 | * Template function plugin which generates script tags. File extension is automatically |
| 13 | * added to the script source and MUST NOT be provided. |
| 14 | * |
| 15 | * If ENABLE_DEBUG_MODE=0 then the extension is '.min.js', don't fail to provide it. |
| 16 | * |
| 17 | * The option VISITOR_USE_TINY_BUILD enables a specialized build, that is designed to |
| 18 | * provide smaller builds for visitors in order to decrease the overall payload and |
| 19 | * reduce page load time. Supporting them is optional and can be supplied by setting |
| 20 | * `hasTiny=true`, the extension is assumed to be `.tiny.min.js`. |
| 21 | * |
| 22 | * Usage: |
| 23 | * {js application='wbb' file='WBB'} |
| 24 | * http://example.com/js/WBB.js |
| 25 | * |
| 26 | * {js application='wcf' file='WCF.User' bundle='WCF.Combined'} |
| 27 | * http://example.com/wcf/js/WCF.User.js (ENABLE_DEBUG_MODE=1) |
| 28 | * http://example.com/wcf/js/WCF.Combined.min.js (ENABLE_DEBUG_MODE=0) |
| 29 | * |
| 30 | * {js application='wcf' lib='jquery'} |
| 31 | * http://example.com/wcf/js/3rdParty/jquery.js |
| 32 | * |
| 33 | * {js application='wcf' lib='jquery-ui' file='awesomeWidget'} |
| 34 | * http://example.com/wcf/js/3rdParty/jquery-ui/awesomeWidget.js |
| 35 | * |
| 36 | * {js application='wcf' file='WCF.User' bundle='WCF.Combined' hasTiny=true} |
| 37 | * http://example.com/wcf/js/WCF.User.js (ENABLE_DEBUG_MODE=1) |
| 38 | * http://example.com/wcf/js/WCF.Combined.min.js (ENABLE_DEBUG_MODE=0) |
| 39 | * http://example.com/wcf/js/WCF.Combined.tiny.min.js (ENABLE_DEBUG_MODE=0 && VISITOR_USE_TINY_BUILD=1) |
| 40 | * |
| 41 | * @author Alexander Ebert |
| 42 | * @copyright 2001-2019 WoltLab GmbH |
| 43 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
| 44 | * @since 3.0 |
| 45 | */ |
| 46 | class JsFunctionTemplatePlugin implements IFunctionTemplatePlugin |
| 47 | { |
| 48 | /** |
| 49 | * list of already included JavaScript files |
| 50 | * @var string[] |
| 51 | */ |
| 52 | protected $includedFiles = []; |
| 53 | |
| 54 | /** |
| 55 | * @inheritDoc |
| 56 | */ |
| 57 | public function execute($tagArgs, TemplateEngine $tplObj) |
| 58 | { |
| 59 | // needed arguments: application and lib/file |
| 60 | if (empty($tagArgs['application'])) { |
| 61 | throw new SystemException("missing 'application' argument in js tag"); |
| 62 | } |
| 63 | if (empty($tagArgs['file']) && empty($tagArgs['lib'])) { |
| 64 | throw new SystemException("missing 'file' or 'lib' argument in js tag"); |
| 65 | } |
| 66 | |
| 67 | $isJquery = false; |
| 68 | if ( |
| 69 | isset($tagArgs['lib']) |
| 70 | && ($tagArgs['lib'] === 'jquery' || $tagArgs['lib'] === 'jquery-ui') |
| 71 | && empty($tagArgs['file']) |
| 72 | ) { |
| 73 | $tagArgs['bundle'] = ''; |
| 74 | $isJquery = true; |
| 75 | } |
| 76 | |
| 77 | $src = WCF::getPath($tagArgs['application']) . (isset($tagArgs['acp']) && $tagArgs['acp'] === 'true' ? 'acp/' : '') . 'js/'; |
| 78 | if (!empty($tagArgs['bundle']) && !ENABLE_DEBUG_MODE) { |
| 79 | $src .= $tagArgs['bundle']; |
| 80 | } elseif (!empty($tagArgs['lib'])) { |
| 81 | if ($isJquery) { |
| 82 | $src .= ENABLE_DEBUG_MODE ? '3rdParty/' . $tagArgs['lib'] : 'WCF.Combined'; |
| 83 | } else { |
| 84 | $src .= '3rdParty/' . $tagArgs['lib']; |
| 85 | if (!empty($tagArgs['file'])) { |
| 86 | $src .= '/' . $tagArgs['file']; |
| 87 | } |
| 88 | } |
| 89 | } else { |
| 90 | $src .= $tagArgs['file']; |
| 91 | } |
| 92 | |
| 93 | if (isset($this->includedFiles[$src])) { |
| 94 | return ''; |
| 95 | } |
| 96 | |
| 97 | $this->includedFiles[$src] = true; |
| 98 | if (!ENABLE_DEBUG_MODE) { |
| 99 | if ( |
| 100 | \defined('VISITOR_USE_TINY_BUILD') |
| 101 | && VISITOR_USE_TINY_BUILD |
| 102 | && !WCF::getUser()->userID |
| 103 | && !empty($tagArgs['hasTiny']) |
| 104 | ) { |
| 105 | $src .= '.tiny'; |
| 106 | } |
| 107 | |
| 108 | $src .= '.min'; |
| 109 | } |
| 110 | $src .= '.js?v=' . LAST_UPDATE_TIME; |
| 111 | |
| 112 | $relocate = !RequestHandler::getInstance()->isACPRequest() && (!isset($tagArgs['core']) || $tagArgs['core'] !== 'true'); |
| 113 | $html = '<script' . ($relocate ? ' data-relocate="true"' : '') . ' data-cfasync="false" src="' . $src . '"></script>' . "\n"; |
| 114 | |
| 115 | if (isset($tagArgs['encodeJs']) && $tagArgs['encodeJs'] === 'true') { |
| 116 | $html = StringUtil::encodeJS($html); |
| 117 | } |
| 118 | |
| 119 | return $html; |
| 120 | } |
| 121 | } |