Skip to content

Commit 04a37f5

Browse files
authored
feat: enhance browser examples, added tab menu and auto consume and improvise ui (#1387)
* feat: enhance browser examples with improved interaction handling and styling * restoring mistake deletion * fix formattng * refactor: moved custom tabs to end. added desciption and td error is showed on the page instead of window * feat: add Enter key functionality to fetch TD URL and refactor clearAllInteractions function * refactor: streamline error handling, hide td desc when error, simlified code
1 parent 06a53a3 commit 04a37f5

File tree

4 files changed

+368
-30
lines changed

4 files changed

+368
-30
lines changed

examples/browser/index.html

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
<link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation/5.5.3/css/foundation.min.css" />
77
<!-- Font Awesome icons -->
88
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.css" />
9+
<link rel="stylesheet" href="styles.css" />
910

1011
<!-- defer to not block rendering -->
1112
<script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script>
1213
<!-- local vs cdn dependency -->
13-
<script src="../../packages/browser-bundle/dist/wot-bundle.min.js" defer></script>
14-
<!-- <script
14+
<!-- <script src="../../packages/browser-bundle/dist/wot-bundle.min.js" defer></script> -->
15+
<script
1516
src="https://cdn.jsdelivr.net/npm/@node-wot/browser-bundle@latest/dist/wot-bundle.min.js"
1617
defer
17-
></script> -->
18+
></script>
1819
<script src="index.js" defer></script>
1920

2021
<script>
@@ -27,8 +28,83 @@
2728
<div id="topbar" class="row">
2829
<div class="medium-12 columns">
2930
<h1>Browsified node-wot</h1>
30-
<input id="td_addr" type="url" value="http://plugfest.thingweb.io:8083/testthing" />
31-
<button id="fetch" type="button">Consume</button>
31+
32+
<!-- Tabs for TD selection -->
33+
<ul class="tabs" data-tab id="td-tabs">
34+
<li class="tab-title active">
35+
<a href="#tab-testthing" id="tab-link-testthing">Test Thing</a>
36+
</li>
37+
<li class="tab-title">
38+
<a href="#tab-smartcoffee" id="tab-link-smartcoffee">Smart Coffee Machine</a>
39+
</li>
40+
<li class="tab-title">
41+
<a href="#tab-counter" id="tab-link-counter">Counter</a>
42+
</li>
43+
<li class="tab-title">
44+
<a href="#tab-custom" id="tab-link-custom">Custom</a>
45+
</li>
46+
</ul>
47+
<div class="tabs-content">
48+
<div class="content active" id="tab-testthing">
49+
<p>Consumed TD at <a href="" target="_blank" class="td-url"></a></p>
50+
<p>
51+
<strong>TD Description:</strong>
52+
<span class="td-description">Loading...</span>
53+
</p>
54+
</div>
55+
<div class="content" id="tab-smartcoffee">
56+
<p>
57+
Consumed TD at
58+
<a href="" target="_blank" class="td-url"></a>
59+
</p>
60+
<p>
61+
<strong>TD Description:</strong>
62+
<span class="td-description">Loading...</span>
63+
</p>
64+
</div>
65+
<div class="content" id="tab-counter">
66+
<p>Consumed TD at <a href="" target="_blank" class="td-url"></a></p>
67+
<p>
68+
<strong>TD Description:</strong>
69+
<span class="td-description">Loading...</span>
70+
</p>
71+
</div>
72+
<div class="content" id="tab-custom">
73+
<div class="row">
74+
<div class="medium-12 columns">
75+
<input
76+
id="td_addr"
77+
type="url"
78+
placeholder="Paste the TD URL to start consuming it"
79+
style="width: 100%"
80+
onkeydown="if(event.key==='Enter') document.getElementById('fetch').click()"
81+
/>
82+
</div>
83+
</div>
84+
<div class="row">
85+
<div class="medium-12 columns" style="margin-top: 10px">
86+
<button id="fetch" type="button" class="button">Consume</button>
87+
</div>
88+
</div>
89+
<div id="custom-td-info" style="margin-top: 10px">
90+
<p>Consumed TD at <a href="" target="_blank" class="td-url"></a></p>
91+
<p>
92+
<strong>TD Description:</strong>
93+
<span class="td-description">Enter a TD URL above to consume it.</span>
94+
</p>
95+
</div>
96+
</div>
97+
</div>
98+
99+
<!-- Error message container -->
100+
<div id="error-container" class="row" style="display: none; margin-top: 10px">
101+
<div class="medium-12 columns">
102+
<div class="alert-box alert" id="error-message">
103+
<span id="error-text"></span>
104+
<a href="#" class="close" id="close-error">&times;</a>
105+
</div>
106+
</div>
107+
</div>
32108
</div>
33109
</div>
34110
<div id="interactions" class="row" style="display: none">

examples/browser/index.js

Lines changed: 187 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,31 @@
1313
**/
1414

1515
function get_td(addr) {
16-
servient.start().then((thingFactory) => {
17-
helpers
18-
.fetch(addr)
19-
.then((td) => {
20-
thingFactory.consume(td).then((thing) => {
21-
removeInteractions();
22-
showInteractions(thing);
16+
clearAllInteractions();
17+
18+
servient
19+
.start()
20+
.then((thingFactory) => {
21+
helpers
22+
.fetch(addr)
23+
.then((td) => {
24+
thingFactory
25+
.consume(td)
26+
.then((thing) => {
27+
showInteractions(thing);
28+
updateTabDescription(addr, td);
29+
})
30+
.catch((err) => {
31+
updateTabDescription(addr, null, "Failed to consume TD: " + err);
32+
});
33+
})
34+
.catch((err) => {
35+
updateTabDescription(addr, null, "Failed to fetch TD: " + err);
2336
});
24-
})
25-
.catch((error) => {
26-
window.alert("Could not fetch TD.\n" + error);
27-
});
28-
});
37+
})
38+
.catch((err) => {
39+
updateTabDescription(addr, null, "Failed to start servient: " + err);
40+
});
2941
}
3042

3143
function showInteractions(thing) {
@@ -110,15 +122,6 @@ function showInteractions(thing) {
110122
}
111123
}
112124

113-
function removeInteractions() {
114-
for (id of ["properties", "actions", "events"]) {
115-
let placeholder = document.getElementById(id);
116-
while (placeholder.firstChild) {
117-
placeholder.removeChild(placeholder.firstChild);
118-
}
119-
}
120-
}
121-
122125
function showSchemaEditor(action, thing) {
123126
let td = thing.getThingDescription();
124127
// Remove old editor
@@ -163,9 +166,170 @@ function removeSchemaEditor() {
163166
}
164167
}
165168

169+
// Error handling functions to show/hide error messages on web page instead of using alert window
170+
function showError(message) {
171+
const errorContainer = document.getElementById("error-container");
172+
const errorText = document.getElementById("error-text");
173+
174+
if (errorContainer && errorText) {
175+
errorText.textContent = message;
176+
errorContainer.style.display = "block";
177+
}
178+
}
179+
180+
function hideError() {
181+
const errorContainer = document.getElementById("error-container");
182+
if (errorContainer) {
183+
errorContainer.style.display = "none";
184+
}
185+
}
186+
187+
function updateTabDescription(url, td, error) {
188+
// Find active tab and update its description
189+
const activeTab = document.querySelector(".tabs-content .content.active");
190+
if (!activeTab) return;
191+
192+
// Update URL link
193+
const urlElement = activeTab.querySelector(".td-url");
194+
if (urlElement && url) {
195+
urlElement.href = url;
196+
urlElement.textContent = url;
197+
}
198+
199+
// Update description
200+
const descriptionElement = activeTab.querySelector(".td-description");
201+
const descriptionParent = descriptionElement ? descriptionElement.closest("p") : null;
202+
203+
if (error) {
204+
// Hide description, show error banner
205+
if (descriptionParent) descriptionParent.style.display = "none";
206+
showError(error);
207+
} else {
208+
// Show description, hide error banner
209+
if (descriptionParent) descriptionParent.style.display = "";
210+
if (descriptionElement) {
211+
descriptionElement.textContent = td?.description || "No description available";
212+
descriptionElement.style.color = "";
213+
}
214+
hideError();
215+
}
216+
}
217+
218+
// Clear all interactions and editor
219+
function clearAllInteractions() {
220+
hideError();
221+
const interactions = document.getElementById("interactions");
222+
if (interactions) {
223+
interactions.style.display = "none";
224+
}
225+
["properties", "actions", "events"].forEach((id) => {
226+
const element = document.getElementById(id);
227+
if (element) element.innerHTML = "";
228+
});
229+
removeSchemaEditor();
230+
}
231+
166232
var servient = new WoT.Core.Servient();
167233
servient.addClientFactory(new WoT.Http.HttpClientFactory());
168234
var helpers = new WoT.Core.Helpers(servient);
169-
document.getElementById("fetch").onclick = () => {
170-
get_td(document.getElementById("td_addr").value);
235+
236+
// Tab configuration
237+
const TD_URLS = {
238+
testthing: "http://plugfest.thingweb.io/http-data-schema-thing",
239+
smartcoffee: "http://plugfest.thingweb.io/http-advanced-coffee-machine",
240+
counter: "http://plugfest.thingweb.io/counter",
171241
};
242+
243+
document.addEventListener("DOMContentLoaded", function () {
244+
// Parse URL parameters to pre-fill the input field
245+
let $_GET = location.search
246+
.substr(1)
247+
.split("&")
248+
.reduce((o, i) => ((u = decodeURIComponent), ([k, v] = i.split("=")), (o[u(k)] = v && u(v)), o), {});
249+
250+
// Tab configuration in correct sequence
251+
const tabLinks = [
252+
{ id: "tab-link-testthing", tab: "tab-testthing" },
253+
{ id: "tab-link-smartcoffee", tab: "tab-smartcoffee" },
254+
{ id: "tab-link-counter", tab: "tab-counter" },
255+
{ id: "tab-link-custom", tab: "tab-custom" },
256+
];
257+
258+
const tdInput = document.getElementById("td_addr");
259+
const fetchBtn = document.getElementById("fetch");
260+
const closeErrorBtn = document.getElementById("close-error");
261+
262+
// Error close button handler
263+
if (closeErrorBtn) {
264+
closeErrorBtn.onclick = (e) => {
265+
e.preventDefault();
266+
hideError();
267+
};
268+
}
269+
270+
// Pre-fill input from URL parameter if provided
271+
if ($_GET["url"]) {
272+
tdInput.value = $_GET["url"];
273+
}
274+
275+
// Tab click handlers
276+
tabLinks.forEach(({ id, tab }) => {
277+
const link = document.getElementById(id);
278+
if (link) {
279+
link.addEventListener("click", function (e) {
280+
e.preventDefault();
281+
clearAllInteractions();
282+
283+
// Switch active tab
284+
document.querySelectorAll("#td-tabs .tab-title").forEach((li) => li.classList.remove("active"));
285+
link.parentElement.classList.add("active");
286+
document.querySelectorAll(".tabs-content .content").forEach((c) => c.classList.remove("active"));
287+
document.getElementById(tab).classList.add("active");
288+
289+
// Auto-consume TD based on tab
290+
if (tab === "tab-testthing") {
291+
get_td(TD_URLS.testthing);
292+
} else if (tab === "tab-smartcoffee") {
293+
get_td(TD_URLS.smartcoffee);
294+
} else if (tab === "tab-counter") {
295+
get_td(TD_URLS.counter);
296+
} else if (tab === "tab-custom") {
297+
// Reset custom TD tab
298+
const customDesc = document.querySelector("#tab-custom .td-description");
299+
if (customDesc) {
300+
customDesc.textContent = "Enter a TD URL above to consume it.";
301+
customDesc.style.color = "";
302+
}
303+
const customUrl = document.querySelector("#tab-custom .td-url");
304+
if (customUrl) {
305+
customUrl.href = "";
306+
customUrl.textContent = "";
307+
}
308+
}
309+
});
310+
}
311+
});
312+
313+
// Custom TD fetch button
314+
if (fetchBtn) {
315+
fetchBtn.onclick = () => {
316+
if (tdInput.value) {
317+
get_td(tdInput.value);
318+
} else {
319+
showError("Please enter a valid URL.");
320+
}
321+
};
322+
}
323+
324+
// Auto-load TD if URL parameter was provided
325+
if ($_GET["url"]) {
326+
document.querySelectorAll("#td-tabs .tab-title").forEach((li) => li.classList.remove("active"));
327+
document.getElementById("tab-link-custom").parentElement.classList.add("active");
328+
document.querySelectorAll(".tabs-content .content").forEach((c) => c.classList.remove("active"));
329+
document.getElementById("tab-custom").classList.add("active");
330+
get_td($_GET["url"]);
331+
} else {
332+
// Default to Test Thing tab
333+
document.getElementById("tab-link-testthing").click();
334+
}
335+
});

examples/browser/smart-coffee-machine.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ <h1 class="text-center">Smart Coffee Machine</h1>
5656
</p>
5757
<p>
5858
The Thing Description for the coffee machine is available at
59-
<a href="http://plugfest.thingweb.io:8083/smart-coffee-machine" target="_blank"
60-
>http://plugfest.thingweb.io:8083/smart-coffee-machine</a
59+
<a href="http://plugfest.thingweb.io/http-advanced-coffee-machine" target="_blank"
60+
>http://plugfest.thingweb.io/http-advanced-coffee-machine</a
6161
>.
6262
</p>
6363
</div>

0 commit comments

Comments
 (0)