Skip to content

Commit

Permalink
feat: better QC page
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Berezovskyi <andriib@kth.se>
  • Loading branch information
berezovskyi committed Nov 16, 2024
1 parent bd62772 commit a87945c
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<%@page import="jakarta.ws.rs.core.UriBuilder"%>
<%@page import="jakarta.ws.rs.core.UriBuilder"%>
<%@page import="org.eclipse.lyo.oslc4j.core.OSLC4JUtils"%>
<%@page import="org.eclipse.lyo.oslc4j.core.model.ServiceProvider"%>
<%@page import="org.eclipse.lyo.oslc4j.core.model.AbstractResource"%>
Expand Down Expand Up @@ -67,14 +67,17 @@
<div class="page-header">
<h1>Query Capability &quot;RequirementQC&quot; results</h1>
<div class="alert alert-secondary" role="alert">
Number of elements:&nbsp;
<%= resources.size()%>
Showing&nbsp;${resources.size()} resources on this page
<% if (nextPageUri != null) { %><p><a href="<%= nextPageUri %>">Next Page</a></p><% } %>
</div>
</div>
<% for (Requirement aResource : resources) { %>
<p><a href="<%= aResource.getAbout() %>" class="oslc-resource-link"><%=aResource.toString()%></a><br /></p>
<% } %>
<c:forEach items="${resources}" var="res">
<div class="card mb-3">
<div class="card-body">
<a href="${fn:escapeXml(res.getAbout())}" class="oslc-resource-link">${fn:escapeXml(res.toString())}</a>
</div>
</div>
</c:forEach>
</div>
<footer class="footer">
<div class="container">
Expand Down
11 changes: 8 additions & 3 deletions src/server-rm/src/main/webapp/static/css/adaptor.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@ code {
font-size: 80%;
}

/* 45/11em are the dialog sizes plus bootstrap margins */
.popover {
max-width: calc(45em + 30px);
max-height: calc(11em + 50px);
max-width: 520px;
max-height: 270px;
}

.popover .popover-body {
max-width: 515px;
max-height: 215px;
overflow: hidden;
}

#delegatedUI {
Expand Down
224 changes: 136 additions & 88 deletions src/server-rm/src/main/webapp/static/js/ui-preview-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,116 +20,164 @@ This file is generated by org.eclipse.lyo.oslc4j.codegenerator

//Setup a popover on each of the oslcLinkElements, where the popover content is an iframe presenting the OSLC UI-Preview.
function setupUiPreviewOnPopover(oslcLinkElements) {
oslcLinkElements.popover({
container: "body",
content: "Loading...",
delay: {"show": 120, "hide": 60},
html: true,
placement: "auto",
trigger: "hover"
});

oslcLinkElements.on("show.bs.popover", function () {
var uiElem = $(this);
var popoverElem = uiElem.data('bs.popover');
getUiPreviewIframes(this.getAttribute("href"), attachIframeToHyperlinkElement, uiElem);
})
// Destroy any existing popovers first
oslcLinkElements.popover('dispose');

// Initialize popovers with improved settings
oslcLinkElements.popover({
container: "body",
content: "Loading...",
delay: {
"show": 120,
"hide": 200 // Increased hide delay to reduce flickering
},
html: true,
placement: "auto",
trigger: "hover",
boundary: 'window', // Ensures proper positioning relative to viewport
popperConfig: {
modifiers: {
preventOverflow: {
boundariesElement: 'viewport'
}
}
}
});

// Add CSS to prevent pointer events on popover
$("<style>")
.prop("type", "text/css")
.html(`
.popover {
pointer-events: none;
}
.popover-body {
pointer-events: auto;
}
`)
.appendTo("head");

// Modified event handler with debouncing
let loadingTimeout;
oslcLinkElements.on("show.bs.popover", function (e) {
const uiElem = $(this);
const popoverElem = uiElem.data('bs.popover');

// Clear any pending loading timeout
clearTimeout(loadingTimeout);

// Set new timeout for loading
loadingTimeout = setTimeout(() => {
getUiPreviewIframes(
this.getAttribute("href"),
attachIframeToHyperlinkElement,
uiElem
);
}, 50); // Small delay to prevent multiple rapid loads
});

// Clean up on hide
oslcLinkElements.on("hide.bs.popover", function () {
clearTimeout(loadingTimeout);
});
}

function attachIframeToHyperlinkElement(compactStructure, uiElem) {
uiElem.attr('data-original-title', compactStructure.title);
var preview = compactStructure.small;
var w = preview.width ? preview.width : "450em";
var h = preview.height ? preview.height : "100em";
var iframeHtml = "<iframe src='" + preview.uri + "' ";
iframeHtml += " style='border:0px; height:" + h + "; width:" + w + "'";
iframeHtml += "></iframe>";
uiElem.attr('data-content', iframeHtml);
uiElem.data('bs.popover').setContent();
uiElem.attr('data-original-title', compactStructure.title);
var preview = compactStructure.small;
var w = preview.width ? preview.width : "450em";
var h = preview.height ? preview.height : "100em";
var w = '100%';
var h = '100%';
var iframeHtml = "<iframe src='" + preview.uri + "' ";
iframeHtml += " style='border:0px; height:" + h + "; width:" + w + "; overflow: hidden'";
iframeHtml += "></iframe>";
uiElem.attr('data-content', iframeHtml);
uiElem.data('bs.popover').setContent();
}

//Perform an asynch GET request to obtain the resource's UI-Preview information (an OSLC Compact resource).
//callbackFunction is then called once the request response is obtained.
//The caller should supply this callbackFunction, with any desired paramters under "callbackParamter"
//The caller should supply this callbackFunction, with any desired paramters under "callbackParamter"
//callbackFunction will be called with the following parameters (a) compactStructure, (d) callbackParamter
//where compactStructure represents more detailed about the OSLC Compact resource.
function getUiPreviewIframes(resourceUrl, callbackFunction, callbackParamter) {
xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
if (this.status==200) {
data = this.responseText;
try {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(data,"text/xml");
var compactStructure = oslcCompactJsonStructure(xmlDoc);
callbackFunction(compactStructure, callbackParamter);
} catch (e) {
iframeHtml = "<b>Error parsing preview dialog info</b>";
callbackFunction("Error", callbackParamter);
}
}
else {
iframeHtml = "<b>Error loading the preview dialog</b> status:" + this.status;
callbackFunction("Error", callbackParamter);
}
};
xmlhttp.open("GET", resourceUrl, true);
xmlhttp.setRequestHeader("Accept", "application/x-oslc-compact+xml");
xmlhttp.send();
xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
if (this.status == 200) {
data = this.responseText;
try {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(data, "text/xml");
var compactStructure = oslcCompactJsonStructure(xmlDoc);
callbackFunction(compactStructure, callbackParamter);
} catch (e) {
iframeHtml = "<b>Error parsing preview dialog info</b>";
callbackFunction("Error", callbackParamter);
}
}
else {
iframeHtml = "<b>Error loading the preview dialog</b> status:" + this.status;
callbackFunction("Error", callbackParamter);
}
};
xmlhttp.open("GET", resourceUrl, true);
xmlhttp.setRequestHeader("Accept", "application/x-oslc-compact+xml");
xmlhttp.send();
}

//returns a JSON struct representing a large and small UI-Preview info (uri, title, height and width) based on an OSLC Compact RDF resource.
function oslcCompactJsonStructure(oslcCompactXmlDocument) {
var compactStructure = {};
var compact = findFirstChildNode(findFirstChildNode(oslcCompactXmlDocument));

var titleChild = findFirstChildNodeNamed(compact, 'dcterms:title');
compactStructure.title = titleChild.textContent;

var smallPrev = findFirstChildNodeNamed(compact, 'oslc:smallPreview');
if (smallPrev !== null) {
var preview = findFirstChildNode(smallPrev);
if (preview) {
compactStructure.small = {};
var document = findFirstChildNodeNamed(preview, 'oslc:document');
if (document)
compactStructure.small.uri = document.getAttribute('rdf:resource');
var height = findFirstChildNodeNamed(preview, 'oslc:hintHeight');
compactStructure.small.height = height.textContent;
var width = findFirstChildNodeNamed(preview, 'oslc:hintWidth');
compactStructure.small.width = width.textContent;
}
var compactStructure = {};
var compact = findFirstChildNode(findFirstChildNode(oslcCompactXmlDocument));

var titleChild = findFirstChildNodeNamed(compact, 'dcterms:title');
compactStructure.title = titleChild.textContent;

var smallPrev = findFirstChildNodeNamed(compact, 'oslc:smallPreview');
if (smallPrev !== null) {
var preview = findFirstChildNode(smallPrev);
if (preview) {
compactStructure.small = {};
var document = findFirstChildNodeNamed(preview, 'oslc:document');
if (document)
compactStructure.small.uri = document.getAttribute('rdf:resource');
var height = findFirstChildNodeNamed(preview, 'oslc:hintHeight');
compactStructure.small.height = height.textContent;
var width = findFirstChildNodeNamed(preview, 'oslc:hintWidth');
compactStructure.small.width = width.textContent;
}
var largePrev = findFirstChildNodeNamed(compact, 'oslc:largePreview');
if (largePrev !== null) {
var preview = findFirstChildNode(largePrev);
if (preview) {
compactStructure.large = {};
var document = findFirstChildNodeNamed(preview, 'oslc:document');
if (document)
compactStructure.large.uri = document.getAttribute('rdf:resource');
var height = findFirstChildNodeNamed(preview, 'oslc:hintHeight');
compactStructure.large.height = height.textContent;
var width = findFirstChildNodeNamed(preview, 'oslc:hintWidth');
compactStructure.large.width = width.textContent;
}
}
var largePrev = findFirstChildNodeNamed(compact, 'oslc:largePreview');
if (largePrev !== null) {
var preview = findFirstChildNode(largePrev);
if (preview) {
compactStructure.large = {};
var document = findFirstChildNodeNamed(preview, 'oslc:document');
if (document)
compactStructure.large.uri = document.getAttribute('rdf:resource');
var height = findFirstChildNodeNamed(preview, 'oslc:hintHeight');
compactStructure.large.height = height.textContent;
var width = findFirstChildNodeNamed(preview, 'oslc:hintWidth');
compactStructure.large.width = width.textContent;
}
return compactStructure;
}
return compactStructure;
}

function findFirstChildNode(e) {
for (i = 0; i < e.childNodes.length; i++) {
if (e.childNodes[i].nodeType === Node.ELEMENT_NODE) {
return e.childNodes[i];
}
for (i = 0; i < e.childNodes.length; i++) {
if (e.childNodes[i].nodeType === Node.ELEMENT_NODE) {
return e.childNodes[i];
}
}
}

function findFirstChildNodeNamed(e, nodeName) {
for (i = 0; i < e.childNodes.length; i++) {
if (e.childNodes[i].nodeType === Node.ELEMENT_NODE
&& e.childNodes[i].nodeName === nodeName) {
return e.childNodes[i];
}
for (i = 0; i < e.childNodes.length; i++) {
if (e.childNodes[i].nodeType === Node.ELEMENT_NODE
&& e.childNodes[i].nodeName === nodeName) {
return e.childNodes[i];
}
}
}

0 comments on commit a87945c

Please sign in to comment.