Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions frontend/apps/monastery/js/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ export const APP_CONSTANTS = {
user:[APP_PATH+"/index.html", APP_PATH+"/login.html", APP_PATH+"/chooser.html", APP_PATH+"/main.html", APP_PATH+"/exit.html", $$.MONKSHU_CONSTANTS.ERROR_HTML],
guest:[APP_PATH+"/index.html", APP_PATH+"/login.html", APP_PATH+"/exit.html", $$.MONKSHU_CONSTANTS.ERROR_HTML],
tekmonks:["*"],
nus:["monkruls-designer"]
nus:["monkruls-designer","api400-designer"]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!--
/* Context menu component.
* (C) 2022 TekMonks. All rights reserved.
* License: See enclosed LICENSE file.
*/
-->
<style>
div#positioner {
height: 0px;
width: 0px;
top: 0px;
left: 0px;
position: absolute;
padding: 0px;
border: 0px;
}

div#menu {
position: absolute;
overflow: hidden;
border: 0px solid #98CCFD;
font-family: inherit;
background: #DFF0FE;
border-radius: 5px;
cursor: pointer;
display: flex;
flex-direction: column;
box-shadow: 0 0 5px #ccc;
z-index: 1000;
}

div#menu > span.menuitem {
display: flex;
flex-direction: row;
}

span.menuitem > span.menuicon{
background-color: #98CCFD;
padding-right: 10px;
}

span.menuitem > span.menutext {
font-size: x-small;
color: #444444;
padding: 5px 10px;
width: 100%;
}
span.menuitem > span.menutext:hover {background-color: #bedffd;}

span.menuitem > span.menubreak {
padding: 0px;
width: 100%;
}
span.menubreak > hr {
font-size: 1px;
border: none;
background-color: #98CCFD;
height: 1px;
}
</style>

{{{styleBody}}}

<div id="positioner"></div>

<div id="menu">
{{#items}}
{{#menuentry}}
<span class="menuitem" onclick='monkshu_env.components["context-menu"].menuClicked(this, "{{{functionID}}}")'>
<span class="menuicon"></span>
<span class="menutext">{{displayText}}</span>
</span>
{{/menuentry}}
{{#menubreak}}
<span class="menuitem">
<span class="menuicon"></span>
<span class="menubreak"><hr></span>
</span>
{{/menubreak}}
{{/items}}
{{{htmlContent}}}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* (C) 2022 TekMonks. All rights reserved.
* License: See enclosed LICENSE file.
*/
import {i18n} from "/framework/js/i18n.mjs";
import {util} from "/framework/js/util.mjs";
import {router} from "/framework/js/router.mjs";
import {monkshu_component} from "/framework/js/monkshu_component.mjs";

const COMPONENT_PATH = util.getModulePath(import.meta), MENU_BREAK_INDICATOR = "menubreak";

/**
* Element was rendered
* @param element Host element
*/
async function elementRendered(element) {
const data = context_menu.getData(element.id)||{}, shadowRoot = context_menu.getShadowRootByHost(element);
if (data.htmlContent) { // run any contained JS scripts
const domHTMLContent = new DOMParser().parseFromString(data.htmlContent, "text/html").documentElement;

router.runShadowJSScripts(domHTMLContent, shadowRoot);
}
}

/**
* Shows the given menu.
* @param hostID The host ID of the context-menu element which should be used to display this menu
* @param contentOrMenuItems The menuitems, can be HTML string or an object of menuitmes of format ->
* {"text to display":function() {function called when clicked}}
* @param x The X coordinates (pageX) where to display the menu
* @param y The Y coordinates (pageY) where to display the menu
* @param adjustX Any adjustment to make for the menu X coordinates (e.g. shift right by 5px or -5px)
* @param adjustY Any adjustment to make for the menu Y coordinates (e.g. shift top by 5px or -5px)
* @param data Any additional data to pass to the HTML renderer
*/
async function showMenu(hostID, contentOrMenuItems, x, y, adjustX, adjustY, data) {
const isMenuHTML = typeof contentOrMenuItems == "string", formattedMenuItems = [];

const menuObject = {}; if (!isMenuHTML) {
const memory = context_menu.getMemory(hostID);
memory.menuFunctions = {}; let functionIndex = 0; for (const menuText in contentOrMenuItems) {
memory.menuFunctions[functionIndex] = {function: contentOrMenuItems[menuText]};
if (menuText != MENU_BREAK_INDICATOR) formattedMenuItems.push({menuentry: {displayText:menuText, functionID: functionIndex++}});
else formattedMenuItems.push({menubreak: true});
};

// add cancellation menu item
formattedMenuItems.push({menubreak: true});
memory.menuFunctions[functionIndex] = {function: _=>{}};
formattedMenuItems.push({menuentry: {displayText:await i18n.get("Cancel"), functionID: functionIndex}});
menuObject.items = formattedMenuItems;
} else menuObject.htmlContent = await router.expandPageData(contentOrMenuItems, undefined, {...data, hostID});

const positioner = context_menu.getShadowRootByHostId(hostID).querySelector("div#positioner"),
positionerRect = positioner.getBoundingClientRect(), yAdjusted = y-positionerRect.y+adjustY||0, xAdjusted = x-positionerRect.x+adjustX||0;

const cloneData = {...data}; if (cloneData.styleBody) delete cloneData.styleBody; const host = context_menu.getHostElementByID(hostID);
const styleBody = `<style>${host.getAttribute("styleBody")||""}\ndiv#menu {top:${yAdjusted}px; left:${xAdjusted}px; border-width:1px}\n${data?.styleBody||""}</style>`;
const dataForMenu = {...menuObject, ...cloneData, styleBody};

window.addEventListener("click", function(_) {window.removeEventListener("click", this); hideMenu(hostID);})
context_menu.bindData(dataForMenu, hostID);
}

/**
* Called when menu clicked. Internal function don't call directly.
* @param containedElement The contained element which caused this event
* @param functionIndex The function index of the function to call.
*/
async function menuClicked(containedElement, functionIndex) {
const memory = context_menu.getMemoryByContainedElement(containedElement);
await hideMenu(context_menu.getHostElementID(containedElement));

if (memory.menuFunctions[functionIndex]) setTimeout(_=>memory.menuFunctions[functionIndex].function(),1); // ensures menu is hidden before action is called :)
}

/**
* Hides the context menu
* @param hostID The host ID of the context menu element.
*/
async function hideMenu(hostID) {
const dataForMenu = {}; await context_menu.bindData(dataForMenu, hostID);
}

// convert this all into a WebComponent so we can use it
export const context_menu = {trueWebComponentMode: true, showMenu, menuClicked, hideMenu, elementRendered}
monkshu_component.register("context-menu", `${COMPONENT_PATH}/context-menu.html`, context_menu);
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
/*
* (C) 2022 TekMonks. All rights reserved.
* License: See enclosed license.txt file.
*/
-->

<style>
body {
width: 100%;
}

select#choices {
width: 100%;
font-family: inherit;
background-color: rgba(255, 255, 255, 1);
padding: 8px;
border: 0px;
border-radius: 4px;
outline: none;
cursor: pointer;
resize: none;
}
</style>


{{{styleBody}}}
<select name="choices" id="choices">
<option value="" disabled selected hidden class="disabled">{{text}}</option>
{{#values}}
<option value="{{value}}" class="values" id="{{value}}">{{value}}</option>
{{/values}}
</select>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* (C) 2022 TekMonks. All rights reserved.
* License: See enclosed LICENSE file.
*/
import { util } from "/framework/js/util.mjs";
import { monkshu_component } from "/framework/js/monkshu_component.mjs";

const COMPONENT_PATH = util.getModulePath(import.meta);

const elementConnected = async (element) => {
Object.defineProperty(element, "value", {
get: (_) => _getValue(element),
set: (value) => _setValue(value, element),
});
const data = {};
data.values = JSON.parse(element.getAttribute("list").replace(/'/g, '"'));
data.text = element.getAttribute("text");
drop_down.setData(element.id, data);
};

/**
* Element was rendered
* @param element Host element
*/
const elementRendered = async (element) => {
if (element.getAttribute("value"))
_setValue(element.getAttribute("value"), element);
};

function _getValue(element) {
const shadowRoot = drop_down.getShadowRootByHostId(
element.getAttribute("id")
);
const value = shadowRoot.querySelector("select").value;
return value;
}

function _setValue(value, element) {
const shadowRoot = drop_down.getShadowRootByHostId(
element.getAttribute("id")
);
shadowRoot.querySelector(`#${value}`).setAttribute("selected", "selected");
}

export const drop_down = { trueWebComponentMode: true, elementConnected, elementRendered };
monkshu_component.register("drop-down",`${COMPONENT_PATH}/drop-down.html`,drop_down);
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!--
/**
* Floating Window hosting component.
* (C) 2022 TekMonks. All rights reserved.
* License: See enclosed LICENSE file.
*/
-->
<style>
body{
margin: 0; padding: 0;
font-family: var(--window-font, sans-serif);
font-size: inherit;
}

div::-webkit-scrollbar {
width: 0.5em !important;
height: 0.5em !important;
scroll-behavior: smooth !important;
}

div::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3) !important;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3) !important;
margin: 40px;
border-radius: 10px !important;
}

div::-webkit-scrollbar-thumb {
background-color: darkgrey !important;
border-radius: 10px !important;
background-clip: padding-box;
}

div#window {
top: var(--window-top, 50%);
left: var(--window-left, 50%);
width: var(--window-width, auto);
height: var(--window-height, auto);
max-height: 90vh;
background: var(--window-background, white);
padding: var(--window-padding, 5px);
position: var(--window-position, fixed);
z-index: 105;
box-shadow: var(--box-shadow, 0 0 5px #ccc);
overflow: auto;
color: #444444;
border: var(--window-border, 1px solid #444444);
border-radius: var(--window-border-radius, 5px);
display: flex;
flex-direction: column;
resize: both;
}

span#header {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
cursor: default;
user-select: none;
}
span#header > span#title {
font-size: var(--window-title-size, x-small);
width: 100%;
}
span#header > img#close {
width: var(--window-close-icon-size, 12px);
height: var(--window-close-icon-size, 12px);
}

div#windowcontent {
width: 100%;
height: 100%;
}
</style>

{{{styleBody}}}

<div id="window">
<span id="header" onmousedown="monkshu_env.components['floating-window'].mouseDownOnHeader(event, this)">
<span id="title">{{title}}{{^title}}Floating Window{{/title}}</span>
<img id="close" src="{{closeIcon}}{{^closeIcon}}{{componentPath}}/img/close.svg{{/closeIcon}}"
onclick="monkshu_env.components['floating-window'].hideWindow(this)">
</span>

<div id="windowcontent"><!-- The window content will go here --></div>
</div>
Loading