Files
harbour-quill/qml/components/PropfindParser.js
T

79 lines
2.5 KiB
JavaScript

// Parse a WebDAV multistatus (PROPFIND) response into flat entries.
// Pure ES5, no deps. Functions are TOP-LEVEL so the QML namespace import
// exposes them directly (see Markdown.js): import "PropfindParser.js" as Prop
// ... Prop.parse(xml, baseUrl) ...
// The module.exports guard at the bottom is for node tests only.
function decodePath(u) {
try {
return decodeURIComponent(u);
} catch (e) {
return u;
}
}
function urlPath(u) {
var m = /^[a-z]+:\/\/[^/]*(\/.*)$/i.exec(u);
return m ? m[1] : u;
}
// entries: [{name, path, isDir, size, mtime}] sorted dirs-first, alpha.
// path is relative to baseUrl, URL-decoded; dirs end with "/".
function parse(xml, baseUrl) {
var entries = [];
if (!xml) return entries;
var basePath = decodePath(urlPath(String(baseUrl || "")));
if (basePath.charAt(basePath.length - 1) === "/") {
basePath = basePath.slice(0, -1);
}
var re = /<(?:[A-Za-z0-9_]+:)?response(?:\s[^>]*)?>([\s\S]*?)<\/(?:[A-Za-z0-9_]+:)?response>/gi;
var blk;
while ((blk = re.exec(xml)) !== null) {
var body = blk[1];
var hrefMatch = /(?:[A-Za-z0-9_]+:)?href>([\s\S]*?)<\//.exec(body);
if (!hrefMatch) continue;
var href = hrefMatch[1].trim();
if (!href) continue;
var decoded = decodePath(href);
var rel = decoded;
if (basePath && decoded.indexOf(basePath) === 0) {
rel = decoded.substring(basePath.length);
}
if (rel.charAt(0) === "/") rel = rel.substring(1);
if (rel === "" || rel === "/") continue;
var isDir = rel.charAt(rel.length - 1) === "/";
var segs = rel.split("/");
var name = isDir ? segs[segs.length - 2] : segs[segs.length - 1];
if (!name) continue;
var mtimeMatch = /(?:[A-Za-z0-9_]+:)?getlastmodified>([\s\S]*?)<\//.exec(body);
var sizeMatch = /(?:[A-Za-z0-9_]+:)?getcontentlength>([\s\S]*?)<\//.exec(body);
entries.push({
name: name,
path: rel,
isDir: isDir,
size: sizeMatch ? parseInt(sizeMatch[1].trim(), 10) : 0,
mtime: mtimeMatch ? mtimeMatch[1].trim() : ""
});
}
entries.sort(function (a, b) {
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
var an = a.name.toLowerCase();
var bn = b.name.toLowerCase();
return an < bn ? -1 : (an > bn ? 1 : 0);
});
return entries;
}
if (typeof module !== "undefined" && module.exports) {
module.exports = { parse: parse };
}