diff --git a/Documentation/Settings.yml b/Documentation/Settings.yml index 699f128ee..72fa44e1b 100644 --- a/Documentation/Settings.yml +++ b/Documentation/Settings.yml @@ -11,7 +11,7 @@ conf.py: copyright: 2017 project: Kitodo.Presentation version: 2.3 - release: 2.3.1 + release: 2.3.2 intersphinx_mapping: t3tsref: - http://docs.typo3.org/typo3cms/TyposcriptReference/ diff --git a/common/class.tx_dlf_helper.php b/common/class.tx_dlf_helper.php index 721197973..9b81c53ff 100644 --- a/common/class.tx_dlf_helper.php +++ b/common/class.tx_dlf_helper.php @@ -846,6 +846,26 @@ public static function isPPN($id) { } + /** + * Determine whether or not $url is a valid URL using HTTP or HTTPS scheme. + * + * @param string $url + * + * @return bool + */ + public static function isValidHttpUrl($url) + { + if (!\TYPO3\CMS\Core\Utility\GeneralUtility::isValidUrl($url)) { + return false; + } + + $parsed = parse_url($url); + $scheme = isset($parsed['scheme']) ? $parsed['scheme'] : ''; + $schemeNormalized = strtolower($scheme); + + return $schemeNormalized === 'http' || $schemeNormalized === 'https'; + } + /** * Load value from user's session. * diff --git a/ext_conf_template.txt b/ext_conf_template.txt index 8005e7302..1a5389796 100644 --- a/ext_conf_template.txt +++ b/ext_conf_template.txt @@ -7,6 +7,9 @@ cliUserGroup = 0 # cat=Basic; type=boolean; label=LLL:EXT:dlf/locallang.xml:config.makeCliUserGroup makeCliUserGroup = 0 +# cat=Basic; type=boolean; label=LLL:EXT:dlf/locallang.xml:config.enableInternalProxy +enableInternalProxy = 0 + # cat=Basic; type=string; label=LLL:EXT:dlf/locallang.xml:config.useragent useragent = Kitodo.Presentation diff --git a/ext_emconf.php b/ext_emconf.php index ce7c858d4..7b61c2905 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -21,7 +21,7 @@ 'uploadfolder' => TRUE, 'createDirs' => '', 'clearCacheOnLoad' => FALSE, - 'version' => '2.3.1', + 'version' => '2.3.2', 'constraints' => array ( 'depends' => array ( 'php' => '7.0.0-', diff --git a/ext_localconf.php b/ext_localconf.php index 525baf125..7da6461f1 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -75,9 +75,10 @@ // Register AJAX eID handlers. $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_search_suggest'] = 'EXT:'.$_EXTKEY.'/plugins/search/class.tx_dlf_search_suggest.php'; -$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_geturl_eid'] = 'EXT:'.$_EXTKEY.'/plugins/pageview/class.tx_dlf_geturl_eid.php'; - -$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_geturl_eid'] = 'EXT:'.$_EXTKEY.'/plugins/pageview/class.tx_dlf_geturl_eid.php'; +$extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dlf']); +if (!empty($extConf) && $extConf['enableInternalProxy']) { + $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_geturl_eid'] = 'EXT:'.$_EXTKEY.'/plugins/pageview/class.tx_dlf_geturl_eid.php'; +} $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_search_in_document_eid'] = 'EXT:'.$_EXTKEY.'/plugins/toolbox/tools/searchindocument/class.tx_dlf_search_in_document_eid.php'; diff --git a/locallang.xml b/locallang.xml index bbed7135a..d17c37bc9 100644 --- a/locallang.xml +++ b/locallang.xml @@ -147,7 +147,7 @@ - + @@ -165,6 +165,7 @@ + @@ -363,7 +364,7 @@ - + @@ -381,6 +382,7 @@ + diff --git a/plugins/pageview/class.tx_dlf_geturl_eid.php b/plugins/pageview/class.tx_dlf_geturl_eid.php index dc2b96ee9..9c9dc909e 100644 --- a/plugins/pageview/class.tx_dlf_geturl_eid.php +++ b/plugins/pageview/class.tx_dlf_geturl_eid.php @@ -47,22 +47,18 @@ public function main($content = '', $conf = array ()) { $this->scriptRelPath = 'plugins/pageview/class.tx_dlf_geturl_eid.php'; $url = GeneralUtility::_GP('url'); + if (!tx_dlf_helper::isValidHttpUrl($url)) { + throw new \InvalidArgumentException('No valid url passed!', 1580482805); + } - $includeHeader = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(GeneralUtility::_GP('header'), 0, 2, 0); - - // first we fetch header separately - $fetchedHeader = GeneralUtility::getUrl($url, 2); - - if ($includeHeader == 0) { - - $fetchedData = GeneralUtility::getUrl($url, $includeHeader); - - } else { - - $fetchedData = $fetchedHeader; - + // get and verify the uHash + $uHash = (string) GeneralUtility::_GP('uHash'); + if (!hash_equals(GeneralUtility::hmac($url, 'PageViewProxy'), $uHash)) { + throw new \InvalidArgumentException('No valid uHash passed!', 1643796565); } + $fetchedData = GeneralUtility::getUrl($url); + // add some self calculated header tags header('Last-Modified: '.gmdate("D, d M Y H:i:s").'GMT'); header('Cache-Control: max-age=3600, must-revalidate'); diff --git a/plugins/pageview/class.tx_dlf_pageview.php b/plugins/pageview/class.tx_dlf_pageview.php index 58ada5905..30717e02d 100644 --- a/plugins/pageview/class.tx_dlf_pageview.php +++ b/plugins/pageview/class.tx_dlf_pageview.php @@ -250,7 +250,7 @@ protected function getImage($page) { // Configure @action URL for form. $linkConf = array ( 'parameter' => $GLOBALS['TSFE']->id, - 'additionalParams' => '&eID=tx_dlf_geturl_eid&url='.urlencode($image['url']), + 'additionalParams' => '&eID=tx_dlf_geturl_eid&url='.urlencode($image['url']) . '&uHash=' . \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($image['url'], 'PageViewProxy'), ); $image['url'] = $this->cObj->typoLink_URL($linkConf); @@ -297,7 +297,7 @@ protected function getFulltext($page) { // Configure @action URL for form. $linkConf = array ( 'parameter' => $GLOBALS['TSFE']->id, - 'additionalParams' => '&eID=tx_dlf_geturl_eid&url='.urlencode($fulltext['url']), + 'additionalParams' => '&eID=tx_dlf_geturl_eid&url='.urlencode($fulltext['url']) . '&uHash=' . \TYPO3\CMS\Core\Utility\GeneralUtility::hmac($fulltext['url'], 'PageViewProxy'), ); $fulltext['url'] = $this->cObj->typoLink_URL($linkConf); diff --git a/plugins/pageview/tx_dlf_pageview.js b/plugins/pageview/tx_dlf_pageview.js index 11218a3e6..5d28a7313 100644 --- a/plugins/pageview/tx_dlf_pageview.js +++ b/plugins/pageview/tx_dlf_pageview.js @@ -159,18 +159,12 @@ dlfViewer.prototype.addCustomControls = function(controlNames) { // // Add image manipulation tool if container is added. // - // It is important to know that the image manipulation tool uses a webgl renderer as basis. Therefor the - // application has as first to check if the renderer is active. Further it has to check if cors supported through - // image. - // - if ($('#tx-dlf-tools-imagetools').length > 0 && dlfUtils.isWebGLEnabled() && this.isCorsEnabled) { + if ($('#tx-dlf-tools-imagetools').length > 0) { // should be called if cors is enabled imageManipulationControl = new dlfViewerImageManipulationControl({ controlTarget: $('.tx-dlf-tools-imagetools')[0], - layers: dlfUtils.createOl3Layers(images, '*'), map: this.map, - view: dlfUtils.createOl3View(images) }); // bind behavior of both together @@ -182,11 +176,6 @@ dlfViewer.prototype.addCustomControls = function(controlNames) { // set on object scope this.imageManipulationControl = imageManipulationControl; - } else if ($('#tx-dlf-tools-imagetools').length > 0) { - - // hide the element because the functionality is not supported through missing webgl or cors support. - $('#tx-dlf-tools-imagetools').addClass('deactivate'); - } }; @@ -339,17 +328,7 @@ dlfViewer.prototype.init = function(controlNames) { if (this.imageUrls.length <= 0) throw new Error('Missing image source objects.'); - /** - * Is cors enabled. Important information for correct renderer and layer initialization - * @type {boolean} - */ - if (this.useInternalProxy) { - this.isCorsEnabled = true; - } else { - this.isCorsEnabled = dlfUtils.isCorsEnabled(this.imageUrls); - } - - this.initLayer(this.imageUrls, this.isCorsEnabled) + this.initLayer(this.imageUrls) .done($.proxy(function(layers){ var controls = controlNames.length > 0 || controlNames[0] === "" @@ -437,11 +416,10 @@ dlfViewer.prototype.init = function(controlNames) { * Function generate the ol3 layer objects for given image sources. Returns a promise. * * @param {Array.<{url: *, mimetype: *}>} imageSourceObjs - * @param {boolean} isCorsEnabled * @return {jQuery.Deferred.)>} * @private */ -dlfViewer.prototype.initLayer = function(imageSourceObjs, isCorsEnabled) { +dlfViewer.prototype.initLayer = function(imageSourceObjs) { // use deferred for async behavior var deferredResponse = new $.Deferred(), @@ -452,12 +430,11 @@ dlfViewer.prototype.initLayer = function(imageSourceObjs, isCorsEnabled) { resolveCallback = $.proxy(function(imageSourceData, layers) { this.images = imageSourceData; deferredResponse.resolve(layers); - }, this), - origin = isCorsEnabled ? '*' : undefined; + }, this); dlfUtils.fetchImageData(imageSourceObjs) .done(function(imageSourceData) { - resolveCallback(imageSourceData, dlfUtils.createOl3Layers(imageSourceData, origin)); + resolveCallback(imageSourceData, dlfUtils.createOl3Layers(imageSourceData)); }); return deferredResponse; diff --git a/plugins/pageview/tx_dlf_pageview_imagemanipulation_control.js b/plugins/pageview/tx_dlf_pageview_imagemanipulation_control.js index 10dc31b7c..86b67f286 100644 --- a/plugins/pageview/tx_dlf_pageview_imagemanipulation_control.js +++ b/plugins/pageview/tx_dlf_pageview_imagemanipulation_control.js @@ -9,17 +9,9 @@ */ /** - * Right know the image manipulation uses an own ol.Map object based on a webgl renderer. This is due to the fact - * that other parts of the viewer application are using vector geometries and ol3 does only support full vector - * renderering with the canvas and dom renderer yet. In contrast the image manipulation tool is only working - * with a webgl renderer. Therefore it uses an own ol.Map object which is overlaid and synchronized with the - * base ol.Map object. - * * @constructor * @param {Object=} options Control options. - * {Array.} layers * {Element} target - * {ol.View} view * {ol.Map} map */ dlfViewerImageManipulationControl = function(options) { @@ -32,30 +24,12 @@ dlfViewerImageManipulationControl = function(options) { dlfUtils.parseDataDic($('#tx-dlf-tools-imagetools')) : {'imagemanipulation-on':'Activate image manipulation', 'imagemanipulation-off':'Deactivate image manipulation', 'saturation':'Saturation', 'hue':'Hue', 'brightness': 'Brightness', 'contrast':'Contrast', 'reset': 'Reset', 'invert': 'Color inverting'}; - /** - * @type {Array.} - * @private - */ - this.layers = options.layers; - /** * @type {ol.Map} * @private */ this.baseMap_ = options.map; - /** - * @type {ol.Map|undefined} - * @private - */ - this.map_ = undefined; - - /** - * @type {ol.View} - * @private - */ - this.view_ = options.view; - /** * @type {Element} * @private @@ -73,6 +47,12 @@ dlfViewerImageManipulationControl = function(options) { */ this.toolContainerEl_ = dlfUtils.exists(options.toolContainer) ? options.toolContainer: $('.tx-dlf-toolbox')[0]; + /** + * @type {HTMLCanvasElement} + * + */ + this.canvas_ = this.baseMap_.getTargetElement().querySelector('canvas'); + // // Append open/close behavior to toolbox // @@ -95,8 +75,8 @@ dlfViewerImageManipulationControl = function(options) { var FILTERS_DEFAULT_ = { 'brightness': 1, 'contrast': 1, - 'hue': 0, - 'saturation': 0 + 'hue-rotate': 0, + 'saturate': 0 }; /** @@ -105,47 +85,14 @@ dlfViewerImageManipulationControl = function(options) { */ this.filters_ = $.extend({}, FILTERS_DEFAULT_); - /** - * Is filter updated - * @type {boolean} - * @private - */ - this.filterUpdated_ = false; - /** * @type {Object} * @private */ this.handler_ = { - 'postcomposeImageFilter': $.proxy(function (event) { - var webglContext = event['glContext'], - canvas = $('#' + this.map_.getTargetElement().id + ' canvas.ol-unselectable')[0]; - - if (webglContext !== undefined && webglContext !== null) { - var gl = webglContext.getGL(); - - if (this.filterUpdated_) { - - glif.reset(); - - for (var filter in this.filters_) { - glif.addFilter(filter, this.filters_[filter]); - }; - - this.filterUpdated_ = false; - } - - glif.apply(gl, canvas); - - // for showing openlayers that the program changed - // if missing openlayers will produce errors because it - // expected other shaders in the webgl program - webglContext.useProgram(undefined); - } - }, this), - 'resetFilter': $.proxy(function(event) { + 'resetFilter': $.proxy(function() { // reset the checked filters - if (this.filters_.hasOwnProperty('invert')) { + if (this.filters_['invert']) { $('#invert-filter').click(); } @@ -163,29 +110,46 @@ dlfViewerImageManipulationControl = function(options) { }; /** - * Activates the image manipulation tool + * Set filter style property on map canvas. + * + * @param {string} filters */ -dlfViewerImageManipulationControl.prototype.activate = function(){ +dlfViewerImageManipulationControl.prototype.setCssFilter_ = function (filters) { + this.canvas_.style.filter = filters; + this.canvas_.style.webkitFilter = filters; +} - // - // Toggle maps - // - $.when($(this.baseMap_.getTargetElement()) - // fadeOut the base map container - .hide()) - // fadeIn image map container - .done($.proxy(function(){ - if (!dlfUtils.exists(this.map_)) { - // create map container and map object if not exists yet - this.createMap_(); - } +/** + * @private + */ +dlfViewerImageManipulationControl.prototype.applyFilters_ = function () { + var filters = ''; - // Show map - $(this.map_.getTargetElement()).show(); + for (var filter in this.filters_) { + if (!this.filters_.hasOwnProperty(filter)) { + continue; + } + + var cssValue = this.valueToCss_(filter, this.filters_[filter]); + if (cssValue === undefined) { + continue; + } + + filters += filter + '(' + cssValue + ') '; + } - // trigger open event - $(this).trigger("activate-imagemanipulation", this.map_); - }, this)); + this.setCssFilter_(filters); +} + + +/** + * Activates the image manipulation tool + */ +dlfViewerImageManipulationControl.prototype.activate = function(){ + // Apply filters from last time + this.applyFilters_(); + + $(this).trigger("activate-imagemanipulation", this.baseMap_); // // Toggle toolbox controls @@ -199,10 +163,6 @@ dlfViewerImageManipulationControl.prototype.activate = function(){ this.createFilters_(); }; $(this.sliderContainer_).show().addClass('open'); - - // add postcompose listener to layers - if (this.map_ !== undefined) - this.map_.on('postcompose', this.handler_.postcomposeImageFilter); }; /** @@ -230,7 +190,7 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() { [1, 0, 2, 0.01], this.dic['contrast'], function(v) { return parseInt(v * 100 - 100); }), - saturationSlider = this.createSlider_('slider-saturation', 'horizontal', 'saturation', + saturationSlider = this.createSlider_('slider-saturation', 'horizontal', 'saturate', [0, -1, 1, 0.01], this.dic['saturation'], function(v) { return parseInt(v * 100); }), @@ -238,7 +198,7 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() { [1, 0, 2, 0.1], this.dic['brightness'],function(v) { return parseInt(v * 100 - 100); }), - hueSlider = this.createSlider_('slider-hue', 'horizontal', 'hue', + hueSlider = this.createSlider_('slider-hue', 'horizontal', 'hue-rotate', [0, -180, 180, 5], this.dic['hue'], function(v) { return parseInt(v); }); @@ -252,19 +212,10 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() { $(this.sliderContainer_).append($('
')); $('#' + elFilterId).on('click', $.proxy(function(event) { - if (event.target.checked === true && !this.filters_.hasOwnProperty('invert')) { - // if checked add the invert filter to the filters - this.filters_['invert'] = true; - } else { - // remove invert filter - if (this.filters_.hasOwnProperty('invert')) { - delete this.filters_['invert']; - } - } + var invert = event.target.checked; // update filter chain - this.filterUpdated_ = true; - this.layers[0].changed(); + this.setFilter_('invert', invert); }, this)); // button for reset to default state @@ -273,72 +224,6 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() { $(resetBtn).on('click', this.handler_.resetFilter); }; -/** - * Setup the map object used from the image manipulation tool and bind it to the baseMap - * @private - */ -dlfViewerImageManipulationControl.prototype.createMap_ = function() { - var mapEl_ = $('
'); - $(this.baseMap_.getTargetElement().parentElement).append(mapEl_); - - this.map_ = new ol.Map({ - layers: this.layers, - target: mapEl_[0].id, - controls: [], - interactions: [ - new ol.interaction.DragRotate(), - new ol.interaction.DragPan(), - new ol.interaction.DragZoom(), - new ol.interaction.PinchRotate(), - new ol.interaction.PinchZoom(), - new ol.interaction.MouseWheelZoom(), - new ol.interaction.KeyboardPan(), - new ol.interaction.KeyboardZoom, - new ol.interaction.DragRotateAndZoom() - ], - // necessary for proper working of the keyboard events - keyboardEventTarget: document, - view: this.view_, - renderer: 'webgl' - }); - - // couple map behavior with baseMap - var adjustViews = function(sourceView, destMap) { - var rotateDiff = sourceView.getRotation() !== destMap.getView().getRotation(); - var resDiff = sourceView.getResolution() !== destMap.getView().getResolution(); - var centerDiff = sourceView.getCenter() !== destMap.getView().getCenter(); - - if (rotateDiff || resDiff || centerDiff) { - destMap.zoomTo(sourceView.getCenter(),sourceView.getZoom(), 50); - destMap.getView().rotate(sourceView.getRotation()); - } - - }, - adjustViewHandler = function(event) { - adjustViews(event.target, this); - }; - - // when deactivate / activate adjust both map centers / zoom - $(this).on("activate-imagemanipulation", $.proxy(function(event, map) { - // pass change events for resolution and rotation to image manipulation map - // created through external view controls - this.baseMap_.getView().on('change:resolution', adjustViewHandler, this.map_); - this.baseMap_.getView().on('change:rotation', adjustViewHandler, this.map_); - - // adjust the view of both maps - adjustViews(this.baseMap_.getView(), this.map_); - }, this)); - $(this).on("deactivate-imagemanipulation", $.proxy(function(event, map) { - // pass change events for resolution and rotation to image manipulation map - // created through external view controls - this.baseMap_.getView().un('change:resolution', adjustViewHandler, this.map_); - this.baseMap_.getView().un('change:rotation', adjustViewHandler, this.map_); - - // adjust the view of both maps - adjustViews(this.map_.getView(), this.baseMap_); - }, this)); -}; - /** * Functions creates a slider + behavior. * @@ -366,7 +251,6 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className, */ var update = $.proxy(function(event, ui){ var value = ui['value'], - layer = this.layers[0], element = valueEl[0], labelValue = dlfUtils.exists(opt_labelFn) ? opt_labelFn(value) : value + '%'; @@ -382,9 +266,7 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className, element.innerHTML = labelValue; // update filters. - this.filters_[key] = value; - this.filterUpdated_ = true; - layer.changed(); + this.setFilter_(key, value); }, this); $(sliderEl).slider({ @@ -410,12 +292,7 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className, * Deactivates the image manipulation control */ dlfViewerImageManipulationControl.prototype.deactivate = function(){ - - // toggle maps - if (dlfUtils.exists(this.map_)) { - $(this.map_.getTargetElement()).hide(); - } - $(this.baseMap_.getTargetElement()).show(); + this.setCssFilter_(""); // toggle view of image manipulation control element $(this.anchor_).removeClass('active') @@ -424,10 +301,6 @@ dlfViewerImageManipulationControl.prototype.deactivate = function(){ $(this.sliderContainer_).hide().removeClass('open'); - // remove postcompose listener to map - if (this.map_ !== undefined) - this.map_.un('postcompose', this.handler_.postcomposeImageFilter); - // trigger close event for trigger map adjust behavior $(this).trigger("deactivate-imagemanipulation"); }; @@ -440,3 +313,39 @@ dlfViewerImageManipulationControl.prototype.deactivate = function(){ dlfViewerImageManipulationControl.prototype.isActive = function() { return $(this.anchor_).hasClass('active'); }; + + +/** + * @param {string} filter The filter to set + * @param {string} value The value to set the filter to + * @private + */ +dlfViewerImageManipulationControl.prototype.setFilter_ = function (filter, value) { + this.filters_[filter] = value; + this.applyFilters_(); +} + +/** + * Convert filter value to its CSS representation. + * + * @param {string} filter + * @param {number} value + * @private + * @return {string} + */ +dlfViewerImageManipulationControl.prototype.valueToCss_ = function (filter, value) { + switch (filter) { + case 'contrast': + case 'brightness': + return (value * 100).toString() + '%'; + + case 'saturate': + return ((value + 1) * 100).toString() + '%'; + + case 'hue-rotate': + return value + 'deg'; + + case 'invert': + return value ? '100%' : '0%'; + } +} diff --git a/plugins/pageview/tx_dlf_utils.js b/plugins/pageview/tx_dlf_utils.js index f7f67afdf..5fd4ccc8e 100644 --- a/plugins/pageview/tx_dlf_utils.js +++ b/plugins/pageview/tx_dlf_utils.js @@ -584,72 +584,6 @@ dlfUtils.isNullEmptyUndefinedOrNoNumber = function (val) { return val === null || val === undefined || val === '' || isNaN(val); }; -/** - * @param {Array.<{url: *, mimetype: *}>} imageObjs - * @return {boolean} - */ -dlfUtils.isCorsEnabled = function (imageObjs) { - // fix for proper working with ie - if (!window.location.origin) { - window.location.origin = window.location.protocol + '//' + window.location.hostname + - (window.location.port ? ':' + window.location.port : ''); - } - - // fetch data from server - // with access control allowed - var response = true; - - imageObjs.forEach(function (imageObj) { - var url = imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.ZOOMIFY - ? imageObj.url.replace('ImageProperties.xml', 'TileGroup0/0-0-0.jpg') - : - imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.IIIF - ? dlfViewerSource.IIIF.getMetdadataURL(imageObj.url) - : imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.IIP - ? dlfViewerSource.IIP.getMetdadataURL(imageObj.url) - : imageObj.url; - - url = window.location.origin + window.location.pathname + '?eID=tx_dlf_geturl_eid&url=' + encodeURIComponent(url) + '&header=2'; - - $.ajax({ - url: url, - async: false - }).done(function (data, type) { - response = type === 'success' && data.indexOf('Access-Control-Allow-Origin') !== -1; - }).error(function (data, type) { - response = false; - }); - }); - return response; -}; - -/** - * Functions checks if WebGL is enabled in the browser - * @return {boolean} - */ -dlfUtils.isWebGLEnabled = function () { - if (!!window.WebGLRenderingContext) { - var canvas = document.createElement("canvas"), - rendererNames = ["webgl", "experimental-webgl", "moz-webgl", "webkit-3d"], - context = false; - - for (var i = 0; i < rendererNames.length; i++) { - try { - context = canvas.getContext(rendererNames[i]); - if (context && typeof context.getParameter === "function") { - // WebGL is enabled; - return true; - } - } catch (e) {} - } - // WebGL not supported - return false; - } - - // WebGL not supported - return false; -}; - /** * @param {Element} element * @return {Object}