WIP treeview: add requests and folders, fold/unfold, switch to selected tab, renaming items changes; WIP inputbox

This commit is contained in:
ezwrk 2024-07-22 18:40:00 +03:00
commit bf13d54b71
3 changed files with 586 additions and 23 deletions

View file

@ -100,8 +100,7 @@
</div>
<div id="main_area">
<div id="treeview1">
<div>
<div id="collection_toolbar" class="navbar">
<div class="dropdown" id="collection_add_menu">
<button class="dropbtn">📁</button>
@ -110,11 +109,12 @@
<div class="dropdown-item" id="import_collection" value="import_collection">Import collection</div>
</div>
</div>
<input id="collection-search" type="text" value="asd"></input>
<input id="collection-search" type="text" value="" placeholder="search request">
</div>
tree
</div>
<div id="treeview1">
</div>
</div>
<div id="request_area">
<div id="top_row_of_the_window">
<div class="tabbar" id="requests_tabbar">
@ -498,6 +498,40 @@
</div>
</div>
<!-- treeview context menu -->
<div class="dropdown" id="treeitem_context">
<div class="dropdown-content">
<div id="context_add_request" class="dropdown-item" value="add_request">Add request</div>
<div id="context_add_folder" class="dropdown-item" value="add_folder">Add folder</div>
<div id="context_clone" class="dropdown-item" value="clone">Clone</div>
<div id="context_export" class="dropdown-item" value="export">Export</div>
<div id="context_delete" class="dropdown-item red" value="delete">Delete</div>
</div>
</div>
<!-- treeview context menu -->
<!-- input box -->
<div class="popup_wrapper" id="app_input_box">
<div id="input_box" class="popup">
<div id="input_box_title">
sample title
</div>
<div id="input_box_message">
this is a sample message
</div>
<div>
<input id="input_box_input" type="text">
</div>
<div>
<input type="button" id="yes">
<input type="button" id="no">
</div>
</div>
</div>
<!-- input box -->
<div class="popup_wrapper" id="app_about">
<div class="popup">

View file

@ -1352,8 +1352,10 @@ function init_menus() {
}
function hide_element() {
this.style.display = 'none'
function hide_element(event) {
if (event.target == this) {
this.style.display = 'none'
}
}
function init_popups() {
@ -1363,18 +1365,99 @@ function init_popups() {
}
}
function input_box(options) {
let output
let box = document.getElementById('app_input_box')
let yes = document.getElementById('yes')
let no = document.getElementById('no')
let title = document.getElementById('input_box_title')
let message = document.getElementById('input_box_message')
let input = document.getElementById('input_box_input')
if (options.buttons.includes('yes')) {
yes.style.display = 'inline-block'
yes.value = 'yes'
} else {
yes.style.display = 'none'
}
if (options.buttons.includes('yes')) {
no.style.display = 'inline-block'
no.value = 'yes'
} else {
no.style.display = 'none'
}
if (options.buttons.includes('confirm')) {
yes.style.display = 'inline-block'
yes.value = 'confirm'
} else {
yes.style.display = 'none'
}
if (options.buttons.includes('cancel')) {
no.style.display = 'inline-block'
no.value = 'cancel'
} else {
no.style.display = 'none'
}
if (options.type == 'input') {
no.style.display = 'inline-block'
} else {
no.style.display = 'none'
}
if (options.title) {
title.display = 'block'
title.textContent = options.title
} else {
title.display = 'none'
}
if (options.title) {
message.display = 'block'
message.textContent = options.message
} else {
message.display = 'none'
}
box.style.display = 'flex'
return output
}
async function keyboard_shortcuts_handler(event) {
//console.log(event)
if (event.ctrlKey && event.code === 'KeyS') {
if (event.ctrlKey) {
//save
if (event.code === 'KeyS') {
// save current request
let request = await build_request()
app.current_request = JSON.parse(JSON.stringify(request))
await write_request_file(app.current_tab)
} else if (event.ctrlKey && event.code === "Enter") {
return
}
// send
if (event.code === "Enter") {
// run qurent request
await send_request()
return
}
}
// renaming
if (event.code === "F2") {
// run qurent request
let new_name = await input_box({type:'input', buttons: ['confirm', 'cancel'], title: 'Type a new name for selected item'})
return
}
}
@ -1759,6 +1842,7 @@ function fill_in_forms() {
}
///===============================================================================
// process response
} else {
@ -1837,7 +1921,7 @@ function window_resize_trigger() {
let u
async function add_request() {
async function add_request(event, data) { // pass data.id to generate request data with a specific id
if (app.current_tab) {
let request = await build_request()
app.current_request = JSON.parse(JSON.stringify(request))
@ -1858,7 +1942,7 @@ async function add_request() {
}
}
let request_id = crypto.randomUUID()
let request_id = data?.id || crypto.randomUUID()
let request_name = "New Request" //+ " " + app.opened_tabs.length
let container = document.getElementById("request_body_wrapper")
@ -1978,7 +2062,217 @@ async function load_previoursly_opened_tabs() {
// }
}
// treeview ===============================
let ppp
function checkOverflow() {
if (this.scrollWidth > this.clientWidth) {
this.style.overflowX = 'auto'
} else {
this.style.overflowX = 'hidden'
}
}
function get_random_request_type() {
let types = ["GET", "POST", "PUT", "UPDATE", "REPORT", "HEAD", "OPTIONS"]
return types[Math.floor(Math.random()*types.length)]
}
function toggle_children_display(target) {
target.setAttribute("opened", !JSON.parse(target.getAttribute("opened")) || "false")
// let divs = this.getElementsByTagName("div")
// for (let d of divs) {
// if (d == this) {continue}
// if (d.style.display == 'none') {
// d.style.display = 'block'
// } else {
// d.style.display = 'none'
// }
// }
event?.stopPropagation();
}
let currently_selected_tree_node
function tree_item_click(event) {
console.log(event)
let target = event.target
while (!target.classList.contains('treeitem')) {
target = target.parentElement
}
if (target.classList.contains("folder")) {
toggle_children_display(target)
}
event.stopPropagation()
}
function select_tree_item(event, element) {
let treeview1 = document.getElementById("treeview1")
let items = treeview1.getElementsByClassName("treeitem")
let target = element || this
while (!target.classList.contains('treeitem')) {
target = target.parentElement
}
currently_selected_tree_node = target || this
for (let item of items) {
if (item == currently_selected_tree_node) {
item.setAttribute("selected", true)
} else {
item.setAttribute("selected", false)
}
}
if (currently_selected_tree_node.classList.contains('request')) {
let navbar = document.getElementById("requests_tabbar")
let buttons = navbar.getElementsByClassName('request_tabbutton')
let found_opened_tab
for (let button of buttons) {
if (button.id == currently_selected_tree_node.id) {
button.click()
found_opened_tab = true
break
}
}
if (!found_opened_tab) {
//
add_request(event, {id : currently_selected_tree_node.id})
}
}
}
let treeview_item_menu_callee
function context_menu(event) {
let target = event.target
let treeitem_context = document.getElementById("treeitem_context")
treeitem_context.style.display = 'none'
let treeview1 = document.getElementById("treeview1")
let items = treeitem_context.getElementsByClassName("dropdown-item")
console.log(target.classList)
for (let item of items) {
let value = item.getAttribute('value')
if (target.classList.contains("request") || target.parentElement.classList.contains("request")) {
if (value == "add_request" || value == "add_folder") {
item.style.display = 'none'
}
} else {
if (value == "add_request" || value == "add_folder") {
item.style.display = 'flex'
}
}
}
//console.log(event)
//console.log(event.clientY, treeview1.clientHeight, treeitem_context.children[0].clientHeight)
treeitem_context.style.top = Math.min(event.clientY - 24, treeview1.clientHeight - treeitem_context.children[0].clientHeight - 24) + 'px'
treeitem_context.style.left = Math.min(event.clientX - 5, treeview1.clientWidth - treeitem_context.children[0].clientWidth - 5) + 'px'
treeitem_context.style.display = 'inline-block'
treeitem_context.children[0].style.display = 'block'
treeview_item_menu_callee = target
//tree_item_click(event)
event.stopPropagation()
event.preventDefault()
}
function select_request(event) {
console.log(this)
select_tree_item(event, this)
event.stopPropagation();
}
function add_item(type, parent) {
if (this.id == 'add_collection' || this.id == 'context_add_folder') {
type = 'folder'
parent = treeview_item_menu_callee
}
if (this.id == 'context_add_request') {
type = 'request'
parent = treeview_item_menu_callee
}
if (parent) {
while (!parent.classList.contains('folder')) {
parent = parent.parentElement
}
}
let item = document.createElement("div")
if (type=="folder") {
item.classList.add("folder")
item.classList.add("treeitem")
let icon = document.createElement("span")
icon.classList.add('folder-icon')
item.appendChild(icon)
let text = document.createElement("span")
text.classList.add('item-text')
text.textContent = "New Folder"
item.appendChild(text)
item.setAttribute("opened", true)
icon.addEventListener("click", tree_item_click)
text.addEventListener("click", select_tree_item)
item.addEventListener("contextmenu", context_menu)
type == 'folder'
} else {
item.classList.add("request")
item.classList.add("treeitem")
let rt = 'GET'//get_random_request_type()
let req_type = document.createElement("span")
req_type.classList.add('request-type')
req_type.classList.add(rt)
req_type.textContent = rt
item.appendChild(req_type)
item.id = crypto.randomUUID()
let text = document.createElement("span")
text.classList.add('item-text')
text.textContent = "New Request"
item.appendChild(text)
text.addEventListener("click", select_request)
item.addEventListener("contextmenu", context_menu)
}
let pe = ppp || parent || document.getElementById("treeview1")
// if (Math.random() > 0.3 && item.classList.contains('folder')) {
// ppp = item
// } else {
// ppp = document.getElementById("treeview1")
// }
// if (item.classList.contains("request") && !pe.classList.contains("folder")) {
// console.log("adding folder for a req")
// // pe = add_item("folder", pe)
// }
console.log(pe, item)
pe.appendChild(item)
document.getElementById("treeview1").scrollBy(0, Number.MAX_SAFE_INTEGER)
return item
}
// treeview ===============================
function init() {
// treeview plaecholder
let treeview1 = document.getElementById("treeview1")
treeview1.addEventListener("scroll", checkOverflow)
for (let i=1; i<50; i++) {
//add_item()
}
// --------------------
console.log('init')
// enable add_row buttons (those adding rows to param tables)
let add_row_buttons = document.getElementsByClassName('add_row_button')
@ -2026,7 +2320,20 @@ function init() {
button.dispatchEvent(event);
}
}
// collection manipulation
let add_collection = document.getElementById('add_collection')
let context_add_request = document.getElementById('context_add_request')
let context_add_folder = document.getElementById('context_add_folder')
let context_clone = document.getElementById('context_clone')
let context_export = document.getElementById('context_export')
let context_delete = document.getElementById('context_delete')
add_collection.addEventListener("click", add_item)
context_add_folder.addEventListener("click", add_item)
context_add_request.addEventListener("click", add_item)
//---------------------------------------
let beautify_raw_data_body = document.getElementById('beautify_raw_data_body')
let beautify_raw_data_response = document.getElementById('beautify_raw_data_response')

View file

@ -375,7 +375,7 @@ input:not(input[type="text"]) {
}
#collection_toolbar {
width: 100%;
width: 200pt;
height: 26pt;
display: flex;
}
@ -392,14 +392,7 @@ input:not(input[type="text"]) {
width:70%;
}
#treeview1 {
display: flex;
flex-grow: initial;
flex-direction: column;
width: 200pt;
height: 100%;
/* outline: 1px solid wheat; */
}
#add_method_input {
border: none;
@ -796,7 +789,7 @@ footer * {
}
/* --------------------------- */
label, button, .treeview, .menuitem, .menu {
label, button, #treeview, .menuitem, .menu {
user-select: none;
cursor: pointer;
}
@ -1035,4 +1028,233 @@ label, button, .treeview, .menuitem, .menu {
#body_binary_file_input_label {
display: inline-block;
}
}
/* treeview */
#treeview1 {
display: flex;
flex-grow: initial;
flex-direction: column;
width: 200pt;
height: calc(100% - 30pt);
/* outline: 1px solid wheat; */
padding-left: 6pt;
overflow: auto;
/* overflow-x: hidden; */
}
#add {
width: 100pt;
height: 25pt;
/* outline: 1px solid burlywood; */
display: inline-block;
position: absolute;
top: 5pt;
left:220pt;
background-color: #222;
border-radius: 5pt;
border-color: burlywood;
border-style: solid;
border-width: 1pt;
}
#add:hover {
background-color: #444;
}
.folder {
/* display: flex; */
cursor: pointer;
line-height: 24pt;
white-space: nowrap;
}
.folder > .request {
margin-left:calc(16pt + 5pt);
line-height: 24pt;
}
.folder > .folder {
margin-left: 21pt;
}
.folder:hover:not(:has(.folder:hover, .request:hover)),
.request:hover {
/* outline: 1px solid red; */
/* background-color: #444; */
/* width: 100%; */
/* height: 24pt; */
/* display: block; */
/* position: absolute; */
/* content: " " */
color: #6bdd92;
}
.folder[opened=true] > .folder,
.folder[opened=true] > .request {
display: block;
}
.folder[opened=false] > .folder,
.folder[opened=false] > .request {
display: none;
}
.folder[opened=true] > .folder-icon {
background-image: url(folder_opened.png);
background-size: contain;
display: inline-block;
}
.folder[opened=false] > .folder-icon {
background-image: url(folder.png);
background-size: contain;
display: inline-block;
}
.folder:hover:not(:has(.folder:hover, .request:hover)) > .mdots,
.request:hover > .mdots {
display: none;
/* display: flex; */
}
.request > .mdots,
.folder > .mdots {
display: none;
}
.folder-icon {
width: 16pt;
height: 16pt;
background-position-y: 0pt;
position: relative;
top: 3pt;
margin-right: 5pt;
}
.request-type {
width: 32pt;
display: inline-block;
position: relative;
top: 0pt;
right: 0pt;
margin-right: 5pt;
font-size: 7pt;
text-align: center;
border-width: 1pt;
border-radius: 5pt;
border-style: solid;
border-color: #666;
padding-left: 3pt;
padding-right: 3pt;
outline: 1px solid #f5f5f545;
outline-offset: -3pt;
line-height: 16pt;
}
.request-type[class*="GET"] {
color: #6bdd92;
background-color: #234730;
}
.request-type[class*="POST"] {
color: #ffe479;
background-color: #3a341c;
}
.request-type[class*="PUT"] {
color: #74aeed;
background-color: #203142;
}
.request-type[class*="UPDATE"] {
color: #c0a8d9;
background-color: #3c3444;
}
.request-type[class*="REPORT"] {
color: #f15eae;
background-color: #471b33;
}
.request-type[class*="HEAD"] {
color: #7cfad0;
background-color: #2a4e42;
}
.request-type[class*="OPTIONS"] {
color: #f79a87;
background-color: #684139;
}
.mdots {
position: relative;
float: right;
margin-right: 5pt;
padding: 0pt 5pt;
text-align: inherit;
display: flex;
height: 21pt;
outline: 1px solid lime;
background: #222;
border-radius: 5pt;
}
.treeitem > .item-text{
padding-right: 10pt;
line-height: 24pt;
}
#treeitem_context {
position: absolute;
font-family: Arial, Helvetica, sans-serif;
}
.treeitem[selected=true] > .item-text {
text-shadow: 0 0 1pt orange;
text-decoration: underline;
}
.treeitem[selected=false] > .item-text {
text-shadow: initial;
text-decoration: initial;
}
/* inputbox */
#input_box_title {
font-weight: bold;
margin-bottom: 10pt;
}
#input_box_input {
width: calc(100% - 10pt);
padding: 0pt;
margin: 5pt 0;
padding: 0 5pt;
}
#input_box {
height: auto;
}
#input_box input {
border-radius: 5pt;
}
#yes, #no {
min-width: 100pt;
float: right;
margin-right: 0;
margin-left: 10pt;
}
/* inputbox */