profile-pane 3.1.5 → 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 -5670
  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 +6 -4
  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 -431
@@ -0,0 +1,340 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createSkillsEditDialog = createSkillsEditDialog;
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
+ const ESCO_SKILL_SEARCH_URI = 'https://ec.europa.eu/esco/api/search?language=$(language)&limit=$(limit)&type=skill&text=$(name)';
17
+ const ESCO_SEARCH_LANGUAGE = 'en';
18
+ const ESCO_SEARCH_LIMIT = 8;
19
+ const ESCO_SKILL_BASE_URI = 'http://data.europa.eu/esco/skill/';
20
+ function normalizeSkillPublicId(value) {
21
+ const normalized = sanitizeSkillFieldValue(value);
22
+ if (!normalized) return '';
23
+ if (normalized.startsWith('skill:')) return normalized;
24
+ if (normalized.startsWith(ESCO_SKILL_BASE_URI)) {
25
+ const suffix = normalized.slice(ESCO_SKILL_BASE_URI.length);
26
+ return suffix ? `skill:${suffix}` : normalized;
27
+ }
28
+ return normalized;
29
+ }
30
+ function buildEscoSkillSearchUrl(name) {
31
+ return ESCO_SKILL_SEARCH_URI.replace('$(language)', encodeURIComponent(ESCO_SEARCH_LANGUAGE)).replace('$(limit)', encodeURIComponent(String(ESCO_SEARCH_LIMIT))).replace('$(name)', encodeURIComponent(name));
32
+ }
33
+ function toSkillLabel(result) {
34
+ return result?.title || result?.searchHit || result?.preferredLabel?.en || result?.uri || '';
35
+ }
36
+ async function fetchEscoSkillSuggestions(name) {
37
+ const query = sanitizeSkillFieldValue(name);
38
+ if (query.length < 2 || typeof fetch !== 'function') return [];
39
+ try {
40
+ const response = await fetch(buildEscoSkillSearchUrl(query), {
41
+ headers: {
42
+ Accept: 'application/json'
43
+ }
44
+ });
45
+ if (!response.ok) return [];
46
+ const payload = await response.json();
47
+ const results = Array.isArray(payload?._embedded?.results) ? payload._embedded.results : [];
48
+ const seen = new Set();
49
+ return results.map(result => {
50
+ const label = sanitizeSkillFieldValue(toSkillLabel(result));
51
+ const uri = typeof result?.uri === 'string' ? result.uri : '';
52
+ return {
53
+ label,
54
+ uri
55
+ };
56
+ }).filter(suggestion => {
57
+ if (!suggestion.label) return false;
58
+ const key = suggestion.label.toLowerCase();
59
+ if (seen.has(key)) return false;
60
+ seen.add(key);
61
+ return true;
62
+ });
63
+ } catch {
64
+ return [];
65
+ }
66
+ }
67
+ function sanitizeSkillFieldValue(value) {
68
+ return (0, _textUtils.sanitizeTextValue)(value);
69
+ }
70
+ function rowHasContent(row) {
71
+ return [row.name].some(_textUtils.hasNonEmptyText);
72
+ }
73
+ function toFormState(details) {
74
+ const rows = (details || []).map(detail => ({
75
+ name: sanitizeSkillFieldValue((0, _textUtils.toText)(detail.name)),
76
+ publicId: normalizeSkillPublicId((0, _textUtils.toText)(detail.publicId)),
77
+ entryNode: (0, _textUtils.toText)(detail.entryNode),
78
+ status: (0, _textUtils.toText)(detail.entryNode) ? 'existing' : 'new'
79
+ })).filter(row => Boolean(row.name || row.publicId || row.entryNode));
80
+ return {
81
+ skills: rows.length ? rows : [{
82
+ name: '',
83
+ publicId: '',
84
+ entryNode: '',
85
+ status: 'new'
86
+ }]
87
+ };
88
+ }
89
+ function matchSkillSuggestion(suggestions, value) {
90
+ const normalized = sanitizeSkillFieldValue(value).toLowerCase();
91
+ if (!normalized) return null;
92
+ return suggestions.find(suggestion => suggestion.label.toLowerCase() === normalized) || null;
93
+ }
94
+ function validateSkillsBeforeSave(rows) {
95
+ const ops = (0, _rowState.summarizeRowOps)(rows, rowHasContent);
96
+ const hasChanges = ops.create.length > 0 || ops.update.length > 0 || ops.remove.length > 0;
97
+ if (!hasChanges) return 'No skill changes detected.';
98
+ for (let i = 0; i < rows.length; i++) {
99
+ const row = rows[i];
100
+ if (!row || row.status === 'deleted') continue;
101
+ if (!(0, _textUtils.hasNonEmptyText)(row.name)) continue;
102
+ if (row.status !== 'existing' && !(0, _textUtils.hasNonEmptyText)(row.publicId)) {
103
+ return `Skill ${i + 1}: please select a skill from the ESCO suggestions.`;
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ function hasInvalidSkillSelection(rows) {
109
+ return rows.some(row => {
110
+ if (!row || row.status === 'deleted') return false;
111
+ if (!(0, _textUtils.hasNonEmptyText)(row.name)) return false;
112
+ return !(0, _textUtils.hasNonEmptyText)(row.publicId);
113
+ });
114
+ }
115
+ function updateSkillsSubmitEnabled(rows) {
116
+ const submitButton = document.querySelector('#profile-modal #modal-buttons button.btn-primary');
117
+ if (!submitButton) return;
118
+ submitButton.disabled = hasInvalidSkillSelection(rows);
119
+ }
120
+ function focusSkillField(form, selector) {
121
+ const nextField = form.querySelector(selector);
122
+ if (!nextField || typeof nextField.focus !== 'function') return;
123
+ nextField.scrollIntoView({
124
+ block: 'start',
125
+ behavior: 'auto'
126
+ });
127
+ nextField.focus();
128
+ if (nextField instanceof HTMLInputElement || nextField instanceof HTMLTextAreaElement) {
129
+ nextField.select();
130
+ }
131
+ }
132
+ function renderSkillInputRow({
133
+ rows,
134
+ index,
135
+ displayIndex,
136
+ onDelete,
137
+ onChange,
138
+ onSkillSearch,
139
+ suggestions
140
+ }) {
141
+ const row = rows[index];
142
+ const label = `Skill ${displayIndex + 1}`;
143
+ const skillName = `skill-${index}`;
144
+ const datalistId = `skill-suggestions-${index}`;
145
+ const hasSelectionIssue = Boolean(row && row.status !== 'deleted' && (0, _textUtils.hasNonEmptyText)(row.name) && !(0, _textUtils.hasNonEmptyText)(row.publicId));
146
+ const handleSkillInput = field => e => {
147
+ const target = e.target;
148
+ const nextValue = sanitizeSkillFieldValue(target.value);
149
+ if (rows[index]) {
150
+ (0, _rowState.applyRowFieldChange)(rows[index], field, nextValue, rowHasContent);
151
+ const matchedSuggestion = matchSkillSuggestion(suggestions, nextValue);
152
+ rows[index].publicId = normalizeSkillPublicId(matchedSuggestion?.uri || '');
153
+ onSkillSearch(index, nextValue);
154
+ onChange();
155
+ }
156
+ };
157
+ const handleDelete = event => {
158
+ event.preventDefault();
159
+ onDelete();
160
+ };
161
+ return (0, _litHtml.html)`
162
+ <div class="profile-edit-dialog__row profile-edit-dialog__row--full profile-edit-dialog__row--skill">
163
+ <label aria-label=${`${label} Name`} class="label profile-edit-dialog__field profile-edit-dialog__field--full">
164
+ <div class="profile-edit-dialog__input-wrap">
165
+ <span class="profile-edit-dialog__search-icon" aria-hidden="true">${_profileIcons.searchIcon}</span>
166
+ <input
167
+ class="input profile-edit-dialog__input--with-leading-icon"
168
+ type="text"
169
+ name=${skillName}
170
+ .value=${row?.name || ''}
171
+ required
172
+ data-contact-field="name"
173
+ data-entry-node=${row?.entryNode || ''}
174
+ data-row-status=${row?.status || 'n/a'}
175
+ placeholder="Skill"
176
+ autocomplete="off"
177
+ list=${datalistId}
178
+ inputmode="text"
179
+ aria-invalid=${hasSelectionIssue ? 'true' : 'false'}
180
+ @input=${handleSkillInput('name')}
181
+ />
182
+ </div>
183
+ <datalist id=${datalistId}>
184
+ ${suggestions.map(suggestion => (0, _litHtml.html)`<option value=${suggestion.label}></option>`)}
185
+ </datalist>
186
+ <small class="profile-edit-dialog__input-help-text">Type to search ESCO and select one suggestion.</small>
187
+ </label>
188
+ <div class="profile-edit-dialog__actions profile-edit-dialog__actions--edge">
189
+ <button
190
+ type="button"
191
+ class="profile-edit-dialog__delete-button"
192
+ aria-label=${`Delete skill ${displayIndex + 1}`}
193
+ title=${_texts.deleteEntryButtonTitleText}
194
+ @click=${handleDelete}
195
+ >
196
+ <span class="profile-edit-dialog__delete-icon" aria-hidden="true">${_profileIcons.trashIcon}</span>
197
+ </button>
198
+ </div>
199
+ </div>
200
+ `;
201
+ }
202
+ function renderSkillsSection(rows, onAddRow, suggestionByIndex, handleSearch) {
203
+ const visibleRows = rows.map((row, index) => ({
204
+ row,
205
+ index
206
+ })).filter(({
207
+ row
208
+ }) => row.status !== 'deleted');
209
+ return (0, _litHtml.html)`
210
+ <section class="profile-edit-dialog__section" aria-label="Skills">
211
+ <fieldset>
212
+ <legend class="sr-only">Skill entries</legend>
213
+ ${visibleRows.map(({
214
+ index
215
+ }, displayIndex) => renderSkillInputRow({
216
+ rows,
217
+ index,
218
+ displayIndex,
219
+ onChange: onAddRow,
220
+ onSkillSearch: handleSearch,
221
+ suggestions: suggestionByIndex[index] || [],
222
+ onDelete: () => {
223
+ (0, _rowState.deleteRow)(rows, index);
224
+ delete suggestionByIndex[index];
225
+ onAddRow();
226
+ }
227
+ }))}
228
+ </fieldset>
229
+ </section>
230
+ `;
231
+ }
232
+ function renderSkillsEditTemplate(form, formState, viewerMode, options = {}) {
233
+ const formStateWithSearch = formState;
234
+ const suggestionByIndex = formStateWithSearch.suggestionByIndex || (formStateWithSearch.suggestionByIndex = {});
235
+ const searchSeqByIndex = formStateWithSearch.searchSeqByIndex || (formStateWithSearch.searchSeqByIndex = {});
236
+ const searchTimerByIndex = formStateWithSearch.searchTimerByIndex || (formStateWithSearch.searchTimerByIndex = {});
237
+ const rerender = (nextOptions = {}) => renderSkillsEditTemplate(form, formState, viewerMode, nextOptions);
238
+ const handleSearch = (rowIndex, term) => {
239
+ if (searchTimerByIndex[rowIndex]) {
240
+ clearTimeout(searchTimerByIndex[rowIndex]);
241
+ }
242
+ const normalized = sanitizeSkillFieldValue(term);
243
+ if (normalized.length < 2) {
244
+ suggestionByIndex[rowIndex] = [];
245
+ rerender();
246
+ return;
247
+ }
248
+ const seq = (searchSeqByIndex[rowIndex] || 0) + 1;
249
+ searchSeqByIndex[rowIndex] = seq;
250
+ searchTimerByIndex[rowIndex] = setTimeout(async () => {
251
+ const suggestions = await fetchEscoSkillSuggestions(normalized);
252
+ if (searchSeqByIndex[rowIndex] !== seq) return;
253
+ suggestionByIndex[rowIndex] = suggestions;
254
+ const row = formState.skills[rowIndex];
255
+ if (row) {
256
+ const matchedSuggestion = matchSkillSuggestion(suggestions, row.name);
257
+ row.publicId = matchedSuggestion ? normalizeSkillPublicId(matchedSuggestion.uri) : row.publicId;
258
+ }
259
+ rerender();
260
+ }, 220);
261
+ };
262
+ (0, _litHtml.render)((0, _litHtml.html)`
263
+ ${renderSkillsSection(formState.skills, rerender, suggestionByIndex, handleSearch)}
264
+ ${viewerMode !== 'owner' ? (0, _litHtml.html)`<p class="profile-edit-dialog__login-message">${_texts.ownerLoginRequiredDialogMessageText}</p>` : null}
265
+ `, form);
266
+ updateSkillsSubmitEnabled(formState.skills);
267
+ if (options.focusSelector) {
268
+ focusSkillField(form, options.focusSelector);
269
+ }
270
+ }
271
+ function createSkillsEditForm(details, viewerMode) {
272
+ const form = document.createElement('form');
273
+ form.classList.add('profile__edit-form');
274
+ const formState = toFormState(details);
275
+ renderSkillsEditTemplate(form, formState, viewerMode);
276
+ const addRow = () => {
277
+ formState.skills.unshift({
278
+ name: '',
279
+ publicId: '',
280
+ entryNode: '',
281
+ status: 'new'
282
+ });
283
+ const formStateWithSearch = formState;
284
+ formStateWithSearch.suggestionByIndex = {};
285
+ formStateWithSearch.searchSeqByIndex = {};
286
+ formStateWithSearch.searchTimerByIndex = {};
287
+ renderSkillsEditTemplate(form, formState, viewerMode, {
288
+ focusSelector: '[name="skill-0"]'
289
+ });
290
+ };
291
+ return {
292
+ form,
293
+ formState,
294
+ addRow
295
+ };
296
+ }
297
+ async function createSkillsEditDialog(event, store, subject, skills, viewerMode, onSaved) {
298
+ const dom = event.currentTarget?.ownerDocument || document;
299
+ const {
300
+ form,
301
+ formState,
302
+ addRow
303
+ } = createSkillsEditForm(skills, viewerMode);
304
+ const result = await (0, _dialog.openInputDialog)({
305
+ title: _texts.editSkillsDialogTitleText,
306
+ dom,
307
+ form,
308
+ headerAction: {
309
+ type: 'button',
310
+ label: '+ Add More',
311
+ ariaLabel: 'Add another skill',
312
+ onClick: addRow
313
+ },
314
+ submitLabel: _texts.dialogSubmitLabelText,
315
+ cancelLabel: _texts.dialogCancelLabelText,
316
+ validate: () => {
317
+ if (viewerMode !== 'owner') {
318
+ return _texts.ownerLoginRequiredDialogMessageText;
319
+ }
320
+ return validateSkillsBeforeSave(formState.skills);
321
+ },
322
+ onSave: async () => {
323
+ const skillOps = (0, _rowState.summarizeRowOps)(formState.skills, rowHasContent);
324
+ const plan = {
325
+ create: skillOps.create,
326
+ update: skillOps.update,
327
+ remove: skillOps.remove
328
+ };
329
+ await (0, _mutations.processSkillsMutations)(store, subject, plan);
330
+ },
331
+ formatSaveError: error => {
332
+ const message = error instanceof Error ? error.message : String(error);
333
+ return `${_texts.saveContactUpdatesFailedPrefixText} ${message}`;
334
+ }
335
+ });
336
+ if (!result) return;
337
+ if (onSaved) {
338
+ await onSaved();
339
+ }
340
+ }
@@ -0,0 +1,5 @@
1
+ import { LiveStore, NamedNode } from 'rdflib';
2
+ import { ViewerMode } from '../../types';
3
+ import { SkillDetails } from './types';
4
+ export declare function renderSkillsSection(store: LiveStore, subject: NamedNode, skills: SkillDetails[], viewerMode: ViewerMode, onSaved?: () => Promise<void> | void): import("lit-html").TemplateResult<1> | "";
5
+ //# sourceMappingURL=SkillsSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillsSection.d.ts","sourceRoot":"","sources":["../../../src/sections/skills/SkillsSection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,YAAY,EAAY,MAAM,SAAS,CAAA;AAgMhD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,YAAY,EAAE,EACtB,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,6CAYrC"}
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.renderSkillsSection = renderSkillsSection;
7
+ var _litHtml = require("lit-html");
8
+ var _textUtils = require("../../textUtils");
9
+ var _SkillsEditDialog = require("./SkillsEditDialog");
10
+ var _profileIcons = require("../../icons-svg/profileIcons");
11
+ var _texts = require("../../texts");
12
+ var _collapsibleSection = require("../shared/collapsibleSection");
13
+ var _mutations = require("./mutations");
14
+ function renderSkillItem(detail, store, subject, viewerMode, onSaved) {
15
+ if (!detail) return (0, _litHtml.html)``;
16
+ const handleRemove = async event => {
17
+ event.preventDefault();
18
+ if (viewerMode !== 'owner') return;
19
+ const removeRow = {
20
+ name: detail.name,
21
+ publicId: detail.publicId,
22
+ entryNode: detail.entryNode.value,
23
+ status: 'deleted'
24
+ };
25
+ await (0, _mutations.processSkillsMutations)(store, subject, {
26
+ create: [],
27
+ update: [],
28
+ remove: [removeRow]
29
+ });
30
+ if (onSaved) {
31
+ await onSaved();
32
+ }
33
+ };
34
+ return (0, _litHtml.html)`
35
+ <li class="skills__item inline-flex-row" role="listitem">
36
+ <span class="skills__item-label">${(0, _textUtils.strToUpperCase)(detail.name)}</span>
37
+ ${viewerMode === 'owner' ? (0, _litHtml.html)`
38
+ <button
39
+ type="button"
40
+ class="skills__remove-button inline-flex-row"
41
+ aria-label="Remove ${detail.name} skill"
42
+ @click=${handleRemove}
43
+ >
44
+ ${_profileIcons.deleteIcon}
45
+ </button>
46
+ ` : ''}
47
+ </li>
48
+ `;
49
+ }
50
+ function renderSkillsSectionDefault(store, subject, skills, viewerMode, onSaved) {
51
+ const hasSkills = Array.isArray(skills) && skills.length > 0;
52
+ const isOwner = viewerMode === 'owner';
53
+ return (0, _litHtml.html)`
54
+ <section
55
+ class="profile__section border-lighter profile-section-collapsible profile-section-collapsible--inline-mobile-actions"
56
+ aria-labelledby="skills-heading"
57
+ role="region"
58
+ tabindex="-1"
59
+ data-expanded="false"
60
+ >
61
+ <header class="profile__section-header profile-section-collapsible__header">
62
+ <h2 id="skills-heading">${_texts.skillsHeadingText}</h2>
63
+ <div class="profile-section-collapsible__actions flex-column">
64
+ ${isOwner ? (0, _litHtml.html)`
65
+ <button
66
+ type="button"
67
+ class="profile__action-button profile-action-text flex-center profile-section-collapsible__edit-button"
68
+ aria-label="Add or edit skills"
69
+ @click=${event => (0, _SkillsEditDialog.createSkillsEditDialog)(event, store, subject, skills, viewerMode, onSaved)}
70
+ >
71
+ <span class="profile-section-collapsible__edit-label profile__add-more-content inline-flex-row">
72
+ <span class="profile__add-more-icon inline-flex-row" aria-hidden="true">${_profileIcons.addIcon}</span>
73
+ Add More
74
+ </span>
75
+ <span class="profile-section-collapsible__edit-icon" aria-hidden="true">${_profileIcons.editIcon}</span>
76
+ </button>
77
+ ` : (0, _litHtml.html)``}
78
+ <button
79
+ type="button"
80
+ class="inline-flex-row"
81
+ aria-label="Toggle skills section"
82
+ aria-controls="skills-panel"
83
+ aria-expanded="false"
84
+ @click=${_collapsibleSection.toggleCollapsibleSection}
85
+ >
86
+ <span class="profile-section-collapsible__chevron" aria-hidden="true">⌄</span>
87
+ </button>
88
+ </div>
89
+ </header>
90
+ <div
91
+ id="skills-panel"
92
+ class="profile-section-collapsible__content"
93
+ aria-hidden="true"
94
+ >
95
+ ${hasSkills ? (0, _litHtml.html)`
96
+ <ul class="skills__list flex-column" role="list" aria-label="Professional skills and competencies">
97
+ ${skills.map(detail => renderSkillItem(detail, store, subject, viewerMode, onSaved))}
98
+ </ul>
99
+ ` : (0, _litHtml.html)`<p>No skills added yet.</p>`}
100
+ </div>
101
+ </section>
102
+ `;
103
+ }
104
+ function renderOwnerEmptySkillsContent(_store, _subject, _skills, _viewerMode, _onSaved) {
105
+ return (0, _litHtml.html)`
106
+ <div class="profile__empty-state-content flex-column-center" role="group" aria-label="Empty skills section">
107
+ <div class="skills__empty-icon-wrapper">
108
+ <span class="skills__empty-icon inline-flex-row">${_profileIcons.lighteningIcon}</span>
109
+ </div>
110
+ <p class="profile__empty-state-message skills__empty-message">
111
+ No skills added yet.
112
+ </p>
113
+ </div>
114
+ `;
115
+ }
116
+ function renderOwnerEmptySkillsSection(store, subject, skills, viewerMode, onSaved) {
117
+ return (0, _litHtml.html)`
118
+ <section
119
+ aria-labelledby="skills-heading"
120
+ data-profile-section="skills"
121
+ class="profile__section--empty border-lighter rounded-md gap-lg profile-section-collapsible profile-section-collapsible--inline-mobile-actions"
122
+ role="region"
123
+ tabindex="-1"
124
+ data-expanded="false"
125
+ >
126
+ <header class="profile__section-header profile-section-collapsible__header">
127
+ <h2 id="skills-heading" tabindex="-1">${_texts.skillsHeadingText}</h2>
128
+ <div class="profile-section-collapsible__actions flex-column">
129
+ <button
130
+ type="button"
131
+ class="profile__action-button profile-action-text flex-center profile-section-collapsible__edit-button"
132
+ aria-label="Add skills"
133
+ @click=${event => {
134
+ return (0, _SkillsEditDialog.createSkillsEditDialog)(event, store, subject, skills, viewerMode, onSaved);
135
+ }}
136
+ >
137
+ <span class="profile-section-collapsible__edit-label profile__add-more-content inline-flex-row">
138
+ <span class="profile__add-more-icon inline-flex-row" aria-hidden="true">${_profileIcons.addIcon}</span>
139
+ Add Skills
140
+ </span>
141
+ <span class="profile-section-collapsible__edit-icon" aria-hidden="true">${_profileIcons.editIcon}</span>
142
+ </button>
143
+ <button
144
+ type="button"
145
+ class="inline-flex-row"
146
+ aria-label="Toggle skills section"
147
+ aria-controls="skills-panel"
148
+ aria-expanded="false"
149
+ @click=${_collapsibleSection.toggleCollapsibleSection}
150
+ >
151
+ <span class="profile-section-collapsible__chevron" aria-hidden="true">⌄</span>
152
+ </button>
153
+ </div>
154
+ </header>
155
+ <div id="skills-panel" class="profile-section-collapsible__content" aria-hidden="true">
156
+ ${renderOwnerEmptySkillsContent(store, subject, skills, viewerMode, onSaved)}
157
+ </div>
158
+ </section>
159
+ `;
160
+ }
161
+ function renderSkillsSection(store, subject, skills, viewerMode, onSaved) {
162
+ const safeSkills = skills || [];
163
+ const hasSkills = Array.isArray(safeSkills) && safeSkills.length > 0;
164
+ const showOwnerEmptySkills = !hasSkills && viewerMode === 'owner';
165
+ const showSection = true;
166
+ return showSection ? (0, _litHtml.html)`
167
+ ${showOwnerEmptySkills ? renderOwnerEmptySkillsSection(store, subject, safeSkills, viewerMode, onSaved) : renderSkillsSectionDefault(store, subject, safeSkills, viewerMode, onSaved)}
168
+ ` : '';
169
+ }
@@ -0,0 +1,6 @@
1
+ import { LiveStore, NamedNode } from 'rdflib';
2
+ import { SkillRow } from './types';
3
+ import { MutationOps } from '../shared/types';
4
+ export type SkillMutationPlan = MutationOps<SkillRow>;
5
+ export declare function processSkillsMutations(store: LiveStore, subject: NamedNode, mutationPlan: SkillMutationPlan): Promise<void>;
6
+ //# sourceMappingURL=mutations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../../../src/sections/skills/mutations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAoB,MAAM,QAAQ,CAAA;AAE/D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAK7C,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAsHrD,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,iBAAiB,iBAQjH"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.processSkillsMutations = processSkillsMutations;
7
+ var _rdflib = require("rdflib");
8
+ var _solidUi = require("solid-ui");
9
+ var _rdfMutationHelpers = require("../shared/rdfMutationHelpers");
10
+ var _idNodeFactory = require("../shared/idNodeFactory");
11
+ var _texts = require("../../texts");
12
+ const ESCO_SKILL_BASE_URI = 'http://data.europa.eu/esco/skill/';
13
+ const SKILL_PREFIX_BASE_URI = 'skill:';
14
+ function ensureSkillPrefix(store) {
15
+ const anyStore = store;
16
+ if (typeof anyStore.setPrefixForURI === 'function') {
17
+ anyStore.setPrefixForURI('skill', SKILL_PREFIX_BASE_URI);
18
+ return;
19
+ }
20
+ if (!anyStore.namespaces) {
21
+ anyStore.namespaces = {};
22
+ }
23
+ anyStore.namespaces.skill = SKILL_PREFIX_BASE_URI;
24
+ }
25
+ function normalizeSkillPublicIdUri(publicId) {
26
+ const normalized = publicId.trim();
27
+ if (!normalized) return normalized;
28
+ if (normalized.startsWith('skill:')) {
29
+ return normalized;
30
+ }
31
+ if (normalized.startsWith(ESCO_SKILL_BASE_URI)) {
32
+ const suffix = normalized.slice(ESCO_SKILL_BASE_URI.length);
33
+ return suffix ? `skill:${suffix}` : normalized;
34
+ }
35
+ return normalized;
36
+ }
37
+ function normalizeNodeId(value) {
38
+ return value.startsWith('_:') ? value.slice(2) : value;
39
+ }
40
+ function collectSkillLinkStatementsByEntryValue(store, subject, doc, entryNode) {
41
+ const normalizedEntryNode = normalizeNodeId(entryNode);
42
+ return store.statementsMatching(subject, _solidUi.ns.schema('skills'), null, doc).filter(statement => {
43
+ const objectValue = normalizeNodeId(statement.object.value);
44
+ return objectValue === normalizedEntryNode || statement.object.value === entryNode;
45
+ });
46
+ }
47
+ function buildSkillsStatements(subject, doc, node, skill) {
48
+ if (!skill.name) return [];
49
+ if (!skill.publicId) {
50
+ throw new Error(`Missing skill publicId for skill: ${skill.name}`);
51
+ }
52
+ const publicIdNode = (0, _rdflib.sym)(normalizeSkillPublicIdUri(skill.publicId));
53
+ return [(0, _rdflib.st)(subject, _solidUi.ns.schema('skills'), node, doc), (0, _rdflib.st)(node, _solidUi.ns.solid('publicId'), publicIdNode, doc), (0, _rdflib.st)(publicIdNode, _solidUi.ns.schema('name'), (0, _rdflib.literal)(skill.name), doc)];
54
+ }
55
+ async function mutateSkillsEntries(store, subject, skillOps) {
56
+ ensureSkillPrefix(store);
57
+ const doc = subject.doc();
58
+ const existingSkillNodes = store.each(subject, _solidUi.ns.schema('skills'));
59
+ const deletions = [];
60
+ const insertions = [];
61
+ const collectLinkedPublicIdStatements = skillNode => {
62
+ const linkedPublicIdStatements = (0, _rdfMutationHelpers.collectLinkedNodeStatements)(store, skillNode, _solidUi.ns.solid('publicId'), doc);
63
+ deletions.push(...linkedPublicIdStatements.linkedStatements);
64
+ };
65
+ skillOps.remove.forEach(skill => {
66
+ if (!skill.entryNode) return;
67
+ const existingNode = (0, _rdfMutationHelpers.findExistingNode)(existingSkillNodes, skill.entryNode);
68
+ deletions.push(...collectSkillLinkStatementsByEntryValue(store, subject, doc, skill.entryNode));
69
+ if (existingNode) {
70
+ if (existingNode.termType !== 'Literal') {
71
+ deletions.push(...(0, _rdfMutationHelpers.collectNodeStatements)(store, existingNode, doc));
72
+ if (existingNode.termType === 'NamedNode') {
73
+ collectLinkedPublicIdStatements(existingNode);
74
+ }
75
+ }
76
+ }
77
+ });
78
+ skillOps.update.forEach(skill => {
79
+ if (!skill.entryNode) return;
80
+ const existingNode = (0, _rdfMutationHelpers.findExistingNode)(existingSkillNodes, skill.entryNode);
81
+ if (!existingNode) {
82
+ insertions.push(...buildSkillsStatements(subject, doc, (0, _idNodeFactory.createIdNode)(doc), skill));
83
+ return;
84
+ }
85
+ deletions.push(...collectSkillLinkStatementsByEntryValue(store, subject, doc, skill.entryNode));
86
+ if (existingNode.termType !== 'Literal') {
87
+ deletions.push(...(0, _rdfMutationHelpers.collectNodeStatements)(store, existingNode, doc));
88
+ if (existingNode.termType === 'NamedNode') {
89
+ collectLinkedPublicIdStatements(existingNode);
90
+ }
91
+ }
92
+ if (existingNode.termType === 'NamedNode') {
93
+ insertions.push(...buildSkillsStatements(subject, doc, existingNode, skill));
94
+ return;
95
+ }
96
+ insertions.push(...buildSkillsStatements(subject, doc, (0, _idNodeFactory.createIdNode)(doc), skill));
97
+ });
98
+ skillOps.create.forEach(skill => {
99
+ insertions.push(...buildSkillsStatements(subject, doc, (0, _idNodeFactory.createIdNode)(doc), skill));
100
+ });
101
+ await (0, _rdfMutationHelpers.applyUpdaterPatch)(store, deletions, insertions);
102
+ }
103
+ async function processSkillsMutations(store, subject, mutationPlan) {
104
+ try {
105
+ await mutateSkillsEntries(store, subject, mutationPlan);
106
+ } catch (error) {
107
+ const message = error instanceof Error ? error.message : String(error);
108
+ throw new Error(`${_texts.mutationSaveSkillsFailedPrefixText} ${message}`);
109
+ }
110
+ }
@@ -0,0 +1,6 @@
1
+ import { LiveStore, NamedNode, Node, Store } from 'rdflib';
2
+ import { SkillDetails } from './types';
3
+ export declare function skillAsText(store: Store, sk: Node): string;
4
+ export declare function presentSkillDetails(subject: NamedNode, store: LiveStore): SkillDetails[];
5
+ export declare function presentSkills(subject: NamedNode, store: LiveStore): string[];
6
+ //# sourceMappingURL=selectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../../src/sections/skills/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAGtC,wBAAgB,WAAW,CAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,GAAE,MAAM,CAe1D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,YAAY,EAAE,CAcxF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAE5E"}