choc.__version__
is a string consisting of three parts, major/minor/revision,
such as "1.6.4"
. See What's New for details on what changed in
each version.
element = choc("TAG", attributes, contents);
- The tag should be a string, either with no colon (case insensitive, HTML tag),
or of the form "namespace:tagname" for XML tags. Namespace aliases can be used
(see
xmlns_xlat
below), or include the full namespace URI. attributes
- optional object mapping attribute names to their desired values. If omitted/null/empty, no attributes will be set.- Attributes will be set using
element.setAttribute
or by direct assignment where this is more suitable. - Force an attribute to be set by assignment by prefixing its name with a dot
eg
{".foo": 42}
to setelement.foo = 42
- Force the use of setAttribute (not usually necessary) by prefixing the name
with an at sign eg
{"@onclick": "hello?"}
- Attributes set by assignment are any that begin "on" (event handlers), plus
the following:
volume
,value
,disabled
,checked
. - For convenience,
htmlFor
andfor
have the same effect, as doclass
andclassName
.
- Attributes will be set using
contents
- optional collection of children. Seeset_content
below. Callingchoc("TAG", attr, contents)
is broadly equivalent to callingset_content(choc("TAG", attr), contents)
(but see 'Special Cases' below).
In additional to the above syntax, this notation is also supported:
element = choc.TAG(attributes, contents);
A destructuring import makes this more convenient:
const {TAG} = choc;
element = TAG(attributes, contents);
This is the recommended idiom, and can be managed by use of the chocimport script.
element = DOM(selector);
- If precisely one element matches this selector, it is returned.
- If nothing matches, returns
undefined
. - If multiple elements match, throws an error.
Note that this is very similar - but not identical - to both document.querySelector
and jQuery's selection. Their behaviours differ when zero or multiple elements match:
document.querySelector
will return the first match, ignoring any others.- jQuery will always return a collection and then apply changes to them all. This is not an error if no elements match, and changes will be applied to no elements.
element = set_content(elem_or_sel, contents);
elem_or_sel
is either a DOM element or a selector. Passing a selector is equivalent to callingelement = set_content(DOM(sel), contents);
but will throw if there is no such element.contents
may be any of the following:- Any falsy value (
null
,undefined
,""
, or0
) - no content at all - Any string or (non-zero) number - the given text. This does not support HTML and is thus safe against injection attacks.
- A
Node
(including an Element as constructed bychoc()
) - moves the node from its current location in the document (if any) into here - An array of zero or more valid types of content
- Note that nested arrays are valid, but arrays containing themselves are not, and will get your page stuck in an infinite loop :)
- Any falsy value (
idx = on(event, selector, callback, options);
event
- name of an event such as"click"
or"paste"
selector
- CSS selector to identify matching elements. The elements do not have to exist at the time the event handler is established.callback
- JavaScript function to call when the event occurs.options
- normally omit this, but if additional options are needed, they can be provided. Not compatible with multiple uses of the same event handler.
The event will be attached to the document. Elements rendered in the document are capable of triggering these events.
Inside the callback, the event object is exactly the one given by the browser, with one additional attribute:
match
- the element which matched the selector
For example, on("click", ".thing", e => set_content(e.match, "Hi!"));
will change the contents of the element clicked on, regardless of the
presence of other elements with the same selector.
This is similar to e.currentTarget
but due to technical limitations,
currentTarget
will always be document
during these event handlers.
NOTE: Asynchronous event handlers are fully supported; however, as
the event object is not reconstructed for each handler, the match
attribute is only available during the initial, synchronous, part of the
function. For example:
on("click", "button", async e => {
console.log(e.match); //Works
const self = e.match;
await something();
console.log(e.match); //Is now null
console.log(self); //This will work though
});
//the same is true for other forms of asynchronicity:
on("click", "button", e => {
console.log(e.match); //Works
setTimeout(() => {
console.log(e.match); //Is now null
}, 1000);
});
apply_fixes({
close_selector: selector,
click_outside: false | true | "formless",
});
Improves support for the <dialog>
element in browsers that lack it, such as
older versions of Firefox. Regardless of the options provided, this will add
the showModal
and close
methods to all dialog elements, with a basic level
of functionality. Additional features can be selected, all are optional:
close_selector
- a CSS selector for clickable elements which should cause a dialog to be immediately closed. For example, set a CSS class on all your close buttons, and quickly and easily close the correct dialog with one event handler.click_outside
- if true, clicking outside any dialog (on the shaded background where it's blocking access to the rest of the document) will close the dialog. If the string"formless"
, this applies only when the dialog doesn't contain aform
element.methods
- if true, will add methods to all DOM elements. Use value of 1, as future expansion may give different meaning to higher numbers. See below for methods added.
Note that this function can be imported and called under the name fix_dialogs
for compatibility with older versions of the Chocolate Factory.
apply_fixes({methods: 1})
will add the following method to all DOM elements:
elem.closest_data("foo")
is approximately equivalent toelem.closest("[data-foo]").dataset.foo
but will returnnull
if no parent element has this data attribute.
template = lindt("TAG", attributes, contents);
Analogous to choc() but for templated usage.
- Like choc(), can be called with attributes and/or contents omitted.
- Like choc(), can be called as
lindt.TAG(attributes, contents)
and is thus suitable for destructuring imports. - Unlike choc(), contents will not be immediately applied to the element, but are retained as part of the template.
- Unlike choc(), does not return an actual DOM element. The resulting template can only be used with replace_content.
lindt
recognizes a special attributekey
which can guide the template matching (see below), and can construct pseudo-element groupings with no tag such aslindt({key: "some_key"}, contents)
. These are equivalent to arrays but have keys associated with them.
The lindt
function is useful only in conjunction with replace_content
.
element = replace_content(elem_or_sel, template);
Analogous to set_content() but for templated usage.
elem_or_sel
is either a DOM element or a selector. Passing a selector is equivalent to callingelement = replace_content(DOM(sel), template);
. Passingnull
will coalesce the template into an actual DOM element and return it, allowing it to be used in other ways. Note that this requires a non-array template.template
may be any of the following:- Any falsy value (
null
,undefined
,""
, or0
) - no content at all - Any string or (non-zero) number - the given text. This does not support HTML and is thus safe against injection attacks.
- A
Node
(including an Element as constructed bychoc()
) - moves the node from its current location in the document (if any) into here - A template created by
lindt()
- An array of zero or more valid types of content
- Note that nested arrays are valid, but arrays containing themselves are not, and will get your page stuck in an infinite loop :)
- Any falsy value (
When using templates, replace_content
will attempt to reuse DOM elements
as much as possible. Repeatedly calling replace_content
on the same element
with similar templates will apply only those changes, keeping other elements
unchanged.
Recommended best practice:
- Aim to match existing elements where appropriate. If matching fails, the old element will be discarded and a new one created.
- Be consistent. Arrays can be used anywhere, but an array will never match a non-array.
- If elements might be reordered, consider giving each one a unique key. This is optional, but if keys are given, they will be used for matching.
- Avoid having multiple arrays next to each other, unless they will ALWAYS be present. For optional arrays, use pseudo-elements instead - construct a lindt template with no tag, which will behave like an array of elements but can be given a key.
(New in 1.7.0)
xmlns_xlat.math = "http://www.w3.org/1998/Math/MathML";
This mapping of aliases to URIs may be externally mutated to create new aliases
as needed. It comes prepopulated with the alias svg
for http://www.w3.org/2000/svg.
The five primary functions choc
, set_content
, on
, DOM
, and fix_dialogs
are made available on the window object as pseudo-globals, for the convenience
of non-module code (where an import
statement is not available). These may
therefore also be used from the browser console.
Though Chocolate Factory tries its best to be generic and handle everything the same way, there are occasionally quirks that are best handled in their own way.
- Normally an element is constructed, then given its attributes, then given its
children. (This parallels the order of parameters.) However, constructing a
SELECT element with a
value
attribute will reapply the value after adding the children, since valid values for a drop-down list are defined by its children. - TODO: Look for any others that need to be documented. There aren't many.