Skip to content

Proposal: Use traversal '->' instead of 'in' for mkq func #3

Description

@figuerom16

This is probably beyond the scope in terms of complexity for moxi, but it won't hurt to demonstrate the idea.

Right now for q() in allows for scoping on a selector, but not a relative selector. ex. q('last .row in closest table') would fail since mkq doesn't handle closest table. This also forces the user to read from right to left.
If we drop in and this we could do: q('closest table -> last .row').
Better yet we can continue the traversal q('closest table -> last .row -> last td').
Or say for a form q('next form -> input').arr().forEach(el=>el.toggleAttribute('disabled')).
It would also mean dropping the one() helper function.

Here is what mkqf (mkq helper function selector) looks like:

mkqf={
	closest:(s,c,t)=>(c||t).closest(s),
	first:(s,c,_)=>(c||doc).querySelector(s),
	last:(s,c,_)=>[...(c||doc).querySelectorAll(s)].at(-1),
	next:(s,c,t)=>[...doc.querySelectorAll(s)].find(el=>(c||t).compareDocumentPosition(el) & 4),
	prev:(s,c,t)=>[...doc.querySelectorAll(s)].findLast(el=>(c||t).compareDocumentPosition(el) & 2),
	split:cmd=>cmd.split(/\s*->\s*/).filter(Boolean),
	run:(cmd,c,t)=>{
		const [,fn,s] = cmd.match(/^(closest|first|last|next|prev)\s+(.+)$/)||[]
		return [fn,fn ? mkqf[fn](s,c,t) : (c||doc).querySelector(cmd)]
	}
},

Changed mkq:

mkq = ctx=>sel=>{
	if (typeof sel != "string") return proxy(sel.nodeType ? [sel] : [...sel])
	const cmds = mkqf.split(sel)
	let i = 0
	for (const cmd of cmds) {
		const [fn, res] = mkqf.run(cmd, ++i > 1 ? ctx : undefined, ctx)
		if (i == cmds.length) return proxy(fn ? (res ? [res] : []) : [...(i > 1 ? ctx : doc).querySelectorAll(cmd)])
		if (!(ctx = res)) break
	}
	return proxy([])
},

If mkqf is exposed as qf to the document fixi could use the moxi function for its relative selectors:

document.addEventListener("fx:config", e => {//Moxi Relative Selectors
	let c, t = e.target
	for (const cmd of qf.split(t.getAttribute("fx-target")||"")) {
		if (!(e.detail.cfg.target = c = qf.run(cmd, c, t)[1])) break
	}
})

Traversal is a nice convenience for users, but entirely optional as it's easy to fork and change the code for ourselves.
Here's my modded implementation of Moxi + Fixi that's using the new method: https://github.com/figuerom16/fixi/blob/master/mofix.js

Feel free to close the issue if it's out of scope/undesired. Thank you for making the project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions