/* global Image, XMLHttpRequest */ var debug = require('./debug'); var warn = debug('utils:src-loader:warn'); /** * Validate a texture, either as a selector or as a URL. * Detects whether `src` is pointing to an image or video and invokes the appropriate * callback. * * `src` will be passed into the callback * * @params {string|Element} src - URL or media element. * @params {function} isImageCb - callback if texture is an image. * @params {function} isVideoCb - callback if texture is a video. */ function validateSrc (src, isImageCb, isVideoCb) { checkIsImage(src, function isAnImageUrl (isImage) { if (isImage) { isImageCb(src); return; } isVideoCb(src); }); } /** * Validates six images as a cubemap, either as selector or comma-separated * URLs. * * @param {string} src - A selector or comma-separated image URLs. Image URLs must be wrapped by `url()`. * @param {string} src - A selector or comma-separated image URLs. Image URLs must be wrapped by `url()`. */ function validateCubemapSrc (src, cb) { var aCubemap; var cubemapSrcRegex = ''; var i; var urls; var validatedUrls = []; for (i = 0; i < 5; i++) { cubemapSrcRegex += '(url\\((?:[^\\)]+)\\),\\s*)'; } cubemapSrcRegex += '(url\\((?:[^\\)]+)\\)\\s*)'; urls = src.match(new RegExp(cubemapSrcRegex)); // `src` is a comma-separated list of URLs. // In this case, re-use validateSrc for each side of the cube. function isImageCb (url) { validatedUrls.push(url); if (validatedUrls.length === 6) { cb(validatedUrls); } } if (urls) { for (i = 1; i < 7; i++) { validateSrc(parseUrl(urls[i]), isImageCb); } return; } // `src` is a query selector to <a-cubemap> containing six $([src])s. aCubemap = validateAndGetQuerySelector(src); if (!aCubemap) { return; } if (aCubemap.tagName === 'A-CUBEMAP' && aCubemap.srcs) { return cb(aCubemap.srcs); } // Else if aCubeMap is not a <a-cubemap>. warn('Selector "%s" does not point to <a-cubemap>', src); } /** * Parses src from `url(src)`. * @param {string} src - String to parse. * @return {string} The parsed src, if parseable. */ function parseUrl (src) { var parsedSrc = src.match(/\url\((.+)\)/); if (!parsedSrc) { return; } return parsedSrc[1]; } /** * Call back whether `src` is an image. * * @param {string|Element} src - URL or element that will be tested. * @param {function} onResult - Callback with whether `src` is an image. */ function checkIsImage (src, onResult) { var request; if (src.tagName) { onResult(src.tagName === 'IMG'); return; } request = new XMLHttpRequest(); // Try to send HEAD request to check if image first. request.open('HEAD', src); request.addEventListener('load', function (event) { var contentType; if (request.status >= 200 && request.status < 300) { contentType = request.getResponseHeader('Content-Type'); if (contentType == null) { checkIsImageFallback(src, onResult); } else { if (contentType.startsWith('image')) { onResult(true); } else { onResult(false); } } } else { checkIsImageFallback(src, onResult); } request.abort(); }); request.send(); } function checkIsImageFallback (src, onResult) { var tester = new Image(); tester.addEventListener('load', onLoad); function onLoad () { onResult(true); } tester.addEventListener('error', onError); function onError () { onResult(false); } tester.src = src; } /** * Query and validate a query selector, * * @param {string} selector - DOM selector. * @return {object|null|undefined} Selected DOM element if exists. null if query yields no results. undefined if `selector` is not a valid selector. */ function validateAndGetQuerySelector (selector) { try { var el = document.querySelector(selector); if (!el) { warn('No element was found matching the selector: "%s"', selector); } return el; } catch (e) { // Capture exception if it's not a valid selector. warn('"%s" is not a valid selector', selector); return undefined; } } module.exports = { parseUrl: parseUrl, validateSrc: validateSrc, validateCubemapSrc: validateCubemapSrc };