/** * Rendering the cObject, QTOBJECT * * @param array $conf Array of TypoScript properties * @return string Output */ public function render($conf = array()) { $params = $prefix = ''; if ($GLOBALS['TSFE']->baseUrl) { $prefix = $GLOBALS['TSFE']->baseUrl; } if ($GLOBALS['TSFE']->absRefPrefix) { $prefix = $GLOBALS['TSFE']->absRefPrefix; } $type = isset($conf['type.']) ? $this->cObj->stdWrap($conf['type'], $conf['type.']) : $conf['type']; // If file is audio and an explicit path has not been set, // take path from audio fallback property if ($type == 'audio' && empty($conf['file'])) { $conf['file'] = $conf['audioFallback']; } $filename = isset($conf['file.']) ? $this->cObj->stdWrap($conf['file'], $conf['file.']) : $conf['file']; $typeConf = $conf[$type . '.']; // Add QTobject js-file $GLOBALS['TSFE']->getPageRenderer()->addJsFile($this->getPathToLibrary('flashmedia/qtobject/qtobject.js')); $replaceElementIdString = str_replace('.', '', uniqid('mmqt', TRUE)); $GLOBALS['TSFE']->register['MMQTID'] = $replaceElementIdString; $qtObject = 'QTObject' . $replaceElementIdString; // Merge with default parameters $conf['params.'] = array_merge((array) $typeConf['default.']['params.'], (array) $conf['params.']); if (is_array($conf['params.']) && is_array($typeConf['mapping.']['params.'])) { ArrayUtility::remapArrayKeys($conf['params.'], $typeConf['mapping.']['params.']); foreach ($conf['params.'] as $key => $value) { $params .= $qtObject . '.addParam("' . $key . '", "' . $value . '");' . LF; } } $params = ($params ? substr($params, 0, -2) : '') . LF . $qtObject . '.write("' . $replaceElementIdString . '");'; $alternativeContent = isset($conf['alternativeContent.']) ? $this->cObj->stdWrap($conf['alternativeContent'], $conf['alternativeContent.']) : $conf['alternativeContent']; $layout = str_replace(array('###ID###', '###QTOBJECT###'), array($replaceElementIdString, '<div id="' . $replaceElementIdString . '">' . $alternativeContent . '</div>'), isset($conf['layout.']) ? $this->cObj->stdWrap($conf['layout'], $conf['layout.']) : $conf['layout']); $width = isset($conf['width.']) ? $this->cObj->stdWrap($conf['width'], $conf['width.']) : $conf['width']; if (!$width) { $width = $conf[$type . '.']['defaultWidth']; } $height = isset($conf['height.']) ? $this->cObj->stdWrap($conf['height'], $conf['height.']) : $conf['height']; if (!$height) { $height = $conf[$type . '.']['defaultHeight']; } $fullFilename = $filename; // If the file name doesn't contain a scheme, prefix with appropriate data if (strpos($filename, '://') === FALSE && !empty($prefix)) { $fullFilename = $prefix . $filename; } $embed = 'var ' . $qtObject . ' = new QTObject("' . $fullFilename . '", "' . $replaceElementIdString . '", "' . $width . '", "' . $height . '");'; $content = $layout . ' <script type="text/javascript"> ' . $embed . ' ' . $params . ' </script>'; if (isset($conf['stdWrap.'])) { $content = $this->cObj->stdWrap($content, $conf['stdWrap.']); } return $content; }
/** * Rendering the cObject, SWFOBJECT * * @param array $conf Array of TypoScript properties * @return string Output */ public function render($conf = array()) { /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */ $pageRenderer = $GLOBALS['TSFE']->getPageRenderer(); $params = $prefix = ''; if ($GLOBALS['TSFE']->baseUrl) { $prefix = $GLOBALS['TSFE']->baseUrl; } if ($GLOBALS['TSFE']->absRefPrefix) { $prefix = $GLOBALS['TSFE']->absRefPrefix; } // Initialize content $replaceElementIdString = str_replace('.', '', uniqid('mmswf', TRUE)); $GLOBALS['TSFE']->register['MMSWFID'] = $replaceElementIdString; $layout = isset($conf['layout.']) ? $this->cObj->stdWrap($conf['layout'], $conf['layout.']) : $conf['layout']; $content = str_replace('###ID###', $replaceElementIdString, $layout); $type = isset($conf['type.']) ? $this->cObj->stdWrap($conf['type'], $conf['type.']) : $conf['type']; $typeConf = $conf[$type . '.']; // Add Flowplayer js-file $pageRenderer->addJsFile($this->getPathToLibrary('flowplayer/flowplayer-3.2.13.min.js')); // Add Flowpayer css for exprss install $pageRenderer->addCssFile($this->getPathToLibrary('flowplayer/express-install/express-install.css')); // Add videoJS js-file $pageRenderer->addJsFile($this->getPathToLibrary('videojs/video-js/video.js')); // Add videoJS css-file $pageRenderer->addCssFile($this->getPathToLibrary('videojs/video-js/video-js.css')); // Add extended videoJS control bar $pageRenderer->addJsFile($this->getPathToLibrary('videojs/video-js/controls/control-bar.js')); $pageRenderer->addCssFile($this->getPathToLibrary('videojs/video-js/controls/control-bar.css')); // Build Flash configuration $player = isset($typeConf['player.']) ? $this->cObj->stdWrap($typeConf['player'], $typeConf['player.']) : $typeConf['player']; if (!$player) { $player = $prefix . $this->getPathToLibrary('flowplayer/flowplayer-3.2.18.swf'); } elseif (strpos($player, 'EXT:') === 0) { $player = $prefix . $GLOBALS['TSFE']->tmpl->getFileName($player); } $installUrl = isset($conf['installUrl.']) ? $this->cObj->stdWrap($conf['installUrl'], $conf['installUrl.']) : $conf['installUrl']; if (!$installUrl) { $installUrl = $prefix . $this->getPathToLibrary('flowplayer/expressinstall.swf'); } elseif (strpos($installUrl, 'EXT:') === 0) { $installUrl = $prefix . $GLOBALS['TSFE']->tmpl->getFileName($installUrl); } $flashVersion = isset($conf['flashVersion.']) ? $this->cObj->stdWrap($conf['flashVersion'], $conf['flashVersion.']) : $conf['flashVersion']; if (!$flashVersion) { $flashVersion = array(9, 115); } $flashConfiguration = array('src' => $player, 'expressInstall' => $installUrl, 'version' => $flashVersion, 'onFail' => '###ONFAIL###'); $flashDownloadUrl = 'http://www.adobe.com/go/getflashplayer'; $onFail = 'function() { if (!(flashembed.getVersion()[0] > 0)) { var message = "<p>" + "' . $GLOBALS['TSFE']->sL('LLL:EXT:cms/locallang_ttc.xlf:media.needFlashPlugin') . '" + "</p>" + "<p>" + "<a href=\\"' . $flashDownloadUrl . '\\">' . $GLOBALS['TSFE']->sL('LLL:EXT:cms/locallang_ttc.xlf:media.downloadFlash') . '</a>" + "</p>"; document.getElementById("' . $replaceElementIdString . '_flash_install_info").innerHTML = "<div class=\\"message\\">" + message + "</div>"; } }'; $flashConfiguration = json_encode($flashConfiguration); $flashConfiguration = str_replace('"###ONFAIL###"', $onFail, $flashConfiguration); $filename = isset($conf['file.']) ? $this->cObj->stdWrap($conf['file'], $conf['file.']) : $conf['file']; if ($filename) { if (strpos($filename, '://') !== FALSE) { $conf['flashvars.']['url'] = $filename; } else { if ($prefix) { $conf['flashvars.']['url'] = $prefix . $filename; } else { $conf['flashvars.']['url'] = str_repeat('../', substr_count($player, '/')) . $filename; } } } if (is_array($conf['sources'])) { foreach ($conf['sources'] as $key => $source) { if (strpos($source, '://') === FALSE) { $conf['sources'][$key] = $prefix . $source; } } } if (is_array($conf['audioSources'])) { foreach ($conf['audioSources'] as $key => $source) { if (strpos($source, '://') === FALSE) { $conf['audioSources'][$key] = $prefix . $source; } } } if (isset($conf['audioFallback']) && strpos($conf['audioFallback'], '://') === FALSE) { $conf['audioFallback'] = $prefix . $conf['audioFallback']; } if (isset($conf['caption']) && strpos($conf['caption'], '://') === FALSE) { $conf['caption'] = $prefix . $conf['caption']; } // Write calculated values in conf for the hook $conf['player'] = $player ?: $filename; $conf['installUrl'] = $installUrl; $conf['filename'] = $conf['flashvars.']['url']; $conf['prefix'] = $prefix; // merge with default parameters $conf['flashvars.'] = array_merge((array) $typeConf['default.']['flashvars.'], (array) $conf['flashvars.']); $conf['params.'] = array_merge((array) $typeConf['default.']['params.'], (array) $conf['params.']); $conf['attributes.'] = array_merge((array) $typeConf['default.']['attributes.'], (array) $conf['attributes.']); $conf['embedParams'] = 'flashvars, params, attributes'; // Hook for manipulating the conf array, it's needed for some players like flowplayer if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'] as $classRef) { \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($classRef, $conf, $this); } } // Flowplayer config $flowplayerVideoConfig = array(); $flowplayerAudioConfig = array(); if (is_array($conf['flashvars.']) && is_array($typeConf['mapping.']['flashvars.'])) { ArrayUtility::remapArrayKeys($conf['flashvars.'], $typeConf['mapping.']['flashvars.']); } else { $conf['flashvars.'] = array(); } $conf['videoflashvars'] = $conf['flashvars.']; $conf['audioflashvars'] = $conf['flashvars.']; $conf['audioflashvars']['url'] = $conf['audioFallback']; // Render video sources $videoSources = ''; if (is_array($conf['sources'])) { foreach ($conf['sources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video']; $videoSources .= '<source src="' . $source . '"' . ($mimeType ? ' type="' . $mimeType . '"' : '') . ' />' . LF; } } // Render audio sources $audioSources = ''; if (is_array($conf['audioSources'])) { foreach ($conf['audioSources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio']; $audioSources .= '<source src="' . $source . '"' . ($mimeType ? ' type="' . $mimeType . '"' : '') . ' />' . LF; } } // Configure captions if ($conf['type'] === 'video' && isset($conf['caption'])) { // Assemble captions track tag $videoCaptions = '<track id="' . $replaceElementIdString . '_captions_track" kind="captions" src="' . $conf['caption'] . '" default>' . LF; // Add videoJS extension for captions $pageRenderer->addJsFile($this->getPathToLibrary('videojs/video-js/controls/captions.js')); // Flowplayer captions $conf['videoflashvars']['captionUrl'] = $conf['caption']; // Flowplayer captions plugin configuration $flowplayerVideoConfig = array_merge_recursive($flowplayerVideoConfig, $this->flowplayerCaptionsConfig); } // Configure flowplayer audio fallback if (isset($conf['audioFallback'])) { $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, $this->flowplayerAudioConfig); } // Configure audio description if ($conf['type'] == 'video') { if (is_array($conf['audioSources']) && count($conf['audioSources'])) { // Add videoJS audio description toggle $pageRenderer->addJsFile($this->getPathToLibrary('videojs/video-js/controls/audio-description.js')); } if (isset($conf['audioFallback'])) { // Audio description flowplayer config (remove controls) $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, $this->flowplayerAudioDescriptionConfig); } } // Assemble Flowplayer configuration if (count($conf['videoflashvars'])) { $flowplayerVideoConfig = array_merge_recursive($flowplayerVideoConfig, array('clip' => $conf['videoflashvars'])); } $flowplayerVideoJsonConfig = str_replace(array('"true"', '"false"'), array('true', 'false'), json_encode($flowplayerVideoConfig)); if (count($conf['audioflashvars'])) { $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, array('clip' => $conf['audioflashvars'])); } $flowplayerAudioJsonConfig = str_replace(array('"true"', '"false"'), array('true', 'false'), json_encode($flowplayerAudioConfig)); // Assemble param tags (required?) if (is_array($conf['params.']) && is_array($typeConf['mapping.']['params.'])) { ArrayUtility::remapArrayKeys($conf['params.'], $typeConf['mapping.']['params.']); } $videoFlashParams = ''; if (is_array($conf['params.'])) { foreach ($conf['params.'] as $name => $value) { $videoFlashParams .= '<param name="' . $name . '" value="' . $value . '" />' . LF; } } $audioFlashParams = $videoFlashParams; // Required param tags $videoFlashParams .= '<param name="movie" value="' . $player . '" />' . LF; $videoFlashParams .= '<param name="flashvars" value=\'config=' . $flowplayerVideoJsonConfig . '\' />' . LF; $audioFlashParams .= '<param name="movie" value="' . $player . '" />' . LF; $audioFlashParams .= '<param name="flashvars" value=\'config=' . $flowplayerAudioJsonConfig . '\' />' . LF; // Assemble audio/video tag attributes $attributes = ''; if (is_array($conf['attributes.']) && is_array($typeConf['attributes.']['params.'])) { ArrayUtility::remapArrayKeys($conf['attributes.'], $typeConf['attributes.']['params.']); } foreach ($this->html5TagAttributes as $attribute) { if ($conf['attributes.'][$attribute] === 'true' || $conf['attributes.'][$attribute] === strtolower($attribute) || $conf['attributes.'][$attribute] === $attribute) { $attributes .= strtolower($attribute) . '="' . strtolower($attribute) . '" '; } } // Media dimensions $width = isset($conf['width.']) ? $this->cObj->stdWrap($conf['width'], $conf['width.']) : $conf['width']; if (!$width) { $width = $conf[$type . '.']['defaultWidth']; } $height = isset($conf['height.']) ? $this->cObj->stdWrap($conf['height'], $conf['height.']) : $conf['height']; if (!$height) { $height = $conf[$type . '.']['defaultHeight']; } // Alternate content $alternativeContent = isset($conf['alternativeContent.']) ? $this->cObj->stdWrap($conf['alternativeContent'], $conf['alternativeContent.']) : $conf['alternativeContent']; // Render video if ($conf['type'] === 'video') { if ($conf['preferFlashOverHtml5']) { // Flash with video tag fallback $conf['params.']['playerFallbackOrder'] = array('flash', 'html5'); $flashDivContent = $videoFlashParams . LF . '<video id="' . $replaceElementIdString . '_video_js" class="video-js" ' . $attributes . 'controls="controls" mediagroup="' . $replaceElementIdString . '" width="' . $width . '" height="' . $height . '">' . LF . $videoSources . $videoCaptions . $alternativeContent . LF . '</video>' . LF; $divContent = ' <div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF . '<noscript>' . LF . '<object id="' . $replaceElementIdString . '_vjs_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $flashDivContent . '</object>' . LF . '</noscript>' . LF; $content = str_replace('###SWFOBJECT###', '<div id="' . $replaceElementIdString . '_video" class="flashcontainer" style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $divContent . '</div>', $content); } else { // Video tag with Flash fallback $conf['params.']['playerFallbackOrder'] = array('html5', 'flash'); $videoTagContent = $videoSources . $videoCaptions; if (isset($conf['videoflashvars']['url'])) { $videoTagContent .= ' <noscript>' . LF . '<object class="vjs-flash-fallback" id="' . $replaceElementIdString . '_vjs_flash_fallback" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $videoFlashParams . LF . $alternativeContent . LF . '</object>' . LF . '</noscript>'; } $divContent = ' <div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF . '<video id="' . $replaceElementIdString . '_video_js" class="video-js" ' . $attributes . 'controls="controls" mediagroup="' . $replaceElementIdString . '" width="' . $width . '" height="' . $height . '">' . LF . $videoTagContent . '</video>'; $content = str_replace('###SWFOBJECT###', '<div id="' . $replaceElementIdString . '_video" class="video-js-box" style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $divContent . '</div>', $content); } } // Render audio if ($conf['type'] === 'audio' || $audioSources || isset($conf['audioFallback'])) { if ($conf['preferFlashOverHtml5']) { // Flash with audio tag fallback $flashDivContent = $audioFlashParams . LF . '<audio id="' . $replaceElementIdString . '_audio_element"' . $attributes . ($conf['type'] === 'video' ? ' mediagroup="' . $replaceElementIdString . 'style="position:absolute;left:-10000px;"' : ' controls="controls"') . ' style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $audioSources . $alternativeContent . LF . '</audio>' . LF; $divContent = ($conf['type'] === 'video' ? '' : '<div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF) . '<noscript>' . LF . '<object id="' . $replaceElementIdString . '_audio_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . ($conf['type'] === 'video' ? 0 : $width) . '" height="' . ($conf['type'] === 'video' ? 0 : $height) . '">' . LF . $flashDivContent . '</object>' . LF . '</noscript>' . LF; $audioContent = '<div id="' . $replaceElementIdString . '_audio_box" class="audio-flash-container" style="width:' . ($conf['type'] === 'video' ? 0 : $width) . 'px; height:' . ($conf['type'] === 'video' ? 0 : $height) . 'px;">' . LF . $divContent . '</div>'; } else { // Audio tag with Flash fallback $audioTagContent = $audioSources; if (isset($conf['audioflashvars']['url'])) { $audioTagContent .= ' <noscript>' . LF . '<object class="audio-flash-fallback" id="' . $replaceElementIdString . '_audio_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $audioFlashParams . LF . $alternativeContent . LF . '</object>' . LF . '</noscript>'; } $divContent = ($conf['type'] === 'video' ? '' : '<div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF) . '<audio id="' . $replaceElementIdString . '_audio_element" class="audio-element"' . $attributes . ($conf['type'] === 'video' ? ' mediagroup="' . $replaceElementIdString . '" style="position:absolute;left:-10000px;"' : ' controls="controls"') . '>' . LF . $audioTagContent . '</audio>' . LF . $audioSourcesEmbeddingJsScript; $audioContent = '<div id="' . $replaceElementIdString . '_audio_box" class="audio-box" style="width:' . ($conf['type'] === 'video' ? 0 : $width) . 'px; height:' . ($conf['type'] === 'video' ? 0 : $height) . 'px;">' . LF . $divContent . '</div>'; } if ($conf['type'] === 'audio') { $content = str_replace('###SWFOBJECT###', $audioContent, $content); } else { $content .= LF . $audioContent; } } // Assemble inline JS code $videoJsSetup = ''; $flowplayerHandlers = ''; if ($conf['type'] === 'video') { // Assemble videoJS options $videoJsOptions = array(); foreach ($this->videoJsOptions as $videoJsOption) { if (isset($conf['params.'][$videoJsOption])) { $videoJsOptions[$videoJsOption] = $conf['params.'][$videoJsOption]; } } $videoJsOptions = count($videoJsOptions) ? json_encode($videoJsOptions) : '{}'; // videoJS setup and videoJS listeners for audio description synchronisation if ($audioSources || isset($conf['audioFallback'])) { $videoJsSetup = ' var ' . $replaceElementIdString . '_video = VideoJS.setup("' . $replaceElementIdString . '_video_js", ' . $videoJsOptions . '); var ' . $replaceElementIdString . '_video_element = document.getElementById("' . $replaceElementIdString . '_video_js"); var ' . $replaceElementIdString . '_audio_element = document.getElementById("' . $replaceElementIdString . '_audio_element"); if (!!' . $replaceElementIdString . '_video_element && !!' . $replaceElementIdString . '_audio_element) { ' . $replaceElementIdString . '_audio_element.muted = true; VideoJS.addListener(' . $replaceElementIdString . '_video_element, "pause", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").pause(); }); VideoJS.addListener(' . $replaceElementIdString . '_video_element, "play", function () { try {document.getElementById("' . $replaceElementIdString . '_audio_element").currentTime = document.getElementById("' . $replaceElementIdString . '_video_js").currentTime} catch(e) {}; document.getElementById("' . $replaceElementIdString . '_audio_element").play(); }); VideoJS.addListener(' . $replaceElementIdString . '_video_element, "seeked", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").currentTime = document.getElementById("' . $replaceElementIdString . '_video_js").currentTime; }); VideoJS.addListener(' . $replaceElementIdString . '_video_element, "volumechange", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").volume = document.getElementById("' . $replaceElementIdString . '_video_js").volume; }); }'; } else { $videoJsSetup = ' var ' . $replaceElementIdString . '_video = VideoJS.setup("' . $replaceElementIdString . '_video_js", ' . $videoJsOptions . '); '; } // Prefer Flash or fallback to Flash $videoSourcesEmbedding = ''; // If we have a video file for Flash if (isset($conf['filename'])) { // If we prefer Flash if ($conf['preferFlashOverHtml5']) { $videoTagAssembly = ''; // Create "source" elements if (is_array($conf['sources']) && count($conf['sources'])) { foreach ($conf['sources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video']; $videoTagAssembly .= ' ' . $replaceElementIdString . '_video_js.appendChild($f.extend(document.createElement("source"), { src: "' . $source . '", type: "' . $mimeType . '" }));'; } // Create "track" elements if (isset($conf['caption'])) { // Assemble captions track tag // It will take a while before the captions are loaded and parsed... $videoTagAssembly .= ' var track = document.createElement("track"); track.setAttribute("src", "' . $conf['caption'] . '"); track.setAttribute("id", "' . $replaceElementIdString . '_captions_track"); track.setAttribute("kind", "captions"); track.setAttribute("default", "default"); ' . $replaceElementIdString . '_video_js.appendChild(track);'; } $videoTagAssembly .= ' $f.extend(' . $replaceElementIdString . '_video_js, { id: "' . $replaceElementIdString . '_video_js", className: "video-js", controls: "controls", mediagroup: "' . $replaceElementIdString . '", preload: "none", width: "' . $width . '", height: "' . $height . '" }); ' . $replaceElementIdString . '_video.appendChild(' . $replaceElementIdString . '_video_js); ' . $replaceElementIdString . '_video.className = "video-js-box";'; $videoTagAssembly .= $videoJsSetup; } $videoSourcesEmbedding = ' var ' . $replaceElementIdString . '_video = document.getElementById("' . $replaceElementIdString . '_video"); var ' . $replaceElementIdString . '_video_js = document.createElement("video"); if (flashembed.getVersion()[0] > 0) { // Flash is available var videoPlayer = flowplayer("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ', ' . $flowplayerVideoJsonConfig . ').load(); videoPlayer.onBeforeUnload(function () { return false; }); } else if (!!' . $replaceElementIdString . '_video_js.canPlayType) { // Flash is not available: fallback to videoJS if video tag is supported ' . $videoTagAssembly . ' } else { // Neither Flash nor video is available: offer to install Flash flashembed("' . $replaceElementIdString . '_video", ' . $flashConfiguration . '); }'; } elseif (is_array($conf['sources'])) { // HTML5 is the preferred rendering method // Test whether the browser supports any of types of the provided sources $supported = array(); foreach ($conf['sources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video']; $supported[] = $replaceElementIdString . '_videoTag.canPlayType("' . $mimeType . '") != ""'; } // Testing whether the browser supports the video tag with any of the provided source types // If no support, embed flowplayer $videoSourcesEmbedding = ' var ' . $replaceElementIdString . '_videoTag = document.createElement(\'video\'); var ' . $replaceElementIdString . '_video_box = document.getElementById("' . $replaceElementIdString . '_video"); if (' . $replaceElementIdString . '_video_box) { if (!' . $replaceElementIdString . '_videoTag || !' . $replaceElementIdString . '_videoTag.canPlayType || !(' . (count($supported) ? implode(' || ', $supported) : 'false') . ')) { // Avoid showing an empty video element if (document.getElementById("' . $replaceElementIdString . '_video_js")) { document.getElementById("' . $replaceElementIdString . '_video_js").style.display = "none"; } if (flashembed.getVersion()[0] > 0) { // Flash is available var videoPlayer = flowplayer("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ', ' . $flowplayerVideoJsonConfig . ').load(); videoPlayer.onBeforeUnload(function () { return false; }); } else { // Neither Flash nor video is available: offer to install Flash flashembed("' . $replaceElementIdString . '_video", ' . $flashConfiguration . '); } } else {' . $videoJsSetup . ' } }'; } } } // Audio fallback to Flash $audioSourcesEmbedding = ''; // If we have an audio file for Flash if (isset($conf['audioFallback'])) { // If we prefer Flash in if ($conf['preferFlashOverHtml5']) { $audioTagAssembly = ''; // Create "source" elements if (is_array($conf['audioSources']) && count($conf['audioSources'])) { foreach ($conf['audioSources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio']; $audioTagAssembly .= ' ' . $replaceElementIdString . '_audio_element.appendChild($f.extend(document.createElement("source"), { src: "' . $source . '", type: "' . $mimeType . '" }));'; } $audioTagAssembly .= ' $f.extend(' . $replaceElementIdString . '_audio_element, { id: "' . $replaceElementIdString . '_audio_element", className: "audio-element", controls: "' . ($conf['type'] === 'video' ? '' : 'controls') . '", mediagroup: "' . $replaceElementIdString . '", preload: "none", width: "' . ($conf['type'] === 'video' ? 0 : $width) . 'px", height: "' . ($conf['type'] === 'video' ? 0 : $height) . 'px" }); ' . $replaceElementIdString . '_audio_box.appendChild(' . $replaceElementIdString . '_audio_element); ' . $replaceElementIdString . '_audio_box.className = "audio-box";'; } $audioSourcesEmbedding = ' var ' . $replaceElementIdString . '_audio_box = document.getElementById("' . $replaceElementIdString . '_audio_box"); var ' . $replaceElementIdString . '_audio_element = document.createElement("audio"); if (flashembed.getVersion()[0] > 0) { // Flash is available var audioPlayer = flowplayer("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ', ' . $flowplayerAudioJsonConfig . ').load(); audioPlayer.onBeforeUnload(function () { return false; }); ' . ($conf['type'] === 'video' ? 'audioPlayer.mute();' : '') . ' } else if (!!' . $replaceElementIdString . '_audio_element.canPlayType) { // Flash is not available: fallback to audio element if audio tag is supported ' . $audioTagAssembly . ' } else { // Neither Flash nor audio is available: offer to install Flash if this is not an audio description of a video ' . ($conf['type'] === 'video' ? '' : 'flashembed("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ');') . ' }'; } elseif (is_array($conf['audioSources'])) { // HTML5 is the preferred rendering method // Test whether the browser supports any of types of the provided sources $supported = array(); foreach ($conf['audioSources'] as $source) { $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source); $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio']; $supported[] = $replaceElementIdString . '_audioTag.canPlayType("' . $mimeType . '") != ""'; } // Testing whether the browser supports the audio tag with any of the provided source types // If no support, embed flowplayer $audioSourcesEmbedding = ' var ' . $replaceElementIdString . '_audioTag = document.createElement(\'audio\'); var ' . $replaceElementIdString . '_audio_box = document.getElementById("' . $replaceElementIdString . '_audio_box"); if (' . $replaceElementIdString . '_audio_box) { if (!' . $replaceElementIdString . '_audioTag || !' . $replaceElementIdString . '_audioTag.canPlayType || !(' . (count($supported) ? implode(' || ', $supported) : 'false') . ')) { // Avoid showing an empty audio element if (document.getElementById("' . $replaceElementIdString . '_audio_element")) { document.getElementById("' . $replaceElementIdString . '_audio_element").style.display = "none"; } if (flashembed.getVersion()[0] > 0) { var audioPlayer = flowplayer("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ', ' . $flowplayerAudioJsonConfig . ').load(); audioPlayer.onBeforeUnload(function () { return false; }); ' . ($conf['type'] === 'video' ? 'audioPlayer.mute()' : '') . ' } else { // Neither Flash nor audio is available: offer to install Flash if this is not an audio description of a video ' . ($conf['type'] === 'video' ? '' : 'flashembed("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ');') . ' } } }'; } // Flowplayer eventHandlers for audio description synchronisation $flowplayerHandlers = ''; if ($conf['type'] === 'video') { $flowplayerHandlers = ' if (flashembed.getVersion()[0] > 0) { // Flash is available var videoPlayer = flowplayer("' . $replaceElementIdString . '_video"); if (videoPlayer) { // Control audio description through video control bar videoPlayer.onVolume(function (volume) { flowplayer("' . $replaceElementIdString . '_audio_box").setVolume(volume); }); videoPlayer.onMute(function () { flowplayer("' . $replaceElementIdString . '_audio_box").mute(); }); videoPlayer.onUnmute(function () { flowplayer("' . $replaceElementIdString . '_audio_box").unmute(); }); videoPlayer.onPause(function () { flowplayer("' . $replaceElementIdString . '_audio_box").pause(); }); videoPlayer.onResume(function () { flowplayer("' . $replaceElementIdString . '_audio_box").resume(); }); videoPlayer.onStart(function () { flowplayer("' . $replaceElementIdString . '_audio_box").play(); }); videoPlayer.onStop(function () { flowplayer("' . $replaceElementIdString . '_audio_box").stop(); }); videoPlayer.onSeek(function (clip, seconds) { flowplayer("' . $replaceElementIdString . '_audio_box").seek(seconds); }); // Mute audio description on start flowplayer("' . $replaceElementIdString . '_audio_box").onStart(function () { this.mute()}); // Audio description toggle var videoContainer = document.getElementById("' . $replaceElementIdString . '_video"); var buttonContainer = document.createElement("div"); $f.extend(buttonContainer, { id: "' . $replaceElementIdString . '_audio_description_toggle", className: "vjs-audio-description-control" }); var button = document.createElement("div"); buttonContainer.appendChild(button); buttonContainer.style.position = "relative"; buttonContainer.style.left = (parseInt(' . $width . ', 10)-27) + "px"; videoContainer.parentNode.insertBefore(buttonContainer, videoContainer.nextSibling); VideoJS.addListener(buttonContainer, "click", function () { var buttonContainer = document.getElementById("' . $replaceElementIdString . '_audio_description_toggle"); var state = buttonContainer.getAttribute("data-state"); if (state == "enabled") { buttonContainer.setAttribute("data-state", "disabled"); flowplayer("' . $replaceElementIdString . '_audio_box").mute(); } else { buttonContainer.setAttribute("data-state", "enabled"); flowplayer("' . $replaceElementIdString . '_audio_box").unmute(); } }); } }'; } } // Wrap up inline JS code $jsInlineCode = $audioSourcesEmbedding . $videoSourcesEmbedding . $flowplayerHandlers; if ($jsInlineCode) { $jsInlineCode = 'VideoJS.DOMReady(function(){' . $jsInlineCode . LF . '});'; } $pageRenderer->addJsInlineCode($replaceElementIdString, $jsInlineCode); if (isset($conf['stdWrap.'])) { $content = $this->cObj->stdWrap($content, $conf['stdWrap.']); } return $content; }
/** * Rename Array keys with a given mapping table * * @param array $array Array by reference which should be remapped * @param array $mappingTable Array with remap information, array/$oldKey => $newKey) * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8 - use ArrayUtility::remapArrayKeys() instead */ public static function remapArrayKeys(&$array, $mappingTable) { static::logDeprecatedFunction(); ArrayUtility::remapArrayKeys($array, $mappingTable); }
/** * @test */ public function remapArrayKeysExchangesKeysWithGivenMapping() { $array = array('one' => 'one', 'two' => 'two', 'three' => 'three'); $keyMapping = array('one' => '1', 'two' => '2'); $expected = array('1' => 'one', '2' => 'two', 'three' => 'three'); ArrayUtility::remapArrayKeys($array, $keyMapping); $this->assertEquals($expected, $array); }
/** * Rendering the cObject, SWFOBJECT * * @param array $conf Array of TypoScript properties * @return string Output */ public function render($conf = array()) { $prefix = ''; if ($GLOBALS['TSFE']->baseUrl) { $prefix = $GLOBALS['TSFE']->baseUrl; } if ($GLOBALS['TSFE']->absRefPrefix) { $prefix = $GLOBALS['TSFE']->absRefPrefix; } $type = isset($conf['type.']) ? $this->cObj->stdWrap($conf['type'], $conf['type.']) : $conf['type']; $typeConf = $conf[$type . '.']; /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */ $pageRenderer = $GLOBALS['TSFE']->getPageRenderer(); // Add SWFobject js-file $pageRenderer->addJsFile($this->getPathToLibrary('flashmedia/swfobject/swfobject.js')); $player = isset($typeConf['player.']) ? $this->cObj->stdWrap($typeConf['player'], $typeConf['player.']) : $typeConf['player']; if (strpos($player, 'EXT:') === 0) { $player = $prefix . $GLOBALS['TSFE']->tmpl->getFileName($player); } $installUrl = isset($conf['installUrl.']) ? $this->cObj->stdWrap($conf['installUrl'], $conf['installUrl.']) : $conf['installUrl']; if (!$installUrl) { $installUrl = $prefix . $this->getPathToLibrary('flashmedia/swfobject/expressInstall.swf'); } // If file is audio and an explicit path has not been set, // take path from audio fallback property if ($type == 'audio' && empty($conf['file'])) { $conf['file'] = $conf['audioFallback']; } $filename = isset($conf['file.']) ? $this->cObj->stdWrap($conf['file'], $conf['file.']) : $conf['file']; $forcePlayer = isset($conf['forcePlayer.']) ? $this->cObj->stdWrap($conf['forcePlayer'], $conf['forcePlayer.']) : $conf['forcePlayer']; if ($filename && $forcePlayer) { if (strpos($filename, '://') !== FALSE) { $conf['flashvars.']['file'] = $filename; } else { if ($prefix) { $conf['flashvars.']['file'] = $prefix . $filename; } else { $conf['flashvars.']['file'] = str_repeat('../', substr_count($player, '/')) . $filename; } } } else { $player = $filename; } // Write calculated values in conf for the hook $conf['player'] = $player; $conf['installUrl'] = $installUrl; $conf['filename'] = $filename; $conf['prefix'] = $prefix; // Merge with default parameters $conf['flashvars.'] = array_merge((array) $typeConf['default.']['flashvars.'], (array) $conf['flashvars.']); $conf['params.'] = array_merge((array) $typeConf['default.']['params.'], (array) $conf['params.']); $conf['attributes.'] = array_merge((array) $typeConf['default.']['attributes.'], (array) $conf['attributes.']); $conf['embedParams'] = 'flashvars, params, attributes'; // Hook for manipulating the conf array, it's needed for some players like flowplayer if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'] as $classRef) { \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($classRef, $conf, $this); } } if (is_array($conf['flashvars.']) && is_array($typeConf['mapping.']['flashvars.'])) { ArrayUtility::remapArrayKeys($conf['flashvars.'], $typeConf['mapping.']['flashvars.']); } $flashvars = 'var flashvars = ' . (!empty($conf['flashvars.']) ? json_encode($conf['flashvars.']) : '{}') . ';'; if (is_array($conf['params.']) && is_array($typeConf['mapping.']['params.'])) { ArrayUtility::remapArrayKeys($conf['params.'], $typeConf['mapping.']['params.']); } $params = 'var params = ' . (!empty($conf['params.']) ? json_encode($conf['params.']) : '{}') . ';'; if (is_array($conf['attributes.']) && is_array($typeConf['attributes.']['params.'])) { ArrayUtility::remapArrayKeys($conf['attributes.'], $typeConf['attributes.']['params.']); } $attributes = 'var attributes = ' . (!empty($conf['attributes.']) ? json_encode($conf['attributes.']) : '{}') . ';'; $flashVersion = isset($conf['flashVersion.']) ? $this->cObj->stdWrap($conf['flashVersion'], $conf['flashVersion.']) : $conf['flashVersion']; if (!$flashVersion) { $flashVersion = '9'; } $replaceElementIdString = str_replace('.', '', uniqid('mmswf', TRUE)); $GLOBALS['TSFE']->register['MMSWFID'] = $replaceElementIdString; $alternativeContent = isset($conf['alternativeContent.']) ? $this->cObj->stdWrap($conf['alternativeContent'], $conf['alternativeContent.']) : $conf['alternativeContent']; $layout = isset($conf['layout.']) ? $this->cObj->stdWrap($conf['layout'], $conf['layout.']) : $conf['layout']; $content = str_replace('###ID###', $replaceElementIdString, $layout); $content = str_replace('###SWFOBJECT###', '<div id="' . $replaceElementIdString . '">' . $alternativeContent . '</div>', $content); $width = isset($conf['width.']) ? $this->cObj->stdWrap($conf['width'], $conf['width.']) : $conf['width']; if (!$width) { $width = $conf[$type . '.']['defaultWidth']; } $height = isset($conf['height.']) ? $this->cObj->stdWrap($conf['height'], $conf['height.']) : $conf['height']; if (!$height) { $height = $conf[$type . '.']['defaultHeight']; } $embed = 'swfobject.embedSWF("' . $conf['player'] . '", "' . $replaceElementIdString . '", "' . $width . '", "' . $height . '", "' . $flashVersion . '", "' . $installUrl . '", ' . $conf['embedParams'] . ');'; $script = $flashvars . $params . $attributes . $embed; $pageRenderer->addJsInlineCode($replaceElementIdString, $script); if (isset($conf['stdWrap.'])) { $content = $this->cObj->stdWrap($content, $conf['stdWrap.']); } return $content; }