diff --git a/scripts/system/create/assets/images/processing.gif b/scripts/system/create/assets/images/processing.gif new file mode 100644 index 0000000000..94d1486b0a Binary files /dev/null and b/scripts/system/create/assets/images/processing.gif differ diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index 9bd0147002..ed9763875d 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -35,7 +35,8 @@ Script.include([ "../libraries/gridTool.js", "entityList/entityList.js", "entitySelectionTool/entitySelectionTool.js", - "audioFeedback/audioFeedback.js" + "audioFeedback/audioFeedback.js", + "modules/brokenURLReport.js" ]); var CreateWindow = Script.require('./modules/createWindow.js'); diff --git a/scripts/system/create/entityList/entityList.js b/scripts/system/create/entityList/entityList.js index 5119d7d3da..02cd9a14ca 100644 --- a/scripts/system/create/entityList/entityList.js +++ b/scripts/system/create/entityList/entityList.js @@ -413,12 +413,14 @@ EntityListTool = function(shouldUseEditTabletApp) { alignGridToSelection(); } else if (data.type === 'alignGridToAvatar') { alignGridToAvatar(); + } else if (data.type === 'brokenURLReport') { + brokenURLReport(selectionManager.selections); } else if (data.type === 'toggleGridVisibility') { toggleGridVisibility(); } else if (data.type === 'toggleSnapToGrid') { - that.toggleSnapToGrid(); + that.toggleSnapToGrid(); } - + }; webView.webEventReceived.connect(onWebEventReceived); diff --git a/scripts/system/create/entityList/html/entityList.html b/scripts/system/create/entityList/html/entityList.html index e054ca121b..75b172e201 100644 --- a/scripts/system/create/entityList/html/entityList.html +++ b/scripts/system/create/entityList/html/entityList.html @@ -308,7 +308,14 @@ - + + + diff --git a/scripts/system/create/entityList/html/js/entityList.js b/scripts/system/create/entityList/html/js/entityList.js index d21e65d47d..e3526296d9 100644 --- a/scripts/system/create/entityList/html/js/entityList.js +++ b/scripts/system/create/entityList/html/js/entityList.js @@ -273,6 +273,7 @@ let elEntityTable, elSnapToGridActivatorCaption, elAlignGridToSelection, elAlignGridToAvatar, + elBrokenURLReport, elFilterTypeMultiselectBox, elFilterTypeText, elFilterTypeOptions, @@ -359,7 +360,8 @@ function loaded() { elSnapToGridActivator = document.getElementById("snapToGridActivator"); elSnapToGridActivatorCaption = document.getElementById("snapToGridActivatorCaption"); elAlignGridToSelection = document.getElementById("alignGridToSelection"); - elAlignGridToAvatar = document.getElementById("alignGridToAvatar"); + elAlignGridToAvatar = document.getElementById("alignGridToAvatar"); + elBrokenURLReport = document.getElementById("brokenURLReport"); elFilterTypeMultiselectBox = document.getElementById("filter-type-multiselect-box"); elFilterTypeText = document.getElementById("filter-type-text"); elFilterTypeOptions = document.getElementById("filter-type-options"); @@ -597,7 +599,11 @@ function loaded() { elAlignGridToAvatar.onclick = function () { EventBridge.emitWebEvent(JSON.stringify({ type: "alignGridToAvatar" })); closeAllEntityListMenu(); - }; + }; + elBrokenURLReport.onclick = function () { + EventBridge.emitWebEvent(JSON.stringify({ type: "brokenURLReport" })); + closeAllEntityListMenu(); + }; elToggleSpaceMode.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: "toggleSpaceMode" })); }; diff --git a/scripts/system/create/modules/brokenURLReport.html b/scripts/system/create/modules/brokenURLReport.html new file mode 100644 index 0000000000..17ab908f0c --- /dev/null +++ b/scripts/system/create/modules/brokenURLReport.html @@ -0,0 +1,102 @@ + + + + + + + + +
+
+

+
+
+ Testing in progress... +

+
+ +
+
+ + + diff --git a/scripts/system/create/modules/brokenURLReport.js b/scripts/system/create/modules/brokenURLReport.js new file mode 100644 index 0000000000..c3a6eba8cd --- /dev/null +++ b/scripts/system/create/modules/brokenURLReport.js @@ -0,0 +1,393 @@ +// +// brokenURLReport.js +// +// Created by Alezia Kurdis on February 22, 2021. +// Copyright 2021 Vircadia contributors. +// +// This script reports broken URLs to the Create Application. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var brokenURLReportHttpRequest; +var brokenURLReportUrlList = []; +var brokenURLReportInvalideUrlList = []; +var brokenURLReportProcessedUrlNo = 0; +var brokenURLReportUrlEntry; +var brokenURLReportMessageBox; +var brokenURLReportOverlayWebWindow; +var BROKEN_URL_REPORT_YES_BUTTON = 0x4000; +var BROKEN_URL_REPORT_NO_BUTTON = 0x10000; +var MAX_URL_BEFORE_WARNING_FOR_LONG_PROCESS = 20; + +function brokenURLReportRequestUrlValidityCheck(no) { + brokenURLReportHttpRequest = new XMLHttpRequest(); + brokenURLReportHttpRequest.requestComplete.connect(brokenURLReportGetResponseStatus); + brokenURLReportHttpRequest.open("GET", brokenURLReportUrlList[no].url); + brokenURLReportHttpRequest.send(); +} + +function brokenURLReportGetResponseStatus() { + if (brokenURLReportHttpRequest.status === 0 || brokenURLReportHttpRequest.status > 299) { + if (brokenURLReportHttpRequest.status === 0) { + brokenURLReportUrlList[brokenURLReportProcessedUrlNo].validity = "0 - URL not well-formed"; + } else { + brokenURLReportUrlList[brokenURLReportProcessedUrlNo].validity = brokenURLReportHttpRequest.status + " - " + brokenURLReportHttpRequest.statusText; + } + brokenURLReportInvalideUrlList.push(brokenURLReportUrlList[brokenURLReportProcessedUrlNo]); + } + brokenURLReportHttpRequest.requestComplete.disconnect(brokenURLReportGetResponseStatus); + brokenURLReportHttpRequest = null; + brokenURLReportProcessedUrlNo = brokenURLReportProcessedUrlNo + 1; + if (brokenURLReportProcessedUrlNo === brokenURLReportUrlList.length) { + brokenURLReportGenerateFormatedReport(brokenURLReportInvalideUrlList); + brokenURLReportUrlList = []; + brokenURLReportInvalideUrlList = []; + brokenURLReportProcessedUrlNo = 0; + } else { + brokenURLReportRequestUrlValidityCheck(brokenURLReportProcessedUrlNo); + } +} + +function brokenURLReportGenerateFormatedReport(brokenURLReportInvalideUrlList) { + var brokenURLReportContent = ""; + if (brokenURLReportInvalideUrlList.length === 0) { + brokenURLReportContent = "

Broken URL Report

" + brokenURLReportUrlList.length + " URL tested.
NO ISSUES HAVE BEEN FOUND.




"; + brokenURLReportContent += "

This report ignores Asset Server URLs (atp://), local drive paths, and any string not starting with 'http'.
"; + Script.setTimeout(function () { + brokenURLReportOverlayWebWindow.emitScriptEvent(brokenURLReportContent); + }, 3000); + return; + } + brokenURLReportContent = "

Broken URL Report

\n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + for (var i = 0; i < brokenURLReportInvalideUrlList.length; i++ ){ + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + brokenURLReportContent += " \n"; + } + brokenURLReportContent += "
 EntityBroken Url
NoTypeName & ID PropertyStatusCurrent URL
" + (i + 1) + "" + brokenURLReportInvalideUrlList[i].type + "" + brokenURLReportInvalideUrlList[i].name + "
" + brokenURLReportInvalideUrlList[i].id + "
" + brokenURLReportInvalideUrlList[i].urlType + "" + brokenURLReportInvalideUrlList[i].validity + "" + brokenURLReportInvalideUrlList[i].url + "
\n"; + brokenURLReportContent += "

" + brokenURLReportUrlList.length + " URL tested.

"; + brokenURLReportContent += "
This report ignores Asset Server URLs (atp://), local drive paths, and any string not starting with 'http'.
"; + + Script.setTimeout(function () { + brokenURLReportOverlayWebWindow.emitScriptEvent(brokenURLReportContent); + }, 3000); +} + +function brokenURLReportGetUrlTypeColor(urlType) { + var color = "#FFFFFF"; + switch (urlType) { + case "script": + color = "#00FF00"; + break; + case "serverScripts": + color = "#FF00FF"; + break; + case "imageURL": + color = "#00FFFF"; + break; + case "materialURL": + color = "#FF6600"; + break; + case "modelURL": + color = "#FFFF00"; + break; + case "compoundShapeURL": + color = "#6666FF"; + break; + case "animation.url": + color = "#6699FF"; + break; + case "textures": + color = "#FF0066"; + break; + case "xTextureURL": + color = "#0000FF"; + break; + case "yTextureURL": + color = "#009966"; + break; + case "zTextureURL": + color = "#993366"; + break; + case "font": + color = "#FFFFFF"; + break; + case "sourceUrl": + color = "#BBFF00"; + break; + case "scriptURL": + color = "#FFBBBB"; + break; + case "filterURL": + color = "#BBBBFF"; + break; + case "skybox.url": + color = "#BBFFFF"; + break; + case "ambientLight.ambientURL": + color = "#FF3300"; + } + return color; +} + +function brokenURLReport(entityIDs) { + if (entityIDs.length === 0) { + audioFeedback.rejection(); + Window.alert("You have nothing selected."); + return; + } else { + var properties; + for (var i = 0; i < entityIDs.length; i++ ){ + properties = Entities.getEntityProperties(entityIDs[i]); + if (properties.script.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "script", + url: properties.script, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.serverScripts.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "serverScripts", + url: properties.serverScripts, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Image" && properties.imageURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "imageURL", + url: properties.imageURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Material" && properties.materialURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "materialURL", + url: properties.materialURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Model" && properties.modelURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "modelURL", + url: properties.modelURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if ( + (properties.type === "Zone" || properties.type === "Model" || properties.type === "ParticleEffect") + && properties.compoundShapeURL.toLowerCase().startsWith("http") + ) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "compoundShapeURL", + url: properties.compoundShapeURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Model" && properties.animation.url.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "animation.url", + url: properties.animation.url, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "ParticleEffect" && properties.textures.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "textures", + url: properties.textures, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "PolyVox" && properties.xTextureURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "xTextureURL", + url: properties.xTextureURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "PolyVox" && properties.yTextureURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "yTextureURL", + url: properties.yTextureURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "PolyVox" && properties.zTextureURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "zTextureURL", + url: properties.zTextureURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Text" && properties.font.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "font", + url: properties.font, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Web" && properties.sourceUrl.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "sourceUrl", + url: properties.sourceUrl, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Web" && properties.scriptURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "scriptURL", + url: properties.scriptURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Zone" && properties.filterURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "filterURL", + url: properties.filterURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Zone" && properties.skybox.url.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "skybox.url", + url: properties.skybox.url, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + if (properties.type === "Zone" && properties.ambientLight.ambientURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "ambientLight.ambientURL", + url: properties.ambientLight.ambientURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } + } + if (brokenURLReportUrlList.length === 0) { + audioFeedback.confirmation(); + Window.alert("No 'http' URL has been found within the current selection."); + return; + } else { + if (brokenURLReportUrlList.length > MAX_URL_BEFORE_WARNING_FOR_LONG_PROCESS) { + var message = "Number of http URLs found: " + brokenURLReportUrlList.length + "\n The analysis may take time. Do you want to proceed?"; + var answer = Window.confirm(message); + if (!answer) { + return; + } + } + if (brokenURLReportOverlayWebWindow !== undefined) { + brokenURLReportOverlayWebWindow.close(); + } + brokenURLReportOverlayWebWindow = new OverlayWebWindow({ + title: "Broken URL Report", + source: Script.resolvePath("brokenURLReport.html"), + width: 1000, + height: 600 + }); + brokenURLReportContent = ""; + brokenURLReportRequestUrlValidityCheck(brokenURLReportProcessedUrlNo); + } + } + + brokenURLReportOverlayWebWindow.webEventReceived.connect(function (message) { + try { + var data = JSON.parse(message); + } catch(e) { + print("brokenURLReport.js: Error parsing JSON"); + return; + } + if (data.action === "select") { + selectionManager.setSelections([data.entityID], this); + } + }); +} diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index efbb531124..9b3e862210 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -1969,7 +1969,7 @@ div.entity-list-menu { } div.menu-separator{ - width: 90%; + width: 100%; height: 2px; background-color: #505050; } @@ -1987,12 +1987,12 @@ button.menu-button { } button.menu-button:hover { - background-color: #00B4EF; + background-color: #919191; border: none; } button.menu-button:active { - background-color: #00B4EF; + background-color: #919191; border: none; }