Skip to content

FYI, my quick and dirty implementation (non-critical usage, so largely untested at this stage) #1

@danielweck

Description

@danielweck

Like Tiny-CFI, this also only supports DOM elements, but with ID assertions (yeah!) :)

(internally I use a custom DOM-Range JSON serialization format, so I have not relied on CFI much, other than for informational purposes ... but CFI can indeed be a useful interoperable "standard" in some cases, so I would love to see a complete mini-footprint robust implementation that includes support for character ranges ;)

export function generateCfiSteps(target) {
    if (!target || target.nodeType !== this.window.Node.ELEMENT_NODE) {
        return undefined;
    }

    let cfi = "";

    let currentElement = target;
    while (currentElement.parentNode && currentElement.parentNode.nodeType === Node.ELEMENT_NODE) {
        const children = currentElement.parentNode.children;

        for (let i = 0; i < children.length; i++) {
            if (currentElement === children[i]) {
                cfi = ((i + 1) * 2) +
                    (currentElement.id ? ("[" + currentElement.id + "]") : "") +
                    (cfi.length ? ("/" + cfi) : "");

                break;
            }
        }

        currentElement = currentElement.parentNode;
    }

    return "/" + cfi;
}

tiny-cfi:

tiny-cfi/tinycfi.js

Lines 1 to 41 in e9fc323

function isWhitespaceNode(node) {
return !/[^\t\n\r ]/.test(node.textContent);
}
export function generateCfiSteps(target, root = this.window.document.documentElement) {
const window = this.window;
const treeWalker = window.document.createTreeWalker(
root,
window.NodeFilter.SHOW_ELEMENT + window.NodeFilter.SHOW_TEXT,
{
acceptNode: function (node) {
if (node.nodeType === window.Node.TEXT_NODE && isWhitespaceNode(node)) {
return window.NodeFilter.FILTER_REJECT;
}
return window.NodeFilter.FILTER_ACCEPT;
}
},
false
);
let currentNode;
if (target.nodeType === window.Node.TEXT_NODE) {
currentNode = target.parentNode;
} else {
currentNode = target;
}
treeWalker.currentNode = currentNode;
const path = [];
do {
let index = 1;
while (treeWalker.previousSibling()) {
index = index + 1;
}
path.push(index * 2);
currentNode = treeWalker.parentNode();
} while (currentNode && currentNode !== root);
return `/${path.reverse().join('/')}`;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions