More tab inferastructure setup

This commit is contained in:
itdominator 2024-01-21 01:36:31 -06:00
parent 2dcfdabe37
commit 729b3850a0
17 changed files with 316 additions and 332 deletions

View File

@ -8,74 +8,8 @@ from gi.repository import Gtk
# Application imports
from ..widgets.separator_widget import Separator
from ..widgets.miniview_widget import MiniViewWidget
from ..widgets.base.notebook.editor_notebook import EditorNotebook
from .editors_paned import EditorsPaned
from ..widgets.controls.tab_bar import TabBar
from .fixed_box import FixedBox
class EditorsPaned(Gtk.Paned):
def __init__(self):
super(EditorsPaned, self).__init__()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_wide_handle(True)
def _setup_signals(self):
...
def _subscribe_to_events(self):
event_system.subscribe("update_paned_handle", self._update_paned_handle)
def _load_widgets(self):
left_view = Gtk.Box()
right_view = Gtk.Box()
left_view.add( TabBar() )
left_view.add( FixedBox() )
right_view.add( TabBar() )
right_view.add( FixedBox() )
left_view.set_orientation( Gtk.Orientation.VERTICAL )
right_view.set_orientation( Gtk.Orientation.VERTICAL )
left_view.show()
right_view.show()
self.add1(left_view)
self.add2(right_view)
# self.add1(FixedBox())
# self.add2(FixedBox())
# self.add1(EditorNotebook())
# self.add2(EditorNotebook())
def _update_paned_handle(self):
rect = self.get_allocation()
pos = -1
try:
size = rect.width / 2
pos = int(size)
except:
...
self.set_position(size)
class EditorsContainer(Gtk.Box):

View File

@ -0,0 +1,52 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.base.notebook.editor_notebook import EditorNotebook
from ..widgets.base.webkit.editor import Editor
class EditorsPaned(Gtk.Paned):
def __init__(self):
super(EditorsPaned, self).__init__()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_wide_handle(True)
def _setup_signals(self):
...
def _subscribe_to_events(self):
event_system.subscribe("update_paned_handle", self._update_paned_handle)
def _load_widgets(self):
self.add1( Editor() )
self.add2( Editor() )
# self.add1( EditorNotebook() )
# self.add2( EditorNotebook() )
def _update_paned_handle(self):
rect = self.get_allocation()
pos = -1
try:
size = rect.width / 2
pos = int(size)
except:
...
self.set_position(size)

View File

@ -14,7 +14,6 @@ from ..mixins.signals_mixins import SignalsMixins
from ..containers.core_widget import CoreWidget
from .base_controller_data import BaseControllerData
from .bridge_controller import BridgeController
from .files_controller import FilesController
@ -59,7 +58,6 @@ class BaseController(SignalsMixins, BaseControllerData):
def _load_controllers(self):
BridgeController()
FilesController()
def load_glade_file(self):
self.builder = Gtk.Builder()

View File

@ -26,14 +26,17 @@ class BridgeController:
def handle_bridge_event(self, event):
match event.topic:
case "save":
event_system.emit("handle_file_event", (event,))
event_system.emit(f"handle_file_event_{event.originator}", (event,))
case "close":
event_system.emit("handle_file_event", (event,))
event_system.emit(f"handle_file_event_{event.originator}", (event,))
case "load_buffer":
event_system.emit(f"handle_file_event_{event.originator}", (event,))
# case "add_tab":
# event_system.emit(f"add_tab_{event.originator}", (event,))
case "error":
content = base64.b64decode( event.content.encode() ).decode("utf-8")
logger.info(content)
case _:
...

View File

@ -12,8 +12,9 @@ from gi.repository import Gtk
class FilesController:
def __init__(self):
def __init__(self, index):
self.INDEX = index
self.opened_files = {}
self._setup_signals()
@ -24,8 +25,8 @@ class FilesController:
...
def _subscribe_to_events(self):
event_system.subscribe("set_pre_drop_dnd", self.set_pre_drop_dnd)
event_system.subscribe("handle_file_event", self.handle_file_event)
event_system.subscribe(f"set_pre_drop_dnd_{self.INDEX}", self.set_pre_drop_dnd)
event_system.subscribe(f"handle_file_event_{self.INDEX}", self.handle_file_event)
def set_pre_drop_dnd(self, gfiles):
keys = self.opened_files.keys()
@ -46,37 +47,38 @@ class FilesController:
def handle_file_event(self, event):
match event.topic:
case "save":
content = base64.b64decode( event.content.encode() ).decode("utf-8")
self.save_session(event.target, content)
content = base64.b64decode( event.content.encode() ).decode("utf-8")
basename = self.save_session(event.target, content)
if basename:
event_system.emit(f"updated_tab_{event.originator}", (event.target, basename,))
case "close":
self.close_session(event.target)
case "load_buffer":
self.load_buffer(event.target)
event_system.emit(f"add_tab_{event.originator}", (event.target, "buffer",))
case _:
return
def load_buffer(self, fhash):
self.opened_files[fhash] = {"file": None, "ftype": "buffer"}
def save_session(self, fhash, content):
keys = self.opened_files.keys()
ftype = self.opened_files[fhash]["ftype"]
gfile = event_system.emit_and_await(
"save_file_dialog", ("", None)
) if not fhash in keys else self.opened_files[fhash]["file"]
if not gfile: return
) if fhash == "buffer" else self.opened_files[fhash]["file"]
file_written = self.write_to_file(fhash, gfile, content)
if not fhash in keys and file_written:
self.insert_to_sessions(fhash, gfile)
event_system.emit(
"updated_tab",
(
self.opened_files[fhash]["ftype"],
gfile.get_basename(),
)
)
if fhash == "buffer" and file_written:
self.update_session(fhash, gfile)
return gfile.get_basename()
def close_session(self, target):
del self.opened_files[target]
def insert_to_sessions(self, fhash, gfile):
def update_session(self, fhash, gfile):
info = gfile.query_info("standard::*", 0, cancellable = None)
ftype = info.get_content_type().replace("x-", "").split("/")[1]

View File

@ -15,10 +15,11 @@ from libs.data_types import Event
class AceEditor(WebKit2.WebView):
def __init__(self):
def __init__(self, index):
super(AceEditor, self).__init__()
# self.get_context().set_sandbox_enabled(False)
self.INDEX = index
self._load_settings()
self._setup_styling()
@ -42,11 +43,11 @@ class AceEditor(WebKit2.WebView):
...
def _subscribe_to_events(self):
event_system.subscribe("load_file", self.load_file)
event_system.subscribe("updated_tab", self.updated_tab)
event_system.subscribe("ui_message", self.ui_message)
event_system.subscribe(f"load_file_{self.INDEX}", self.load_file)
event_system.subscribe(f"new_session_{self.INDEX}", self.new_session)
event_system.subscribe(f"switch_session_{self.INDEX}", self.switch_session)
event_system.subscribe(f"close_session_{self.INDEX}", self.close_session)
event_system.subscribe(f"ui_message_{self.INDEX}", self.ui_message)
def _load_settings(self):
self.set_settings( WebkitUISettings() )
@ -72,6 +73,7 @@ class AceEditor(WebKit2.WebView):
try:
event = Event( **json.loads(message) )
event.originator = self.INDEX
event_system.emit("handle_bridge_event", (event,))
except Exception as e:
logger.info(e)
@ -80,8 +82,16 @@ class AceEditor(WebKit2.WebView):
command = f"loadFile('{ftype}', '{fhash}', '{file}', '{content}')"
self.run_javascript(command, None, None)
def updated_tab(self, ftype, fname):
command = f"updatedTab('{ftype}', '{fname}')"
def new_session(self):
command = f"newSession()"
self.run_javascript(command, None, None)
def switch_session(self, fhash):
command = f"switchSession('{fhash}')"
self.run_javascript(command, None, None)
def close_session(self, fhash):
command = f"closeSession('{fhash}')"
self.run_javascript(command, None, None)
def ui_message(self, message, mtype):

View File

@ -0,0 +1,48 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ....controllers.files_controller import FilesController
from ...controls.tab_bar import TabBar
from .fixed_box import FixedBox
class Editor(Gtk.Box):
ccount = 0
def __new__(cls, *args, **kwargs):
obj = super(Editor, cls).__new__(cls)
cls.ccount += 1
return obj
def __init__(self):
super(Editor, self).__init__()
self.INDEX = self.ccount
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show()
def _setup_styling(self):
self.set_orientation( Gtk.Orientation.VERTICAL )
def _setup_signals(self):
...
def _subscribe_to_events(self):
FilesController(self.INDEX)
def _load_widgets(self):
self.add( TabBar(self.INDEX) )
self.add( FixedBox(self.INDEX) )

View File

@ -6,8 +6,8 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.base.webkit.dnd_box import DnDBox
from ..widgets.base.webkit.ace_editor import AceEditor
from .dnd_box import DnDBox
from .ace_editor import AceEditor
@ -17,8 +17,10 @@ class FixedBox(Gtk.Fixed):
(aka our DnDBox) above the Webkit2.Webview to intercept and proxy accordingly.
"""
def __init__(self):
def __init__(self, index):
super(FixedBox, self).__init__()
self.INDEX = index
self._setup_styling()
self._setup_signals()
@ -39,7 +41,7 @@ class FixedBox(Gtk.Fixed):
...
def _load_widgets(self):
self.ace_editor = AceEditor()
self.ace_editor = AceEditor(self.INDEX)
self.dnd_box = DnDBox()
self.add( self.ace_editor )

View File

@ -11,9 +11,11 @@ from ..tab_header_widget import TabHeaderWidget
class TabBar(Gtk.Notebook):
def __init__(self):
def __init__(self, index):
super(TabBar, self).__init__()
self.INDEX = index
self.set_group_name("editor_widget")
self._setup_styling()
@ -29,12 +31,10 @@ class TabBar(Gtk.Notebook):
def _setup_signals(self):
self.connect("switch-page", self._switch_page_update)
# self.connect("key-press-event", self._key_press_event)
# self.connect("key-release-event", self._key_release_event)
...
def _subscribe_to_events(self):
...
event_system.subscribe(f"add_tab_{self.INDEX}", self.add_tab)
event_system.subscribe(f"update_tab_{self.INDEX}", self.update_tab)
def _load_widgets(self):
start_box = Gtk.Box()
@ -51,28 +51,50 @@ class TabBar(Gtk.Notebook):
self.set_action_widget(start_box, 0)
self.set_action_widget(end_box, 1)
self.add_tab_click(None)
def _switch_page_update(self, notebook, page, page_num):
print(page_num)
...
def add_tab_click(self, widget):
container = Gtk.Box()
page_num = self.append_page(container, TabHeaderWidget(container, self._close_tab))
event_system.emit(f"new_session_{self.INDEX}")
def add_tab(self, fhash, title = "[BAD TITLE]"):
container = Gtk.EventBox()
header = TabHeaderWidget(container, self._close_tab)
page_num = self.append_page(container, header)
container.fhash = fhash
header.label.set_label(title)
self.set_tab_detachable(container, True)
self.set_tab_reorderable(container, True)
self.show_all()
self.set_current_page(page_num)
def update_tab(self, fhash, title = "[BAD TITLE]"):
container = Gtk.EventBox()
header = TabHeaderWidget(container, self._close_tab)
page_num = self.append_page(container, header)
header.label.set_label(title)
self.set_tab_detachable(container, True)
self.set_tab_reorderable(container, True)
self.show_all()
self.set_current_page(page_num)
# Note: Need to get parent instead given we pass the close_tab method
# from a potentially former notebook.
def _close_tab(self, widget, container):
notebook = container.get_parent()
page_num = notebook.page_num(container)
notebook.remove_page(page_num)
if notebook.get_n_pages() < 2: return
page_num = notebook.page_num(container)
event_system.emit(f"close_session_{self.INDEX}", (container.fhash))
notebook.remove_page(page_num)
# def close_tab(self, button, container, source_view, eve = None):
@ -91,6 +113,4 @@ class TabBar(Gtk.Notebook):
# if notebook.NAME == "notebook_2" and notebook.get_n_pages() == 0:
# notebook.hide()
# event_system.emit("focused_target_changed", ("notebook_1",))
# event_system.emit("focused_target_changed", ("notebook_1",))

View File

@ -37,20 +37,20 @@ class TabHeaderWidget(Gtk.Box):
...
def _load_widgets(self):
label = Gtk.Label(label = "buffer")
self.label = Gtk.Label(label = "buffer")
close = Gtk.Button()
icon = Gtk.Image(stock = Gtk.STOCK_CLOSE)
# TODO: Setup with settings and from file
label.set_xalign(0.0)
label.set_margin_left(25)
label.set_margin_right(25)
label.set_hexpand(True)
self.label.set_xalign(0.0)
self.label.set_margin_left(25)
self.label.set_margin_right(25)
self.label.set_hexpand(True)
close.set_always_show_image(True)
close.set_hexpand(False)
close.set_image( Gtk.Image.new_from_icon_name("gtk-close", 4) )
close.connect("released", self.close_tab, *(self.content,))
self.add(label)
self.add(close)
self.add(self.label)
self.add(close)

View File

@ -13,3 +13,4 @@ class Event:
topic: str
target: str
content: str
originator: int = -1

View File

@ -14,27 +14,7 @@
</head>
<body>
<div class="row">
<div id="page-alert-zone" class="col">
</div>
</div>
<div class="container editor-container">
<div class="row">
<div class="col col-md-10 scroller">
<ul class="nav nav-tabs">
</ul>
</div>
<div class="col col-auto align-self-end">
<ul>
<li id="add-tab-icon" class="add-session-bottom" role="presentation" onclick="newSession(this)">
<a href="#">
<i class="bi bi-plus-square" aria-hidden="true"></i>
</a>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col">
<pre id="editor">
@ -43,12 +23,6 @@
</div>
</div>
<p>
<div id="status-bar">Status Bar: ...</div>
</p>
<!-- For internal scripts... -->
<!-- <script src="js/libs/jquery-3.7.1.min.js"></script> -->
@ -64,14 +38,13 @@
<script src="resources/js/libs/ace_editor/ext-settings_menu.js"></script>
<script src="resources/js/libs/ace_editor/ace-linters.js"></script>
<!-- For Application... -->
<!-- <script src="resources/js/newton/ajax.js"></script> -->
<!-- <script src="resources/js/newton/post-ajax.js"></script> -->
<script src="resources/js/newton/dnd-sort.js"></script>
<script src="resources/js/newton/keybinding-newton.js"></script>
<script src="resources/js/newton/globals.js"></script>
<script src="resources/js/newton/utils.js"></script>
<script src="resources/js/newton/keybinding-newton.js"></script>
<script src="resources/js/newton/ui-logic.js"></script>
<script src="resources/js/newton/events.js"></script>
</body>

View File

@ -1,36 +0,0 @@
// Taken from: https://stackoverflow.com/questions/10588607/tutorial-for-html5-dragdrop-sortable-list
let dndSelected = null
function dragOver(e) {
if (isBefore(dndSelected, e.target)) {
e.target.parentNode.insertBefore(dndSelected, e.target);
} else {
try {
e.target.parentNode.insertBefore(dndSelected, e.target.nextSibling);
} catch(e) {
return;
}
}
}
function dragEnd() {
dndSelected = null;
}
function dragStart(e) {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', null);
dndSelected = e.target;
}
function isBefore(el1, el2) {
let cur;
if (el2.parentNode === el1.parentNode) {
for (cur = el1.previousSibling; cur; cur = cur.previousSibling) {
if (cur === el2) return true;
}
}
return false;
}

View File

@ -1,17 +1,11 @@
const messenger = (window.webkit) ? window.webkit.messageHandlers : (message) => {
console.log("Message: " + message);
};
let aceSessions = {};
let currentSession = null;
window.onload = (eve) => {
console.log("Loaded...");
loadInitialSessions();
loadEditor();
loadInitialSessionTab();
console.log("Window Loaded...");
}
window.onerror = function(msg, url, line, col, error) {
// Note that col & error are new to the HTML 5 spec and may not be supported in every browser.
const suppressErrorAlert = false;
@ -23,35 +17,4 @@ window.onerror = function(msg, url, line, col, error) {
// If you return true, then error alerts (like in older versions of Internet Explorer) will be suppressed.
return suppressErrorAlert;
};
ace.require("ace/ext/language_tools");
let StatusBar = ace.require('ace/ext/statusbar').StatusBar;
let editor = ace.edit("editor");
// Note: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
editor.setOptions({
printMarginColumn: 80,
enableBasicAutocompletion: true,
enableInlineAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
highlightActiveLine: true,
useSoftTabs: true,
tabSize: 4,
tooltipFollowsMouse: true,
useWrapMode: false,
scrollPastEnd: 0.5,
mergeUndoDeltas: false
});
// Note: https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts
editor.commands.addCommands(editorCommands);
editor.setTheme("ace/theme/one_dark");
const statusBar = new StatusBar(editor, document.getElementById('status-bar'));
};

View File

@ -0,0 +1,7 @@
const messenger = (window.webkit) ? window.webkit.messageHandlers : (message) => {
console.log("Message: " + message);
};
let editor = null;
let aceSessions = {};
let currentSession = null;

View File

@ -1,87 +1,62 @@
const loadFile = (ftype, fhash, file, content) => {
session = ace.createEditSession( atob(content) );
aceSessions[fhash] = {"ftype": ftype, "file": file, "session": session};
const loadEditor = () => {
ace.require("ace/ext/language_tools");
let tab = `
<li class='tab active-tab' role="presentation" fhash='${fhash}' ftype='${ftype}' draggable="true"
ondragend="dragEnd()" ondragover="dragOver(event)" ondragstart="dragStart(event)"
>
<span class='file-name' onclick='switchSession(this)'>${file}</span>
<span class='close-button' onclick='closeSession(this)'>
<i class="bi bi-x-square" aria-hidden="true"></i>
</span>
</li>
`;
editor = ace.edit("editor");
// Note: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
editor.setOptions({
printMarginColumn: 80,
enableBasicAutocompletion: true,
enableInlineAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
highlightActiveLine: true,
useSoftTabs: true,
tabSize: 4,
tooltipFollowsMouse: true,
useWrapMode: false,
scrollPastEnd: 0.5,
mergeUndoDeltas: false
});
// TODO: Need to account for given editor we have focused when implimented...
document.getElementsByClassName("nav-tabs")[0]
.insertAdjacentHTML('beforeend', tab);
// Note: https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts
editor.commands.addCommands(editorCommands);
editor.setTheme("ace/theme/one_dark");
}
const loadInitialSessionTab = async () => {
newSession(null, editor.getSession());
}
const newSession = async (elm = null, session = null) => {
let ftype = "buffer";
let fhash = await getSHA256Hash( new Date().toString() );
session = ( isNotNullOrUndefined(session) ) ? session : ace.createEditSession("");
aceSessions[fhash] = {"ftype": ftype, "file": "", "session": session};
setSession(ftype, fhash, session);
sendMessage("load_buffer", fhash, "");
}
const switchSession = (fhash) => {
ftype = aceSessions[fhash]["ftype"];
session = aceSessions[fhash]["session"];
setSession(ftype, fhash, session);
}
const updatedTab = (ftype, fname) => {
let elm = document.querySelectorAll(`[fhash="${currentSession}"]`)[0];
let tabTitleElm = elm.children[0];
aceSessions[currentSession]["ftype"] = ftype;
aceSessions[currentSession]["file"] = fname;
elm.setAttribute("ftype", ftype);
tabTitleElm.textContent = fname;
const closeSession = (fhash) => {
delete aceSessions[fhash];
keys = Object.keys(aceSessions);
console.log(keys.length);
}
const loadInitialSessions = () => {
let elms = document.getElementsByClassName("add-session-bottom");
for (let i = 0; i < elms.length; i++) {
elms[i].click();
}
}
const newSession = async (elm) => {
let ftype = "buffer";
let fhash = await getSHA256Hash( new Date().toString() );
let session = ace.createEditSession("");
let tab = `
<li class='tab active-tab' role="presentation" fhash='${fhash}' ftype='${ftype}' draggable="true"
ondragend="dragEnd()" ondragover="dragOver(event)" ondragstart="dragStart(event)"
>
<span class='file-name' onclick='switchSession(this)'>buffer</span>
<span class='close-button' onclick='closeSession(this)'>
<i class="bi bi-x-square" aria-hidden="true"></i>
</span>
</li>
`;
aceSessions[fhash] = {"ftype": "buffer", "file": "", "session": session};
let container = elm.parentElement.parentElement.parentElement;
let tabs = container.children[0].children[0];
tabs.insertAdjacentHTML('beforeend', tab);
setSession(ftype, fhash, session);
}
const saveSession = () => {
let fhash = currentSession;
let session = aceSessions[fhash]["session"];
let data = session.getValue();
sendMessage("save", fhash, data);
}
const setSession = (ftype, fhash, session) => {
if (currentSession) {
let currentElm = document.querySelectorAll(`[fhash="${currentSession}"]`)[0];
currentElm.classList.remove("active-tab");
}
currentSession = fhash;
let currentElm = document.querySelectorAll(`[fhash="${currentSession}"]`)[0];
currentElm.classList.add("active-tab");
editor.setSession(session);
if (ftype !== "buffer") {
@ -89,39 +64,71 @@ const setSession = (ftype, fhash, session) => {
}
}
const switchSession = (elm) => {
let parentElm = elm.parentElement;
let ftype = parentElm.getAttribute("ftype");
let fhash = parentElm.getAttribute("fhash");
let session = aceSessions[fhash]["session"];
const loadFile = (ftype, fhash, file, content) => {
session = ace.createEditSession( atob(content) );
aceSessions[fhash] = {"ftype": ftype, "file": file, "session": session};
// let tab = `
// <li class='tab active-tab' role="presentation" fhash='${fhash}' ftype='${ftype}' draggable="true"
// ondragend="dragEnd()" ondragover="dragOver(event)" ondragstart="dragStart(event)"
// >
// <span class='file-name' onclick='switchSession(this)'>${file}</span>
// <span class='close-button' onclick='closeSession(this)'>
// <i class="bi bi-x-square" aria-hidden="true"></i>
// </span>
// </li>
// `;
// TODO: Need to account for given editor we have focused when implimented...
// document.getElementsByClassName("nav-tabs")[0]
// .insertAdjacentHTML('beforeend', tab);
setSession(ftype, fhash, session);
}
const closeSession = (elm) => {
let keys = Object.keys(aceSessions);
if (keys.length < 2) return
const updatedTab = (ftype, fname) => {
// let elm = document.querySelectorAll(`[fhash="${currentSession}"]`)[0];
// let tabTitleElm = elm.children[0];
let parentElm = elm.parentElement;
let ftype = parentElm.getAttribute("ftype");
let fhash = parentElm.getAttribute("fhash");
aceSessions[currentSession]["ftype"] = ftype;
aceSessions[currentSession]["file"] = fname;
if (ftype !== "buffer") {
sendMessage("close", fhash, "");
}
// elm.setAttribute("ftype", ftype);
// tabTitleElm.textContent = fname;
}
if (fhash === currentSession) {
let siblingElm = getSiblingElm(parentElm);
if ( isNotNullOrUndefined(siblingElm) ) {
let sftype = siblingElm.getAttribute("ftype");
let sfhash = siblingElm.getAttribute("fhash");
setSession(sftype, sfhash, aceSessions[sfhash]["session"]);
}
}
parentElm.remove();
delete aceSessions[fhash];
const saveSession = () => {
let fhash = currentSession;
let session = aceSessions[fhash]["session"];
let data = session.getValue();
sendMessage("save", fhash, data);
}

View File

@ -41,11 +41,11 @@ const getSHA256Hash = async (input) => {
let textAsBuffer = new TextEncoder().encode(input);
let hashBuffer = await window.crypto.subtle.digest("SHA-256", textAsBuffer);
let hashArray = Array.from( new Uint8Array(hashBuffer) );
let hash = hashArray.map(
let fhash = hashArray.map(
(item) => item.toString(16).padStart(2, "0")
).join("");
return hash;
return fhash;
};
const clearChildNodes = (parent) => {