@@ -290,7 +290,7 @@ function init() {
if (config.basePath && !absoluteURL(p)) {
if (config.basePath && !absoluteURL(p)) {
p = config.basePath + p;
p = config.basePath + p;
}
}
panoImage[i].src = p;
panoImage[i].src = encodeURI( p) ;
}
}
} else if (config.type == 'multires') {
} else if (config.type == 'multires') {
onImageLoad();
onImageLoad();
@@ -308,7 +308,7 @@ function init() {
for (i = 0; i < config.panoramas.length; i++) {
for (i = 0; i < config.panoramas.length; i++) {
if (panoImage.canPlayType(config.panoramas[i].type).length > 0) {
if (panoImage.canPlayType(config.panoramas[i].type).length > 0) {
panoImage.crossOrigin = 'anonymous';
panoImage.crossOrigin = 'anonymous';
panoImage.src = absoluteURL(config.panoramas[i].file) ? config.panoramas[i].file : p + config.panoramas[i].file;
panoImage.src = encodeURI( absoluteURL(config.panoramas[i].file) ? config.panoramas[i].file : p + config.panoramas[i].file) ;
break;
break;
}
}
}
}
@@ -333,7 +333,7 @@ function init() {
if (xhr.status != 200) {
if (xhr.status != 200) {
// Display error if image can't be loaded
// Display error if image can't be loaded
var a = document.createElement('a');
var a = document.createElement('a');
a.href = p;
a.href = encodeURI( p) ;
a.innerHTML = a.href;
a.innerHTML = a.href;
anError('The file ' + a.outerHTML + ' could not be accessed.');
anError('The file ' + a.outerHTML + ' could not be accessed.');
}
}
@@ -1120,15 +1120,15 @@ function createHotSpots() {
});
});
config.hotSpots.forEach(function(hs) {
config.hotSpots.forEach(function(hs) {
var div = document.createElement('div');
var div = document.createElement('div');
div.className = 'pnlm-hotspot pnlm-tooltip pnlm-sprite pnlm-' + hs.type;
div.className = 'pnlm-hotspot pnlm-tooltip pnlm-sprite pnlm-' + escapeHTML( hs.type) ;
var span = document.createElement('span');
var span = document.createElement('span');
span.innerHTML = hs.text;
span.innerHTML = escapeHTML( hs.text) ;
var a;
var a;
if (hs.URL) {
if (hs.URL) {
a = document.createElement('a');
a = document.createElement('a');
a.setAttribute('href', hs.URL);
a.setAttribute('href', encodeURI( hs.URL) );
a.setAttribute('target', '_blank');
a.setAttribute('target', '_blank');
renderContainer.appendChild(a);
renderContainer.appendChild(a);
div.style.cursor = 'pointer';
div.style.cursor = 'pointer';
@@ -1136,19 +1136,19 @@ function createHotSpots() {
a.appendChild(div);
a.appendChild(div);
} else if (hs.video) {
} else if (hs.video) {
var video = document.createElement('video');
var video = document.createElement('video');
video.setAttribute('src',hs.video);
video.setAttribute('controls',true);
video.setAttribute('style','width:' + hs.width + 'px');
video.setAttribute('src', encodeURI( hs.video) );
video.setAttribute('controls', true);
video.setAttribute('style', 'width:' + hs.width + 'px');
renderContainer.appendChild(div);
renderContainer.appendChild(div);
span.appendChild(video);
span.appendChild(video);
} else if (hs.image) {
} else if (hs.image) {
a = document.createElement('a');
a = document.createElement('a');
a.setAttribute('href', hs.image);
a.setAttribute('href', encodeURI( hs.image) );
a.setAttribute('target', '_blank');
a.setAttribute('target', '_blank');
span.appendChild(a);
span.appendChild(a);
var image = document.createElement('img');
var image = document.createElement('img');
image.setAttribute('src',hs.image);
image.setAttribute('style','width:' + hs.width + 'px');
image.setAttribute('src', encodeURI( hs.image) );
image.setAttribute('style', 'width:' + hs.width + 'px');
renderContainer.appendChild(div);
renderContainer.appendChild(div);
a.appendChild(image);
a.appendChild(image);
@@ -1300,7 +1300,7 @@ function processOptions() {
preview = new Image();
preview = new Image();
preview.crossOrigin = 'anonymous';
preview.crossOrigin = 'anonymous';
preview.src = p;
preview.src = encodeURI( p) ;
preview.className = 'pnlm-preview-img';
preview.className = 'pnlm-preview-img';
renderContainer.appendChild(preview);
renderContainer.appendChild(preview);
}
}
@@ -1310,17 +1310,17 @@ function processOptions() {
if (config.hasOwnProperty(key)) {
if (config.hasOwnProperty(key)) {
switch(key) {
switch(key) {
case 'title':
case 'title':
infoDisplay.title.innerHTML = config[key];
infoDisplay.title.innerHTML = escapeHTML( config[key]) ;
infoDisplay.container.style.display = 'inline';
infoDisplay.container.style.display = 'inline';
break;
break;
case 'author':
case 'author':
infoDisplay.author.innerHTML = 'by ' + config[key];
infoDisplay.author.innerHTML = 'by ' + escapeHTML( config[key]) ;
infoDisplay.container.style.display = 'inline';
infoDisplay.container.style.display = 'inline';
break;
break;
case 'fallback':
case 'fallback':
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + config[key] + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + encodeURI( config[key]) + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
break;
break;
case 'hfov':
case 'hfov':
@@ -1358,11 +1358,6 @@ function processOptions() {
config.autoRotateStopDelay = config[key];
config.autoRotateStopDelay = config[key];
break;
break;
case 'header':
// Add contents to header
document.getElementsByTagName('head')[0].innerHTML += config[key];
break;
case 'showZoomCtrl':
case 'showZoomCtrl':
if (config[key]) {
if (config[key]) {
// Show zoom controls
// Show zoom controls
@@ -1549,6 +1544,21 @@ function loadScene(sceneId, targetPitch, targetYaw) {
}
}
/**
/**
* Escapes HTML string (to mitigate possible DOM XSS attacks).
* @private
* @param {string} s - String to escape
* @returns {string} Escaped string
*/
function escapeHTML(s) {
return String(s).replace(/&/g, '&')
.replace('"', '"')
.replace("'", ''')
.replace('<', '<')
.replace('>', '>')
.replace('/', '/');
}
/**
* Returns the pitch of the center of the view.
* Returns the pitch of the center of the view.
* @memberof Viewer
* @memberof Viewer
* @instance
* @instance