diff --git a/package-lock.json b/package-lock.json index f706ff2b..c814cff7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2119,9 +2119,9 @@ } }, "node_modules/@csstools/cascade-layer-name-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-3.0.1.tgz", - "integrity": "sha512-EqmSJE8CcNoGXcgpiOD12PPMeuJZwiGMX69HPoam+GzltcjZjr6THQ0S+8a0NtQuefJtILzoDyQj+fp7+Qiorg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-3.0.2.tgz", + "integrity": "sha512-B731RJ9pfJj3D5GJPp8ccsaaHMdwBmlOb4QWAYQUFpmMxonxJvNeeIoo0E89CjMJaKDvQXy9MKpSXY/i7XgeFA==", "dev": true, "funding": [ { @@ -2138,7 +2138,7 @@ "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.2", "@csstools/css-tokenizer": "^4.0.2" } }, @@ -2163,9 +2163,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.1.tgz", - "integrity": "sha512-EtC7SoN1j6J4E4DCwg5QgbO5TGxgxIA1RXqe+W+qUM+BUcezx9wT+/tiQ/WO2yCX4i5X+Cuf9ciJ22aP4UEwWw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.3.tgz", + "integrity": "sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==", "devOptional": true, "funding": [ { @@ -2182,14 +2182,14 @@ "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.2", "@csstools/css-tokenizer": "^4.0.2" } }, "node_modules/@csstools/css-color-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.4.tgz", - "integrity": "sha512-DyefytAZ735mX4Dq/WcDAXFtXhaEFvme0ZS9tVEBAc2whxUthXr0R0L2rmEPm59SrMBkGrFzQviBXMs/UtnABQ==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.6.tgz", + "integrity": "sha512-iiPQ3iRWwnJkeEn6RIu6SJPr7hYrLz6XZ9s/QZl+2/LI5KQVjpl2fdmDSZKuD4xP6GMmMPgHFFXg6k1Wkz0Trg==", "devOptional": true, "funding": [ { @@ -2204,20 +2204,20 @@ "license": "MIT", "dependencies": { "@csstools/color-helpers": "^6.1.2", - "@csstools/css-calc": "^3.4.1" + "@csstools/css-calc": "^3.4.3" }, "engines": { "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.2", "@csstools/css-tokenizer": "^4.0.2" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.1.tgz", - "integrity": "sha512-ShL8BqPfbKJrJiKFH0xBbN0i7Nrh9HXYRuF+pzyj93R/BL2YAsUxJeqANErzqM+0JGl7vjHp+3OIgd/DL69YIA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.2.tgz", + "integrity": "sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==", "devOptional": true, "funding": [ { @@ -2238,9 +2238,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz", - "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.15.tgz", + "integrity": "sha512-J0u7HkVl2nzSlhsiTOp4AmwcUQ3D+mGEEKfBy/7To5/y7F2OHwyLrXfrhR0SMgr4p5Lo+eaMVSeai24zUcBIxA==", "devOptional": true, "funding": [ { @@ -2283,9 +2283,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.1.tgz", - "integrity": "sha512-DR5NpEOOxDOhmMWPJlhYAV9gTmV4XpfYjtE+aXSCurkxS65KzNogI4wqzRIoujieQcmFkeRtK1nRIF8ImUZTDg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.2.tgz", + "integrity": "sha512-qx19O8AbbLLbDSAcI6YOby/Vq8rV51psgIvlF5OZT/L8fQJDCyQifL6k+kYU4a8ySpzJ4RBzZkIs530bAn8y4Q==", "dev": true, "funding": [ { @@ -2302,7 +2302,7 @@ "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.2", "@csstools/css-tokenizer": "^4.0.2" } }, @@ -2815,9 +2815,9 @@ } }, "node_modules/@lezer/javascript": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.5.tgz", - "integrity": "sha512-sWg4yX1J6XW67AaAynVt0iwF0M5c+np36TEu+P2ifAJ8haRYvHnWDV28r1jdwnJehWCwXECutAUy56K4RBZIyg==", + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.6.tgz", + "integrity": "sha512-sEvOqpl4vJQca0NugSQK02vQPbc5KrvoojnYGoqqFgFO0MtcYhwGiHKVEB+LuXYJnfyXo4QPA8ztbrEa4Fw5NA==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -3024,9 +3024,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.151.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.151.0.tgz", - "integrity": "sha512-J1yXrIlNDZVzE3ada310xeAw7nH8yCAyLPuUIsjKatFPmfn5bS1oW+cM+QsGOtVWd5nhSpbwZWx/rue+r5Z+PA==", + "version": "0.152.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.152.0.tgz", + "integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/oxc-project" @@ -3075,9 +3075,9 @@ } }, "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.11.tgz", - "integrity": "sha512-A5kXfGKvKWWZE0TtPrfsvT+q4Y5d1QG8gGUzpYjGydM+fARM9MuX90PrXYXe0XbsDVgyxxNzHo6giCj90bsFNw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz", + "integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==", "cpu": [ "arm" ], @@ -3091,9 +3091,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.11.tgz", - "integrity": "sha512-z6cTycz+iJ4PVkuL4HHW4DfTfoeU/2nqYYuSOrTmH7yHK5Y0LCOnA03V4ZNxavyVaU1oOqUgIg2klN/s+USGOA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz", + "integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==", "cpu": [ "arm64" ], @@ -3107,9 +3107,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.11.tgz", - "integrity": "sha512-jShvqNtP6vDC6/A5JOAzbVV+DkgHqhl/ScVCJEbt+TUY6QYz7YnXcrg3sLtFBniro0f/Ld50ZwCWA6f7KYD1nQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz", + "integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==", "cpu": [ "arm64" ], @@ -3123,9 +3123,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.11.tgz", - "integrity": "sha512-f2i2xiNWq1Z1l2++q2fuhZRdLAT3aqxD6vRNm1RAxpUoBcdqNB3C0s1Bt+K+PbEx2F5F4gQp6hqKkphCY/xF9w==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz", + "integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==", "cpu": [ "x64" ], @@ -3139,9 +3139,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.11.tgz", - "integrity": "sha512-4Ir5FSOKIAMr4r0kExpt1s3bMgzJU3rA45AYOHtQpls0oNeqcYBKrWMlckrYH4KCfGLfkfn1tN1dmZPMVsdXow==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz", + "integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==", "cpu": [ "x64" ], @@ -3155,9 +3155,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.11.tgz", - "integrity": "sha512-/gnRDM+39BROzAN/k1OZjDPnDMcZxB/0EUxKjONO5yVkNEvlsoMDrxGNKgZi/ttFriS2gwlDNzB65pvNbFOXIQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz", + "integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==", "cpu": [ "arm" ], @@ -3171,9 +3171,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.11.tgz", - "integrity": "sha512-PFaK8HwvAHbaKbBcDNQihjMKYvFnA5hiENx/l5tphTDz1E0WFp32l0A7aq7lyUwGsRw/xSrNIy/gIK4thrSCrw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz", + "integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==", "cpu": [ "arm64" ], @@ -3190,9 +3190,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.11.tgz", - "integrity": "sha512-AskzJUIKRLPxkruR1wLKewGbOw+EYfU/9lOrBFj4AFrEA8hPpKFnODWNu2WLaNs0QNkEb9QIJufmVZZIL/bJlg==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz", + "integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==", "cpu": [ "arm64" ], @@ -3209,9 +3209,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.11.tgz", - "integrity": "sha512-qlUGAheh2yh8afH7QBgx0PrRHN85hKnNd78x8MeMhXivuevgd8vgf6/CstOzmNKY/lLTHvNTrPy98cLnAugzJw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz", + "integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==", "cpu": [ "ppc64" ], @@ -3228,9 +3228,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.11.tgz", - "integrity": "sha512-secpEad+0vCbSfn8upFySkDskv+bGPk3THSDS9Y89yc4rb4kzqHp8Dmyd9BkQW4SnhNXBZCl/6CrO//hZahNJQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz", + "integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==", "cpu": [ "s390x" ], @@ -3247,9 +3247,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.11.tgz", - "integrity": "sha512-mOVBT3dPpkWm8XBWPmU4bf+U6dYDLeMo/9ojUmis4N0L5uu10qra5vOyngZ7/PSdoE4G9KvRt4bloRxNjLas7A==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz", + "integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==", "cpu": [ "x64" ], @@ -3266,9 +3266,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.11.tgz", - "integrity": "sha512-Is78i9A8Ui4SqcxUwFJ9uMmjDn58IbVTjFWYdQestFEgeuEmHMLGNriXnVJKkwG2YiZjw8cP0zCTyDMdDGtOOg==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz", + "integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==", "cpu": [ "x64" ], @@ -3285,9 +3285,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.11.tgz", - "integrity": "sha512-dUCXneZ87INUMyQ0D+C0HrEBNUPNXHaPmU5GTjyKTJEiussw9Kaj5Ln8UztPe4epV/ffvgNBEadksdYhmW6xJA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz", + "integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==", "cpu": [ "arm64" ], @@ -3301,9 +3301,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.11.tgz", - "integrity": "sha512-jByxb6qfd+bH1xUd0qnfFnb17i9sWBPY2tOavJ0l3tdr3OTu+Kvtm8cd/JV5nFt657b1VqGltxg9olOEfofXWw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz", + "integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==", "cpu": [ "arm64" ], @@ -3317,9 +3317,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.11.tgz", - "integrity": "sha512-/PzKqzAJ03i19oy2ItPvyvaVjOjBCNnfaJs8yvUdGBKmiESgnrJSQ2awd81QzFbbnAmu7YO9ZnJrDCb9VSJPRA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz", + "integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==", "cpu": [ "x64" ], @@ -3566,9 +3566,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.20.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.4.tgz", - "integrity": "sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==", + "version": "22.20.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz", + "integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3620,9 +3620,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.10.tgz", - "integrity": "sha512-HpbUakT7xp5miBUywCHf36ZEuAJNklBJDDsGpUIjMzOSmM8ELSfA9Sa/QDPeNeqeoN31u+UTCkL4klCOVvRm4Q==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.12.tgz", + "integrity": "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==", "dev": true, "license": "MIT", "engines": { @@ -4434,9 +4434,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.26", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.26.tgz", - "integrity": "sha512-GLQdD3y6UF8iVuMJl5fHgE4jdn/ua7n+toKfLgNlg3BqQtOZjpy68T8Tup8/wGWZCDlm7KMg7tPb4MPn7oN0TQ==", + "version": "2.11.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.27.tgz", + "integrity": "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4634,9 +4634,9 @@ } }, "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "license": "MIT", "engines": { "node": ">=18" @@ -5095,9 +5095,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.442", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.442.tgz", - "integrity": "sha512-najZYZ3+ZpjN1z3VOsrBiv5ej18vQgfV2lvEmxWzfmKrk4bdm3Owseyud4yGU6DfFn9pyunoAHDDyM4KmP78Ew==", + "version": "1.5.444", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.444.tgz", + "integrity": "sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==", "dev": true, "license": "ISC" }, @@ -5770,9 +5770,9 @@ } }, "node_modules/exsolve": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", - "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.3.tgz", + "integrity": "sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==", "dev": true, "license": "MIT" }, @@ -6132,9 +6132,9 @@ "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "17.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.12.0.tgz", - "integrity": "sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==", + "version": "17.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz", + "integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==", "dev": true, "license": "MIT", "engines": { @@ -7975,9 +7975,9 @@ "license": "MIT" }, "node_modules/n3": { - "version": "2.7.12", - "resolved": "https://registry.npmjs.org/n3/-/n3-2.7.12.tgz", - "integrity": "sha512-Hy6dfGg9yniLQpSBirvH2E2yO3EG7dSmA3aefRbtO411oqtzG8roD3h1kTc/N065bivCOPfTFIjf0KlwW7KlnQ==", + "version": "2.10.6", + "resolved": "https://registry.npmjs.org/n3/-/n3-2.10.6.tgz", + "integrity": "sha512-LtWkgNd9dtqOTLBIScGei02zo3U0JTh9JtGKpOiEWJ15vEfxXZbIX5XURyjstAoc6YYTElQvJ+8vTvJ8G4pEZw==", "license": "MIT", "dependencies": { "buffer": "^6.0.3", @@ -8625,9 +8625,9 @@ } }, "node_modules/postcss-custom-media": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-12.0.2.tgz", - "integrity": "sha512-qn+su6Ux/TVzBSPYlRxC3Kq5DZNWBZt7y1wj38mnHT+whYnM21IxuYVKJ2E9qahBo0KGvcv/1rAB/F5iY1UiIA==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-12.0.3.tgz", + "integrity": "sha512-pgOICT/unQexoA/Vh4ZvyAUrcwwA/nHh0SJcOwOombpwDEj1x5N6zK+kz97wy9NslhU6UxhE5c5Q/M2gpYfkJA==", "dev": true, "funding": [ { @@ -8641,10 +8641,10 @@ ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^3.0.1", - "@csstools/css-parser-algorithms": "^4.0.1", + "@csstools/cascade-layer-name-parser": "^3.0.2", + "@csstools/css-parser-algorithms": "^4.0.2", "@csstools/css-tokenizer": "^4.0.2", - "@csstools/media-query-list-parser": "^5.0.1" + "@csstools/media-query-list-parser": "^5.0.2" }, "engines": { "node": ">=20.19.0" @@ -9082,12 +9082,12 @@ } }, "node_modules/rolldown": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.11.tgz", - "integrity": "sha512-qpSwIyz0jHQq5qXBTNxFmE6664rJ7O+4TvPFOiOaBSrz8IOHc1koKKSqTM2H6u1UG1+TveuC6vaDHKXFOvb1Kw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.12.tgz", + "integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.151.0", + "@oxc-project/types": "=0.152.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -9097,21 +9097,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.11", - "@rolldown/binding-android-arm64": "1.2.11", - "@rolldown/binding-darwin-arm64": "1.2.11", - "@rolldown/binding-darwin-x64": "1.2.11", - "@rolldown/binding-freebsd-x64": "1.2.11", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.11", - "@rolldown/binding-linux-arm64-gnu": "1.2.11", - "@rolldown/binding-linux-arm64-musl": "1.2.11", - "@rolldown/binding-linux-ppc64-gnu": "1.2.11", - "@rolldown/binding-linux-s390x-gnu": "1.2.11", - "@rolldown/binding-linux-x64-gnu": "1.2.11", - "@rolldown/binding-linux-x64-musl": "1.2.11", - "@rolldown/binding-openharmony-arm64": "1.2.11", - "@rolldown/binding-win32-arm64-msvc": "1.2.11", - "@rolldown/binding-win32-x64-msvc": "1.2.11" + "@rolldown/binding-android-arm-eabi": "1.2.12", + "@rolldown/binding-android-arm64": "1.2.12", + "@rolldown/binding-darwin-arm64": "1.2.12", + "@rolldown/binding-darwin-x64": "1.2.12", + "@rolldown/binding-freebsd-x64": "1.2.12", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", + "@rolldown/binding-linux-arm64-gnu": "1.2.12", + "@rolldown/binding-linux-arm64-musl": "1.2.12", + "@rolldown/binding-linux-ppc64-gnu": "1.2.12", + "@rolldown/binding-linux-s390x-gnu": "1.2.12", + "@rolldown/binding-linux-x64-gnu": "1.2.12", + "@rolldown/binding-linux-x64-musl": "1.2.12", + "@rolldown/binding-openharmony-arm64": "1.2.12", + "@rolldown/binding-win32-arm64-msvc": "1.2.12", + "@rolldown/binding-win32-x64-msvc": "1.2.12" } }, "node_modules/safe-array-concat": { @@ -9516,9 +9516,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -10209,9 +10209,9 @@ } }, "node_modules/unplugin-dts": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unplugin-dts/-/unplugin-dts-1.1.1.tgz", - "integrity": "sha512-Z2VcabC0hjYuzF62oWmZXVoxagkM8bUWgqUy+dotoJTPnooR5mNaxbpv63JCmcaxdGCW2Bb75omK6FOryOYCRg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unplugin-dts/-/unplugin-dts-1.1.2.tgz", + "integrity": "sha512-RDqy90XUmFj6rz4U5YoTMdYdaCJe2ZnQZaWIjkWS4952Gv0zBTQyqWtlGgVMPYHa982dURvyoc+sUOFIcDFv+w==", "dev": true, "license": "MIT", "dependencies": { @@ -10360,15 +10360,15 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz", - "integrity": "sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.2.tgz", + "integrity": "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==", "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.28", - "rolldown": "~1.2.9", + "rolldown": "~1.2.11", "tinyglobby": "^0.2.17" }, "bin": { diff --git a/src/defaultPane.css b/src/defaultPane.css index bbb216a5..1fa74a19 100644 --- a/src/defaultPane.css +++ b/src/defaultPane.css @@ -17,13 +17,13 @@ margin-bottom: var(--spacing-base, 0.5rem); } -.defaultPane > tr { +.defaultPane > div { display: grid; grid-template-columns: minmax(0, var(--default-pane-predicate-column)) minmax(0, 1fr); align-items: flex-start; } -.defaultPane > tr > td.pred { +.defaultPane > div > div.pred { grid-column: 1; display: flex; align-items: flex-start; @@ -32,7 +32,7 @@ min-width: 0; } -.defaultPane > tr > td.pred > .labelTD { +.defaultPane > div > div.pred > .labelTD { flex: 1 1 auto; min-width: 0; margin: 0; @@ -40,61 +40,61 @@ padding-bottom: 0; } -.defaultPane > tr > td.pred > .iconTD { +.defaultPane > div > div.pred > .iconTD { flex: 0 0 auto; width: auto; margin: 0; } -.defaultPane > tr > td.obj { +.defaultPane > div > div.obj { grid-column: 2; min-width: 0; box-sizing: border-box; align-self: start; } -.defaultPane > tr > td[colspan='2'] { +.defaultPane > div > div[colspan='2'] { grid-column: 1 / -1; } -.defaultPane[data-layout='mobile'] > tr { +.defaultPane[data-layout='mobile'] > div { grid-template-columns: minmax(0, 1fr); } -.defaultPane[data-layout='mobile'] > tr > td.pred, -.defaultPane[data-layout='mobile'] > tr > td.obj { +.defaultPane[data-layout='mobile'] > div > div.pred, +.defaultPane[data-layout='mobile'] > div > div.obj { display: block; grid-column: 1; width: 100%; box-sizing: border-box; } -.defaultPane[data-layout='mobile'] > tr > td.pred { +.defaultPane[data-layout='mobile'] > div > div.pred { padding-bottom: var(--spacing-small, 0.1rem); } -.defaultPane[data-layout='mobile'] > tr > td.obj { +.defaultPane[data-layout='mobile'] > div > div.obj { padding-left: var(--default-pane-object-indent) !important; } @media (max-width: 700px) { - .defaultPane > tr { + .defaultPane > div { grid-template-columns: minmax(0, 1fr); } - .defaultPane > tr > td.pred, - .defaultPane > tr > td.obj { + .defaultPane > div > div.pred, + .defaultPane > div > div.obj { display: block; grid-column: 1; width: 100%; box-sizing: border-box; } - .defaultPane > tr > td.pred { + .defaultPane > div > div.pred { padding-bottom: var(--spacing-small, 0.1rem); } - .defaultPane > tr > td.obj { + .defaultPane > div > div.obj { padding-left: var(--default-pane-object-indent) !important; } } diff --git a/src/outline/manager.js b/src/outline/manager.js index fe5029bd..b118fb26 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -13,6 +13,7 @@ import { UserInput } from './userInput.js' import * as queryByExample from './queryByExample.js' import { loadContainerRepresentation } from '../utils/podUtils' import { isWebIdUri } from '../utils/webIdUtils' +import { createOutlineDomHelpers } from './outlineDomHelpers' import '../components/file-explorer-header' export default function (context) { @@ -40,11 +41,34 @@ export default function (context) { this.UserInput = new UserInput(this) this.clipboardAddress = 'tabulator:clipboard' // Weird this.UserInput.clipboardInit(this.clipboardAddress) - const outlineElement = this.outlineElement + + const { + outlineObjectDiv, + outlinePredicateDiv, + termWidget + } = createOutlineDomHelpers({ + dom, + UI, + kb: store, + outlineIcons, + expandMouseDownListener, + selectableTDClickListener, + setSelected, + viewAsBoringDefault, + removeNodeIconMouseDownListener + }) + + this.outlineObjectDiv = outlineObjectDiv + this.outlinePredicateDiv = outlinePredicateDiv + // old name: outlineObjectTD + this.outlineObjectTD = outlineObjectDiv + // old name: outlinePredicateTD + this.outlinePredicateTD = outlinePredicateDiv + this.termWidget = termWidget this.init = function () { - const table = getOutlineContainer() - table.outline = this + const outlineHost = getOutlineContainer() + outlineHost.outline = this } this.getLayoutMode = function () { @@ -86,7 +110,7 @@ export default function (context) { // / ////////////////////// Representing data - // Represent an object in summary form as a table cell + // Represent an object in summary form as a content block function appendRemoveIcon (node, subject, removeNode) { const image = UI.utils.AJARImage( @@ -173,129 +197,6 @@ export default function (context) { return img } // appendAccessIcon - /** make the td for an object (grammatical object) - * @param obj - an RDF term - * @param view - a VIEW function (rather than a bool asImage) - **/ - - this.outlineObjectTD = function outlineObjectTD ( - obj, - view, - deleteNode, - statement - ) { - const td = dom.createElement('td') - td.classList.add('obj') - td.setAttribute('notSelectable', 'false') - if (!obj) { - td.textContent = 'No object available.' - return td - } - const theClass = 'obj' - - // set about and put 'expand' icon - if ( - obj.termType === 'NamedNode' || - obj.termType === 'BlankNode' || - (obj.termType === 'Literal' && - obj.value.slice && - (obj.value.slice(0, 6) === 'ftp://' || - obj.value.slice(0, 8) === 'https://' || - obj.value.slice(0, 7) === 'http://')) - ) { - td.setAttribute('about', obj.toNT()) - td.appendChild( - UI.utils.AJARImage( - UI.icons.originalIconBase + 'tbl-expand-trans.png', - 'expand', - undefined, - dom - ) - ).addEventListener('click', expandMouseDownListener) - } - td.setAttribute('class', theClass) // this is how you find an object - if (kb.whether(obj, UI.ns.rdf('type'), UI.ns.link('Request'))) { - td.className = 'undetermined' - } // @@? why-timbl - - if (!view) { - // view should be a function pointer - view = viewAsBoringDefault - } - td.appendChild(view(obj)) - if (deleteNode) { - appendRemoveIcon(td, obj, deleteNode) - } - - // set DOM methods - td.tabulatorSelect = function () { - setSelected(this, true) - } - td.tabulatorDeselect = function () { - setSelected(this, false) - } - - td.addEventListener('click', selectableTDClickListener) - return td - } // outlineObjectTD - - this.outlinePredicateTD = function outlinePredicateTD ( - predicate, - newTr, - inverse, - internal - ) { - const predicateTD = dom.createElement('TD') - predicateTD.setAttribute('about', predicate.toNT()) - predicateTD.setAttribute('class', internal ? 'pred internal' : 'pred') - - let lab - switch (predicate.termType) { - case 'BlankNode': // TBD - predicateTD.className = 'undetermined' - break - case 'NamedNode': - lab = UI.utils.predicateLabelForXML(predicate, inverse) - break - case 'Collection': // some choices of predicate - lab = UI.utils.predicateLabelForXML(predicate.elements[0], inverse) - } - lab = lab ? lab.slice(0, 1).toUpperCase() + lab.slice(1) : '...' - // if (kb.statementsMatching(predicate,rdf('type'), UI.ns.link('Request')).length) predicateTD.className='undetermined'; - - const labelTD = dom.createElement('TD') - labelTD.classList.add('labelTD') - labelTD.setAttribute('notSelectable', 'true') - labelTD.appendChild(dom.createTextNode(lab)) - predicateTD.appendChild(labelTD) - labelTD.style.width = '100%' - predicateTD.appendChild(termWidget.construct(dom)) // termWidget is global??? - for (const w in outlineIcons.termWidgets) { - if (!newTr || !newTr.AJAR_statement) break // case for TBD as predicate - // alert(Icon.termWidgets[w]+' '+Icon.termWidgets[w].filter) - if ( - outlineIcons.termWidgets[w].filter && - outlineIcons.termWidgets[w].filter( - newTr.AJAR_statement, - 'pred', - inverse - ) - ) { - termWidget.addIcon(predicateTD, outlineIcons.termWidgets[w]) - } - } - - // set DOM methods - predicateTD.tabulatorSelect = function () { - setSelected(this, true) - } - predicateTD.tabulatorDeselect = function () { - setSelected(this, false) - } - predicateTD.addEventListener('click', selectableTDClickListener) - return predicateTD - } // outlinePredicateTD - function getOutlineContainer () { return getOrCreateContainer('OutlineView', 'Resource browser') } @@ -319,11 +220,7 @@ export default function (context) { * @returns {HTMLElement} */ function getOrCreateContainer (id) { - const containerHost = - document.getElementById('MainContent') || - document.body - - // OutlineView is a table + // OutlineView is a simple block container if (id === 'OutlineView') { const existingOutline = document.getElementById('OutlineView') if (existingOutline) { @@ -335,7 +232,7 @@ export default function (context) { document.body if (containerHost) { - const OutlineView = document.createElement('table') + const OutlineView = document.createElement('div') OutlineView.id = 'OutlineView' OutlineView.classList.add('outline-view') OutlineView.setAttribute('aria-label', 'Resource browser') @@ -387,17 +284,6 @@ export default function (context) { } } - function findContainingTable (td) { - let containingTable - for (containingTable = td; containingTable.parentNode; containingTable = containingTable.parentNode) { - if (containingTable.nodeName === 'TABLE') break - } - if (containingTable.nodeName !== 'TABLE') { - throw new Error('outline: internal error.') - } - return containingTable - } - function renderPaneIntoProvider (provider, subject, pane, options) { if (!provider || !pane) return @@ -427,10 +313,12 @@ export default function (context) { if (!outlineView) return const subjectId = subject.toNT() - const subjectTd = outlineView.querySelector('td.paneView[about="' + subjectId + '"]') - if (!subjectTd) return + const subjectNode = outlineView.querySelector('[about="' + subjectId + '"]') + if (!subjectNode) return - const provider = subjectTd.querySelector('file-explorer-provider') + const provider = subjectNode.matches?.('file-explorer-provider') + ? subjectNode + : subjectNode.querySelector('file-explorer-provider') if (!provider) return if (!pane) { UI.log.warn('outline: Unable to open pane in place: pane is undefined.') @@ -442,23 +330,19 @@ export default function (context) { renderPaneIntoProvider(provider, subject, pane, provider.paneRenderOptions) } - async function expandedProviderTR (subject, requiredPane, options) { + async function expandedProviderTR (subject, requiredPane, options, provider) { options = options || {} - // TODO: hide the main storage header - // const showHeader = !!requiredPane - const tr = dom.createElement('tr') + provider = provider || dom.createElement('file-explorer-provider') + provider.classList.add('paneView', 'tdFlex') + provider.setAttribute('notSelectable', 'true') + provider.setAttribute('role', 'grid') + provider.setAttribute('about', subject.toNT()) if (options.hover) { // By default no hide till hover as community deems it confusing - tr.classList.add('hoverControl') + provider.classList.add('hoverControl') } - const td = tr.appendChild(dom.createElement('td')) - td.classList.add('paneView', 'tdFlex') - td.setAttribute('notSelectable', 'true') - td.setAttribute('about', subject.toNT()) - td.setAttribute('colspan', '2') - const provider = td.appendChild(dom.createElement('file-explorer-provider')) provider.context = context provider.subjectUri = subject.uri provider.onBack = () => collapseMouseDownListener({ target: provider }) @@ -478,10 +362,9 @@ export default function (context) { provider.handleAccessClick = () => openPaneInPlace(subject, paneRegistry.byName('sharing')) if (provider.pane) { - tr.classList.add('outlinePaneRow') renderPaneIntoProvider(provider, subject, provider.pane, options) } - return tr + return provider } // / ////////////////////////////////////////////////////////////////////////// @@ -510,13 +393,12 @@ export default function (context) { // Remove a node from the DOM so that Firefox refreshes the screen OK // Just deleting it cause whitespace to accumulate. function removeAndRefresh (d) { - const table = d.parentNode - const par = table.parentNode - const placeholder = dom.createElement('table') - placeholder.classList.add('placeholderTable') - par.replaceChild(placeholder, table) - table.removeChild(d) - par.replaceChild(table, placeholder) // Attempt to + const parent = d.parentNode + const grandParent = parent.parentNode + const placeholder = dom.createElement('div') + grandParent.replaceChild(placeholder, parent) + parent.removeChild(d) + grandParent.replaceChild(parent, placeholder) // Attempt to } const propertyTable = (this.propertyTable = function propertyTable ( @@ -525,21 +407,19 @@ export default function (context) { requiredPane, options ) { - UI.log.debug('Property table for: ' + subject) + UI.log.debug('Property block for: ' + subject) subject = kb.canon(subject) // if (!requiredPane) requiredPane = panes.defaultPane; if (!table) { - // Create a new property table - table = dom.createElement('table') - table.classList.add('tableFullWidth') - expandedProviderTR(subject, requiredPane, options).then(providerTR => { - table.appendChild(providerTR) - }) - - return table + const provider = dom.createElement('file-explorer-provider') + expandedProviderTR(subject, requiredPane, options, provider) + return provider } else { - // New display of existing table, keeping expanded bits + const existingProvider = table.matches?.('file-explorer-provider') + ? table + : table.firstElementChild || table + expandedProviderTR(subject, requiredPane, options, existingProvider) UI.log.info('Re-expand: ' + table) // do some other stuff here return table @@ -547,12 +427,13 @@ export default function (context) { }) /* propertyTable */ function propertyTR (doc, st, inverse) { - const tr = doc.createElement('TR') + const tr = doc.createElement('div') tr.AJAR_statement = st tr.AJAR_inverse = inverse // tr.AJAR_variable = null; // @@ ?? was just 'tr.AJAR_variable' tr.setAttribute('predTR', 'true') - const predicateTD = thisOutline.outlinePredicateTD(st.predicate, tr, inverse) + tr.setAttribute('role', 'row') + const predicateTD = thisOutline.outlinePredicateDiv(st.predicate, tr, inverse) tr.appendChild(predicateTD) // @@ add 'internal' to predicateTD's class for style? mno return tr } @@ -560,10 +441,6 @@ export default function (context) { // / ////////// Property list function appendPropertyTRs (parent, plist, inverse, predicateFilter) { - // UI.log.info('@appendPropertyTRs, 'this' is %s, dom is %s, '+ // Gives 'can't access dead object' - // 'thisOutline.document is %s', this, dom.location, thisOutline.document.location); - // UI.log.info('@appendPropertyTRs, dom is now ' + this.document.location); - // UI.log.info('@appendPropertyTRs, dom is now ' + thisOutline.document.location); UI.log.debug('Property list length = ' + plist.length) if (plist.length === 0) return '' let sel, j, k @@ -629,7 +506,7 @@ export default function (context) { sel(plist[k]).lang.indexOf(outline.labeller.LanguagePreference) >= 0 ) { tr.appendChild( - thisOutline.outlineObjectTD( + thisOutline.outlineObjectDiv( sel(plist[k]), defaultpropview, undefined, @@ -644,7 +521,7 @@ export default function (context) { } tr.appendChild( - thisOutline.outlineObjectTD(sel(s), defaultpropview, undefined, s) + thisOutline.outlineObjectDiv(sel(s), defaultpropview, undefined, s) ) /* Note: showNobj shows between n to 2n objects. @@ -679,10 +556,10 @@ export default function (context) { displayed++ s = plist[j + l] defaultpropview = views.defaults[s.predicate.uri] - const trObj = dom.createElement('tr') + const trObj = dom.createElement('div') trObj.style.colspan = '1' trObj.appendChild( - thisOutline.outlineObjectTD( + thisOutline.outlineObjectDiv( sel(plist[j + l]), defaultpropview, undefined, @@ -709,8 +586,12 @@ export default function (context) { if (show < predDups) { // Add the x more here - const moreTR = dom.createElement('tr') - const moreTD = moreTR.appendChild(dom.createElement('td')) + const moreTR = dom.createElement('div') + const moreTD = moreTR.appendChild(dom.createElement('div')) + moreTD.setAttribute( + 'style', + 'margin: 0.2em; border: none; padding: 0; vertical-align: top;' + ) moreTD.classList.add('obj') moreTD.setAttribute('notSelectable', 'false') if (predDups > n) { @@ -779,52 +660,6 @@ export default function (context) { this.appendPropertyTRs = appendPropertyTRs - /* termWidget - ** - */ - const termWidget = {} // @@@@@@ global - globalThis.termWidget = termWidget - termWidget.construct = function (dom) { - dom = dom || document - const td = dom.createElement('TD') - td.setAttribute('class', 'iconTD') - td.setAttribute('notSelectable', 'true') - return td - } - termWidget.addIcon = function (td, icon, listener) { - const iconTD = td.childNodes[1] - if (!iconTD) return - const img = UI.utils.AJARImage(icon.src, icon.alt, icon.tooltip, dom) - iconTD.appendChild(img) - if (listener) { - img.addEventListener('click', listener) - } - } - termWidget.removeIcon = function (td, icon) { - const iconTD = td.childNodes[1] - let baseURI - if (!iconTD) return - for (let x = 0; x < iconTD.childNodes.length; x++) { - const elt = iconTD.childNodes[x] - const eltSrc = elt.src - - // ignore first '?' and everything after it //Kenny doesn't know what this is for - try { - baseURI = dom.location.href.split('?')[0] - } catch (e) { - baseURI = '' - } - const relativeIconSrc = $rdf.uri.join(icon.src, baseURI) - if (eltSrc === relativeIconSrc) { - iconTD.removeChild(elt) - } - } - } - termWidget.replaceIcon = function (td, oldIcon, newIcon, listener) { - termWidget.removeIcon(td, oldIcon) - termWidget.addIcon(td, newIcon, listener) - } - // / /////////////////////////////////////////////////// VALUE BROWSER VIEW // / /////////////////////////////////////////////////////// TABLE VIEW @@ -893,9 +728,16 @@ export default function (context) { function setSelectedParent (node, inc) { const onIcon = outlineIcons.termWidgets.optOn const offIcon = outlineIcons.termWidgets.optOff + const isPredicateRow = (element) => { + return Boolean( + element && + typeof element.getAttribute === 'function' && + (element.getAttribute('predTR') === 'true' || element.getAttribute('data-outline-node') === 'predicate') + ) + } for (let n = node; n.parentNode; n = n.parentNode) { while (true) { - if (n.getAttribute('predTR')) { + if (isPredicateRow(n)) { let num = n.getAttribute('parentOfSelected') if (!num) num = 0 else num = parseInt(num) @@ -918,8 +760,8 @@ export default function (context) { ) } break - } else if (n.previousSibling && n.previousSibling.nodeName === 'TR') { - n = n.previousSibling + } else if (n.previousElementSibling) { + n = n.previousElementSibling } else break } } @@ -972,10 +814,10 @@ export default function (context) { // UI.log.info('selection has ' +selection.map(function(item){return item.textContent;}).join(', ')); // UI.log.debug('@outline setSelected, intended to '+(newValue?'select ':'deselect ')+node+node.textContent); // if (newValue === selected(node)) return; //we might not need this anymore... - if (node.nodeName !== 'TD') { + if (node.nodeName !== 'TD' && node.nodeName !== 'DIV') { UI.log.debug('down' + node.nodeName) throw new Error( - 'Expected TD in setSelected: ' + + 'Expected TD or DIV in setSelected: ' + node.nodeName + ' : ' + node.textContent @@ -1041,6 +883,7 @@ export default function (context) { selection = [] } + /* srcElement is the old IE-era version of event.target. */ /** Get the target of an event **/ this.targetOf = function (e) { let target @@ -1091,13 +934,8 @@ export default function (context) { ) { setSelected(selectedTd.nextSibling, true) } else { - const newSelected = dom.evaluate( - 'table/div/tr/td[2]', - selectedTd, - null, - XPathResult.FIRST_ORDERED_NODE_TYPE, - null - ).singleNodeValue + const nextRow = selectedTd.parentNode && selectedTd.parentNode.nextSibling + const newSelected = nextRow ? nextRow.lastChild : null setSelected(newSelected, true) } break @@ -1110,7 +948,7 @@ export default function (context) { setSelected(selectedTd.previousSibling, true) return true // do not shrink signal } else { - setSelected(UI.utils.ancestor(selectedTd.parentNode, 'TD'), true) + setSelected(selectedTd.parentNode && selectedTd.parentNode.firstChild, true) } // supplied by thieOutline.focusTd break case 'moveTo': @@ -1232,8 +1070,10 @@ export default function (context) { break case 37: { // left if (this.walk('left')) return - const titleTd = UI.utils.ancestor(selectedTd.parentNode, 'TD') - outlineCollapse(selectedTd, UI.utils.getAbout(kb, titleTd)) + const subjectNode = selectedTd.firstElementChild?.matches('file-explorer-provider') + ? selectedTd.firstElementChild + : selectedTd.querySelector('file-explorer-provider') + outlineCollapse(selectedTd, UI.utils.getAbout(kb, subjectNode)) break } case 39: // right @@ -1247,7 +1087,7 @@ export default function (context) { this.walk('right') return } - if (selectedTd.firstChild.tagName !== 'TABLE') { + if (!selectedTd.firstElementChild?.matches('file-explorer-provider')) { // not expanded sf.addCallback('done', setSelectedAfterward) sf.addCallback('fail', setSelectedAfterward) @@ -1357,7 +1197,7 @@ export default function (context) { const target = thisOutline.targetOf(e) const subject = UI.utils.getAbout(kb, target) const pane = e.altKey ? paneRegistry.byName('internal') : undefined - const p = target.parentNode.parentNode + const p = target.closest?.('[data-outline-node="object"]') || target.parentNode?.parentNode || target outlineCollapse(p, subject, pane) } @@ -1412,9 +1252,9 @@ export default function (context) { // var p = target.parentNode let node for ( - node = UI.utils.ancestor(target, 'TD'); + node = UI.utils.ancestor(target, 'td') || UI.utils.ancestor(target, 'tr') || UI.utils.ancestor(target, 'div'); node && !(node.getAttribute('notSelectable') === 'false'); // Default now is not selectable - node = UI.utils.ancestor(node.parentNode, 'TD') + node = UI.utils.ancestor(node.parentNode, 'td') || UI.utils.ancestor(node.parentNode, 'tr') || UI.utils.ancestor(node.parentNode, 'div') ) { // ... } @@ -1444,7 +1284,7 @@ export default function (context) { // go to UserInput let st if (node.parentNode) st = node.parentNode.AJAR_statement - if (!st) return // For example in the title TD of an expanded pane + if (!st) return // For example in the title block of an expanded pane const target = st.why const editable = store.updater.editable(target.uri, kb) if (sel && editable) thisOutline.UserInput.Click(e, selection[0]) // was next 2 lines @@ -1550,27 +1390,13 @@ export default function (context) { // first expand newTable = propertyTable(subject, undefined, pane, options) } else { - UI.log.info(' ... p is ' + p) - for ( - newTable = p.firstChild; - newTable.nextSibling; - newTable = newTable.nextSibling - ) { - UI.log.info(' ... checking node ' + newTable) - if (newTable.nodeName === 'table') break - } - newTable = propertyTable(subject, newTable, pane, options) + newTable = propertyTable(subject, p, pane, options) } already = true - if ( - UI.utils.ancestor(p, 'TABLE') && - UI.utils.ancestor(p, 'TABLE').style.backgroundColor === 'white' - ) { - newTable.style.backgroundColor = '#eee' - } else { - newTable.style.backgroundColor = 'white' + if (newTable !== p) { + UI.utils.emptyNode(p).appendChild(newTable) } - UI.utils.emptyNode(p).appendChild(newTable) + thisOutline.focusTd = p // I don't know why I couldn't use 'this'...because not defined in callbacks UI.log.debug('expand: Node for ' + subject + ' expanded') // fetch seeAlso when render() @@ -1654,23 +1480,12 @@ export default function (context) { sf.addCallback('done', expand) // @@@@@@@ This can really mess up existing work sf.addCallback('fail', expand) // Need to do if there s one a gentle resync of page with store - const returnConditions = [] // this is quite a general way to do cut and paste programming - // I might make a class for this if (subject.uri && subject.uri.split(':')[0] === 'rdf') { // what is this? -tim render() return } - for (let i = 0; i < returnConditions.length; i++) { - let returnCode - if (returnCode === returnConditions[i](subject)) { - render() - UI.log.debug('outline 1815') - if (returnCode[1]) outlineElement.removeChild(outlineElement.lastChild) - return - } - } if ( subject.uri && !immediate && @@ -1746,21 +1561,7 @@ export default function (context) { } // outlineExpand function outlineCollapse (p, subject) { - let row = UI.utils.ancestor(p, 'TR') - row = UI.utils.ancestor(row.parentNode, 'TR') // two levels up - let statement - if (row) statement = row.AJAR_statement - let level // find level (the enclosing TD) - for ( - level = p.parentNode; - level.tagName !== 'TD'; - level = level.parentNode - ) { - if (typeof level === 'undefined') { - alert('Not enclosed in TD!') - return - } - } + const statement = p.AJAR_statement || (p.parentNode && p.parentNode.AJAR_statement) UI.log.debug('Collapsing subject ' + subject) let myview @@ -1770,12 +1571,12 @@ export default function (context) { } UI.log.debug('view= ' + myview) let deleteNode - if (level.parentNode.parentNode.id === 'outline') { - deleteNode = level.parentNode + if (p.parentNode && p.parentNode.id === 'outline') { + deleteNode = p } thisOutline.replaceTD( - thisOutline.outlineObjectTD(subject, myview, deleteNode, statement), - level + thisOutline.outlineObjectDiv(subject, myview, deleteNode, statement), + p ) } // outlineCollapse @@ -1799,15 +1600,10 @@ export default function (context) { function outlineRefocus (p, subject) { // Shift-expand or shift-collapse: Maximize - let outer = null - for (let level = p.parentNode; level; level = level.parentNode) { - UI.log.debug('level ' + level.tagName) - if (level.tagName === 'TD') outer = level - } // find outermost td - UI.utils.emptyNode(outer).appendChild(propertyTable(subject)) + UI.utils.emptyNode(p).appendChild(propertyTable(subject)) setUrlBarAndTitle(subject) // dom.title = UI.utils.label(subject) - outer.setAttribute('about', subject.toNT()) + p.setAttribute('about', subject.toNT()) } // outlineRefocus outline.outlineRefocus = outlineRefocus @@ -1844,40 +1640,43 @@ export default function (context) { @param pane -- optional -- pane to be used for expanded display @param solo -- optional -- the window will be cleared out and only the subject displayed @param referer -- optional -- where did we hear about this from anyway? - @param table -- option -- default is an HTML table element in which to put the outline. + @param host -- option -- default is the outline host element used for the view. @param showNavbar -- optional -- when false, suppress automatic navbar reveal */ - this.GotoSubject = function (subject, expand, pane, solo, referrer, table, showNavbar = true) { - const outlineContainer = getOutlineContainer() - if (showNavbar && (!table || table === outlineContainer)) { + this.GotoSubject = function (subject, expand, pane, solo, referrer, host, showNavbar = true) { + const outlineHost = getOutlineContainer() + if (showNavbar && (!host || host === outlineHost)) { showSolidPanesNavbar() } - table = table || outlineContainer // if does not exist create a compatible host in the current shell + host = host || outlineHost // if does not exist create a compatible host in the current shell if (solo) { - UI.utils.emptyNode(table) - table.style.width = '100%' + host.style.width = '100%' + UI.utils.emptyNode(host) } - function GotoSubjectDefault () { - const tr = dom.createElement('tr') - tr.classList.add('outlineRow1') - tr.style.verticalAlign = 'top' - table.appendChild(tr) - const td = thisOutline.outlineObjectTD(subject, undefined, tr) - tr.appendChild(td) - return td + function createSubjectBlock () { + const subjectBlock = dom.createElement('div') + subjectBlock.classList.add('outline-subject-block') + const block = thisOutline.outlineObjectDiv(subject, undefined, subjectBlock) + subjectBlock.appendChild(block) + host.appendChild(subjectBlock) + return subjectBlock } - const td = GotoSubjectDefault() + const subjectBlock = createSubjectBlock() if (solo) setUrlBarAndTitle(subject) // dom.title = UI.utils.label(subject) // 'Tabulator: '+ No need to advertize if (expand) { - outlineExpand(td, subject, { + outlineExpand(subjectBlock, subject, { pane, solo }) + } else { + if (!solo) { + createSubjectBlock() + } } if ( @@ -1976,8 +1775,7 @@ export default function (context) { } } else if (obj.termType === 'Collection') { // obj.elements is an array of the elements in the collection - rep = dom.createElement('table') - rep.classList.add('tableFullWidth') + rep = dom.createElement('div') rep.setAttribute('about', obj.toNT()) /* Not sure which looks best -- with or without. I think without @@ -1987,13 +1785,13 @@ export default function (context) { */ for (let i = 0; i < obj.elements.length; i++) { const elt = obj.elements[i] - const row = rep.appendChild(dom.createElement('tr')) - const numcell = row.appendChild(dom.createElement('td')) + const row = rep.appendChild(dom.createElement('div')) + const numcell = row.appendChild(dom.createElement('div')) numcell.classList.add('obj') numcell.setAttribute('notSelectable', 'false') numcell.setAttribute('about', obj.toNT()) numcell.innerHTML = i + 1 + ')' - row.appendChild(thisOutline.outlineObjectTD(elt)) + row.appendChild(thisOutline.outlineObjectDiv(elt)) } } else if (obj.termType === 'Graph') { rep = paneRegistry diff --git a/src/outline/outlineDomHelpers.ts b/src/outline/outlineDomHelpers.ts new file mode 100644 index 00000000..40d3cc61 --- /dev/null +++ b/src/outline/outlineDomHelpers.ts @@ -0,0 +1,225 @@ +import { uri } from 'rdflib' +import { utils } from 'solid-ui' + +type OutlineIcon = { + src: string + alt: string + tooltip?: string + width: number +} + +type TermWidget = { + construct: (domArg?: Document) => HTMLElement + addIcon: (iconHost: ParentNode, icon: OutlineIcon, listener?: EventListener) => void + removeIcon: (iconHost: ParentNode, icon: OutlineIcon) => void + replaceIcon: (iconHost: ParentNode, oldIcon: OutlineIcon, newIcon: OutlineIcon, listener?: EventListener) => void +} + +export function createOutlineDomHelpers ({ + dom, + UI, + kb, + outlineIcons, + expandMouseDownListener, + selectableTDClickListener, + setSelected, + viewAsBoringDefault, + removeNodeIconMouseDownListener +}) { + function appendRemoveIcon (node, subject, removeNode) { + const image = utils.AJARImage( + outlineIcons.src.icon_remove_node, + 'remove', + undefined, + dom + ) + image.addEventListener('click', removeNodeIconMouseDownListener) + image.node = removeNode + image.setAttribute('about', subject.toNT()) + image.style.marginLeft = '5px' + image.style.marginRight = '10px' + node.appendChild(image) + return image + } + + const termWidget = {} as TermWidget + globalThis.termWidget = termWidget + + termWidget.construct = function (domArg) { + domArg = domArg || document + const iconContainer = domArg.createElement('div') + iconContainer.setAttribute( + 'style', + 'margin: 0.2em; border: none; padding: 0; vertical-align: top;' + ) + iconContainer.setAttribute('class', 'iconTD') + iconContainer.setAttribute('notSelectable', 'true') + iconContainer.style.width = '0px' + return iconContainer + } + + termWidget.addIcon = function (iconHost, icon, listener) { + const iconTD = iconHost.childNodes[1] as HTMLElement | undefined + if (!iconTD) return + const img = utils.AJARImage(icon.src, icon.alt, icon.tooltip, dom) + const width = Number.parseInt(iconTD.style.width || '0', 10) + icon.width + iconTD.style.width = width + 'px' + iconTD.appendChild(img) + if (listener) { + img.addEventListener('click', listener) + } + } + + termWidget.removeIcon = function (iconHost, icon) { + const iconTD = iconHost.childNodes[1] as HTMLElement | undefined + let baseURI + if (!iconTD) return + const width = Number.parseInt(iconTD.style.width || '0', 10) - icon.width + iconTD.style.width = width + 'px' + for (let x = 0; x < iconTD.childNodes.length; x++) { + const elt = iconTD.childNodes[x] as HTMLImageElement + const eltSrc = elt.src + + try { + baseURI = dom.location.href.split('?')[0] + } catch (e) { + baseURI = '' + } + const relativeIconSrc = uri.join(icon.src, baseURI) + if (eltSrc === relativeIconSrc) { + iconTD.removeChild(elt) + } + } + } + + termWidget.replaceIcon = function (iconHost, oldIcon, newIcon, listener) { + termWidget.removeIcon(iconHost, oldIcon) + termWidget.addIcon(iconHost, newIcon, listener) + } + + // old name: outlineObjectTD + function outlineObjectDiv ( + obj, + view, + deleteNode, + statement + ) { + const objectDiv = dom.createElement('div') + objectDiv.classList.add('obj') + objectDiv.setAttribute('notSelectable', 'false') + objectDiv.setAttribute('role', 'gridcell') + objectDiv.setAttribute('tabindex', '0') + objectDiv.setAttribute('data-outline-node', 'object') + if (!obj) { + objectDiv.textContent = 'No object available.' + return objectDiv + } + const theClass = 'obj' + + if ( + obj.termType === 'NamedNode' || + obj.termType === 'BlankNode' || + (obj.termType === 'Literal' && + obj.value.slice && + (obj.value.slice(0, 6) === 'ftp://' || + obj.value.slice(0, 8) === 'https://' || + obj.value.slice(0, 7) === 'http://')) + ) { + objectDiv.setAttribute('about', obj.toNT()) + objectDiv.appendChild( + UI.utils.AJARImage( + UI.icons.originalIconBase + 'tbl-expand-trans.png', + 'expand', + undefined, + dom + ) + ).addEventListener('click', expandMouseDownListener) + } + objectDiv.setAttribute('class', theClass) + if (kb.whether(obj, UI.ns.rdf('type'), UI.ns.link('Request'))) { + objectDiv.className = 'undetermined' + } + + if (!view) { + view = viewAsBoringDefault + } + objectDiv.appendChild(view(obj)) + if (deleteNode) { + appendRemoveIcon(objectDiv, obj, deleteNode) + } + + objectDiv.tabulatorSelect = function () { + setSelected(this, true) + } + objectDiv.tabulatorDeselect = function () { + setSelected(this, false) + } + + objectDiv.addEventListener('click', selectableTDClickListener) + return objectDiv + } + + // old name: outlinePredicateTD + function outlinePredicateDiv ( + predicate, + newTr, + inverse, + internal + ) { + const predicateTD = dom.createElement('div') + predicateTD.setAttribute('about', predicate.toNT()) + predicateTD.setAttribute('class', internal ? 'pred internal' : 'pred') + predicateTD.setAttribute('role', 'gridcell') + predicateTD.setAttribute('data-outline-node', 'predicate') + + let lab + switch (predicate.termType) { + case 'BlankNode': + predicateTD.className = 'undetermined' + break + case 'NamedNode': + lab = UI.utils.predicateLabelForXML(predicate, inverse) + break + case 'Collection': + lab = UI.utils.predicateLabelForXML(predicate.elements[0], inverse) + } + lab = lab ? lab.slice(0, 1).toUpperCase() + lab.slice(1) : '...' + + const labelTD = dom.createElement('div') + labelTD.classList.add('labelTD') + labelTD.setAttribute('notSelectable', 'true') + labelTD.appendChild(dom.createTextNode(lab)) + predicateTD.appendChild(labelTD) + labelTD.style.width = '100%' + predicateTD.appendChild(termWidget.construct(dom)) + for (const w in outlineIcons.termWidgets) { + if (!newTr || !newTr.AJAR_statement) break + if ( + outlineIcons.termWidgets[w].filter && + outlineIcons.termWidgets[w].filter( + newTr.AJAR_statement, + 'pred', + inverse + ) + ) { + termWidget.addIcon(predicateTD, outlineIcons.termWidgets[w]) + } + } + + predicateTD.tabulatorSelect = function () { + setSelected(this, true) + } + predicateTD.tabulatorDeselect = function () { + setSelected(this, false) + } + predicateTD.addEventListener('click', selectableTDClickListener) + return predicateTD + } + + return { + appendRemoveIcon, + outlineObjectDiv, + outlinePredicateDiv, + termWidget + } +} diff --git a/src/outline/queryByExample.js b/src/outline/queryByExample.js index 9f7ddd76..9835f4ee 100644 --- a/src/outline/queryByExample.js +++ b/src/outline/queryByExample.js @@ -14,11 +14,18 @@ const optionalSubqueriesIndex = [] function predParentOf (node) { let n = node + const isPredicateRow = (element) => { + return Boolean( + element && + typeof element.getAttribute === 'function' && + (element.getAttribute('predTR') === 'true' || element.getAttribute('data-outline-node') === 'predicate') + ) + } while (true) { - if (n.getAttribute('predTR')) { + if (isPredicateRow(n)) { return n - } else if (n.previousSibling && n.previousSibling.nodeName === 'TR') { - n = n.previousSibling + } else if (n.previousElementSibling) { + n = n.previousElementSibling } else { console.log('Could not find predParent') return node diff --git a/src/outline/userInput.js b/src/outline/userInput.js index e6a7af47..01d5e66a 100644 --- a/src/outline/userInput.js +++ b/src/outline/userInput.js @@ -54,6 +54,23 @@ export function UserInput (outline) { let movedArrow = false // hq + function getStatementRow (node) { + let current = node + while (current && current !== myDocument) { + if (current.AJAR_statement) { + return current + } + current = current.parentNode + } + + return UI.utils.ancestor(node, 'DIV') || UI.utils.ancestor(node, 'TR') + } + + function getStatementContainer (node) { + const row = getStatementRow(node) + return row?.parentNode || UI.utils.ancestor(node, 'TABLE') + } + // var updateService=new updateCenter(kb); if (!UserInputFormula) { @@ -87,11 +104,11 @@ export function UserInput (outline) { const target = UI.utils.getTarget(e) // UI.log.warn(ancestor(target,'TABLE').textContent); - const insertTr = myDocument.createElement('tr') - UI.utils - .ancestor(target, 'DIV') - .insertBefore(insertTr, UI.utils.ancestor(target, 'TR')) - const tempTr = myDocument.createElement('tr') + const insertTr = myDocument.createElement('div') + const targetRow = getStatementRow(target) + const targetContainer = getStatementContainer(target) + targetContainer.insertBefore(insertTr, targetRow) + const tempTr = myDocument.createElement('div') const reqTerm1 = This.generateRequest('(TBD)', tempTr, true) insertTr.appendChild(tempTr.firstChild) const reqTerm2 = This.generateRequest( @@ -104,11 +121,10 @@ export function UserInput (outline) { // Take the why of the last TR and write to it. if ( - UI.utils.ancestor(target, 'TR').previousSibling && // there is a previous predicate/object line - UI.utils.ancestor(target, 'TR').previousSibling.AJAR_statement + targetRow.previousSibling && // there is a previous predicate/object line + targetRow.previousSibling.AJAR_statement ) { - const preStat = UI.utils.ancestor(target, 'TR').previousSibling - .AJAR_statement + const preStat = targetRow.previousSibling.AJAR_statement // This should always(?) input a non-inverse statement This.formUndetStat( insertTr, @@ -122,7 +138,7 @@ export function UserInput (outline) { // no previous row: write to the document defining the subject const subject = UI.utils.getAbout( store, - UI.utils.ancestor(target.parentNode.parentNode, 'TD') + targetContainer.parentNode ) const doc = store.sym($rdf.Util.uri.docpart(subject.uri)) This.formUndetStat(insertTr, subject, reqTerm1, reqTerm2, doc, false) @@ -321,7 +337,7 @@ export function UserInput (outline) { let trNode try { obj = UI.utils.getTerm(target) - trNode = UI.utils.ancestor(target, 'TR') + trNode = getStatementRow(target) } catch (e) { UI.log.warn('userinput.js: ' + e + UI.utils.getAbout(store, selectedTd)) UI.log.error(target + ' getStatement Error:' + e) @@ -449,7 +465,7 @@ export function UserInput (outline) { ) // TODO: DEFINE ERROR CALLBACK defaultpropview = this.views.defaults[s.predicate.uri] - trCache = UI.utils.ancestor(this.lastModified, 'TR') + trCache = getStatementRow(this.lastModified) try { store.updater.update([], [s], function ( uri, @@ -493,7 +509,7 @@ export function UserInput (outline) { // TODO: DEFINE ERROR CALLBACK const valueCache = this.lastModified.value - trCache = UI.utils.ancestor(this.lastModified, 'TR') + trCache = getStatementRow(this.lastModified) const oldValue = this.lastModified.defaultValue s2 = $rdf.st( s.subject, @@ -548,10 +564,7 @@ export function UserInput (outline) { bnodeTerm: s.subject }) } else { - s1 = UI.utils.ancestor( - UI.utils.ancestor(this.lastModified, 'TR').parentNode, - 'TR' - ).AJAR_statement + s1 = getStatementRow(this.lastModified).AJAR_statement s2 = $rdf.st(s.subject, selectedPredicate, textTerm, s.why) const type = store.the(s.subject, rdf('type')) s3 = store.anyStatementMatching( @@ -562,10 +575,7 @@ export function UserInput (outline) { ) // TODO: DEFINE ERROR CALLBACK // because the table is repainted, so... - trCache = UI.utils.ancestor( - UI.utils.ancestor(this.lastModified, 'TR'), - 'TD' - ).parentNode + trCache = getStatementRow(this.lastModified).parentNode try { store.updater.update([], [s1, s2, s3], function ( uri, @@ -593,10 +603,7 @@ export function UserInput (outline) { // a subtle bug occurs here, if foaf:nick hasn't been dereferneced, // this add will cause a repainting } - const enclosingTd = UI.utils.ancestor( - this.lastModified.parentNode.parentNode, - 'TD' - ) + const enclosingTd = getStatementContainer(this.lastModified).parentNode const defaultPane = panes.byName('default') // @@ check outline.outlineExpand(enclosingTd, s.subject, { pane: defaultPane, @@ -618,7 +625,7 @@ export function UserInput (outline) { } } else if (this.lastModified.isNew) { // generate 'Request', there is no way you can input ' (Please Input) ' - trNode = UI.utils.ancestor(this.lastModified, 'TR') + trNode = getStatementRow(this.lastModified) reqTerm = this.generateRequest( '(To be determined. Re-type of drag an object onto this field)' ) @@ -638,10 +645,7 @@ export function UserInput (outline) { return } else if (s.predicate.termType === 'Collection') { store.removeMany(s.subject) - const upperTr = UI.utils.ancestor( - UI.utils.ancestor(this.lastModified, 'TR').parentNode, - 'TR' - ) + const upperTr = getStatementRow(this.lastModified) preStat = upperTr.AJAR_statement reqTerm = this.generateRequest( '(To be determined. Re-type of drag an object onto this field)' @@ -678,7 +682,7 @@ export function UserInput (outline) { } } // case modified - literal modification only(for now). - trNode = UI.utils.ancestor(this.lastModified, 'TR') + trNode = getStatementRow(this.lastModified) // var defaultpropview = this.views.defaults[s.predicate.uri] if (!this.statIsInverse) { @@ -913,9 +917,9 @@ export function UserInput (outline) { break } case 'selected': { // header , undetermined generated - const paneDiv = UI.utils.ancestor(selectedTd, 'TABLE').lastChild + const paneDiv = getStatementContainer(selectedTd) const newTr = paneDiv.insertBefore( - myDocument.createElement('tr'), + myDocument.createElement('div'), paneDiv.lastChild ) // var titleTerm=UI.utils.getAbout(kb,UI.utils.ancestor(newTr,'TD')); @@ -1000,7 +1004,7 @@ export function UserInput (outline) { */ subject = UI.utils.getAbout( store, - UI.utils.ancestor(selectedTd, 'TABLE').parentNode + getStatementContainer(selectedTd).parentNode ) subjectClass = store.any(subject, rdf('type')) sparqlText = [] @@ -1057,7 +1061,7 @@ export function UserInput (outline) { */ subject = UI.utils.getAbout( store, - UI.utils.ancestor(selectedTd, 'TABLE').parentNode + getStatementContainer(selectedTd).parentNode ) subjectClass = store.any(subject, rdf('type')) const object = selectedTd.parentNode.AJAR_statement.object @@ -1498,7 +1502,7 @@ export function UserInput (outline) { getStatementAbout: function getStatementAbout (something) { // var trNode=something.parentNode; - const trNode = UI.utils.ancestor(something, 'TR') + const trNode = getStatementRow(something) if (!trNode) { throw new Error('No ancestor TR for the TD we clicked on:' + something) } @@ -1611,7 +1615,7 @@ export function UserInput (outline) { } // if(!isEnd && HCIoptions["bottom insert highlights"].enabled) trIterator=trIterator.previousSibling; - const insertTr = myDocument.createElement('tr') + const insertTr = myDocument.createElement('div') // style stuff, I'll have to investigate appendPropertyTRs() somehow insertTr.style.colspan = '1' insertTr.style.display = 'block' @@ -1657,7 +1661,7 @@ export function UserInput (outline) { if (trNew) { trNode = trNew } else { - trNode = UI.utils.ancestor(this.lastModified, 'TR') + trNode = getStatementRow(this.lastModified) } UI.utils.emptyNode(trNode) } diff --git a/test/unit/outline/manager.test.ts b/test/unit/outline/manager.test.ts index 693663a4..66b322f1 100644 --- a/test/unit/outline/manager.test.ts +++ b/test/unit/outline/manager.test.ts @@ -32,7 +32,7 @@ const mockPaneRegistry = { } describe('manager', () => { - describe('outline object td', () => { + describe('outline object div', () => { describe('for a named node', () => { let result beforeAll(() => { @@ -40,11 +40,11 @@ describe('manager', () => { const row = document.createElement('tr') table.appendChild(row) const manager = new OutlineManager({ dom: document, session: { paneRegistry: mockPaneRegistry } }) - result = manager.outlineObjectTD(sym('https://namednode.example/'), null, null, null) + result = manager.outlineObjectDiv(sym('https://namednode.example/'), null, null, null) row.appendChild(result) }) - it('is a html td element', () => { - expect(result.nodeName).toBe('TD') + it('is a html div element', () => { + expect(result.nodeName).toBe('DIV') }) it('about attribute refers to node', () => { expect(result).toHaveAttribute('about', '') @@ -95,10 +95,10 @@ describe('manager', () => { let result beforeAll(() => { const manager = new OutlineManager({ dom: document }) - result = manager.outlineObjectTD(sym('tel:+1-201-555-0123'), null, null, null) + result = manager.outlineObjectDiv(sym('tel:+1-201-555-0123'), null, null, null) }) - it('is a html td element', () => { - expect(result.nodeName).toBe('TD') + it('is a html div element', () => { + expect(result.nodeName).toBe('DIV') }) it('about attribute refers to tel uri', () => { expect(result).toHaveAttribute('about', '') @@ -142,10 +142,10 @@ describe('manager', () => { let result beforeAll(() => { const manager = new OutlineManager({ dom: document }) - result = manager.outlineObjectTD(lit('some text'), null, null, null) + result = manager.outlineObjectDiv(lit('some text'), null, null, null) }) - it('is a html td element', () => { - expect(result.nodeName).toBe('TD') + it('is a html div element', () => { + expect(result.nodeName).toBe('DIV') }) it('has no about attribute', () => { expect(result).not.toHaveAttribute('about') @@ -172,10 +172,10 @@ describe('manager', () => { let result beforeAll(() => { const manager = new OutlineManager({ dom: document }) - result = manager.outlineObjectTD(blankNode('blank-node'), null, null, null) + result = manager.outlineObjectDiv(blankNode('blank-node'), null, null, null) }) - it('is a html td element', () => { - expect(result.nodeName).toBe('TD') + it('is a html div element', () => { + expect(result.nodeName).toBe('DIV') }) it('has about attribute', () => { expect(result).toHaveAttribute('about', '_:blank-node') @@ -193,5 +193,16 @@ describe('manager', () => { expect(result).toHaveTextContent('...') }) }) + + describe('outlineObjectTD compatibility alias', () => { + it('returns the same div-based object block', () => { + const manager = new OutlineManager({ dom: document }) + const result = manager.outlineObjectTD(sym('https://alias.example/'), null, null, null) + + expect(result.nodeName).toBe('DIV') + expect(result).toHaveAttribute('about', '') + expect(result).toHaveClass('obj') + }) + }) }) })