ApiChain and CssChain JS.
HTML template/slot and DOM manipulation library
Collection API inherits the element API and Array.
GitHub
| Demo: css-chain
| tests project
html elements methods
CssChain
searches HTML by css
and returns an Array inherited object which has
all methods and properties of its elements.
When method is called, each element would invoke this method and then same CssChain object is returned.
import $ from 'https://unpkg.com/css-chain@1/CssChain.js'
$( '*[title]', rootEL ).addEventListener( 'click', ev=> alert(ev.target.title) );
^^ adds event listener to all selected elements in rootEl
DOM tree
chained calls | HTMLElement API |
---|
| |
CssChain( 'a' )
.addEventListener( 'mouseover' , ev=> alert(ev.target.classList.add('hovered') ) )
.addEventListener( 'mouseleave', ev=> alert(ev.target.classList.remove('hovered') ) )
.on( 'focus' , ev=> alert(ev.target.classList.add('focused') ) )
.on( 'mouseleave', ev=> alert(ev.target.classList.remove('focused') ) )
^^ adds multiple event handlers in chainable dot notation.
Typescript
import CssChain from 'css-chain'
code has typings enabled by default. The chain type is a mixin of
HTMLElementMixin and array of this mixin. To add the type checking for custom element(s)
CssChain accept generics parameter and needs at least once initialisation by
3rd parameter as array of either custom element tags or classes.
import {CssChain as $ } from 'css-chain';
class DemoElement { b:string; setB(_b: string) { this.b = _b; } }
customElements.define('demo-element', DemoElement );
const $X = $<DemoElement>('demo-element', el, ['demo-element']);
expect($X.b).to.equal('initial');
$X.setB('1');
CssChain initialization
CssChain(css)
return mixin of HTMLElementMixin and arrayCssChain(css,from:Node|Node[]|CssChain)
css selector to be applied on node(s)CssChain(css,from, protoArr)
-||- with prototype(s) for members and methods of CssChain, needed to support methods
of web component
To avoid passing the prototype each time, it could be initialized in module global scope:
import {CssChain as $ } from 'css-chain';
$([],[],[DemoElement]);
special methods
forEach()
- same as Array.forEach
returns CssChainmap()
- same as Array.map
returns new CssChain with elements from callbackpush(...arr)
- same as Array.push
returns appended CssChainquerySelector(css)
- selects 1st element, returns CssChainquerySelectorAll(css)
- selects all children matching css
, returns CssChain$
- alias to querySelectorAll()
attr(name)
(alias for getAttribute
) returns 1st element attribute value or undefined
for empty collectionattr(name, val|cb(el,i,arr))
(alias for setAttribute
) sets elements attribute, returns CssChainattr(name, val|cb(el,i,arrCss,arrThis),css)
(alias for setAttribute
) sets css
-defined sub-tree elements attribute, returns CssChainprop(name)
returns 1st element property value or undefined
for empty collectionprop(name, val|cb(el,i,arr))
sets elements attribute, returns CssChainprop(name, val|cb(el,i,arrCss,arrThis), css)
sets css
-defined sub-tree elements attribute, returns CssChainparent()
- set of immediate parents of current collection, duplications removedparent(css)
- set of parents of current set which
matches
the selector, duplications removedon(eventName, cb)
- alias to addEventListenerremove(eventName, cb)
- alias to removeEventListenerremove()
- delete all nodes, returns empty CssChainerase()
- removes content of collection nodes, collection nodes remaintxt()
- returns text of whole collectiontxt( val | cb(el,i,arr))
- sets text for each element from val
or callbacktxt( val | cb(el,i,arrCss,arrThis), css )
sets text for children elements defined by css, returns original collectionhtml()
- returns concatenated innerHTML of collectionhtml( cb(el,i,arr) )
- sets innerHTML of each collection elementhtml(htmlText)
- sets innerHTML of each collection elementhtml(strArr|NodeList)
- array duplicated within each collection elementhtml( val, css )
sets html for children elements defined by css. val
type is one of above. Returns original collectioncloneNode(deep)
- returns collection of cloned elements of current one by Node.cloneNode(deep)clone()
- clone nodes(deep) or objects(shallow). Returns cloned collectionclone(doc)
- clone nodes to be inserted into document using Document.importNode()clone( count, cb( clonedNode, index ) )
when callback result is a string or node it is used as return valueclone( arr )
alias of clone(arr.length)
clone( arr, cb( clonedNode, dataItem, index, arr ) )
call callback after cloneappend( html )
,append( html[] )
, append( node[] )
append HTML text or nodes
Light DOM
Shadow DOM and its twin Light DOM
allows
to use template and work with dynamic content withing template.
Both often represent the content of web component
as convenient way to generate DOM subtree by JavaScript.
In the light DOM
as opposite to Shadow DOM
the render root is part of usual DOM without engaging the shadowRoot.
There the template clone would take a render root DOM subtree payload as the source for its slot
assignment.
Once slots are populated into this clone, it would replace the render root content.
Of course such benefits of shadow DOM as template reuse and CSS encapsulation are lost in light DOM. But the modular
development with templates, HTML5 standard dynamic content use convention and API are still around.
global CSS
is available for styling the light DOM components, which could be advantage in some environments where css encapsulation
of shadow DOM in web components prevents usual css styling.
Light DOM API
template()
would render the current node as a template with immediate children with slot='xxx'
as assignedNodes payload for <slot name='xxx'>
. There is no default slot in such case as the inner DOM serves the
default content.template(css)
, typically template('template')
would extract the template defined by selector,
clone it with assigned slots from remaining childrentemplate(node)
the children are used as slot content within node clone which is set as a child
slots
<slot name='xxx'></slot>
is an HTML tag, a marker where dynamic content would be placed.
It works with shadow and light DOM in same manner.
When used with template()
or by shadow DOM, dynamic content is taken from DOM subtree marked by slot='xxx'
attribute.
Otherwise slot
content could be manipulated by JS API:
slots()
- returns all slotsslots('')
- returns slot without nameslots(',name1,name2...')
- returns named slots. Blank name defines unnamed(default) slotslots(name, val | cb(el,i,arr) )
assigns slot content, alias to HTMLSlotElement.assign(nodes)
when cb
is defined slots content is set by html(cb)
slots().innerText
,slots().innerHTML
, slots().txt()
, slots().html()
sets slotted content
html elements properties
When property is assigned to collection, this property would be set for all elements in collection.
The property get would return property from 1st element.
import { CssChain as $ } from '../src/CssChain.js';
$( 'input' ).value = 'not defined';
v = $( 'input' ).prop( value,'not defined' );
let v = $( 'input' ).value;
v = $( 'input' ).prop( value );
Array of raw objects
$([ {a:1},{a:2} ]).a=1;
v = $([ {a:1},{a:2} ]).a;
$( [ { a:1,f(v){ this.a=v} }, { b:2,f(v){ this.b=v}} ])
.f(3);
Array of class objects
Could be initiated in same fashion as raw objects.
But for performance better to provide the reference object as a second parameter:
class A{ f(){} }
const x = new A(), y = new A();
$( [x,y], A ).f()
cssChain - initiated by css selector from HTMLElement API
Registered interfaces are taken from window object by window.HTML*Element
pattern.
To use API from custom elements, add those in array of last
Api selected either from elements in collection or from window.HTML*Element
.
import {CssChain as $} from 'api-chain/CssChain.js';
$('input').value='';
$('input').forEach( (el,i) => el.value=i )
$('[type="checkbox"]')
.prop( 'checked', false )
.addEventListener('click' ,function(){ })
.addEventListener('change',function(){ this.checked; })
.on( 'hover', ()=>showTooltip() )
const firstFormUrl = $('form').action;
const firstLinkUrl = $('a').href;
$('a').prop('href');
$('a').attr('href');
optimization
API simulation is expensive when done on each occasion. Pre-generated API wrappers could be added on app load time. CssChain on module load applied the whole set of window.HTML*Element
.
In the call of ApiChain the last parameter is an array of prototype objects. The classes listed in this array would be stored in global map and generated API would be reused next time same class is listed within last parameter.
class A{ f1(){} } class B{ f2(){} }
const a = new A, b = new A;
ApiChain( [a,b] ).f1().f2()
ApiChain( [], [A,B] )
ApiChain( [a,b] ).f1().f2()
Samples of use
PokéAPI Explorer: