Skip to content

Commit

Permalink
Merge branch 'tree-browser-lit-component'
Browse files Browse the repository at this point in the history
* Branch commit log:
  ui/b/treebrowser.js: bring back caret animation
  ui/b/contextmenu.js: only process/prevent clicks on menuitems
  ui/b/contextmenu.js: use check_visibility()
  ui/util.js: ignore 'mouseup' on backdrops, those are often not prevented
  ui/kbd.js: use check_visibility()
  ui/util.js: add check_visibility, remove inside_display_none
	* Add check_visibility() that handles Chrome oddities with <details/>
	* Remove inside_display_none(), use check_visibility() instead
  ui/b/contextmenu.js: CSS styling for <summary/>
  ui/b/shell.vue: use b-treebrowser
  ui/b/devicepanel.vue: use b-treebrowser and enable menuitems
  ui/b/treeselector*.vue: remove unused Vue tree impl
  ui/b/treebrowser.js: reimplement tree browser as LitComponent
	* Start Vue tree component port
	* Merge tree components
	* Use <details/> and <summary/> for collapsing
	* Adjust CSS for new DOM layout
	* Expand/collapse with left/right keys
	* Call Kbd focus functions for up/down/left/right
  ui/Makefile.mk, ui/postcss.config.mjs: set + use $POSTCSS_IMPORT_PATH
  ui/Makefile.mk: cleanup postcss rule, add explicit CSS output file
  ui/postcss.config.mjs: adapt import paths, generate external sourcemap for CSS
  ui/tailwind.config.mjs: remove, tailwind config is part of postcss.config.mjs
  ui/b/noticeboard.js: whitespace
  misc/synsmell.py: degrade fixmes to a warning
  ui/tailwind.scss: add CSS for a proper :focus outline
  ui/kbd.js: export move_focus_{prev|next|left|right} functions
  ui/kbd.js: support focus on <summary/>
  ui/kbd.js: match_key_event(): support multiple keys
  ui/b/noticeboard.js: fix DOM element property access
  ui/b/propinput.js: fix method chaining
  ui/b/knob.js: fix method chaining
  ui/b/textinput.js: fix method chaining
  ui/Makefile.mk: dont eslint Vue files without config
  ase/loop.cc: fix stderr output from signal handler

Signed-off-by: Tim Janik <timj@gnu.org>
  • Loading branch information
tim-janik committed May 30, 2024
2 parents 0e77871 + 46b6e99 commit e06849c
Show file tree
Hide file tree
Showing 18 changed files with 293 additions and 391 deletions.
30 changes: 29 additions & 1 deletion ase/loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1089,11 +1089,39 @@ void
USignalSource::destroy()
{}

static std::array<char,12>
write_uint (uint32_t i)
{
std::array<char,12> a;
char *c = &a.back();
ASE_ASSERT (c>=&a[0] && c<&a[a.size()]);
*c-- = 0;
*c = '0' + (i % 10);
i /= 10;
while (i != 0) {
*(--c) = '0' + (i % 10);
i /= 10;
}
if (c > &a[0])
memmove (&a[0], c, &a.back() + 1 - c);
ASE_ASSERT (c>=&a[0] && c<&a[a.size()]);
return a;
}

void
USignalSource::install_sigaction (int8 signum)
{
struct sigaction action;
action.sa_handler = [] (int signum) { fputs ("sighandler", stdout); USignalSource::raise (signum); };
action.sa_handler = [] (int signum) {
constexpr size_t N = 1024;
char buf[N] = __FILE__ ":";
strncat (buf, &write_uint (__LINE__)[0], N);
strncat (buf, ": sa_handler: signal=", N);
strncat (buf, &write_uint (signum)[0], N);
strncat (buf, "\n", N);
::write (2, buf, strlen (buf));
USignalSource::raise (signum);
};
sigemptyset (&action.sa_mask);
action.sa_flags = SA_NOMASK;
sigaction (signum, &action, nullptr);
Expand Down
2 changes: 1 addition & 1 deletion misc/synsmell.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def line_matcher (code, text, has_comment, orig, filename):
warning = "missing whitespace after parenthesis"
# ban-fixme
elif m := checks['ban-fixme'] and has_comment and re.search (r'\bFI[X]ME\b', text, re.IGNORECASE):
error = "comment indicates unfinished code"
warning = "comment indicates unfinished code"
# ban-todo
elif m := checks['ban-todo'] and has_comment and re.search (r'\bTODO\b', text, re.IGNORECASE):
error = "comment indicates open issues"
Expand Down
64 changes: 33 additions & 31 deletions ui/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ui/jscopy.wildcards ::= $(wildcard \
ui/cjs.wildcards ::= $(wildcard \
)
ui/nocopy.wildcards ::= $(wildcard \
ui/*css \
ui/*.scss \
ui/sfc-compile.js \
ui/slashcomment.js \
)
Expand Down Expand Up @@ -92,7 +92,7 @@ $>/ui/index.html: $(ui/js.targets)

# == ui/index.html ==
$>/ui/index.html: ui/index.html $>/ui/global.css node_modules/.npm.done | $>/ui/
@ $(eval ui/csshash != cat $>/ui/global.css | sha256sum | sed 's/ *-//')
@ $(eval ui/csshash != sha256sum < $>/ui/global.css | sed -r 's/^([0-9a-f]{12}).*/\1/i')
$(QGEN)
$Q rm -f $>/ui/doc && ln -s ../doc $>/ui/doc # do here, b/c MAKE is flaky in tracking symlink timestamps
$Q echo ' { "config": { $(strip $(PACKAGE_VERSIONS)),' > $>/ui/config.json
Expand Down Expand Up @@ -146,57 +146,59 @@ $(ui/b/vuejs.targets): $>/%.js: %.vue | $>/ui/b/ node_modules/.npm.done
$Q node ui/sfc-compile.js --debug -I $>/ui/ $< -O $(@D)
$>/.ui-reload-stamp: $(ui/b/vuejs.targets)

# == UI/GLOBALSCSS_IMPORTS ==
UI/GLOBALSCSS_IMPORTS =
# Material-Icons
$>/ui/material-icons.css: ui/Makefile.mk | $>/ui/ node_modules/.npm.done
# == ui/material-icons.css ==
$>/ui/material-icons.css: ui/Makefile.mk | node_modules/.npm.done $>/ui/
$(QGEN)
$Q grep -q '/material-icons.woff2' node_modules/material-icons/iconfont/filled.css || \
{ echo "$<: failed to find font in node_modules/material-icons/iconfont/" >&2 ; false ; }
$Q cp node_modules/material-icons/iconfont/material-icons.woff2 $>/ui/material-icons.woff2
$Q sed -re 's|\boptimizeLegibility\b|optimizelegibility|g' \
node_modules/material-icons/iconfont/filled.css > $@.tmp
$Q mv $@.tmp $@
UI/GLOBALSCSS_IMPORTS += $>/ui/material-icons.css
# AnklangIcons
$>/.ui-reload-stamp: $>/ui/material-icons.css

# == ui/assets/AnklangIcons.css ==
$>/ui/assets/AnklangIcons.css: ui/Makefile.mk | $>/ui/assets/
$(QGEN)
$Q rm -fr $>/ui/anklangicons/ && tar xf external/blobs4anklang/icons/anklangicons-201123.1.tgz -C $>/ui/
$Q cd $>/ui/anklangicons/ && $(CP) AnklangIcons.woff2 ../assets/ && $(CP) AnklangIcons.css ../assets/AnklangIcons.css.tmp
$Q sed -e 's|@font-face *{|@font-face { font-display: block; |' -i $>/ui/assets/AnklangIcons.css.tmp
$Q rm -r $>/ui/anklangicons/ && mv $@.tmp $@
UI/GLOBALSCSS_IMPORTS += $>/ui/assets/AnklangIcons.css
# Fork-Awesome
$>/ui/assets/fork-awesome.css: ui/Makefile.mk | node_modules/.npm.done $>/ui/assets/
$>/.ui-reload-stamp: $>/ui/assets/AnklangIcons.css

# == ui/assets/fork-awesome.css ==
$>/ui/assets/fork-awesome.css: ui/Makefile.mk | node_modules/.npm.done $>/ui/assets/
$(QGEN)
$Q $(CP) node_modules/fork-awesome/fonts/forkawesome-webfont.woff2 $>/ui/assets/
$Q sed -e "/^ *src: *url/s,src: *url(.*);,src: url('forkawesome-webfont.woff2');," \
-e 's|@font-face *{|@font-face { font-display: block; |' \
node_modules/fork-awesome/css/fork-awesome.css > $@.tmp
$Q mv $@.tmp $@
UI/GLOBALSCSS_IMPORTS += $>/ui/assets/fork-awesome.css
# ui/cursors/
$>/.ui-reload-stamp: $>/ui/assets/fork-awesome.css

# == ui/cursors/cursors.css ==
$>/ui/cursors/cursors.css: $(wildcard ui/cursors/*) Makefile.mk | $>/ui/cursors/
$(QECHO) COPY $<
$Q for SVG in `sed -n "/url.'cursors\//{ s/.*('//; s/').*//; p }" ui/cursors/cursors.css` ; do \
$(CP) ui/"$$SVG" $>/ui/cursors/ || break ; done
$Q $(CP) ui/cursors/cursors.css $@
UI/GLOBALSCSS_IMPORTS += $>/ui/cursors/cursors.css
# ui/spinner.svg
$>/ui/spinner.scss: ui/assets/spinner.svg
$>/.ui-reload-stamp: $>/ui/cursors/cursors.css

# == ext/spinner.scss ==
$>/ext/spinner.scss: ui/assets/spinner.svg | $>/ext/ui/assets/
$(QGEN)
$Q sed -rn '/@keyframe/,$${ p; /^\s*}\s*$$/q; }' $< > $@
UI/GLOBALSCSS_IMPORTS += $>/ui/spinner.scss
$>/ui/global.css: $>/ext/spinner.scss

# == ext/ui/b/*.js ==
ui/b/js.files := $(wildcard ui/b/*.js)
ext/ui/b/js.files := $(ui/b/js.files:%=$>/ext/%)
$(ext/ui/b/js.files): $>/ext/ui/b/.stamp
$>/ext/ui/b/.stamp: $(ui/b/js.files) ui/jsextract.js | $>/ext/ui/b/
$(ext/ui/b/js.files): $>/ext/ui/b/.jsstamp
$>/ext/ui/b/.jsstamp: $(ui/b/js.files) ui/jsextract.js | $>/ext/ui/b/
$(QECHO) EXTRACT 'ext/ui/b/*.js'
$Q node ui/jsextract.js -O $>/ext/ui/b/ $(ui/b/js.files)
$Q touch $@
ext/ui/lint: $>/ext/ui/b/.stamp
ext/ui/lint: $>/ext/ui/b/.jsstamp
-$Q cd $>/ext/ \
&& $(abspath node_modules/.bin/stylelint) -c $(abspath ui/stylelintrc.cjs) \
$${INSIDE_EMACS:+-f unix} $(ext/ui/b/js.files:$>/ext/%=%) |& \
Expand All @@ -207,19 +209,19 @@ ui/lint: ext/ui/lint
# == ui/global.css ==
ui/b/vuecss.targets ::= $(ui/vue.wildcards:%.vue=$>/%.vuecss)
$(ui/b/vuecss.targets): $(ui/b/vuejs.targets) ;
ui/tailwind.inputs := $(wildcard ui/*.html ui/*.css ui/*.scss ui/*.js ui/b/*.js ui/b/*.vue $(ui/b/js.files))
ui/tailwind.inputs := $(wildcard ui/*.html ui/*.*css ui/*.*js ui/b/*.*js ui/b/*.vue)
$>/ui/global.css: ui/global.scss $(ui/tailwind.inputs) $(ext/ui/b/js.files) ui/stylelintrc.cjs ui/postcss.config.mjs $(UI/GLOBALSCSS_IMPORTS) $(ui/b/vuecss.targets) | $>/ui/
$(QGEN)
$Q echo '@charset "UTF-8";' > $@.imp
$Q echo "@import 'dark.scss';" >> $@.imp
$Q echo "@import 'global.scss';" >> $@.imp
$Q echo '@charset "UTF-8";' > $>/ext/imports.scss
$Q echo "@import 'ui/dark.scss';" >> $>/ext/imports.scss
$Q echo "@import 'ui/global.scss';" >> $>/ext/imports.scss
$Q for f in $(ui/b/vuecss.targets:$>/ui/b/%=%) ; do \
echo "@import 'b/$${f}';" || exit 1 ; done >> $@.imp
echo "@import '$>/ui/b/$${f}';" || exit 1 ; done >> $>/ext/imports.scss
$Q for f in $(ext/ui/b/js.files); do \
echo "@import '$$f';" || exit 1 ; done >> $@.imp
$Q test -r ui/postcss.config.mjs || { echo 'ui/postcss.config.mjs: not readable'; false; }
$Q node_modules/.bin/postcss --config ui/ < $@.imp > $@.tmp
$Q rm -f $@.imp && mv $@.tmp $@
echo "@import '$$f';" || exit 1 ; done >> $>/ext/imports.scss
$Q POSTCSS_IMPORT_PATH=.:$>/ext \
node_modules/.bin/postcss --config ui < $>/ext/imports.scss -o $>/ext/ui/global.css
$Q mv $>/ext/ui/global.css* $(@D)
$>/.ui-reload-stamp: $>/ui/global.css

# == all-components.js ==
Expand Down Expand Up @@ -281,7 +283,7 @@ $>/ui/anklang.png: $>/ui/favicon.ico
$>/.ui-build-stamp: $>/ui/favicon.ico $>/ui/anklang.png

# == eslint ==
ui/eslint.files ::= $(wildcard ui/*.html ui/*.js ui/b/*.js ui/b/*.vue)
ui/eslint.files ::= $(wildcard ui/*.html ui/*.js ui/b/*.js)
$>/.eslint.done: ui/eslintrc.js $(ui/eslint.files) ui/Makefile.mk node_modules/.npm.done | $>/ui/
$(QECHO) RUN eslint
$Q node_modules/.bin/eslint -c ui/eslintrc.js -f unix --cache --cache-location $>/.eslintcache \
Expand Down Expand Up @@ -338,7 +340,7 @@ ui/rebuild:
@: # rebuild live reload targets
$(MAKE) $>/.ui-reload-stamp NPMBLOCK=y -j`nproc` |& tee $>/ui-build.log || { ( : \
&& echo '<html><head><title>anklang/ui: make error</title></head><body><pre>' \
&& cat out/ui-build.log && echo '</pre>' \
&& cat $>/ui-build.log && echo '</pre>' \
&& echo '<script>setTimeout(_=>window.location.reload(), 3000)</script></body></html>' \
) > $>/ui/index.html && touch --date=1990-01-01 $>/ui/index.html ; }
@: # close open sockets, only works if *same* executable still runs
Expand Down
29 changes: 14 additions & 15 deletions ui/b/contextmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ dialog.b-contextmenu::backdrop {
* and second, showing a modal dialog via menu item would result in bad flickernig. */
background: transparent;
}
b-contextmenu push-button,
b-contextmenu button {
b-contextmenu :is(button, push-button, summary) {
@apply hflex flex-nowrap items-stretch px-4 py-1 text-left;
background: transparent; color: $b-menu-foreground; border: 1px solid transparent;
cursor: pointer; user-select: none; outline: none;
Expand Down Expand Up @@ -302,8 +301,8 @@ class BContextMenu extends LitComponent {
const toggles = await Promise.all (proms);
this.stop_observer();
for (let i = 0; i < proms.length; i++) {
const element = proms[i]['element'], toggle = !!toggles[i];
element.toggleAttribute ('disabled', !toggle);
const element = proms[i]['element'], disabled = !toggles[i];
element.toggleAttribute ('disabled', disabled);
}
this.start_observer();
proms.length = 0;
Expand Down Expand Up @@ -341,7 +340,7 @@ class BContextMenu extends LitComponent {
if (!popup_options)
popup_options = { origin: null };
const origin = popup_options.origin === null ? null : popup_options.origin?.$el || popup_options.origin || event?.currentTarget;
if (origin instanceof Element && Util.inside_display_none (origin))
if (origin instanceof Element && !Util.check_visibility (origin))
return false; // cannot popup around hidden origin
this.toggle_force_children (false); // add [disabled] attribute to chldren
const toggles = this.toggle_active_children(); // concurrently, enable active children
Expand Down Expand Up @@ -393,22 +392,22 @@ class BContextMenu extends LitComponent {
// event is this.click, not bubbeling
if (this.allowed_click === event)
return;
const target = event.target;
const uri = get_uri (target);
// ignore clicks on non-menuitem elements
if (target && !valid_uri (uri))
return;
// prevent any further bubbeling
Util.prevent_event (event);
// allows one click activation per frame
if (Util.frame_stamp() == this.menudata.menu_stamp)
return;
// turn bubbled click into menu activation
const target = event.target;
const uri = get_uri (target);
if (target && valid_uri (uri))
{
const isactive = !target.check_isactive ? true : target.check_isactive (false);
if (isactive instanceof Promise)
return (async () => (await isactive) && this.click (uri)) ();
if (isactive)
return this.click (uri);
}
const isactive = !target.check_isactive ? true : target.check_isactive (false);
if (isactive instanceof Promise)
return (async () => (await isactive) && this.click (uri)) ();
if (isactive)
return this.click (uri);
}
click (uri)
{
Expand Down
8 changes: 4 additions & 4 deletions ui/b/devicepanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
data-tip="**CLICK** Add New Elements" />
<b-contextmenu ref="devicepanelcmenu" id="g-devicepanelcmenu" :activate.prop="activate" :isactive.prop="isactive" >
<b-menutitle> Devices </b-menutitle>
<b-treeselector :tree="devicetypes" :defaultcollapse="false"> </b-treeselector>
<b-treebrowser :tree="devicetypes" :defaultexpand="false"> </b-treebrowser>
</b-contextmenu>
</h-flex>
<span class="b-devicepanel-after-scroller"></span>
Expand All @@ -87,7 +87,7 @@ async function list_device_types () {
const list = [];
for (const c of Object.keys (cats).sort())
list.push (cats[c]);
return Object.freeze ({ entries: list });
return Object.freeze (list);
}
function observable_device_data () {
Expand Down Expand Up @@ -118,7 +118,7 @@ export default {
async activate (uri)
{
// close popup to remove focus guards
if (this.chain_ && !uri.startsWith ('DevicePanel:')) // assuming b-treeselector.devicetypes
if (this.chain_ && !uri.startsWith ('DevicePanel:')) // assuming b-treebrowser.devicetypes
{
const sibling = this.menu_origin?.sibling;
let newdev;
Expand All @@ -136,7 +136,7 @@ export default {
{
if (!this.track)
return false;
return false;
return true;
},
menuopen (event)
{
Expand Down
1 change: 1 addition & 0 deletions ui/b/knob.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class BKnob extends LitComponent {
}
disconnectedCallback()
{
super.disconnectedCallback();
this.clear_notify_cb?.();
this.clear_notify_cb = undefined;
}
Expand Down
9 changes: 5 additions & 4 deletions ui/b/noticeboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,21 @@ b-noticeboard {
}`;

// == SCRIPT ==
const POPDOWN = Symbol.for ('b_noticeboard_POPDOWN');
class BNoticeboard extends LitComponent {
createRenderRoot() { return this; }
TIMEOUT = 15 * 1000; // time for note to last
FADING = 233; // fade in/out in milliseconds, see app.scss
connectedCallback()
connectedCallback()
{
super.connectedCallback();
}
create_note (text, timeout) {
const h53 = Util.hash53 (text);
const dupselector = ".note-board-note[data-hash53='" + h53 + "']";
for (const dup of this.querySelectorAll (dupselector))
if (dup && dup.__popdown) // deduplicate existing messages
dup.__popdown();
if (dup && dup[POPDOWN]) // deduplicate existing messages
dup[POPDOWN]();
// create note with FADEIN
const note = document.createElement ('div');
note.setAttribute ('data-hash53', '' + h53);
Expand Down Expand Up @@ -109,7 +110,7 @@ class BNoticeboard extends LitComponent {
note.parentNode.removeChild (note);
}, this.FADING + 1);
};
note.__popdown = popdown;
note[POPDOWN] = popdown;
close.onclick = popdown;
// show note with delay and throttling
const popup = () => {
Expand Down
1 change: 1 addition & 0 deletions ui/b/propinput.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class BPropInput extends LitComponent {
}
disconnectedCallback()
{
super.disconnectedCallback();
this.prop && this.prop.delnotify_ (this.request_update);
}
get classes() {
Expand Down
2 changes: 1 addition & 1 deletion ui/b/shell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ html.b-shell-during-drag .b-app {
<!-- browser -->
<v-flex class="b-shell-sidebar -row28 -col1" style="width:10em" >
Browser <br />
<b-treeselector :tree="m.filetree" v-show="Data.panel3 == 'b'" ></b-treeselector>
<b-treebrowser :tree="m.filetree" v-show="Data.panel3 == 'b'" ></b-treebrowser>
<span v-show="Data.panel3 == 'i'" ><a href="">Info Panel</a></span>
</v-flex>

Expand Down
1 change: 1 addition & 0 deletions ui/b/textinput.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class BTextInput extends LitComponent {
}
disconnectedCallback()
{
super.disconnectedCallback();
this.prop && this.prop.delnotify_ (this.request_update);
}
handle_input (event) // emit 'input' with constrained value
Expand Down
Loading

0 comments on commit e06849c

Please sign in to comment.