Skip to content

Commit 0781f87

Browse files
ok
1 parent de919f3 commit 0781f87

8 files changed

Lines changed: 223 additions & 72 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<div class="card">
2+
<div class="card-body">
3+
<fieldset class="card-text">
4+
<legend>Property</legend>
5+
<div class="mb-3">
6+
<label :for="'formselect-property-type-' + uuid" class="form-label">Type</label>
7+
<input type="text" class="form-control" :id="'formselect-property-type-' + uuid" placeholder="PropertyType" @input="onPropertyTypeChanged" />
8+
</div>
9+
<div class="mb-3">
10+
<label :for="'forminput-property-name-' + uuid" class="form-label">Name</label>
11+
<input type="text" class="form-control" :id="'forminput-property-name-' + uuid" placeholder="PropertyName" @input="onPropertyNameChanged" />
12+
</div>
13+
</fieldset>
14+
</div>
15+
</div>

site/idesigner/index.html

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,32 @@
1010
<nav id="vjs-navbar"></nav>
1111
<div id="vjs-appcontent">
1212
<div class="container mt-4">
13-
<h1>Interface Designer Page</h1>
13+
<h1>Interface Designer</h1>
14+
<form>
15+
<fieldset>
16+
<legend>Metadata</legend>
17+
<div class="mb-3" id="form-interface-metadata">
18+
<label for="forminput-interface-name" class="form-label">Interface Name</label>
19+
<input type="text" class="form-control" id="forminput-interface-name" placeholder="IInterfaceName">
20+
</div>
21+
</fieldset>
22+
<fieldset>
23+
<legend>Properties</legend>
24+
<div class="mb-3" id="form-interface-properties">
25+
26+
</div>
27+
<div class="mb-3">
28+
<button type="button" class="btn btn-primary mb-3" id="formcontrol-add-property">Add Property</button>
29+
</div>
30+
</fieldset>
31+
32+
</form>
1433
</div>
1534
</div>
1635
<script src="../lib/js/bootstrap.min.js"></script>
1736
<script src="../lib/js/jquery-3.7.1.min.js"></script>
18-
<script src="../lib/js/vue.global.prod.min.js"></script>
37+
<script src="../lib/js/vue-3.5.17.min.js"></script>
1938
<script src="../resources/scripts/vue.js"></script>
39+
<script src="../resources/scripts/idesigner.js"></script>
2040
</body>
2141
</html>

site/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ <h1>Home Page</h1>
1515
</div>
1616
<script src="./lib/js/bootstrap.min.js"></script>
1717
<script src="./lib/js/jquery-3.7.1.min.js"></script>
18-
<script src="./lib/js/vue.global.prod.min.js"></script>
18+
<script src="./lib/js/vue-3.5.17.min.js"></script>
1919
<script src="./resources/scripts/vue.js"></script>
2020
</body>
2121
</html>

site/lib/js/vue-3.5.17.min.js

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/lib/js/vue.global.prod.min.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

site/resources/config.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"_comment": "All locations are relative to the site's root directory ( /site/. ).",
3+
"locations": {
4+
"components": {
5+
"navbar": "./components/navbar.html",
6+
"idesigner": {
7+
"property": "./components/idesigner/property.html"
8+
}
9+
},
10+
"navbar": {
11+
"home": {
12+
"name": "Home",
13+
"url": "./"
14+
},
15+
"idesigner": {
16+
"name": "Interface Designer",
17+
"url": "./idesigner/"
18+
}
19+
}
20+
}
21+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/** @import * as $ from "../../lib/js/jquery-3.7.1.min.js" **/
2+
/** @import * as Vue from "../../lib/js/vue-3.5.17.min.js" **/
3+
4+
// Storage for the working interface.
5+
const interface = {
6+
metadata: {
7+
name: undefined
8+
},
9+
properties: []
10+
};
11+
12+
function onInterfaceNameChanged(element) {
13+
interface.metadata.name = element.target.value;
14+
}
15+
16+
async function onAddProperty(element) {
17+
const $properties = $("#form-interface-properties");
18+
19+
// Create the property element and load the HTML content into it.
20+
const id = crypto.randomUUID();
21+
const $property = $("<div>").attr("id", `property-${id}`);
22+
$properties.before($property, $properties.children().last());
23+
await loadInto($property, relativeToScript(`../../${config.locations.components.idesigner.property}`));
24+
25+
// Add the property to the interface storage
26+
interface.properties.push({
27+
id: id,
28+
type: undefined,
29+
name: undefined
30+
});
31+
32+
// Construct the Vue app for the property
33+
const app = Vue.createApp({
34+
setup() {
35+
return {
36+
"uuid": Vue.ref(id)
37+
}
38+
},
39+
methods: {
40+
onPropertyNameChanged(event) {
41+
// Update the interface properties with the new name
42+
const property = interface.properties.find(prop => prop.id === id);
43+
if (property) {
44+
property.name = event.target.value;
45+
}
46+
console.debug(`Property ${id} name changed: ${event.target.value}`);
47+
}
48+
}
49+
});
50+
app.mount(`#property-${id}`);
51+
}
52+
53+
(async function() {
54+
// Inputs
55+
const $interfaceName = $("#forminput-interface-name");
56+
$interfaceName.on("input", onInterfaceNameChanged);
57+
58+
// Controls
59+
const $addProperty = $("#formcontrol-add-property");
60+
$addProperty.on("click", onAddProperty);
61+
})();

site/resources/scripts/vue.js

Lines changed: 78 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
/** @import * as $ from "../../lib/js/jquery-3.7.1.min.js" **/
2+
/** @import * as Vue from "../../lib/js/vue-3.5.17.min.js" **/
3+
4+
const log_prefix = "[vue.js] ";
5+
16
/* Helper script for resolving relative paths */
7+
const src = document.currentScript.src;
28
function relativeToScript(path) {
3-
return new URL(path, new URL('.', document.currentScript.src)).toString();
9+
return new URL(path, new URL('.', src)).toString();
410
}
511

612
/* Helper script for loading an HTML file into an existing element */
7-
async function loadInto(element, path) {
13+
function loadInto(element, path) {
814
return new Promise((resolve, reject) => {
915
$.ajax({
1016
url: path,
@@ -26,77 +32,88 @@ async function loadInto(element, path) {
2632
});
2733
}
2834

29-
/* Global app reference */
30-
class InteractiveUML {
31-
constructor() {
32-
// Elements
33-
this.elements = {
34-
navbar: null,
35-
appcontent: null
36-
};
37-
38-
// Vue apps
39-
this.vueapps = {
40-
navbar: null,
41-
appcontent: null
42-
};
43-
}
35+
/**
36+
* Loads the configuration from config.json.
37+
* @returns {Promise<Object>} A promise that resolves to the configuration object.
38+
*/
39+
function loadConfig() {
40+
return new Promise(function(resolve, reject) {
41+
$.getJSON(relativeToScript("../config.json")).done(function(json) {
42+
console.log(`${log_prefix}Configuration loaded successfully!`, json);
43+
resolve(json);
44+
}).fail(function(xhr, status, error) {
45+
reject(`Error loading config.json: ${xhr.status} - ${xhr.statusText}`);
46+
});
47+
});
4448
}
45-
globalThis.app = new InteractiveUML();
4649

47-
/* Main script for Vue functionality */
48-
'use strict';
49-
(async function () {
50-
// Global variables
51-
const home_loc = relativeToScript('../../');
52-
const idesigner_loc = relativeToScript('../../idesigner/');
53-
const navbar_id = 'vjs-navbar';
54-
const navbar_loc = relativeToScript('../../components/navbar.html');
55-
const appcontent_id = 'vjs-appcontent';
50+
/**
51+
* Loads HTML content into the specified element, replacing the element with the new contents.
52+
* @param {HTMLElement} element The HTML element to load content into.
53+
* @param {string} path The path to the HTML file to load.
54+
* @returns {Promise<void>} A promise that resolves when the content is loaded.
55+
*/
56+
function loadHtmlContent(element, path) {
57+
return new Promise(function(resolve, reject) {
58+
$.get(path).done(function(data) {
59+
const $orig = $(element);
60+
const $new = $(data);
61+
const id = $orig.attr('id');
62+
$orig.replaceWith($new);
63+
$new.attr('id', id); // restore the ID
64+
resolve();
65+
}).fail(function(xhr, status, error) {
66+
reject(`Error loading HTML content from ${path}: ${xhr.status} - ${xhr.statusText}`);
67+
});
68+
});
69+
}
5670

57-
// Find and verify HTML elements
58-
const html_navbar = document.querySelector(`#${navbar_id}`);
59-
if (html_navbar == undefined) {
60-
console.error("Unable to load navbar, #vjs-navbar not found!");
61-
return;
62-
}
63-
if (html_navbar.tagName.localeCompare('nav', undefined, { sensitivity: 'base' }) != 0) {
64-
console.error("Navbar element is not a <nav> tag, please check your HTML!");
65-
return;
66-
}
67-
const jq_navbar = $(html_navbar);
68-
app.elements.navbar = jq_navbar;
69-
const html_appcontent = document.querySelector(`#${appcontent_id}`);
70-
if (html_appcontent == undefined) {
71-
console.error("Unable to load content, #vjs-appcontent not found!");
72-
return;
73-
}
74-
const jq_appcontent = $(html_appcontent);
75-
app.elements.appcontent = jq_appcontent;
71+
/**
72+
* Prepares the navigation bar by loading its content and setting up Vue.js.
73+
* @param {*} config
74+
*/
75+
async function loadNavbar(config) {
76+
// Find the preconfigured navbar element
77+
const $navbar = $('#vjs-navbar');
78+
if ($navbar.length == 0) return await Promise.reject("Navbar element not found in the document!");
79+
console.debug(`${log_prefix}Found navbar element:`, $navbar[0]);
7680

77-
// Load navigation bar
78-
await loadInto(jq_navbar, navbar_loc, navbar_id);
81+
// Load the navbar HTML content
82+
const navbar_loc = relativeToScript(`../../${config.locations.components.navbar}`);
83+
console.debug(`${log_prefix}Loading navbar content from:`, navbar_loc);
84+
await loadInto($navbar, navbar_loc);
7985

80-
// Initialize Vue app for the navbar
86+
// Create the Vue app for the navbar
8187
const vue_navbar = Vue.createApp({
8288
setup() {
83-
const navItems = Vue.ref([
84-
{ name: 'Home', href: home_loc, active: false },
85-
{ name: 'IInterface Designer', href: idesigner_loc, active: false }
86-
]);
87-
const currentUrl = new URL(window.location.href);
88-
for (const item of navItems.value) {
89+
const items = [];
90+
$.each(config.locations.navbar, function(key, value) {
91+
console.debug(`${log_prefix}Adding navbar item:`, value);
92+
items.push({
93+
name: value.name,
94+
href: relativeToScript(`../../${value.url}`),
95+
active: false
96+
});
97+
});
98+
const url = new URL(window.location.href);
99+
for (const item of items) {
89100
const itemUrl = new URL(item.href, document.baseURI);
90-
if (itemUrl.pathname.localeCompare(currentUrl.pathname, undefined, { sensitivity: 'base' }) === 0) {
101+
if (itemUrl.pathname.localeCompare(url.pathname, undefined, { sensitivity: 'base' }) === 0) {
91102
item.active = true;
92103
}
93104
}
94-
return { navItems };
105+
return {
106+
"navItems": Vue.ref(items),
107+
};
95108
}
96109
});
97-
vue_navbar.mount('#' + navbar_id);
98-
app.vueapps.navbar = vue_navbar;
110+
vue_navbar.mount('#vjs-navbar');
111+
console.log(`${log_prefix}Vue app for navbar mounted successfully!`, vue_navbar);
112+
}
99113

100-
// Done! ^-^
101-
console.log("Vue.js script loaded successfully!", app);
114+
/* Main script for Vue functionality */
115+
'use strict';
116+
(async function () {
117+
globalThis.config = await loadConfig();
118+
await loadNavbar(config);
102119
})();

0 commit comments

Comments
 (0)