Repository navigation
v5.10.0
The wf init starters, rewritten to work on first use, and the compiler
and runtime bugs that clicking through them turned up; what an editor
built on the compiler asks of it — icons, events, a member's ///, a
build of one route, a faster check; and a pre-render, a test and a PDF
that draw what the live page draws.
Additions
-
Starters that work on first use (chapter 38).
wf init spahasDayandNightthemes with a switch that calls
setTheme, a task list that adds a task on Enter through aFormand
asks in aModalbefore deleting one, a Settings page with validated
fields, andtests/app.wfandtests/tasks.wf.wf init statichas a
validated contact form with a required agreementCheckbox, English and
Arabic translations, andtests/site.wf.wf testpasses in a new
project. -
A test can place a whole page (chapter 24)
by its name, as it places a component (Tasks, thenclick "Add"),
with its state, stores and handlers running. This works for a page with
no route parameter whose name no component also has. In a test that
acts,press "Enter"in a form's text field submits the form, and
click "Name"also finds, by its name, an element whose role is a link,
a tab, a menu item (aMenu.Item), an option, a tree item, a switch, a
checkbox or a radio (chapter 24). -
on blurandon focuson a page (chapter 9).
A page, a component orapphears the window lose and gain focus for as
long as it shows, for example to save when the window is left. Both
listen on the window;on keydownandon keyupstill listen on the
document. -
on auxclick,on focusinandon focusouton any element
(chapter 37).
on auxclick(e)hears a click with a button other than the main one
(e.button == 1is the middle button, to close a tab);on focusinand
on focusouthear focus move onto or off the element or anything inside
it. -
23 icons for editors and tools (chapter 28),
55 in all:folder,folder-plus,file,refresh,alert-circle,
clock,dot,diff,book,git-branch,git-pull-request,pin,
more-horizontal,window-minimize,window-maximize,outline,
help-circle,collapse-all,chevron-up,globe,external-link,
panel-downandpanel-up. They go wherever an icon name does and are
drawn incurrentColor. -
Menu.Item.danger(chapter 9),
ordanger: true, draws an item that cannot be undone, such as Delete
or Discard, in the danger colour. -
A
Tooltip'sshortcut:reaches its control
(chapter 9):
Tooltip("Save", shortcut: "mod+s") { Button("Save") }also gives the
buttonaria-keyshortcutsin ARIA's spelling (Control+S, or
Meta+Son Apple's systems), unless it has one. -
A member's
///is its documentation (chapter 5).
A///comment above astate,persist,derivedoractionin a
page, a component or a store stays with it, in.wfand.wfxalike;
the parser used to drop it. A///above anything else in a body is
still dropped. -
Portal(chapter 32).
Portal(into: node) { … }draws its block into a node somebody else's
code made: an editor's tooltip, a map's popup, a chart's legend. The
library keeps the node's place, its keys and its focus; the page keeps
what is in it.into:takes an element, aref:handle or null; named
another node the block moves there with its state, and null keeps it
aside. Its handlers,emitand lifetimes belong to where it is written.
Portalis now a built-in's name, so a project's own component or store
of that name is reported. -
Markdown(text).inert(chapter 37),
for text somebody else wrote, such as a language server's documentation:
entities are decoded and shown as text, a link is its words and a
picture is left out.
For tools
Each is for a tool built on the compiler
(chapter 38); paths
are under webfluent::.
- A build of one route.
BuildOptions::only_route(Some("/posts/hello"))
renders the page answering that route, for a preview that cannot wait
for a whole build. With aBuildCache, a page the cache holds for its
current inputs, in memory or on disk, is reused (pages_reused); any
other page this session has painted is written as it was last painted
and counted in the newBuildReport::pages_deferred; a page never
painted is rendered. The next build without the option renders what was
deferred, and its output equals a build from nothing. Without a cache it
builds everything, and what was last painted is kept only in memory, so
aBuildCache::on_diskreopened in a new session defers nothing. - A member's documentation in the tree.
StateDecl,DerivedDecl
andActionDeclcarrydoc: Option<String>, the///lines joined with
\n;Statement::doc()andStatement::set_doc()read and set it, for
a completion or a hover to show.print::statementwrites a documented
member under its///, so a store whose members are documented prints
back as itself.reprintandedit::rewrite_declarationreplace, remove
and insert a member together with its///: a member taken out left its
doc to document the next one, and one put in at the front went between
the first member and its doc.print::written_start(source, &statement)
is public: where a statement is written from, its///when it has one. - A code's guide entry.
diagnostics::codes::guide_section(code)
returns a diagnostic code's section of the Diagnostics chapter as
Markdown, without its heading (whatwf explainprints after the
summary, before setting it for a terminal), orNone. The code is
matched as given:T06, nott06. - A test's steps outside Chrome.
testing::step_script(what, name, value)returns the JavaScript expression aclick,typeorpress
step evaluates in the page, which answers"ok","none"or
"no-option", so an editor's own window can find controls aswf test
does. - A rendered test in its locale.
testing::render_testtakes the
locale as a fourth argument (Tests::locale()is the project's default,
oren), andtemplate::render_program_fragment_in(program, data, messages, locale)renders with that locale's plural rules. - The framing decision.
codegen::csp::frames_itself(&program),
config::project::frame_options(&config)("DENY"or"SAMEORIGIN")
and theBuildConfig::frames_itselfflag, which the build fills in, so
a server an editor runs for its preview can send whatwf servesends. - A starter's files.
init::Template::files()lists a starter's own
files, as (path, text) pairs with the project's name still{{name}};
init::createwrites them, and.gitignore,AGENTS.mdandpublic/
beside them. - The registry (chapter 38):
wf registry --jsonlists the new icons,auxclick,focusinand
focusoutamong every element's events, anddangeronMenu.Item. - Paged layout.
paged::style::Length::Mix(points, percent)holds a
calc()of both (calc(50% - 12px)isMix(-9.0, 50.0));Stylegains
has_mix()andsettle_mix(w, h, main);codegen::builtin::span_class
writes aColumn's span class. check_project_viaruns its phases on scoped threads, and calls a
Project'sfile_ofandsource_ofup front, on the calling thread.
The findings and their order are unchanged.
Fixes
-
A handler reads
keyandvalue(chapter 9).
on keydown { if key == "Enter" { … } }passed the check and threw
ReferenceError: key is not definedon the first key press, which broke
Enter in the SPA starter. A handler that readskeynow gets
event?.key, and one that readsvaluegetsevent?.target?.value, on
every kind of handler; a state, a loop item or a parameter of that name
is left alone. -
A layer that starts open no longer stops the page drawing
(chapter 9).
AModal,Dialog,Popoveror state-openedMenuwhosevisible:
wastruefrom the start asked to open before it was in the document,
and threw; each now opens once it is there. A layer anchored to an
element stayed clamped to the window's edge once the element scrolled
away; it now hides with it (data-anchor-hidden), stays open and shows
again when the element comes back. The Escape that closes an open
ModalorDialogno longer reaches the page behind it. -
Menus and tooltips (chapter 9).
Menu(label:)is the list's accessible name; the button's words come
fromtrigger:(aDropdown's still fromlabel:), so a menu that
visible:opens no longer draws a stray button. Each menu and each
tooltip drawn gets its own id at run time (WF.uid), where every copy a
foror a component drew shared one, soaria-controlsand
aria-describedbycould name another copy's. A menu keeps itsclass:
and itsstyle { }class as it opens and closes. -
Forms ask their rules (chapter 16).
AFormwith nobind:in a page or component withvalidaterules
ranon submitanyway; it now stops on a failing rule and shows the
messages. Each page and each copy of a component has its own form
handles: a page's carried into the next page compiled, and every copy of
a component shared one form. A validatedCheckboxorSwitchshows
its message beneath it, announced and tied to the control
(aria-describedby,aria-invalid). A field's character count follows
a value the program sets, such as a reset. -
Controls given a value work (chapter 16).
Switch(checked: value)withoutbind:drew no input; it now follows
the value, and itson changehears the click. ASwitch'son change
was never attached. A boundCheckboxorRadiowith its own
on changelost the binding's write; the binding now writes first and
the handler runs after it. -
Text that reads state follows it (chapter 21).
Each of these was worked out once, when the page was drawn: the labels
ofCheckbox,Radio,Switch,Slider,DatePickerand
FileUpload; aTable'scaption:;Tabs.Pagetitles;Tooltip
text; aModal's orDialog'stitle:; aMenu'strigger:and a
Dropdown'slabel:; anAvatar'ssrc:,alt:andinitials:; a
Skeleton'swidth:,height:andsize:; and anIcon's positional
name (Icon(if done { "check" } else { "clock" })). So
Checkbox(label: t("…"))now changes language withsetLocale. Fixed
text compiles as before. -
Stores (chapter 12). A
store outlives the page that reads it first: its derived values and
effects belonged to that page's scope and stopped when the reader moved
on. Aderivedthat reads one written below it in the same store
follows it, where it kept its first value. The built script declares
each store after the stores ituses, so a read made while the script
starts never meets a store not declared yet. -
The pre-render paints what the live page draws
(chapter 26).
ACheckbox,RadioorSwitchis its<label>and<input>, ticked
and disabled as its state starts, where only the labels' words showed.
AMenuorDropdownis its button and a hidden list, where its
entries lay in the page, and a menu that state opens is its list alone.
A part written with flags carries their
classes (Menu.Item.danger), andColumn(span: 8)itswf-col--8,
where every column was painted the same width.disabled,required
andcontrolsare written only whentrue, here and in the template
engine, soButton("Go", disabled: false)is not a dead button.
.pop()and.shift()are evaluated on a list the build knows. -
A test that looks reads the page as a reader does
(chapter 24). The template
engine draws aMenuorDropdownas its button and hidden list,
keyLabel("mod+shift+p")as the build writes it (Ctrl+Shift+P), and
at()with a count in the default locale's CLDR form.expectdecodes
every numeric entity and the common named ones, soexpect "It isn't"
matches. In a test that acts,expecttreats any run of white space as
one space, as a test that looks already did. -
Column spans leave room for the gap (chapter 37).
span: 8andspan: 4in aRowwith a gap came to 100% plus the gap,
and the second always wrapped; each span now gives up its share of the
gap, a gap or a span given per breakpoint too. A PDF lays a
Columnout at itsspan:, where every column came out equal, and the
PDF engine'scalc()is a real parser: no spaces needed, nested
parentheses, unary minus, functions inside, and a sum of a percentage
and points resolved against the box it lands in
(chapter 34). -
The
Navbarfollows the theme (chapter 37).
Its background was a fixed translucent white; it is now the theme's
surface, and its text the theme's text colour. -
setLocaleis remembered (chapter 21)
across page loads, inlocalStorageunderwf:locale, so a static site
keeps the reader's language from page to page. A?lang=address still
wins, without changing the saved choice. -
A site may frame its own pages (chapter 23).
AFramewhosesrc:is site-relative ("/preview/","/embed/{id}")
was refused by the site's own headers. A project that places one is
servedX-Frame-Options: SAMEORIGINbywf serve, and its_headers
says the same withframe-ancestors 'self'; every other project keeps
DENYand'none'. -
An
Avatar'ssrc:is checked like any othersrc:
(chapter 23): a
run-time value goes throughWF.safeUrl. -
Long keyed lists no longer stall as they grow
(chapter 20). A keyedforread the place
of every item it kept before each change, so a 960-line log appended
line by line froze the page for 3.5 s. Only items whose index changes
are measured now; a list that only grows at its end measures nothing. -
A
Splittermoves from where it is drawn
(chapter 9).
A drag or an arrow key starts from the region's drawn size, not the
bound value, and a reset writesreset:as given, soreset: 0can
mean the region's default share. -
() => …takes no arguments (chapter 14).
It was typed as taking one, so it could fail to fit a script parameter
whose JSDoc says() => boolean. -
webfluenton Windows (chapter 2).
A barewfrunsWF.msc, the Windows Firewall console, which comes
first onPATH. The.msi, the release zip andinstall.ps1now also
install the binary aswebfluent.exe, sowebfluent buildworks;
wf.exedoes too. The.msinow keeps oneUpgradeCode, where each
release had its own, so the next one replaces it instead of installing
beside it. The Node binding looks forwebfluent.exeandwf.exeby
their full names (chapter 35). -
The check does less (chapter 38).
Theenvlint lexes only a file whose text could nameenv.…, and the
output checks work out what a build can evaluate only once they find a
Chartor aQrCode: on Halyard the check went from 28 ms to 18 ms.
Its phases also run side by side, which helps most on a busy machine. -
A build into another folder reuses the cache
(chapter 38). The cache's key held the
output folder, so two builds of one project into different folders, as
an editor's previews are, never shared a page. -
Markdown links are checked, and backslash escapes work
(chapter 27). Every link and
picture inMarkdowngoes through the scheme check the rest of a page
does, so[x](javascript:…)is drawn as its words. A backslash before
punctuation draws that character (\*is*, not emphasis), as
CommonMark has it, and the build and the browser draw Markdown alike,
line breaks and white space included. -
Escape goes to the newest layer that can take it
(chapter 9).
A tooltip under the pointer no longer takes Escape from the page (an
editor's completion list behind a toolbar button lost it); it hides and
lets the key go on. An openModalorDialogis the newest layer, so
its Escape comes before a popover's beneath it, and a press inside it no
longer closes that popover.on closeon a modal is its event, with no
V09. -
Every built-in takes what any element takes
(chapter 37).role:,
tabindex:,aria-*,data-*andonhandlers reached aPopover,
Menu,Tooltip,Modal,VirtualList,Splitter,Tabs,
Sidebar,Sliderand the rest only in part, or not at all; each now
writes them on its element, in the live page, the pre-render and the
template engine alike, asC04says.disabled: truedisables a
Slider,DatePickerorFileUpload. Anhtml:written on an element
is an attribute, never markup. -
A long list drawn before its box is laid out
(chapter 37) paints the
right rows in its first frame, the rowreveal:names among them, where
it drew about forty and trimmed them a frame later. -
A pre-rendered modal has its title as its heading, as the live page
draws it, not as atitle=tooltip; anIconButton's owntitle:wins
over its label on every page. -
A test reads a page as a reader does
(chapter 24).expectreads
a plain render as a browser lays it out: elements that touch read as
touching, where the render's line breaks put a space between them. A
test run in a browser loads the project's own stylesheets and serves
public/beside the page, as the built page does. -
A record with all its fields defaulted is
Offers()
(chapter 12), wherever an
expression goes, a prop's default among them; a left-out field of a
default record is filled in, in the pre-render too. -
data-x: trueisdata-x="true"on every page, given to an element
or passed through a component's call, and a call'sdata-*,aria-*,
id:andclass:reach the component's root in the template engine. -
A local is its own (chapter 12). A
let, a parameter or a loop's name in a store's action that shares a
member's name was compiled to the member, so writing it wrote the store;
in a page or a component, one that shared a prop's name read the prop.
Upgrading
See chapter 46: Markdown's backslash
escapes and checked links, attributes that built-ins now write, a modal's
Escape and painted title, column spans that leave room for the gap, a Menu's label: that no longer names its button, a
form without bind: that asks its rules, a bound box whose on change
wrote the value itself, and pre-rendered HTML and test snapshots that now
match the live page are what a project may notice. On Windows, type
webfluent and uninstall an older MSI. Run wf check.
Full Changelog: v5.9.0...v5.10.0