separate indexing for states & nodes
This commit is contained in:
parent
f66a6247bb
commit
209d9a2763
78
editor.css
78
editor.css
@ -19,7 +19,7 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
z-index: 5;
|
z-index: 11;
|
||||||
float: left;
|
float: left;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
@ -55,16 +55,14 @@ body {
|
|||||||
color: rgb(75, 151, 151);
|
color: rgb(75, 151, 151);
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchmenu {
|
|
||||||
width: 400px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchmenu #search-container {
|
|
||||||
/* position: fixed;
|
.menuitem #search-container {
|
||||||
|
position: fixed;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
bottom: 0px; */
|
bottom: 0px;
|
||||||
padding: 5 5 5 5;
|
width: 400px;
|
||||||
|
padding: 2 2 2 2;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-top: 4px solid transparent;
|
border-top: 4px solid transparent;
|
||||||
border-bottom: 4px solid transparent;
|
border-bottom: 4px solid transparent;
|
||||||
@ -74,27 +72,27 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#search-container input {
|
#search-container input {
|
||||||
/* height: 100%; */
|
height: 100%;
|
||||||
height: 40px;
|
/* height: 40px; */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 15px;
|
border-radius: 10px;
|
||||||
border: 1px solid rgb(117, 117, 117);
|
border: .5px solid rgba(0, 0, 0, 0.123);
|
||||||
padding-left: 10px;
|
padding-left: 38px;
|
||||||
padding-right: 38px;
|
padding-right: 10px;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: all 100ms ease-out 50ms;
|
transition: all 100ms ease-out 50ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container:hover input, #search-container input:active, #search-container input:focus {
|
#search-container:hover input, #search-container input:active, #search-container input:focus {
|
||||||
border: 2px solid rgb(117, 117, 117);
|
/* border: 2px solid rgb(117, 117, 117); */
|
||||||
/* box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); */
|
box-shadow: 0 0px 10px 0 rgba(0, 0, 0, 0.12);
|
||||||
padding-left: 9px;
|
/* padding-left: 9px;
|
||||||
padding-right: 37px;
|
padding-right: 37px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container input:focus {
|
#search-container input:focus {
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
box-shadow: 0 0px 10px 0 rgba(0, 0, 0, 0.24);
|
||||||
transform: scale(1.02);
|
/* transform: scale(1.02); */
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
@ -111,29 +109,33 @@ body {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
top: 10;
|
top: 7;
|
||||||
right: 10;
|
left: 7;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
transition: all 100ms ease-out 50ms;
|
transition: all 100ms ease-out 50ms;
|
||||||
/* background-color: rgb(120, 120, 120); */
|
/* background-color: rgb(120, 120, 120); */
|
||||||
}
|
}
|
||||||
#search-container .search-button:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-container .search-button svg {
|
#search-container .search-button svg {
|
||||||
stroke: rgb(117, 117, 117);
|
stroke: rgb(117, 117, 117);
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-results {
|
#search-results {
|
||||||
display: none;
|
width: 400px;
|
||||||
position: relative;
|
overflow: hidden;
|
||||||
padding: 20 20 20 20;
|
}
|
||||||
|
|
||||||
|
#search-options {
|
||||||
|
padding: 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-result-list {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-results div {
|
#search-result-list div {
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
@ -143,15 +145,27 @@ body {
|
|||||||
transition: all 100ms ease-out 50ms;
|
transition: all 100ms ease-out 50ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-results div:hover {
|
#search-result-list div:hover {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: rgb(75, 151, 151);
|
color: rgb(75, 151, 151);
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-results div:active {
|
#search-result-list div:active {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
/* position: relative;
|
||||||
|
display: block; */
|
||||||
|
padding-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.checkbox input {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.submenu {
|
.submenu {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
|||||||
35
editor.html
35
editor.html
@ -126,18 +126,31 @@
|
|||||||
<div class="submenu menu-lightmode">Visualiser & editor for Uni2work workflows</div>
|
<div class="submenu menu-lightmode">Visualiser & editor for Uni2work workflows</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menuitem" onclick="openSearchMenu(this)">
|
<div class="menuitem" onclick="openSearchMenu(this)">
|
||||||
<div class="menubutton">Search</div>
|
<div id="search-container">
|
||||||
<div id="searchmenu" class="submenu menu-lightmode" onclick="event.stopPropagation()">
|
<input id="search-input" type="text" placeholder="Search" onclick="showSearchResults()" oninput="search(this.value)">
|
||||||
<div id="search-container">
|
<span class="search-button">
|
||||||
<input id="search-input" type="text" placeholder="Nodes, Edges, ..." onclick="showSearchResults()" oninput="search(this.value)">
|
<svg height="18" width="18" xmlns="http://www.w3.org/2000/svg">
|
||||||
<span class="search-button">
|
<circle cx="11" cy="7" r="6" stroke-width="2" fill="none" />
|
||||||
<svg height="18" width="18" xmlns="http://www.w3.org/2000/svg">
|
<polyline points="8,10 2,16" style="fill:none;stroke-width:2" stroke-linecap="round" />
|
||||||
<circle cx="11" cy="7" r="6" stroke-width="2" fill="none" />
|
</svg>
|
||||||
<polyline points="8,10 2,16" style="fill:none;stroke-width:2" stroke-linecap="round" />
|
</span>
|
||||||
</svg>
|
</div>
|
||||||
</span>
|
<div id="search-results" class="submenu menu-lightmode" onclick="event.stopPropagation()">
|
||||||
|
<div id="search-options">
|
||||||
|
<label class="checkbox" title="Nodes">
|
||||||
|
<input id="search-option-states" type="checkbox" checked="checked">
|
||||||
|
Nodes
|
||||||
|
</label>
|
||||||
|
<label class="checkbox" title="Edges">
|
||||||
|
<input id="search-option-edges" type="checkbox" checked="checked">
|
||||||
|
Edges
|
||||||
|
</label>
|
||||||
|
<label class="checkbox" title="Roles">
|
||||||
|
<input id="search-option-roles" type="checkbox">
|
||||||
|
Roles
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="search-results"></div>
|
<div id="search-result-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menuitem">
|
<div class="menuitem">
|
||||||
|
|||||||
136
editor.js
136
editor.js
@ -52,6 +52,20 @@ var selectedMenuItem = null;
|
|||||||
|
|
||||||
Array.from(document.getElementsByClassName('submenu')).forEach(subMenu => subMenu.style.top = mainMenu.offsetHeight + 15);
|
Array.from(document.getElementsByClassName('submenu')).forEach(subMenu => subMenu.style.top = mainMenu.offsetHeight + 15);
|
||||||
|
|
||||||
|
var lastSubMenu = null;
|
||||||
|
|
||||||
|
function positionSubmenuBackdrop() {
|
||||||
|
var smRect = lastSubMenu.getBoundingClientRect();
|
||||||
|
submenuBackdrop.style.top = smRect.top;// sideHeading.offsetHeight + parseFloat(smStyle.paddingTop) + parseFloat(shStyle.marginTop) + parseFloat(shStyle.marginBottom);
|
||||||
|
submenuBackdrop.style.left = smRect.left;
|
||||||
|
submenuBackdrop.style.width = lastSubMenu.offsetWidth;
|
||||||
|
submenuBackdrop.style.height = lastSubMenu.offsetHeight;
|
||||||
|
// var sbStyle = window.getComputedStyle(sideButtons);
|
||||||
|
// sideContent.style.bottom = sideButtons.offsetHeight + parseFloat(smStyle.paddingBottom) + parseFloat(sbStyle.marginTop) + parseFloat(sbStyle.marginBottom);
|
||||||
|
// console.log(sideHeading.offsetHeight + shStyle.marginTop + shStyle.marginBottom);
|
||||||
|
// var width =
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {HTMLElement} menuitem
|
* @param {HTMLElement} menuitem
|
||||||
@ -71,24 +85,11 @@ function openMenuItem(menuitem) {
|
|||||||
fadeOut(null, ...fadeOuts);
|
fadeOut(null, ...fadeOuts);
|
||||||
menuitem.classList.add('selectedmenuitem');
|
menuitem.classList.add('selectedmenuitem');
|
||||||
var fadeIns = [{element: submenuBackdrop, max: 1}];
|
var fadeIns = [{element: submenuBackdrop, max: 1}];
|
||||||
var lastSubMenu = null;
|
|
||||||
Array.from(menuitem.getElementsByClassName('submenu')).forEach(subMenu => {
|
Array.from(menuitem.getElementsByClassName('submenu')).forEach(subMenu => {
|
||||||
fadeIns.push({element: subMenu, max: 1});
|
fadeIns.push({element: subMenu, max: 1});
|
||||||
lastSubMenu = subMenu;
|
lastSubMenu = subMenu;
|
||||||
});
|
});
|
||||||
function callback() {
|
fadeIn(positionSubmenuBackdrop, ...fadeIns);
|
||||||
var smRect = lastSubMenu.getBoundingClientRect();
|
|
||||||
console.log(smRect);
|
|
||||||
submenuBackdrop.style.top = smRect.top;// sideHeading.offsetHeight + parseFloat(smStyle.paddingTop) + parseFloat(shStyle.marginTop) + parseFloat(shStyle.marginBottom);
|
|
||||||
submenuBackdrop.style.left = smRect.left;
|
|
||||||
submenuBackdrop.style.width = lastSubMenu.offsetWidth;
|
|
||||||
submenuBackdrop.style.height = lastSubMenu.offsetHeight;
|
|
||||||
// var sbStyle = window.getComputedStyle(sideButtons);
|
|
||||||
// sideContent.style.bottom = sideButtons.offsetHeight + parseFloat(smStyle.paddingBottom) + parseFloat(sbStyle.marginTop) + parseFloat(sbStyle.marginBottom);
|
|
||||||
// console.log(sideHeading.offsetHeight + shStyle.marginTop + shStyle.marginBottom);
|
|
||||||
// var width =
|
|
||||||
}
|
|
||||||
fadeIn(callback, ...fadeIns);
|
|
||||||
selectedMenuItem = menuitem;
|
selectedMenuItem = menuitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,59 +129,70 @@ function openAboutMenu(menuitem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openSearchMenu(menuitem) {
|
function openSearchMenu(menuitem) {
|
||||||
document.getElementById('search-input').value = null;
|
if (selectedMenuItem === menuitem) return;
|
||||||
while (searchResults.firstChild)
|
var val = document.getElementById('search-input').value;
|
||||||
searchResults.removeChild(searchResults.lastChild);
|
if (val === '' || val === null)
|
||||||
|
while (searchResultList.firstChild)
|
||||||
|
searchResultList.removeChild(searchResultList.lastChild);
|
||||||
openMenuItem(menuitem);
|
openMenuItem(menuitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('filepanel').style.opacity = 0;
|
document.getElementById('filepanel').style.opacity = 0;
|
||||||
|
|
||||||
//Search
|
//Search
|
||||||
const searchIndex = new FlexSearch.Index({tokenize: 'forward'});
|
const nodeIndex = new FlexSearch.Index({tokenize: 'forward'});
|
||||||
|
const actionIndex = new FlexSearch.Index({tokenize: 'forward'});
|
||||||
// const searchDocument = new FlexSearch.Document();
|
// const searchDocument = new FlexSearch.Document();
|
||||||
// const searchWorker = new FlexSearch.Worker();
|
// const searchWorker = new FlexSearch.Worker();
|
||||||
|
const soStates = document.getElementById('search-option-states');
|
||||||
|
const soEdges = document.getElementById('search-option-edges');
|
||||||
|
|
||||||
function search(text) {
|
function search(text) {
|
||||||
while (searchResults.firstChild)
|
while (searchResultList.firstChild)
|
||||||
searchResults.removeChild(searchResults.lastChild);
|
searchResultList.removeChild(searchResultList.lastChild);
|
||||||
var results = searchIndex.search(text, 10);
|
var searchStates = soStates.checked;
|
||||||
results.forEach(result => {
|
var searchActions = soEdges.checked
|
||||||
var target = null;
|
var stateResults = searchStates ? nodeIndex.search(text, searchActions ? 5 : 10) : null;
|
||||||
if (result.startsWith('state_name_')) {
|
var actionResults = searchActions ? actionIndex.search(text, searchStates ? 5 : 10) : null;
|
||||||
result = result.replace('state_name_', '');
|
|
||||||
workflow.states.forEach(state => {
|
function defineFocus(div, target) {
|
||||||
if (state.id === result)
|
div.onclick = (_ => {
|
||||||
target = state;
|
var x = y = null;
|
||||||
|
if (target.actionData) {
|
||||||
|
x = target.source.x + (target.target.x - target.source.x);
|
||||||
|
y = target.source.y + (target.target.y - target.source.y);
|
||||||
|
} else {
|
||||||
|
x = target.x;
|
||||||
|
y = target.y;
|
||||||
|
}
|
||||||
|
document.getElementById('search-input').value = null;
|
||||||
|
closeMenuItem();
|
||||||
|
wfGraph.centerAt(x, y, 400);
|
||||||
|
wfGraph.zoom(5, 400);
|
||||||
|
select(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(possibleTargets, results, heading) {
|
||||||
|
var h = document.createElement('h3');
|
||||||
|
h.innerHTML = heading;
|
||||||
|
searchResultList.appendChild(h);
|
||||||
|
results.forEach(result => {
|
||||||
|
var target = null;
|
||||||
|
possibleTargets.forEach(stateOrEdge => {
|
||||||
|
if (stateOrEdge.id === result)
|
||||||
|
target = stateOrEdge;
|
||||||
});
|
});
|
||||||
} else {
|
var r = document.createElement('div');
|
||||||
result = result.replace('action_name_', '');
|
r.innerHTML = target.name;
|
||||||
workflow.actions.forEach(action => {
|
searchResultList.appendChild(r);
|
||||||
if (action.id === result)
|
defineFocus(r, target);
|
||||||
target = action;
|
})
|
||||||
});
|
}
|
||||||
}
|
|
||||||
var r = document.createElement('div');
|
stateResults && format(workflow.states, stateResults, 'States');
|
||||||
r.innerHTML = target.name;
|
actionResults && format(workflow.actions, actionResults, 'Edges');
|
||||||
searchResults.appendChild(r);
|
positionSubmenuBackdrop();
|
||||||
function defineFocus(div, target) {
|
|
||||||
div.onclick = (_ => {
|
|
||||||
var x = y = null;
|
|
||||||
if (target.actionData) {
|
|
||||||
x = target.source.x + (target.target.x - target.source.x);
|
|
||||||
y = target.source.y + (target.target.y - target.source.y);
|
|
||||||
} else {
|
|
||||||
x = target.x;
|
|
||||||
y = target.y;
|
|
||||||
}
|
|
||||||
closeMenuItem();
|
|
||||||
wfGraph.centerAt(x, y, 400);
|
|
||||||
wfGraph.zoom(5, 400);
|
|
||||||
select(target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
defineFocus(r, target);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSearchResults() {
|
function showSearchResults() {
|
||||||
@ -369,8 +381,9 @@ const contextMenuBg = document.getElementById('ctmenubg'); //Click on background
|
|||||||
const contextMenuSt = document.getElementById('ctmenust'); //Click on state
|
const contextMenuSt = document.getElementById('ctmenust'); //Click on state
|
||||||
const contextMenuEd = document.getElementById('ctmenued'); //Click on edge
|
const contextMenuEd = document.getElementById('ctmenued'); //Click on edge
|
||||||
//Search
|
//Search
|
||||||
const searchContainer = document.getElementById('search-container');
|
const searchContainer = document.getElementById('search-container');
|
||||||
const searchResults = document.getElementById('search-results');
|
const searchResults = document.getElementById('search-results');
|
||||||
|
const searchResultList = document.getElementById('search-result-list');
|
||||||
// Counters for placeholder IDs of states/actions added via GUI
|
// Counters for placeholder IDs of states/actions added via GUI
|
||||||
var stateIdCounter = 0;
|
var stateIdCounter = 0;
|
||||||
var actionIdCounter = 0;
|
var actionIdCounter = 0;
|
||||||
@ -378,6 +391,9 @@ var stateAbbreviations = [];
|
|||||||
var newStateCoords = {'x': 0, 'y': 0}; //Initial coordinates of the next new state
|
var newStateCoords = {'x': 0, 'y': 0}; //Initial coordinates of the next new state
|
||||||
|
|
||||||
sidePanel.style.top = mainMenu.offsetHeight + 15;
|
sidePanel.style.top = mainMenu.offsetHeight + 15;
|
||||||
|
searchContainer.style.left = mainMenu.offsetWidth / 2 - searchContainer.offsetWidth / 2;
|
||||||
|
searchResults.style.left = searchContainer.style.left;
|
||||||
|
searchResults.style.maxHeight = 0.6 * window.innerHeight;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -633,7 +649,7 @@ function prepareWorkflow() {
|
|||||||
state.stateData.viewers.forEach(v => viewers.push(new Role(v)));
|
state.stateData.viewers.forEach(v => viewers.push(new Role(v)));
|
||||||
state.stateData.viewers = viewers;
|
state.stateData.viewers = viewers;
|
||||||
state.stateData.payload = new Payload(state.stateData.payload);
|
state.stateData.payload = new Payload(state.stateData.payload);
|
||||||
searchIndex.add('state_name_' + state.id, state.name);
|
nodeIndex.add(state.id, state.name);
|
||||||
})
|
})
|
||||||
|
|
||||||
workflow.actions.forEach(action => {
|
workflow.actions.forEach(action => {
|
||||||
@ -650,7 +666,7 @@ function prepareWorkflow() {
|
|||||||
action.actionData['actor Viewers'].forEach(v => viewActors.push(new Role(v)));
|
action.actionData['actor Viewers'].forEach(v => viewActors.push(new Role(v)));
|
||||||
action.actionData['actor Viewers'] = viewActors;
|
action.actionData['actor Viewers'] = viewActors;
|
||||||
action.actionData.form = new Payload(action.actionData.form);
|
action.actionData.form = new Payload(action.actionData.form);
|
||||||
searchIndex.add('action_name_' + action.id, action.name);
|
actionIndex.add(action.id, action.name);
|
||||||
})
|
})
|
||||||
|
|
||||||
workflow.actions.forEach(act => act.actionData.actors.forEach(a => {
|
workflow.actions.forEach(act => act.actionData.actors.forEach(a => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user