diff --git a/luci-app-passwall/root/usr/share/passwall/tasks.sh b/luci-app-passwall/root/usr/share/passwall/tasks.sh index 3f237364..5a633c49 100755 --- a/luci-app-passwall/root/usr/share/passwall/tasks.sh +++ b/luci-app-passwall/root/usr/share/passwall/tasks.sh @@ -8,10 +8,7 @@ LOCK_FILE=${LOCK_PATH}/${CONFIG}_tasks.lock CFG_UPDATE_INT=0 exec 99>"$LOCK_FILE" -flock -n 99 -if [ "$?" != 0 ]; then - exit 0 -fi +flock -n 99 || exit 0 while true do @@ -23,7 +20,7 @@ do restart_interval_mode=$(expr "$restart_interval_mode" \* 60) if [ -n "$restart_week_mode" ]; then [ "$restart_week_mode" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$restart_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG restart cron > /dev/null 2>&1 & } + [ "$(expr "$CFG_UPDATE_INT" % "$restart_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG restart cron > /dev/null 2>&1 99>&- & } } fi @@ -32,7 +29,7 @@ do rules_update_interval_mode=$(expr "$rules_update_interval_mode" \* 60) if [ -n "$rules_update_week_mode" ]; then [ "$rules_update_week_mode" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$rules_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & } + [ "$(expr "$CFG_UPDATE_INT" % "$rules_update_interval_mode")" -eq 0 ] && { lua "$APP_PATH/rule_update.lua" log all cron > /dev/null 2>&1 99>&- & } } fi @@ -53,9 +50,9 @@ do sub_update_week_mode=${name%_*} sub_update_interval_mode=${name#*_} sub_update_interval_mode=$(expr "$sub_update_interval_mode" \* 60) - cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') + cfgids=$(tr '\n' ',' < "${TMP_SUB_PATH}/${name}" | sed 's/,$//') [ "$sub_update_week_mode" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$sub_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & } + [ "$(expr "$CFG_UPDATE_INT" % "$sub_update_interval_mode")" -eq 0 ] && { lua "$APP_PATH/subscribe.lua" start "$cfgids" cron > /dev/null 2>&1 99>&- & } } done rm -rf $TMP_SUB_PATH @@ -65,6 +62,6 @@ do CFG_UPDATE_INT=$(expr "$CFG_UPDATE_INT" + 10) - sleep 600 + sleep 600 99>&- done 2>/dev/null diff --git a/luci-theme-footstrap/htdocs/luci-static/resources/fs-select.js b/luci-theme-footstrap/htdocs/luci-static/resources/fs-select.js index b6130c3b..0753b0ba 100644 --- a/luci-theme-footstrap/htdocs/luci-static/resources/fs-select.js +++ b/luci-theme-footstrap/htdocs/luci-static/resources/fs-select.js @@ -312,9 +312,22 @@ function applyDecision(t, d) { if (d.breakCol !== -1) markBreakColumn(t, t.querySelectorAll('.tr'), d.breakCol); } +/* A first cell with no break opportunity (no space, no hyphen: "/dev/mtdblock6") is marked so a carded half-cell can + * widen to it: CSS cannot tell a token from a phrase, and `anywhere` cut it mid-word at 94-106px. + * textContent reads no layout; the class is a function of the text, so a poll's identical copy gets + * the same answer, and an unchanged mark is not rewritten (no mutation for the observers). */ +function markTokenCells(t) { + t.querySelectorAll('.tr > .td:first-child').forEach((c) => { + const txt = c.textContent.trim(); + const on = !!txt && !(/[\s\u002d\u00ad\u2010-\u2014]/).test(txt); + if (c.classList.contains('fs-td-token') !== on) c.classList.toggle('fs-td-token', on); + }); +} + function fitTables() { let cw; document.querySelectorAll(stackables()).forEach((t) => { + markTokenCells(t); if (fit.scrolling() && t.classList.contains('fs-fitted')) { if (t._fsBreakCol >= 0) markBreakColumn(t, t.querySelectorAll('.tr'), t._fsBreakCol); return; @@ -560,6 +573,8 @@ function wireTypeahead() { return baseclass.extend({ /* test-only: the slot-cache key, driven directly */ shapeOf, /* fs:probe */ + /* test-only: the token-cell predicate */ + markTokenCells, /* fs:probe */ __init__() { wireTypeahead(); diff --git a/luci-theme-footstrap/styles/theme/30-tables.css b/luci-theme-footstrap/styles/theme/30-tables.css index 79bc12d6..34fb6ed0 100644 --- a/luci-theme-footstrap/styles/theme/30-tables.css +++ b/luci-theme-footstrap/styles/theme/30-tables.css @@ -374,6 +374,10 @@ .table.fs-stacked .td:not(.cbi-section-actions):not([class*="col-"]):not(:has(.cbi-progressbar)) { flex: 1 1 50% !important; } + /* a first cell that is one token (fs-select.js): "/dev/mtdblock6" is 110px, the half-split left + * 94-106px at 360-390 and `anywhere` cut it mid-word. fit-content of one token is the token, + * capped at the row, so a 64-char hash still breaks inside the card; a phrase keeps its half. */ + .table.fs-stacked .tr > .td.fs-td-token:first-child:not(.cbi-section-actions):not([class*="col-"]) { min-width: fit-content; } /* a meter takes the whole line — its own title prints over the cell's caption otherwise */ .table.fs-stacked .td:has(.cbi-progressbar) { flex: 1 1 100% !important; }