@needle-tools/engine 3.2.13-alpha → 3.2.15-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/needle-engine.js +8177 -8108
- package/dist/needle-engine.min.js +274 -288
- package/dist/needle-engine.umd.cjs +264 -278
- package/lib/engine/codegen/register_types.js +2 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_license.js +11 -24
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.d.ts +1 -1
- package/lib/engine-components/SceneSwitcher.js +25 -1
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.d.ts +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js +13 -6
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +11 -4
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/utils/OpenURL.d.ts +21 -0
- package/lib/engine-components/utils/OpenURL.js +125 -0
- package/lib/engine-components/utils/OpenURL.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/engine/codegen/register_types.js +2 -0
- package/src/engine/engine_license.ts +12 -25
- package/src/engine-components/SceneSwitcher.ts +28 -3
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/export/usdz/USDZExporter.ts +10 -6
- package/src/engine-components/ui/EventSystem.ts +11 -5
- package/src/engine-components/utils/OpenURL.ts +119 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.15-alpha",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"postprocessing": "^6.30.1",
|
|
62
62
|
"simplex-noise": "^4.0.1",
|
|
63
63
|
"stats.js": "^0.17.0",
|
|
64
|
-
"three": "npm:@needle-tools/three@^0.146.
|
|
64
|
+
"three": "npm:@needle-tools/three@^0.146.8",
|
|
65
65
|
"three-mesh-ui": "^6.4.5",
|
|
66
66
|
"three.quarks": "^0.7.3",
|
|
67
67
|
"uuid": "^9.0.0",
|
|
@@ -95,6 +95,7 @@ import { Networking } from "../../engine-components/Networking";
|
|
|
95
95
|
import { NoiseModule } from "../../engine-components/ParticleSystemModules";
|
|
96
96
|
import { ObjectRaycaster } from "../../engine-components/ui/Raycaster";
|
|
97
97
|
import { OffsetConstraint } from "../../engine-components/OffsetConstraint";
|
|
98
|
+
import { OpenURL } from "../../engine-components/utils/OpenURL";
|
|
98
99
|
import { OrbitControls } from "../../engine-components/OrbitControls";
|
|
99
100
|
import { ParticleBurst } from "../../engine-components/ParticleSystemModules";
|
|
100
101
|
import { ParticleSubEmitter } from "../../engine-components/ParticleSystemSubEmitter";
|
|
@@ -284,6 +285,7 @@ TypeStore.add("Networking", Networking);
|
|
|
284
285
|
TypeStore.add("NoiseModule", NoiseModule);
|
|
285
286
|
TypeStore.add("ObjectRaycaster", ObjectRaycaster);
|
|
286
287
|
TypeStore.add("OffsetConstraint", OffsetConstraint);
|
|
288
|
+
TypeStore.add("OpenURL", OpenURL);
|
|
287
289
|
TypeStore.add("OrbitControls", OrbitControls);
|
|
288
290
|
TypeStore.add("ParticleBurst", ParticleBurst);
|
|
289
291
|
TypeStore.add("ParticleSubEmitter", ParticleSubEmitter);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getParam } from "./engine_utils";
|
|
1
|
+
import { getParam, isMobileDevice } from "./engine_utils";
|
|
2
2
|
import { ContextEvent, ContextRegistry } from "./engine_context_registry";
|
|
3
3
|
import { IContext } from "./engine_types";
|
|
4
4
|
import { logoSVG } from "./assets";
|
|
@@ -31,8 +31,8 @@ async function showLicenseInfo(ctx: IContext) {
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
const licenseElementIdentifier = "needle-license-element";
|
|
34
|
-
const licenseDuration =
|
|
35
|
-
const licenseDelay =
|
|
34
|
+
const licenseDuration = 5000;
|
|
35
|
+
const licenseDelay = 200;
|
|
36
36
|
|
|
37
37
|
function onNonCommercialVersionDetected(ctx: IContext) {
|
|
38
38
|
setTimeout(() => insertNonCommercialUseHint(ctx), 2000);
|
|
@@ -62,7 +62,8 @@ function insertNonCommercialUseHint(ctx: IContext) {
|
|
|
62
62
|
|
|
63
63
|
const textElement = document.createElement("div");
|
|
64
64
|
textElement.classList.add("text");
|
|
65
|
-
|
|
65
|
+
// if (!isMobileDevice())
|
|
66
|
+
// textElement.innerHTML = "Needle Engine<br/><span class=\"non-commercial\">Non Commercial</span>";
|
|
66
67
|
licenseElement.appendChild(textElement);
|
|
67
68
|
|
|
68
69
|
licenseElement.title = "Needle Engine — non commercial version";
|
|
@@ -157,11 +158,11 @@ function createLicenseStyle() {
|
|
|
157
158
|
animation-delay: ${licenseDelay / 1000}s;
|
|
158
159
|
animation-easing: ease-in-out;
|
|
159
160
|
mix-blend-mode: difference;
|
|
160
|
-
color: rgb(
|
|
161
|
+
color: rgb(0, 0, 0);
|
|
161
162
|
mix-blend-mode: difference;
|
|
162
163
|
line-height: 1em;
|
|
163
164
|
margin-left: -3px;
|
|
164
|
-
text-shadow: 0 0 2px rgba(200,200,200, .
|
|
165
|
+
text-shadow: 0 0 2px rgba(200,200,200, .5);
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
${selector} .text .non-commercial {
|
|
@@ -175,30 +176,16 @@ function createLicenseStyle() {
|
|
|
175
176
|
transform: translate(0px, 10px);
|
|
176
177
|
pointer-events: none;
|
|
177
178
|
}
|
|
178
|
-
|
|
179
|
-
transform: translate(0, -5px);
|
|
180
|
-
opacity: 1;
|
|
181
|
-
}
|
|
182
|
-
2% {
|
|
183
|
-
transform: translate(0, 2.5px);
|
|
184
|
-
}
|
|
185
|
-
3% {
|
|
179
|
+
8% {
|
|
186
180
|
transform: translate(0, 0px);
|
|
187
181
|
pointer-events: all;
|
|
182
|
+
opacity: 1;
|
|
183
|
+
transform: scale(1.1)
|
|
188
184
|
}
|
|
189
|
-
|
|
190
|
-
transform: scale(1)
|
|
191
|
-
}
|
|
192
|
-
4.5% {
|
|
193
|
-
transform: scale(1.3)
|
|
194
|
-
}
|
|
195
|
-
6% {
|
|
196
|
-
transform: scale(1.32)
|
|
197
|
-
}
|
|
198
|
-
7% {
|
|
185
|
+
20% {
|
|
199
186
|
transform: scale(1)
|
|
200
187
|
}
|
|
201
|
-
|
|
188
|
+
90% {
|
|
202
189
|
opacity: 1;
|
|
203
190
|
pointer-events: all;
|
|
204
191
|
transform: scale(1)
|
|
@@ -186,8 +186,33 @@ export class SceneSwitcher extends Behaviour {
|
|
|
186
186
|
return this.select(this._currentIndex - 1);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
select(index: number): Promise<boolean> {
|
|
190
|
-
if (debug) console.log("select", index)
|
|
189
|
+
select(index: number | string): Promise<boolean> {
|
|
190
|
+
if (debug) console.log("select", index);
|
|
191
|
+
|
|
192
|
+
if(typeof index === "object"){
|
|
193
|
+
// If a user tries to reference a scene object in a UnityEvent and invoke select(obj)
|
|
194
|
+
// Then the object will be serialized as a object { guid : ... } or with the index json pointer
|
|
195
|
+
// This case is not supported right now. Object references in the editor must not be scene references
|
|
196
|
+
console.warn("Switching to \"" + index + "\" might not work. Please either use an index or a AssetReference (not a scene reference)");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (typeof index === "string") {
|
|
200
|
+
// If the parameter is a string we try to resolve the scene by its uri
|
|
201
|
+
// it's either already known in the scenes array
|
|
202
|
+
// or we create/get a new AssetReference and try to switch to that
|
|
203
|
+
const scene = this.scenes?.find(s => s.uri === index);
|
|
204
|
+
if (!scene) {
|
|
205
|
+
// Ok the scene is unknown to the scene switcher
|
|
206
|
+
// we create a new asset reference (or get an existing one)
|
|
207
|
+
// And switch to that. With this we can not modify the history
|
|
208
|
+
// Until the scene switcher can store the uri in the history instead of the index
|
|
209
|
+
const reference = AssetReference.getOrCreate(this.sourceId ?? "", index, this.context);
|
|
210
|
+
return this.switchScene(reference);
|
|
211
|
+
}
|
|
212
|
+
if (scene) index = this.scenes.indexOf(scene);
|
|
213
|
+
else return couldNotLoadScenePromise;
|
|
214
|
+
}
|
|
215
|
+
|
|
191
216
|
if (!this.scenes?.length) return couldNotLoadScenePromise;
|
|
192
217
|
if (index < 0) {
|
|
193
218
|
if (this.clamp) return couldNotLoadScenePromise;
|
|
@@ -225,7 +250,7 @@ export class SceneSwitcher extends Behaviour {
|
|
|
225
250
|
GameObject.add(scene.asset, this.gameObject);
|
|
226
251
|
if (this.useSceneLighting)
|
|
227
252
|
this.context.sceneLighting.enable(scene)
|
|
228
|
-
if (this.useHistory) {
|
|
253
|
+
if (this.useHistory && index >= 0) {
|
|
229
254
|
// save the loaded scene as an url parameter
|
|
230
255
|
if (this.queryParameterName?.length)
|
|
231
256
|
setParamWithoutReload(this.queryParameterName, index.toString(), this.useHistory);
|
|
@@ -93,6 +93,7 @@ export { Networking } from "../Networking";
|
|
|
93
93
|
export { NoiseModule } from "../ParticleSystemModules";
|
|
94
94
|
export { ObjectRaycaster } from "../ui/Raycaster";
|
|
95
95
|
export { OffsetConstraint } from "../OffsetConstraint";
|
|
96
|
+
export { OpenURL } from "../utils/OpenURL";
|
|
96
97
|
export { OrbitControls } from "../OrbitControls";
|
|
97
98
|
export { ParticleBurst } from "../ParticleSystemModules";
|
|
98
99
|
export { ParticleSubEmitter } from "../ParticleSystemSubEmitter";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { delay, getParam, isiOS, isMobileDevice, isSafari } from "../../../engine/engine_utils";
|
|
2
|
-
import { Object3D, Color } from "three";
|
|
3
|
-
import * as THREE from "three";
|
|
2
|
+
import { Object3D, Color, Mesh, Matrix4 } from "three";
|
|
4
3
|
import { USDZExporter as ThreeUSDZExporter } from "three/examples/jsm/exporters/USDZExporter";
|
|
5
4
|
import { AnimationExtension } from "./extensions/Animation"
|
|
6
5
|
import { ensureQuicklookLinkIsCreated } from "./utils/quicklook";
|
|
@@ -13,6 +12,7 @@ import { serializable } from "../../../engine/engine_serialization";
|
|
|
13
12
|
import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../../engine/debug/debug";
|
|
14
13
|
import { Context } from "../../../engine/engine_setup";
|
|
15
14
|
import { WebARSessionRoot } from "../../webxr/WebARSessionRoot";
|
|
15
|
+
import { hasProLicense } from "../../../engine/engine_license";
|
|
16
16
|
|
|
17
17
|
const debug = getParam("debugusdz");
|
|
18
18
|
|
|
@@ -37,6 +37,9 @@ export class USDZExporter extends Behaviour {
|
|
|
37
37
|
@serializable()
|
|
38
38
|
autoExportAnimations: boolean = false;
|
|
39
39
|
|
|
40
|
+
@serializable()
|
|
41
|
+
exportFileName?: string;
|
|
42
|
+
|
|
40
43
|
@serializable(QuickLookOverlay)
|
|
41
44
|
overlay?: QuickLookOverlay;
|
|
42
45
|
|
|
@@ -72,7 +75,7 @@ export class USDZExporter extends Behaviour {
|
|
|
72
75
|
if (!this.objectToExport) this.objectToExport = this.gameObject;
|
|
73
76
|
|
|
74
77
|
|
|
75
|
-
if (isDevEnvironment() && (!this.objectToExport
|
|
78
|
+
if (isDevEnvironment() && (!this.objectToExport?.children?.length && !(this.objectToExport as Mesh)?.isMesh)) {
|
|
76
79
|
showBalloonWarning("USDZ Exporter has nothing to export");
|
|
77
80
|
console.warn("USDZExporter has no objects to export assigned:", this)
|
|
78
81
|
}
|
|
@@ -114,7 +117,7 @@ export class USDZExporter extends Behaviour {
|
|
|
114
117
|
const scale = 1 / this.webARSessionRoot!.arScale;
|
|
115
118
|
scene.matrix.makeScale(scale, scale, scale);
|
|
116
119
|
if (this.webARSessionRoot.invertForward) {
|
|
117
|
-
scene.matrix.multiply(new
|
|
120
|
+
scene.matrix.multiply(new Matrix4().makeRotationY(Math.PI));
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
123
|
|
|
@@ -131,8 +134,9 @@ export class USDZExporter extends Behaviour {
|
|
|
131
134
|
const eventArgs = { self: this, exporter: exporter, extensions: extensions, object: this.objectToExport };
|
|
132
135
|
this.dispatchEvent(new CustomEvent("before-export", { detail: eventArgs }))
|
|
133
136
|
|
|
134
|
-
let name =
|
|
137
|
+
let name = this.exportFileName ?? this.objectToExport?.name ?? this.name;
|
|
135
138
|
if (debug) name += "-" + getFormattedDate();
|
|
139
|
+
else if (!hasProLicense()) name = name + " - Made with Needle";
|
|
136
140
|
|
|
137
141
|
//@ts-ignore
|
|
138
142
|
exporter.debug = debug;
|
|
@@ -152,7 +156,7 @@ export class USDZExporter extends Behaviour {
|
|
|
152
156
|
|
|
153
157
|
// see https://developer.apple.com/documentation/arkit/adding_an_apple_pay_button_or_a_custom_action_in_ar_quick_look
|
|
154
158
|
const overlay = this.buildQuicklookOverlay();
|
|
155
|
-
console.log(overlay);
|
|
159
|
+
if(debug) console.log(overlay);
|
|
156
160
|
const callToAction = overlay.callToAction ? encodeURIComponent(overlay.callToAction) : "";
|
|
157
161
|
const checkoutTitle = overlay.checkoutTitle ? encodeURIComponent(overlay.checkoutTitle) : "";
|
|
158
162
|
const checkoutSubtitle = overlay.checkoutSubtitle ? encodeURIComponent(overlay.checkoutSubtitle) : "";
|
|
@@ -6,14 +6,14 @@ import * as ThreeMeshUI from 'three-mesh-ui'
|
|
|
6
6
|
import { Context } from "../../engine/engine_setup";
|
|
7
7
|
import { OrbitControls } from "../OrbitControls";
|
|
8
8
|
import { IPointerEventHandler, PointerEventData } from "./PointerEvents";
|
|
9
|
-
import { Raycaster } from "./Raycaster";
|
|
9
|
+
import { ObjectRaycaster, Raycaster } from "./Raycaster";
|
|
10
10
|
import { InputEvents } from "../../engine/engine_input";
|
|
11
11
|
import { Object3D } from "three";
|
|
12
12
|
import { ICanvasGroup, IGraphic } from "./Interfaces";
|
|
13
13
|
import { getParam } from "../../engine/engine_utils";
|
|
14
14
|
import { UIRaycastUtils } from "./RaycastUtils";
|
|
15
15
|
import { $shadowDomOwner } from "./BaseUIComponent";
|
|
16
|
-
import { showBalloonMessage, showBalloonWarning } from "../../engine/debug";
|
|
16
|
+
import { isDevEnvironment, showBalloonMessage, showBalloonWarning } from "../../engine/debug";
|
|
17
17
|
|
|
18
18
|
const debug = getParam("debugeventsystem");
|
|
19
19
|
|
|
@@ -86,9 +86,15 @@ export class EventSystem extends Behaviour {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
start() {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
if (this.raycaster.length <= 0) {
|
|
90
|
+
const res = GameObject.findObjectOfType(Raycaster, this.context);
|
|
91
|
+
if (!res) {
|
|
92
|
+
const rc = GameObject.addNewComponent(this.context.scene, ObjectRaycaster);
|
|
93
|
+
this.raycaster.push(rc);
|
|
94
|
+
if (isDevEnvironment())
|
|
95
|
+
console.warn("Added an ObjectRaycaster to the scene because no raycaster was found", this);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
register(rc: Raycaster) {
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
import { IPointerClickHandler, PointerEventData } from "../ui";
|
|
3
|
+
import { Behaviour } from "../Component";
|
|
4
|
+
import { serializable } from "../../engine/engine_serialization";
|
|
5
|
+
import { isDevEnvironment, showBalloonMessage } from "../../engine/debug";
|
|
6
|
+
import { isSafari } from "../../engine/engine_utils";
|
|
7
|
+
import { ObjectRaycaster, Raycaster } from "../ui/Raycaster";
|
|
8
|
+
import { tryGetUIComponent } from "../ui/Utils";
|
|
9
|
+
|
|
10
|
+
export enum OpenURLMode {
|
|
11
|
+
NewTab = 0,
|
|
12
|
+
SameTab = 1,
|
|
13
|
+
NewWindow = 2
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class OpenURL extends Behaviour implements IPointerClickHandler {
|
|
17
|
+
|
|
18
|
+
@serializable()
|
|
19
|
+
clickable: boolean = true;
|
|
20
|
+
|
|
21
|
+
@serializable()
|
|
22
|
+
url?: string;
|
|
23
|
+
|
|
24
|
+
@serializable()
|
|
25
|
+
mode: OpenURLMode = OpenURLMode.NewTab;
|
|
26
|
+
|
|
27
|
+
async open() {
|
|
28
|
+
if (!this.url) {
|
|
29
|
+
console.error("URL is not set", this);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this._validateUrl();
|
|
34
|
+
|
|
35
|
+
if (isDevEnvironment()) showBalloonMessage("Open URL: " + this.url)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
switch (this.mode) {
|
|
39
|
+
case OpenURLMode.NewTab:
|
|
40
|
+
if (isSafari()) {
|
|
41
|
+
globalThis.open(this.url, "_blank");
|
|
42
|
+
}
|
|
43
|
+
else
|
|
44
|
+
globalThis.open(this.url, "_blank");
|
|
45
|
+
break;
|
|
46
|
+
case OpenURLMode.SameTab:
|
|
47
|
+
if (isSafari()) {
|
|
48
|
+
globalThis.open(this.url, "_top");
|
|
49
|
+
}
|
|
50
|
+
else globalThis.open(this.url, "_self");
|
|
51
|
+
break;
|
|
52
|
+
case OpenURLMode.NewWindow:
|
|
53
|
+
if (isSafari()) {
|
|
54
|
+
globalThis.open(this.url, "_top");
|
|
55
|
+
}
|
|
56
|
+
else globalThis.open(this.url, "_new");
|
|
57
|
+
break;
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
start(): void {
|
|
63
|
+
const raycaster = this.gameObject.getComponentInParent(ObjectRaycaster);
|
|
64
|
+
if (!raycaster) this.gameObject.addNewComponent(ObjectRaycaster);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
onEnable(): void {
|
|
68
|
+
if (isSafari()) window.addEventListener("touchend", this._safariNewTabWorkaround);
|
|
69
|
+
}
|
|
70
|
+
onDisable(): void {
|
|
71
|
+
if (isSafari()) window.removeEventListener("touchend", this._safariNewTabWorkaround);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onPointerEnter(args) {
|
|
75
|
+
if (!args.used && this.clickable)
|
|
76
|
+
this.context.input.setCursorPointer();
|
|
77
|
+
}
|
|
78
|
+
onPointerExit() {
|
|
79
|
+
if (this.clickable)
|
|
80
|
+
this.context.input.setCursorNormal();
|
|
81
|
+
}
|
|
82
|
+
onPointerClick(args: PointerEventData) {
|
|
83
|
+
if (this.clickable && !args.used && this.url?.length)
|
|
84
|
+
this.open();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private _safariNewTabWorkaround = () => {
|
|
88
|
+
if (!this.clickable || !this.url?.length) return;
|
|
89
|
+
// we only need this workaround for opening a new tab
|
|
90
|
+
if (this.mode === OpenURLMode.SameTab) return;
|
|
91
|
+
// When we process the click directly in the browser event we can open a new tab
|
|
92
|
+
// by emitting a link attribute and calling onClick
|
|
93
|
+
const raycaster = this.gameObject.getComponentInParent(Raycaster);
|
|
94
|
+
if (raycaster) {
|
|
95
|
+
const hits = raycaster.performRaycast();
|
|
96
|
+
if (!hits) return;
|
|
97
|
+
for (const hit of hits) {
|
|
98
|
+
if (hit.object === this.gameObject || tryGetUIComponent(hit.object)?.gameObject === this.gameObject) {
|
|
99
|
+
this._validateUrl();
|
|
100
|
+
var a = document.createElement('a') as HTMLAnchorElement;
|
|
101
|
+
a.setAttribute("target", "_blank");
|
|
102
|
+
a.setAttribute("href", this.url);
|
|
103
|
+
a.click();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private _validateUrl() {
|
|
111
|
+
if (!this.url) return;
|
|
112
|
+
if (this.url.startsWith("www.")) {
|
|
113
|
+
if (isDevEnvironment()) {
|
|
114
|
+
console.warn("URL is not valid, adding https:// to the start of the URL", this.url);
|
|
115
|
+
}
|
|
116
|
+
this.url = "https://" + this.url;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|