profile-pane 3.1.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +16 -0
  2. package/lib/04567ff683933c35c465.png +0 -0
  3. package/lib/10163fd9b5a0e00d63a0.png +0 -0
  4. package/lib/1234dcb2eec2e45f252b.png +0 -0
  5. package/lib/20899934157df4db56cb.png +0 -0
  6. package/lib/33760bf79f097f449da5.png +0 -0
  7. package/lib/578d2b6ed32e7624164e.png +0 -0
  8. package/lib/5f62a5b2b7e99b9640c7.png +0 -0
  9. package/lib/6525766ecd288ec60129.png +0 -0
  10. package/lib/7800be6f6c4b5b0f4f20.png +0 -0
  11. package/lib/976473cf5fe24d657d4b.png +0 -0
  12. package/lib/ChatWithMe.d.ts +2 -1
  13. package/lib/ChatWithMe.d.ts.map +1 -1
  14. package/lib/ChatWithMe.js +3 -3
  15. package/lib/ProfileView.d.ts +1 -1
  16. package/lib/ProfileView.d.ts.map +1 -1
  17. package/lib/ProfileView.js +71 -131
  18. package/lib/ProfileViewModelPresenter.d.ts +23 -0
  19. package/lib/ProfileViewModelPresenter.d.ts.map +1 -0
  20. package/lib/ProfileViewModelPresenter.js +37 -0
  21. package/lib/QRCodeCard.d.ts +3 -1
  22. package/lib/QRCodeCard.d.ts.map +1 -1
  23. package/lib/QRCodeCard.js +86 -66
  24. package/lib/addMeToYourFriends.d.ts +3 -3
  25. package/lib/addMeToYourFriends.d.ts.map +1 -1
  26. package/lib/addMeToYourFriends.js +14 -30
  27. package/lib/bda84f59e7216675a208.png +0 -0
  28. package/lib/buttonsHelper.js +1 -1
  29. package/lib/cd68e8f3990ba8b2139e.png +0 -0
  30. package/lib/e7074a7e2cb69e51cfd3.png +0 -0
  31. package/lib/editProfilePane/EditCVCard.d.ts +1 -0
  32. package/lib/editProfilePane/EditCVCard.d.ts.map +1 -1
  33. package/lib/editProfilePane/EditCVCard.js +2 -1
  34. package/lib/editProfilePane/EditCommunitiesCard.d.ts +1 -1
  35. package/lib/editProfilePane/EditCommunitiesCard.d.ts.map +1 -1
  36. package/lib/editProfilePane/EditCommunitiesCard.js +2 -1
  37. package/lib/editProfilePane/EditContactsCard.d.ts +1 -0
  38. package/lib/editProfilePane/EditContactsCard.d.ts.map +1 -1
  39. package/lib/editProfilePane/EditContactsCard.js +2 -0
  40. package/lib/editProfilePane/EditFriendsCard.d.ts +1 -1
  41. package/lib/editProfilePane/EditFriendsCard.d.ts.map +1 -1
  42. package/lib/editProfilePane/EditFriendsCard.js +2 -1
  43. package/lib/editProfilePane/EditOtherPreferences.d.ts +1 -0
  44. package/lib/editProfilePane/EditOtherPreferences.d.ts.map +1 -1
  45. package/lib/editProfilePane/EditOtherPreferences.js +1 -0
  46. package/lib/editProfilePane/EditProfileView.d.ts +1 -1
  47. package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
  48. package/lib/editProfilePane/EditProfileView.js +1 -1
  49. package/lib/editProfilePane/EditSocialCard.d.ts +1 -0
  50. package/lib/editProfilePane/EditSocialCard.d.ts.map +1 -1
  51. package/lib/editProfilePane/EditSocialCard.js +2 -1
  52. package/lib/editProfilePane/editProfilePresenter.d.ts +1 -0
  53. package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
  54. package/lib/editProfilePane/editProfilePresenter.js +2 -0
  55. package/lib/f3772696fb7ee53c23d8.png +0 -0
  56. package/lib/icons-svg/contactIcons.d.ts +3 -0
  57. package/lib/icons-svg/contactIcons.d.ts.map +1 -0
  58. package/lib/icons-svg/contactIcons.js +32 -0
  59. package/lib/icons-svg/profileIcons.d.ts +22 -0
  60. package/lib/icons-svg/profileIcons.d.ts.map +1 -0
  61. package/lib/icons-svg/profileIcons.js +309 -0
  62. package/lib/index.d.ts +1 -3
  63. package/lib/index.d.ts.map +1 -1
  64. package/lib/index.js +42 -19
  65. package/lib/profile-pane.js +15629 -5666
  66. package/lib/profile-pane.js.map +1 -1
  67. package/lib/profile-pane.min.js +2171 -230
  68. package/lib/profile-pane.min.js.map +1 -1
  69. package/lib/rdfFormsHelper.d.ts +1 -0
  70. package/lib/rdfFormsHelper.d.ts.map +1 -1
  71. package/lib/rdfFormsHelper.js +2 -0
  72. package/lib/sections/bio/BioEditDialog.d.ts +6 -0
  73. package/lib/sections/bio/BioEditDialog.d.ts.map +1 -0
  74. package/lib/sections/bio/BioEditDialog.js +119 -0
  75. package/lib/sections/bio/BioSection.d.ts +7 -0
  76. package/lib/sections/bio/BioSection.d.ts.map +1 -0
  77. package/lib/sections/bio/BioSection.js +131 -0
  78. package/lib/sections/bio/mutations.d.ts +4 -0
  79. package/lib/sections/bio/mutations.d.ts.map +1 -0
  80. package/lib/sections/bio/mutations.js +43 -0
  81. package/lib/sections/bio/selectors.d.ts +4 -0
  82. package/lib/sections/bio/selectors.d.ts.map +1 -0
  83. package/lib/sections/bio/selectors.js +15 -0
  84. package/lib/sections/bio/types.d.ts +15 -0
  85. package/lib/sections/bio/types.d.ts.map +1 -0
  86. package/lib/sections/bio/types.js +5 -0
  87. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +7 -0
  88. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -0
  89. package/lib/sections/contactInfo/ContactInfoEditDialog.js +658 -0
  90. package/lib/sections/contactInfo/ContactInfoSection.d.ts +5 -0
  91. package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -0
  92. package/lib/sections/contactInfo/ContactInfoSection.js +229 -0
  93. package/lib/sections/contactInfo/mutations.d.ts +4 -0
  94. package/lib/sections/contactInfo/mutations.d.ts.map +1 -0
  95. package/lib/sections/contactInfo/mutations.js +150 -0
  96. package/lib/sections/contactInfo/selectors.d.ts +4 -0
  97. package/lib/sections/contactInfo/selectors.d.ts.map +1 -0
  98. package/lib/sections/contactInfo/selectors.js +104 -0
  99. package/lib/sections/contactInfo/types.d.ts +44 -0
  100. package/lib/sections/contactInfo/types.d.ts.map +1 -0
  101. package/lib/sections/contactInfo/types.js +5 -0
  102. package/lib/sections/education/EducationEditDialog.d.ts +7 -0
  103. package/lib/sections/education/EducationEditDialog.d.ts.map +1 -0
  104. package/lib/sections/education/EducationEditDialog.js +459 -0
  105. package/lib/sections/education/EducationSection.d.ts +7 -0
  106. package/lib/sections/education/EducationSection.d.ts.map +1 -0
  107. package/lib/sections/education/EducationSection.js +126 -0
  108. package/lib/sections/education/mutations.d.ts +4 -0
  109. package/lib/sections/education/mutations.d.ts.map +1 -0
  110. package/lib/sections/education/mutations.js +60 -0
  111. package/lib/sections/education/selectors.d.ts +4 -0
  112. package/lib/sections/education/selectors.d.ts.map +1 -0
  113. package/lib/sections/education/selectors.js +64 -0
  114. package/lib/sections/education/types.d.ts +20 -0
  115. package/lib/sections/education/types.d.ts.map +1 -0
  116. package/lib/sections/education/types.js +5 -0
  117. package/lib/sections/heading/HeadingEditDialog.d.ts +6 -0
  118. package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -0
  119. package/lib/sections/heading/HeadingEditDialog.js +742 -0
  120. package/lib/sections/heading/HeadingSection.d.ts +9 -0
  121. package/lib/sections/heading/HeadingSection.d.ts.map +1 -0
  122. package/lib/sections/heading/HeadingSection.js +97 -0
  123. package/lib/sections/heading/camera.d.ts +19 -0
  124. package/lib/sections/heading/camera.d.ts.map +1 -0
  125. package/lib/sections/heading/camera.js +199 -0
  126. package/lib/sections/heading/dateHelpers.d.ts +4 -0
  127. package/lib/sections/heading/dateHelpers.d.ts.map +1 -0
  128. package/lib/sections/heading/dateHelpers.js +48 -0
  129. package/lib/sections/heading/imageHelpers.d.ts +4 -0
  130. package/lib/sections/heading/imageHelpers.d.ts.map +1 -0
  131. package/lib/sections/heading/imageHelpers.js +81 -0
  132. package/lib/sections/heading/mutations.d.ts +4 -0
  133. package/lib/sections/heading/mutations.d.ts.map +1 -0
  134. package/lib/sections/heading/mutations.js +190 -0
  135. package/lib/sections/heading/selectors.d.ts +5 -0
  136. package/lib/sections/heading/selectors.d.ts.map +1 -0
  137. package/lib/sections/heading/selectors.js +157 -0
  138. package/lib/sections/heading/types.d.ts +36 -0
  139. package/lib/sections/heading/types.d.ts.map +1 -0
  140. package/lib/sections/heading/types.js +5 -0
  141. package/lib/sections/languages/LanguageEditDialog.d.ts +7 -0
  142. package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -0
  143. package/lib/sections/languages/LanguageEditDialog.js +457 -0
  144. package/lib/sections/languages/LanguageSection.d.ts +5 -0
  145. package/lib/sections/languages/LanguageSection.d.ts.map +1 -0
  146. package/lib/sections/languages/LanguageSection.js +137 -0
  147. package/lib/sections/languages/mutations.d.ts +6 -0
  148. package/lib/sections/languages/mutations.d.ts.map +1 -0
  149. package/lib/sections/languages/mutations.js +296 -0
  150. package/lib/sections/languages/selectors.d.ts +5 -0
  151. package/lib/sections/languages/selectors.d.ts.map +1 -0
  152. package/lib/sections/languages/selectors.js +146 -0
  153. package/lib/sections/languages/types.d.ts +15 -0
  154. package/lib/sections/languages/types.d.ts.map +1 -0
  155. package/lib/sections/languages/types.js +5 -0
  156. package/lib/sections/projects/ProjectEditDialog.d.ts +7 -0
  157. package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -0
  158. package/lib/sections/projects/ProjectEditDialog.js +182 -0
  159. package/lib/sections/projects/ProjectSection.d.ts +6 -0
  160. package/lib/sections/projects/ProjectSection.d.ts.map +1 -0
  161. package/lib/sections/projects/ProjectSection.js +220 -0
  162. package/lib/sections/projects/mutations.d.ts +4 -0
  163. package/lib/sections/projects/mutations.d.ts.map +1 -0
  164. package/lib/sections/projects/mutations.js +188 -0
  165. package/lib/sections/projects/selectors.d.ts +5 -0
  166. package/lib/sections/projects/selectors.d.ts.map +1 -0
  167. package/lib/sections/projects/selectors.js +163 -0
  168. package/lib/sections/projects/types.d.ts +28 -0
  169. package/lib/sections/projects/types.d.ts.map +1 -0
  170. package/lib/sections/projects/types.js +8 -0
  171. package/lib/sections/resume/ResumeEditDialog.d.ts +7 -0
  172. package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -0
  173. package/lib/sections/resume/ResumeEditDialog.js +629 -0
  174. package/lib/sections/resume/ResumeSection.d.ts +7 -0
  175. package/lib/sections/resume/ResumeSection.d.ts.map +1 -0
  176. package/lib/sections/resume/ResumeSection.js +160 -0
  177. package/lib/sections/resume/mutations.d.ts +6 -0
  178. package/lib/sections/resume/mutations.d.ts.map +1 -0
  179. package/lib/sections/resume/mutations.js +172 -0
  180. package/lib/sections/resume/selectors.d.ts +4 -0
  181. package/lib/sections/resume/selectors.d.ts.map +1 -0
  182. package/lib/sections/resume/selectors.js +142 -0
  183. package/lib/sections/resume/types.d.ts +33 -0
  184. package/lib/sections/resume/types.d.ts.map +1 -0
  185. package/lib/sections/resume/types.js +8 -0
  186. package/lib/sections/shared/collapsibleSection.d.ts +2 -0
  187. package/lib/sections/shared/collapsibleSection.d.ts.map +1 -0
  188. package/lib/sections/shared/collapsibleSection.js +24 -0
  189. package/lib/sections/shared/contactTypeUtils.d.ts +7 -0
  190. package/lib/sections/shared/contactTypeUtils.d.ts.map +1 -0
  191. package/lib/sections/shared/contactTypeUtils.js +48 -0
  192. package/lib/sections/shared/idNodeFactory.d.ts +3 -0
  193. package/lib/sections/shared/idNodeFactory.d.ts.map +1 -0
  194. package/lib/sections/shared/idNodeFactory.js +14 -0
  195. package/lib/sections/shared/phoneCountries.d.ts +20 -0
  196. package/lib/sections/shared/phoneCountries.d.ts.map +1 -0
  197. package/lib/sections/shared/phoneCountries.js +1080 -0
  198. package/lib/sections/shared/rdfList.d.ts +3 -0
  199. package/lib/sections/shared/rdfList.d.ts.map +1 -0
  200. package/lib/sections/shared/rdfList.js +34 -0
  201. package/lib/sections/shared/rdfMutationHelpers.d.ts +12 -0
  202. package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -0
  203. package/lib/sections/shared/rdfMutationHelpers.js +82 -0
  204. package/lib/sections/shared/rowState.d.ts +21 -0
  205. package/lib/sections/shared/rowState.d.ts.map +1 -0
  206. package/lib/sections/shared/rowState.js +52 -0
  207. package/lib/sections/shared/sanitizeUtils.d.ts +5 -0
  208. package/lib/sections/shared/sanitizeUtils.d.ts.map +1 -0
  209. package/lib/sections/shared/sanitizeUtils.js +22 -0
  210. package/lib/sections/shared/sectionCardHelpers.d.ts +11 -0
  211. package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -0
  212. package/lib/sections/shared/sectionCardHelpers.js +105 -0
  213. package/lib/sections/shared/types.d.ts +7 -0
  214. package/lib/sections/shared/types.d.ts.map +1 -0
  215. package/lib/sections/shared/types.js +5 -0
  216. package/lib/sections/skills/SkillsEditDialog.d.ts +7 -0
  217. package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -0
  218. package/lib/sections/skills/SkillsEditDialog.js +340 -0
  219. package/lib/sections/skills/SkillsSection.d.ts +5 -0
  220. package/lib/sections/skills/SkillsSection.d.ts.map +1 -0
  221. package/lib/sections/skills/SkillsSection.js +169 -0
  222. package/lib/sections/skills/mutations.d.ts +6 -0
  223. package/lib/sections/skills/mutations.d.ts.map +1 -0
  224. package/lib/sections/skills/mutations.js +110 -0
  225. package/lib/sections/skills/selectors.d.ts +6 -0
  226. package/lib/sections/skills/selectors.d.ts.map +1 -0
  227. package/lib/sections/skills/selectors.js +37 -0
  228. package/lib/sections/skills/types.d.ts +14 -0
  229. package/lib/sections/skills/types.d.ts.map +1 -0
  230. package/lib/sections/skills/types.js +5 -0
  231. package/lib/sections/social/SocialEditDialog.d.ts +7 -0
  232. package/lib/sections/social/SocialEditDialog.d.ts.map +1 -0
  233. package/lib/sections/social/SocialEditDialog.js +362 -0
  234. package/lib/sections/social/SocialSection.d.ts +8 -0
  235. package/lib/sections/social/SocialSection.d.ts.map +1 -0
  236. package/lib/sections/social/SocialSection.js +201 -0
  237. package/lib/sections/social/constants.d.ts +3 -0
  238. package/lib/sections/social/constants.d.ts.map +1 -0
  239. package/lib/sections/social/constants.js +16 -0
  240. package/lib/sections/social/helpers.d.ts +15 -0
  241. package/lib/sections/social/helpers.d.ts.map +1 -0
  242. package/lib/sections/social/helpers.js +316 -0
  243. package/lib/sections/social/mutations.d.ts +4 -0
  244. package/lib/sections/social/mutations.d.ts.map +1 -0
  245. package/lib/sections/social/mutations.js +298 -0
  246. package/lib/sections/social/selectors.d.ts +4 -0
  247. package/lib/sections/social/selectors.d.ts.map +1 -0
  248. package/lib/sections/social/selectors.js +43 -0
  249. package/lib/sections/social/types.d.ts +19 -0
  250. package/lib/sections/social/types.d.ts.map +1 -0
  251. package/lib/sections/social/types.js +5 -0
  252. package/lib/styles/BioSection.css +77 -0
  253. package/lib/styles/CVCard.css +107 -2
  254. package/lib/styles/ContactInfoEditDialog.css +153 -0
  255. package/lib/styles/EditDialogs.css +1028 -0
  256. package/lib/styles/EducationCard.css +103 -0
  257. package/lib/styles/HeadingSection.css +309 -0
  258. package/lib/styles/ProfileCard.css +10 -42
  259. package/lib/styles/ProfileView.css +53 -8
  260. package/lib/styles/ProjectsCard.css +206 -0
  261. package/lib/styles/QRCodeCard.css +29 -10
  262. package/lib/styles/SocialCard.css +41 -13
  263. package/lib/styles/dialog.css +209 -0
  264. package/lib/styles/utilities.css +638 -256
  265. package/lib/textUtils.d.ts +6 -0
  266. package/lib/textUtils.d.ts.map +1 -0
  267. package/lib/textUtils.js +44 -0
  268. package/lib/texts.d.ts +45 -4
  269. package/lib/texts.d.ts.map +1 -1
  270. package/lib/texts.js +46 -5
  271. package/lib/types.d.ts +2 -0
  272. package/lib/types.d.ts.map +1 -0
  273. package/lib/types.js +5 -0
  274. package/lib/ui/dialog.d.ts +29 -0
  275. package/lib/ui/dialog.d.ts.map +1 -0
  276. package/lib/ui/dialog.js +269 -0
  277. package/lib/ui/errors.d.ts +2 -0
  278. package/lib/ui/errors.d.ts.map +1 -0
  279. package/lib/ui/errors.js +10 -0
  280. package/package.json +8 -6
  281. package/lib/CVCard.d.ts +0 -4
  282. package/lib/CVCard.d.ts.map +0 -1
  283. package/lib/CVCard.js +0 -114
  284. package/lib/CVPresenter.d.ts +0 -25
  285. package/lib/CVPresenter.d.ts.map +0 -1
  286. package/lib/CVPresenter.js +0 -119
  287. package/lib/FriendList.d.ts +0 -6
  288. package/lib/FriendList.d.ts.map +0 -1
  289. package/lib/FriendList.js +0 -27
  290. package/lib/ProfileCard.d.ts +0 -6
  291. package/lib/ProfileCard.d.ts.map +0 -1
  292. package/lib/ProfileCard.js +0 -62
  293. package/lib/SocialCard.d.ts +0 -5
  294. package/lib/SocialCard.d.ts.map +0 -1
  295. package/lib/SocialCard.js +0 -51
  296. package/lib/SocialPresenter.d.ts +0 -11
  297. package/lib/SocialPresenter.d.ts.map +0 -1
  298. package/lib/SocialPresenter.js +0 -117
  299. package/lib/StuffCard.d.ts +0 -10
  300. package/lib/StuffCard.d.ts.map +0 -1
  301. package/lib/StuffCard.js +0 -52
  302. package/lib/StuffPresenter.d.ts +0 -14
  303. package/lib/StuffPresenter.d.ts.map +0 -1
  304. package/lib/StuffPresenter.js +0 -53
  305. package/lib/presenter.d.ts +0 -14
  306. package/lib/presenter.d.ts.map +0 -1
  307. package/lib/presenter.js +0 -68
  308. package/lib/styles/FriendList.css +0 -12
  309. package/lib/styles/StuffCard.css +0 -23
  310. package/lib/styles/editProfile.css +0 -62
  311. package/lib/styles/profileRDFFormsEnforced.css +0 -427
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.processLanguageMutations = processLanguageMutations;
7
+ var _rdflib = require("rdflib");
8
+ var _solidUi = require("solid-ui");
9
+ var _selectors = require("./selectors");
10
+ var _rdfList = require("../shared/rdfList");
11
+ var _idNodeFactory = require("../shared/idNodeFactory");
12
+ var _texts = require("../../texts");
13
+ // Language entries are serialized as an ordered rdf:List of id nodes, where
14
+ // each id node points to an IANA URI via solid:publicId.
15
+ const LANGUAGE_IANA_NS = 'https://www.w3.org/ns/iana/language-code/';
16
+ function ensureLanguagePrefix(store) {
17
+ const registerPrefix = target => {
18
+ if (!target) return;
19
+ if (typeof target.setPrefixForURI === 'function') {
20
+ target.setPrefixForURI('l', LANGUAGE_IANA_NS);
21
+ return;
22
+ }
23
+ if (!target.namespaces) {
24
+ target.namespaces = {};
25
+ }
26
+ target.namespaces.l = LANGUAGE_IANA_NS;
27
+ };
28
+ const anyStore = store;
29
+ registerPrefix(anyStore);
30
+ registerPrefix(anyStore?.updater?.store);
31
+ }
32
+ function normalizeText(value) {
33
+ return (value || '').trim();
34
+ }
35
+ function normalizeLanguageCode(value) {
36
+ const normalized = normalizeText(value).toLowerCase();
37
+ if (!normalized) return '';
38
+ if (normalized.startsWith(LANGUAGE_IANA_NS)) {
39
+ return normalized.slice(LANGUAGE_IANA_NS.length);
40
+ }
41
+ return normalized;
42
+ }
43
+ function rowsFromOrderedInput(orderedRows) {
44
+ return (orderedRows || []).filter(row => row.status !== 'deleted').filter(row => Boolean(normalizeText(row.publicId) || normalizeText(row.name) || normalizeText(row.entryNode))).map(row => ({
45
+ ...row,
46
+ name: normalizeText(row.name),
47
+ publicId: normalizeText(row.publicId),
48
+ proficiency: normalizeText(row.proficiency),
49
+ entryNode: normalizeText(row.entryNode)
50
+ }));
51
+ }
52
+ function buildRdfListStatements(items, doc) {
53
+ if (!items.length) {
54
+ return {
55
+ head: _solidUi.ns.rdf('nil'),
56
+ statements: []
57
+ };
58
+ }
59
+ const listNodes = items.map(() => (0, _rdflib.blankNode)());
60
+ const statements = [];
61
+ items.forEach((item, index) => {
62
+ const current = listNodes[index];
63
+ const next = listNodes[index + 1] || _solidUi.ns.rdf('nil');
64
+ statements.push((0, _rdflib.st)(current, _solidUi.ns.rdf('first'), item, doc));
65
+ statements.push((0, _rdflib.st)(current, _solidUi.ns.rdf('rest'), next, doc));
66
+ });
67
+ return {
68
+ head: listNodes[0],
69
+ statements
70
+ };
71
+ }
72
+ function buildLanguageStatements(subject, doc, rows) {
73
+ const languageRows = rows.map(row => ({
74
+ name: normalizeText(row.name),
75
+ publicId: normalizeLanguageCode(row.publicId)
76
+ })).filter(row => Boolean(row.publicId));
77
+ if (languageRows.length === 0) return [];
78
+ const entryNodes = languageRows.map(() => (0, _idNodeFactory.createIdNode)(doc));
79
+ const statements = [];
80
+ const rdfList = buildRdfListStatements(entryNodes, doc);
81
+ statements.push((0, _rdflib.st)(subject, _solidUi.ns.schema('knowsLanguage'), rdfList.head, doc));
82
+ statements.push(...rdfList.statements);
83
+ entryNodes.forEach((entryNode, index) => {
84
+ const publicIdNode = (0, _rdflib.sym)(`${LANGUAGE_IANA_NS}${languageRows[index].publicId}`);
85
+ statements.push((0, _rdflib.st)(entryNode, _solidUi.ns.solid('publicId'), publicIdNode, doc));
86
+ if (languageRows[index].name) {
87
+ statements.push((0, _rdflib.st)(publicIdNode, _solidUi.ns.schema('name'), (0, _rdflib.literal)(languageRows[index].name, 'en'), doc));
88
+ }
89
+ });
90
+ return statements;
91
+ }
92
+ function collectListChainNodes(store, listHead, doc) {
93
+ const visited = new Set();
94
+ const nodes = [];
95
+ let current = listHead;
96
+ while (current) {
97
+ const key = `${current.termType}:${current.value}`;
98
+ if (visited.has(key)) break;
99
+ visited.add(key);
100
+ nodes.push(current);
101
+ const rest = store.any(current, _solidUi.ns.rdf('rest'), null, doc);
102
+ if (!rest || rest.termType === 'NamedNode' && rest.value === _solidUi.ns.rdf('nil').value) {
103
+ break;
104
+ }
105
+ current = rest;
106
+ }
107
+ return nodes;
108
+ }
109
+ function isPatchFailure(message) {
110
+ const text = (message || '').toLowerCase();
111
+ // Different pods surface PATCH incompatibility with different status codes/messages.
112
+ return text.includes(' on patch ') || text.includes('web error: 501') || text.includes('web error: 405') || text.includes('web error: 400');
113
+ }
114
+ function isMissingGetRecordError(message) {
115
+ return (message || '').toLowerCase().includes('no record of our http get request for document');
116
+ }
117
+ function statementKey(statement) {
118
+ return `${statement.subject?.toNT?.() || statement.subject?.value} ${statement.predicate?.toNT?.() || statement.predicate?.value} ${statement.object?.toNT?.() || statement.object?.value} ${statement.why?.toNT?.() || statement.why?.value}`;
119
+ }
120
+ function sanitizePatchStatements(store, deletions, insertions) {
121
+ const safeDeletions = Array.from(new Map((deletions || []).filter(statement => {
122
+ if (!statement || !statement.subject || !statement.predicate || !statement.object) return false;
123
+ if (store.holds(statement.subject, statement.predicate, statement.object, statement.why)) return true;
124
+ return store.statementsMatching(statement.subject, statement.predicate, statement.object, statement.why).length > 0;
125
+ }).map(statement => [statementKey(statement), statement])).values());
126
+ const safeInsertions = Array.from(new Map((insertions || []).filter(statement => Boolean(statement && statement.subject && statement.predicate && statement.object)).map(statement => [statementKey(statement), statement])).values());
127
+ return {
128
+ safeDeletions,
129
+ safeInsertions
130
+ };
131
+ }
132
+ async function runPutFallback(store, doc, deletions, insertions) {
133
+ const updater = store.updater;
134
+ const fetcher = store.fetcher;
135
+ if (!updater || typeof updater.serialize !== 'function' || !fetcher || typeof fetcher.webOperation !== 'function') {
136
+ throw new Error('Language updates are not supported by this store updater.');
137
+ }
138
+ const currentStatements = store.statementsMatching(undefined, undefined, undefined, doc).slice();
139
+ const deletionKeys = new Set((deletions || []).map(statement => statementKey(statement)));
140
+ // Rebuild full document state for PUT when patch-oriented flows cannot be used.
141
+ const nextStatements = currentStatements.filter(statement => !deletionKeys.has(statementKey(statement))).concat(insertions || []);
142
+ const contentType = 'text/turtle';
143
+ const body = updater.serialize(doc.value, nextStatements, contentType);
144
+ const response = await fetcher.webOperation('PUT', doc.value, {
145
+ noMeta: true,
146
+ contentType,
147
+ body
148
+ });
149
+ if (!response || response.ok !== true) {
150
+ const status = response?.status || 'unknown';
151
+ throw new Error(`Web error: ${status} on PUT of <${doc.value}>`);
152
+ }
153
+
154
+ // PUT bypasses UpdateManager's local-store patching, so apply the same changes locally.
155
+ store.remove(deletions);
156
+ insertions.forEach(statement => {
157
+ store.add(statement.subject, statement.predicate, statement.object, statement.why);
158
+ });
159
+ }
160
+ async function runUpdateWithDavFallback(store, doc, deletions, insertions) {
161
+ const updater = store.updater;
162
+ if (!updater || typeof updater.update !== 'function') {
163
+ throw new Error('Language updates are not supported by this store updater.');
164
+ }
165
+ const {
166
+ safeDeletions,
167
+ safeInsertions
168
+ } = sanitizePatchStatements(store, deletions, insertions);
169
+ if (safeDeletions.length === 0 && safeInsertions.length === 0) {
170
+ return;
171
+ }
172
+ const tryUpdate = () => new Promise((resolve, reject) => {
173
+ updater.update(safeDeletions, safeInsertions, (_uri, ok, message) => {
174
+ if (ok === true) {
175
+ resolve();
176
+ return;
177
+ }
178
+ reject(new Error(message || 'Failed to save languages'));
179
+ });
180
+ });
181
+ try {
182
+ // Preferred path: let rdflib pick the server-supported update protocol.
183
+ await tryUpdate();
184
+ return;
185
+ } catch (error) {
186
+ const message = error instanceof Error ? error.message : String(error);
187
+ if (!isPatchFailure(message) || typeof updater.updateDav !== 'function') {
188
+ throw error;
189
+ }
190
+ if (store.fetcher && typeof store.fetcher.load === 'function') {
191
+ try {
192
+ await store.fetcher.load(doc);
193
+ } catch {
194
+ // Continue; updateDav may still fail and we handle that below.
195
+ }
196
+ }
197
+ try {
198
+ // First fallback for PATCH failures: DAV-style whole-document update.
199
+ await new Promise((resolve, reject) => {
200
+ updater.updateDav(doc, safeDeletions, safeInsertions, (_uri, ok, body) => {
201
+ if (ok === true) {
202
+ resolve();
203
+ return;
204
+ }
205
+ reject(new Error(body || message || 'Failed to save languages'));
206
+ });
207
+ });
208
+ } catch (davError) {
209
+ const davMessage = davError instanceof Error ? davError.message : String(davError);
210
+ if (!isMissingGetRecordError(davMessage)) {
211
+ throw davError;
212
+ }
213
+ // Some stores cannot run updateDav without prior fetch metadata; use direct PUT.
214
+ await runPutFallback(store, doc, safeDeletions, safeInsertions);
215
+ }
216
+ }
217
+ }
218
+ function mergeLanguageOps(existingRows, languageOps) {
219
+ const byEntryNode = new Map();
220
+ existingRows.forEach(row => {
221
+ byEntryNode.set(row.entryNode, row);
222
+ });
223
+ languageOps.remove.forEach(row => {
224
+ if (!row.entryNode) return;
225
+ byEntryNode.delete(row.entryNode);
226
+ });
227
+ languageOps.update.forEach(row => {
228
+ if (!row.entryNode) return;
229
+ if (!byEntryNode.has(row.entryNode)) return;
230
+ byEntryNode.set(row.entryNode, row);
231
+ });
232
+ languageOps.create.forEach(row => {
233
+ if (!normalizeText(row.publicId)) return;
234
+ byEntryNode.set(`new:${row.name}:${Math.random()}`, {
235
+ ...row,
236
+ publicId: normalizeText(row.publicId),
237
+ proficiency: normalizeText(row.proficiency)
238
+ });
239
+ });
240
+ const dedupedByLanguage = new Map();
241
+ Array.from(byEntryNode.values()).forEach(row => {
242
+ const publicId = normalizeText(row.publicId);
243
+ if (!publicId) return;
244
+ if (!dedupedByLanguage.has(publicId)) {
245
+ dedupedByLanguage.set(publicId, {
246
+ ...row,
247
+ publicId,
248
+ proficiency: normalizeText(row.proficiency)
249
+ });
250
+ }
251
+ });
252
+ return Array.from(dedupedByLanguage.values());
253
+ }
254
+ async function mutateLanguageEntries(store, subject, languageOps, orderedRows) {
255
+ ensureLanguagePrefix(store);
256
+ const doc = subject.doc();
257
+ const existingRows = (0, _selectors.presentLanguages)(subject, store).map(detail => ({
258
+ name: normalizeText(detail.name),
259
+ publicId: normalizeText(detail.publicId),
260
+ proficiency: normalizeText(detail.proficiency),
261
+ entryNode: detail.entryNode.value,
262
+ status: 'existing'
263
+ }));
264
+ const nextRows = orderedRows && orderedRows.length ? rowsFromOrderedInput(orderedRows) : mergeLanguageOps(existingRows, languageOps);
265
+ const listObjects = store.each(subject, _solidUi.ns.schema('knowsLanguage'), null, doc);
266
+ const existingListHeads = listObjects.filter(node => node.termType === 'BlankNode' || node.termType === 'NamedNode');
267
+ const existingListNodes = Array.from(new Map(existingListHeads.flatMap(node => collectListChainNodes(store, node, doc)).map(node => [`${node.termType}:${node.value}`, node])).values());
268
+ const existingLanguageNodes = Array.from(new Set(listObjects.flatMap(node => (0, _rdfList.expandRdfList)(store, node)).filter(node => node.termType === 'NamedNode' || node.termType === 'BlankNode').map(node => `${node.termType}:${node.value}`))).map(key => {
269
+ const [termType, ...rest] = key.split(':');
270
+ const value = rest.join(':');
271
+ return termType === 'BlankNode' ? store.bnode(value) : store.sym(value);
272
+ });
273
+ const existingPublicIdNodes = Array.from(new Map(existingLanguageNodes.map(node => store.any(node, _solidUi.ns.solid('publicId'), null, doc)).filter(node => Boolean(node && node.termType === 'NamedNode')).map(node => [`${node.termType}:${node.value}`, node])).values());
274
+ const deletions = store.statementsMatching(subject, _solidUi.ns.schema('knowsLanguage'), null, doc);
275
+ existingListNodes.forEach(node => {
276
+ deletions.push(...store.statementsMatching(node, null, null, doc));
277
+ });
278
+ existingLanguageNodes.forEach(node => {
279
+ // Remove old language-entry statements so save always rewrites canonical shape.
280
+ deletions.push(...store.statementsMatching(node, null, null, doc));
281
+ });
282
+ existingPublicIdNodes.forEach(node => {
283
+ // Language labels are attached to the publicId resource (l:xx) and should be removed for deleted rows.
284
+ deletions.push(...store.statementsMatching(node, _solidUi.ns.schema('name'), null, doc));
285
+ });
286
+ const insertions = buildLanguageStatements(subject, doc, nextRows);
287
+ await runUpdateWithDavFallback(store, doc, deletions, insertions);
288
+ }
289
+ async function processLanguageMutations(store, subject, mutationPlan, orderedRows) {
290
+ try {
291
+ await mutateLanguageEntries(store, subject, mutationPlan, orderedRows);
292
+ } catch (error) {
293
+ const message = error instanceof Error ? error.message : String(error);
294
+ throw new Error(`${_texts.mutationSaveLanguagesFailedPrefixText} ${message}`);
295
+ }
296
+ }
@@ -0,0 +1,5 @@
1
+ import { NamedNode, Store, Node, LiveStore } from 'rdflib';
2
+ import { LanguageDetails } from './types';
3
+ export declare function languageAsText(store: Store, lan: Node): string;
4
+ export declare function presentLanguages(subject: NamedNode, store: LiveStore): LanguageDetails[];
5
+ //# sourceMappingURL=selectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../../src/sections/languages/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAO,MAAM,QAAQ,CAAA;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAwIzC,wBAAgB,cAAc,CAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAE,MAAM,CAO9D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,eAAe,EAAE,CA8BxF"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.languageAsText = languageAsText;
7
+ exports.presentLanguages = presentLanguages;
8
+ var _rdflib = require("rdflib");
9
+ var _solidUi = require("solid-ui");
10
+ var _rdfList = require("../shared/rdfList");
11
+ const IANA_LANGUAGE_BASE = 'https://www.w3.org/ns/iana/language-code/';
12
+ function normalizeText(value) {
13
+ return value.replace(/\s+/g, ' ').trim();
14
+ }
15
+ function isRdfListNode(store, node) {
16
+ const hasCollectionElements = Array.isArray(node?.elements);
17
+ if (hasCollectionElements) return true;
18
+ if (node.termType !== 'BlankNode' && node.termType !== 'NamedNode') return false;
19
+ return Boolean(store.any(node, _solidUi.ns.rdf('first')));
20
+ }
21
+ function normalizeLanguageCode(value) {
22
+ return (value || '').trim().toLowerCase();
23
+ }
24
+ function languageNameFromCode(code) {
25
+ const normalized = (code || '').trim().toLowerCase();
26
+ if (!normalized) return '';
27
+ try {
28
+ const DisplayNamesCtor = Intl?.DisplayNames;
29
+ if (typeof DisplayNamesCtor === 'function') {
30
+ const displayNames = new DisplayNamesCtor(['en'], {
31
+ type: 'language'
32
+ });
33
+ const localized = displayNames.of(normalized);
34
+ if (localized) return localized;
35
+ }
36
+ } catch {
37
+ // Fallback below.
38
+ }
39
+ return normalized;
40
+ }
41
+ function languageNameFromPublicId(publicIdValue) {
42
+ const value = (publicIdValue || '').trim();
43
+ if (!value) return '';
44
+ if (value.startsWith(IANA_LANGUAGE_BASE)) {
45
+ const code = normalizeLanguageCode(value.slice(IANA_LANGUAGE_BASE.length));
46
+ return languageNameFromCode(code);
47
+ }
48
+ return languageNameFromCode(value);
49
+ }
50
+ function englishOrAnyLiteralValue(store, subject, predicate) {
51
+ const values = store.statementsMatching(subject, predicate);
52
+ const english = values.find(statement => {
53
+ const language = statement.object?.lang || '';
54
+ return language.toLowerCase().startsWith('en');
55
+ });
56
+ if (english && typeof english.object?.value === 'string') {
57
+ return english.object.value;
58
+ }
59
+ const firstLiteral = values.find(statement => statement.object?.termType === 'Literal');
60
+ if (firstLiteral && typeof firstLiteral.object?.value === 'string') {
61
+ return firstLiteral.object.value;
62
+ }
63
+ return '';
64
+ }
65
+ function englishLabelForNode(store, node) {
66
+ const labels = store.statementsMatching(node, _solidUi.ns.rdfs('label'));
67
+ const english = labels.find(statement => {
68
+ const language = statement.object?.lang || '';
69
+ return language.toLowerCase().startsWith('en');
70
+ });
71
+ if (english && english.object && typeof english.object.value === 'string') {
72
+ return english.object.value;
73
+ }
74
+ return '';
75
+ }
76
+ function languageNameFromIanaNode(store, node) {
77
+ const schemaName = englishOrAnyLiteralValue(store, node, _solidUi.ns.schema('name'));
78
+ if (schemaName) return normalizeText(schemaName);
79
+ const localLabel = englishLabelForNode(store, node);
80
+ if (localLabel) return normalizeText(localLabel);
81
+ if (node.value.startsWith(IANA_LANGUAGE_BASE)) {
82
+ return languageNameFromPublicId(node.value);
83
+ }
84
+ return '';
85
+ }
86
+ function toStoredPublicIdValue(lan, publicIdNode) {
87
+ if (publicIdNode?.termType === 'NamedNode') {
88
+ return publicIdNode.value;
89
+ }
90
+ if (publicIdNode?.termType === 'Literal') {
91
+ const code = normalizeLanguageCode(publicIdNode.value);
92
+ return code || undefined;
93
+ }
94
+ if (lan.termType === 'NamedNode' && lan.value.startsWith(IANA_LANGUAGE_BASE)) {
95
+ return lan.value;
96
+ }
97
+ return undefined;
98
+ }
99
+ function languageNameFromLanguageNode(store, lan, publicIdNode) {
100
+ if (publicIdNode?.termType === 'NamedNode') {
101
+ const nodeName = languageNameFromIanaNode(store, publicIdNode);
102
+ if (nodeName) return nodeName;
103
+ return languageNameFromPublicId(publicIdNode.value);
104
+ }
105
+ if (publicIdNode?.termType === 'Literal') {
106
+ const code = normalizeLanguageCode(publicIdNode.value);
107
+ if (!code) return '';
108
+ const ianaNode = (0, _rdflib.sym)(`${IANA_LANGUAGE_BASE}${code}`);
109
+ const nodeName = languageNameFromIanaNode(store, ianaNode);
110
+ if (nodeName) return nodeName;
111
+ return languageNameFromCode(code);
112
+ }
113
+ if (lan.termType === 'NamedNode') {
114
+ const nodeName = languageNameFromIanaNode(store, lan);
115
+ if (nodeName) return nodeName;
116
+ }
117
+ return '';
118
+ }
119
+ function languageAsText(store, lan) {
120
+ if (lan.termType === 'Literal') return lan.value; // Not normal but allow this
121
+
122
+ if (lan.termType !== 'NamedNode' && lan.termType !== 'BlankNode') return '';
123
+ const publicIdNode = store.any(lan, _solidUi.ns.solid('publicId')) || undefined;
124
+ return languageNameFromLanguageNode(store, lan, publicIdNode);
125
+ }
126
+ function presentLanguages(subject, store) {
127
+ const languageObjects = store.each(subject, _solidUi.ns.schema('knowsLanguage'));
128
+ const expandedLists = languageObjects.filter(node => isRdfListNode(store, node)).map(node => (0, _rdfList.expandRdfList)(store, node));
129
+ const longestList = expandedLists.sort((a, b) => b.length - a.length)[0] || [];
130
+ const standaloneNodes = languageObjects.filter(node => !isRdfListNode(store, node));
131
+ const languageNodes = [...longestList, ...standaloneNodes];
132
+ const details = languageNodes.map(lan => ({
133
+ name: languageAsText(store, lan),
134
+ publicId: toStoredPublicIdValue(lan, store.any(lan, _solidUi.ns.solid('publicId')) || undefined),
135
+ proficiency: store.anyValue(lan, _solidUi.ns.schema('proficiencyLevel')) || undefined,
136
+ entryNode: lan
137
+ })).filter(item => Boolean(item.name));
138
+ const dedupedByLanguage = new Map();
139
+ details.forEach(item => {
140
+ const key = item.publicId || item.name;
141
+ if (!dedupedByLanguage.has(key)) {
142
+ dedupedByLanguage.set(key, item);
143
+ }
144
+ });
145
+ return Array.from(dedupedByLanguage.values());
146
+ }
@@ -0,0 +1,15 @@
1
+ import { Node } from 'rdflib';
2
+ import { RowStatus } from '../shared/types';
3
+ export interface LanguageFields {
4
+ name: string;
5
+ publicId?: string;
6
+ proficiency?: string;
7
+ }
8
+ export interface LanguageDetails extends LanguageFields {
9
+ entryNode: Node;
10
+ }
11
+ export interface LanguageRow extends LanguageFields {
12
+ entryNode: string;
13
+ status: RowStatus;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/sections/languages/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,SAAS,CAAA;CAClB"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,7 @@
1
+ import { ProjectDetails } from './types';
2
+ import '../../styles/EditDialogs.css';
3
+ import '../../styles/ContactInfoEditDialog.css';
4
+ import { LiveStore, NamedNode } from 'rdflib';
5
+ import { ViewerMode } from '../../types';
6
+ export declare function createProjectsEditDialog(event: Event, store: LiveStore, subject: NamedNode, projects: ProjectDetails[], viewerMode: ViewerMode, onSaved?: () => Promise<void> | void): Promise<void>;
7
+ //# sourceMappingURL=ProjectEditDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectEditDialog.d.ts","sourceRoot":"","sources":["../../../src/sections/projects/ProjectEditDialog.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAc,MAAM,SAAS,CAAA;AACpD,OAAO,8BAA8B,CAAA;AACrC,OAAO,wCAAwC,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AA0JxC,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,cAAc,EAAE,EAC1B,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,iBAmDrC"}
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createProjectsEditDialog = createProjectsEditDialog;
7
+ var _dialog = require("../../ui/dialog");
8
+ var _litHtml = require("lit-html");
9
+ require("../../styles/EditDialogs.css");
10
+ require("../../styles/ContactInfoEditDialog.css");
11
+ var _rowState = require("../shared/rowState");
12
+ var _textUtils = require("../../textUtils");
13
+ var _mutations = require("./mutations");
14
+ var _profileIcons = require("../../icons-svg/profileIcons");
15
+ var _texts = require("../../texts");
16
+ function sanitizeProjectFieldValue(value) {
17
+ return (0, _textUtils.sanitizeTextValue)(value);
18
+ }
19
+ function isValidProjectUrl(value) {
20
+ const text = sanitizeProjectFieldValue(value);
21
+ if (!text) return false;
22
+ try {
23
+ const parsed = new URL(text);
24
+ return parsed.protocol === 'https:' && parsed.pathname === '/profile/card' && parsed.hash === '#me';
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ function rowHasContent(row) {
30
+ return [row.url, row.entryNode].some(_textUtils.hasNonEmptyText);
31
+ }
32
+ async function pasteWebIdIntoRow(row) {
33
+ const clipboardText = await navigator.clipboard.readText();
34
+ const url = sanitizeProjectFieldValue(clipboardText);
35
+ if (!url) return '';
36
+ (0, _rowState.applyRowFieldChange)(row, 'url', url, rowHasContent);
37
+ return url;
38
+ }
39
+ function toFormState(_details) {
40
+ return {
41
+ project: {
42
+ url: '',
43
+ entryNode: '',
44
+ status: 'new'
45
+ }
46
+ };
47
+ }
48
+ function validateProjectBeforeSave(row) {
49
+ if (!(0, _textUtils.hasNonEmptyText)(row.url) && !(0, _textUtils.hasNonEmptyText)(row.entryNode)) {
50
+ return 'Add a project WebID.';
51
+ }
52
+ if (!(0, _textUtils.hasNonEmptyText)(row.url)) {
53
+ return 'WebID is required.';
54
+ }
55
+ if (!isValidProjectUrl(row.url)) {
56
+ return 'Please enter a valid WebID in the form https://example.com/profile/card#me.';
57
+ }
58
+ return null;
59
+ }
60
+ function renderProjectInputRow(row, onChange) {
61
+ const projectUrl = 'project-0';
62
+ const handleUrlInput = e => {
63
+ const target = e.target;
64
+ const nextValue = sanitizeProjectFieldValue(target.value);
65
+ (0, _rowState.applyRowFieldChange)(row, 'url', nextValue, rowHasContent);
66
+ };
67
+ const handlePaste = async event => {
68
+ event.preventDefault();
69
+ try {
70
+ const url = await pasteWebIdIntoRow(row);
71
+ onChange();
72
+ if (!isValidProjectUrl(url)) return;
73
+ const dom = event.currentTarget?.ownerDocument || document;
74
+ const saveButton = dom.querySelector('#profile-modal #modal-buttons .btn-primary');
75
+ saveButton?.click();
76
+ } catch {
77
+ // Clipboard access may fail due to browser permissions; keep dialog usable.
78
+ }
79
+ };
80
+ return (0, _litHtml.html)`
81
+ <div class="profile-edit-dialog__row profile-edit-dialog__row--project">
82
+ <label aria-label="Project or community WebID" class="label profile-edit-dialog__field profile-edit-dialog__field--full">
83
+ <p>Type or paste a project or community WebID.</p>
84
+ <div class="profile-edit-dialog__input-wrap">
85
+ <input
86
+ class="input profile-edit-dialog__input--with-action"
87
+ type="text"
88
+ name=${projectUrl}
89
+ .value=${row?.url || ''}
90
+ required
91
+ data-contact-field="url"
92
+ data-entry-node=${row?.entryNode || ''}
93
+ data-row-status=${row?.status || 'n/a'}
94
+ placeholder="Type or paste project/community WebID here"
95
+ autocomplete="off"
96
+ inputmode="text"
97
+ @input=${handleUrlInput}
98
+ />
99
+ <button
100
+ type="button"
101
+ class="profile-edit-dialog__paste-button rounded-sm gap-xxs"
102
+ aria-label="Paste project or community URL from clipboard"
103
+ title=${_texts.pasteEntryButtonTitleText}
104
+ @click=${handlePaste}
105
+ >
106
+ <span class="profile-edit-dialog__paste-icon" aria-hidden="true">${_profileIcons.pasteIcon}</span>
107
+ Paste
108
+ </button>
109
+ </div>
110
+ </label>
111
+ </div>
112
+ `;
113
+ }
114
+ function renderProjectsEditTemplate(form, formState, viewerMode) {
115
+ const rerender = () => renderProjectsEditTemplate(form, formState, viewerMode);
116
+ (0, _litHtml.render)((0, _litHtml.html)`
117
+ ${renderProjectInputRow(formState.project, rerender)}
118
+ ${viewerMode !== 'owner' ? (0, _litHtml.html)`<p class="profile-edit-dialog__login-message">${_texts.ownerLoginRequiredDialogMessageText}</p>` : null}
119
+ `, form);
120
+ }
121
+ function createProjectsEditForm(details, viewerMode) {
122
+ const form = document.createElement('form');
123
+ form.classList.add('profile__edit-form');
124
+ form.classList.add('profile__edit-form--projects');
125
+ const formState = toFormState(details);
126
+ renderProjectsEditTemplate(form, formState, viewerMode);
127
+ return {
128
+ form,
129
+ formState
130
+ };
131
+ }
132
+ async function createProjectsEditDialog(event, store, subject, projects, viewerMode, onSaved) {
133
+ const dom = event.currentTarget?.ownerDocument || document;
134
+ const {
135
+ form,
136
+ formState
137
+ } = createProjectsEditForm(projects, viewerMode);
138
+ const dialogPromise = (0, _dialog.openInputDialog)({
139
+ title: _texts.editProjectsDialogTitleText,
140
+ dom,
141
+ form,
142
+ headerAction: {
143
+ type: 'close'
144
+ },
145
+ validate: () => {
146
+ if (viewerMode !== 'owner') {
147
+ return _texts.ownerLoginRequiredDialogMessageText;
148
+ }
149
+ return validateProjectBeforeSave(formState.project);
150
+ },
151
+ onSave: async () => {
152
+ const projectOps = (0, _rowState.summarizeRowOps)([formState.project], rowHasContent);
153
+ const plan = {
154
+ create: projectOps.create,
155
+ update: projectOps.update,
156
+ remove: projectOps.remove
157
+ };
158
+ await (0, _mutations.processProjectsMutations)(store, subject, plan);
159
+ },
160
+ formatSaveError: error => {
161
+ const message = error instanceof Error ? error.message : String(error);
162
+ return `${_texts.saveProjectsUpdatesFailedPrefixText} ${message}`;
163
+ }
164
+ });
165
+ const modalButtons = dom.querySelector('#profile-modal #modal-buttons');
166
+ const previousButtonsDisplay = modalButtons?.style.display;
167
+ if (modalButtons) {
168
+ modalButtons.style.display = 'none';
169
+ }
170
+ let result = null;
171
+ try {
172
+ result = await dialogPromise;
173
+ } finally {
174
+ if (modalButtons) {
175
+ modalButtons.style.display = previousButtonsDisplay || '';
176
+ }
177
+ }
178
+ if (!result) return;
179
+ if (onSaved) {
180
+ await onSaved();
181
+ }
182
+ }
@@ -0,0 +1,6 @@
1
+ import { LiveStore, NamedNode } from 'rdflib';
2
+ import { ViewerMode } from '../../types';
3
+ import { ProjectDetails } from './types';
4
+ import '../../styles/ProjectsCard.css';
5
+ export declare function renderProjectSection(store: LiveStore, subject: NamedNode, projects: ProjectDetails[], viewerMode: ViewerMode, onSaved?: () => Promise<void> | void): import("lit-html").TemplateResult<1> | "";
6
+ //# sourceMappingURL=ProjectSection.d.ts.map