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.
- package/README.md +16 -0
- package/lib/04567ff683933c35c465.png +0 -0
- package/lib/10163fd9b5a0e00d63a0.png +0 -0
- package/lib/1234dcb2eec2e45f252b.png +0 -0
- package/lib/20899934157df4db56cb.png +0 -0
- package/lib/33760bf79f097f449da5.png +0 -0
- package/lib/578d2b6ed32e7624164e.png +0 -0
- package/lib/5f62a5b2b7e99b9640c7.png +0 -0
- package/lib/6525766ecd288ec60129.png +0 -0
- package/lib/7800be6f6c4b5b0f4f20.png +0 -0
- package/lib/976473cf5fe24d657d4b.png +0 -0
- package/lib/ChatWithMe.d.ts +2 -1
- package/lib/ChatWithMe.d.ts.map +1 -1
- package/lib/ChatWithMe.js +3 -3
- package/lib/ProfileView.d.ts +1 -1
- package/lib/ProfileView.d.ts.map +1 -1
- package/lib/ProfileView.js +71 -131
- package/lib/ProfileViewModelPresenter.d.ts +23 -0
- package/lib/ProfileViewModelPresenter.d.ts.map +1 -0
- package/lib/ProfileViewModelPresenter.js +37 -0
- package/lib/QRCodeCard.d.ts +3 -1
- package/lib/QRCodeCard.d.ts.map +1 -1
- package/lib/QRCodeCard.js +86 -66
- package/lib/addMeToYourFriends.d.ts +3 -3
- package/lib/addMeToYourFriends.d.ts.map +1 -1
- package/lib/addMeToYourFriends.js +14 -30
- package/lib/bda84f59e7216675a208.png +0 -0
- package/lib/buttonsHelper.js +1 -1
- package/lib/cd68e8f3990ba8b2139e.png +0 -0
- package/lib/e7074a7e2cb69e51cfd3.png +0 -0
- package/lib/editProfilePane/EditCVCard.d.ts +1 -0
- package/lib/editProfilePane/EditCVCard.d.ts.map +1 -1
- package/lib/editProfilePane/EditCVCard.js +2 -1
- package/lib/editProfilePane/EditCommunitiesCard.d.ts +1 -1
- package/lib/editProfilePane/EditCommunitiesCard.d.ts.map +1 -1
- package/lib/editProfilePane/EditCommunitiesCard.js +2 -1
- package/lib/editProfilePane/EditContactsCard.d.ts +1 -0
- package/lib/editProfilePane/EditContactsCard.d.ts.map +1 -1
- package/lib/editProfilePane/EditContactsCard.js +2 -0
- package/lib/editProfilePane/EditFriendsCard.d.ts +1 -1
- package/lib/editProfilePane/EditFriendsCard.d.ts.map +1 -1
- package/lib/editProfilePane/EditFriendsCard.js +2 -1
- package/lib/editProfilePane/EditOtherPreferences.d.ts +1 -0
- package/lib/editProfilePane/EditOtherPreferences.d.ts.map +1 -1
- package/lib/editProfilePane/EditOtherPreferences.js +1 -0
- package/lib/editProfilePane/EditProfileView.d.ts +1 -1
- package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
- package/lib/editProfilePane/EditProfileView.js +1 -1
- package/lib/editProfilePane/EditSocialCard.d.ts +1 -0
- package/lib/editProfilePane/EditSocialCard.d.ts.map +1 -1
- package/lib/editProfilePane/EditSocialCard.js +2 -1
- package/lib/editProfilePane/editProfilePresenter.d.ts +1 -0
- package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
- package/lib/editProfilePane/editProfilePresenter.js +2 -0
- package/lib/f3772696fb7ee53c23d8.png +0 -0
- package/lib/icons-svg/contactIcons.d.ts +3 -0
- package/lib/icons-svg/contactIcons.d.ts.map +1 -0
- package/lib/icons-svg/contactIcons.js +32 -0
- package/lib/icons-svg/profileIcons.d.ts +22 -0
- package/lib/icons-svg/profileIcons.d.ts.map +1 -0
- package/lib/icons-svg/profileIcons.js +309 -0
- package/lib/index.d.ts +1 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +42 -19
- package/lib/profile-pane.js +15629 -5666
- package/lib/profile-pane.js.map +1 -1
- package/lib/profile-pane.min.js +2171 -230
- package/lib/profile-pane.min.js.map +1 -1
- package/lib/rdfFormsHelper.d.ts +1 -0
- package/lib/rdfFormsHelper.d.ts.map +1 -1
- package/lib/rdfFormsHelper.js +2 -0
- package/lib/sections/bio/BioEditDialog.d.ts +6 -0
- package/lib/sections/bio/BioEditDialog.d.ts.map +1 -0
- package/lib/sections/bio/BioEditDialog.js +119 -0
- package/lib/sections/bio/BioSection.d.ts +7 -0
- package/lib/sections/bio/BioSection.d.ts.map +1 -0
- package/lib/sections/bio/BioSection.js +131 -0
- package/lib/sections/bio/mutations.d.ts +4 -0
- package/lib/sections/bio/mutations.d.ts.map +1 -0
- package/lib/sections/bio/mutations.js +43 -0
- package/lib/sections/bio/selectors.d.ts +4 -0
- package/lib/sections/bio/selectors.d.ts.map +1 -0
- package/lib/sections/bio/selectors.js +15 -0
- package/lib/sections/bio/types.d.ts +15 -0
- package/lib/sections/bio/types.d.ts.map +1 -0
- package/lib/sections/bio/types.js +5 -0
- package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +7 -0
- package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -0
- package/lib/sections/contactInfo/ContactInfoEditDialog.js +658 -0
- package/lib/sections/contactInfo/ContactInfoSection.d.ts +5 -0
- package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -0
- package/lib/sections/contactInfo/ContactInfoSection.js +229 -0
- package/lib/sections/contactInfo/mutations.d.ts +4 -0
- package/lib/sections/contactInfo/mutations.d.ts.map +1 -0
- package/lib/sections/contactInfo/mutations.js +150 -0
- package/lib/sections/contactInfo/selectors.d.ts +4 -0
- package/lib/sections/contactInfo/selectors.d.ts.map +1 -0
- package/lib/sections/contactInfo/selectors.js +104 -0
- package/lib/sections/contactInfo/types.d.ts +44 -0
- package/lib/sections/contactInfo/types.d.ts.map +1 -0
- package/lib/sections/contactInfo/types.js +5 -0
- package/lib/sections/education/EducationEditDialog.d.ts +7 -0
- package/lib/sections/education/EducationEditDialog.d.ts.map +1 -0
- package/lib/sections/education/EducationEditDialog.js +459 -0
- package/lib/sections/education/EducationSection.d.ts +7 -0
- package/lib/sections/education/EducationSection.d.ts.map +1 -0
- package/lib/sections/education/EducationSection.js +126 -0
- package/lib/sections/education/mutations.d.ts +4 -0
- package/lib/sections/education/mutations.d.ts.map +1 -0
- package/lib/sections/education/mutations.js +60 -0
- package/lib/sections/education/selectors.d.ts +4 -0
- package/lib/sections/education/selectors.d.ts.map +1 -0
- package/lib/sections/education/selectors.js +64 -0
- package/lib/sections/education/types.d.ts +20 -0
- package/lib/sections/education/types.d.ts.map +1 -0
- package/lib/sections/education/types.js +5 -0
- package/lib/sections/heading/HeadingEditDialog.d.ts +6 -0
- package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -0
- package/lib/sections/heading/HeadingEditDialog.js +742 -0
- package/lib/sections/heading/HeadingSection.d.ts +9 -0
- package/lib/sections/heading/HeadingSection.d.ts.map +1 -0
- package/lib/sections/heading/HeadingSection.js +97 -0
- package/lib/sections/heading/camera.d.ts +19 -0
- package/lib/sections/heading/camera.d.ts.map +1 -0
- package/lib/sections/heading/camera.js +199 -0
- package/lib/sections/heading/dateHelpers.d.ts +4 -0
- package/lib/sections/heading/dateHelpers.d.ts.map +1 -0
- package/lib/sections/heading/dateHelpers.js +48 -0
- package/lib/sections/heading/imageHelpers.d.ts +4 -0
- package/lib/sections/heading/imageHelpers.d.ts.map +1 -0
- package/lib/sections/heading/imageHelpers.js +81 -0
- package/lib/sections/heading/mutations.d.ts +4 -0
- package/lib/sections/heading/mutations.d.ts.map +1 -0
- package/lib/sections/heading/mutations.js +190 -0
- package/lib/sections/heading/selectors.d.ts +5 -0
- package/lib/sections/heading/selectors.d.ts.map +1 -0
- package/lib/sections/heading/selectors.js +157 -0
- package/lib/sections/heading/types.d.ts +36 -0
- package/lib/sections/heading/types.d.ts.map +1 -0
- package/lib/sections/heading/types.js +5 -0
- package/lib/sections/languages/LanguageEditDialog.d.ts +7 -0
- package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -0
- package/lib/sections/languages/LanguageEditDialog.js +457 -0
- package/lib/sections/languages/LanguageSection.d.ts +5 -0
- package/lib/sections/languages/LanguageSection.d.ts.map +1 -0
- package/lib/sections/languages/LanguageSection.js +137 -0
- package/lib/sections/languages/mutations.d.ts +6 -0
- package/lib/sections/languages/mutations.d.ts.map +1 -0
- package/lib/sections/languages/mutations.js +296 -0
- package/lib/sections/languages/selectors.d.ts +5 -0
- package/lib/sections/languages/selectors.d.ts.map +1 -0
- package/lib/sections/languages/selectors.js +146 -0
- package/lib/sections/languages/types.d.ts +15 -0
- package/lib/sections/languages/types.d.ts.map +1 -0
- package/lib/sections/languages/types.js +5 -0
- package/lib/sections/projects/ProjectEditDialog.d.ts +7 -0
- package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -0
- package/lib/sections/projects/ProjectEditDialog.js +182 -0
- package/lib/sections/projects/ProjectSection.d.ts +6 -0
- package/lib/sections/projects/ProjectSection.d.ts.map +1 -0
- package/lib/sections/projects/ProjectSection.js +220 -0
- package/lib/sections/projects/mutations.d.ts +4 -0
- package/lib/sections/projects/mutations.d.ts.map +1 -0
- package/lib/sections/projects/mutations.js +188 -0
- package/lib/sections/projects/selectors.d.ts +5 -0
- package/lib/sections/projects/selectors.d.ts.map +1 -0
- package/lib/sections/projects/selectors.js +163 -0
- package/lib/sections/projects/types.d.ts +28 -0
- package/lib/sections/projects/types.d.ts.map +1 -0
- package/lib/sections/projects/types.js +8 -0
- package/lib/sections/resume/ResumeEditDialog.d.ts +7 -0
- package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -0
- package/lib/sections/resume/ResumeEditDialog.js +629 -0
- package/lib/sections/resume/ResumeSection.d.ts +7 -0
- package/lib/sections/resume/ResumeSection.d.ts.map +1 -0
- package/lib/sections/resume/ResumeSection.js +160 -0
- package/lib/sections/resume/mutations.d.ts +6 -0
- package/lib/sections/resume/mutations.d.ts.map +1 -0
- package/lib/sections/resume/mutations.js +172 -0
- package/lib/sections/resume/selectors.d.ts +4 -0
- package/lib/sections/resume/selectors.d.ts.map +1 -0
- package/lib/sections/resume/selectors.js +142 -0
- package/lib/sections/resume/types.d.ts +33 -0
- package/lib/sections/resume/types.d.ts.map +1 -0
- package/lib/sections/resume/types.js +8 -0
- package/lib/sections/shared/collapsibleSection.d.ts +2 -0
- package/lib/sections/shared/collapsibleSection.d.ts.map +1 -0
- package/lib/sections/shared/collapsibleSection.js +24 -0
- package/lib/sections/shared/contactTypeUtils.d.ts +7 -0
- package/lib/sections/shared/contactTypeUtils.d.ts.map +1 -0
- package/lib/sections/shared/contactTypeUtils.js +48 -0
- package/lib/sections/shared/idNodeFactory.d.ts +3 -0
- package/lib/sections/shared/idNodeFactory.d.ts.map +1 -0
- package/lib/sections/shared/idNodeFactory.js +14 -0
- package/lib/sections/shared/phoneCountries.d.ts +20 -0
- package/lib/sections/shared/phoneCountries.d.ts.map +1 -0
- package/lib/sections/shared/phoneCountries.js +1080 -0
- package/lib/sections/shared/rdfList.d.ts +3 -0
- package/lib/sections/shared/rdfList.d.ts.map +1 -0
- package/lib/sections/shared/rdfList.js +34 -0
- package/lib/sections/shared/rdfMutationHelpers.d.ts +12 -0
- package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -0
- package/lib/sections/shared/rdfMutationHelpers.js +82 -0
- package/lib/sections/shared/rowState.d.ts +21 -0
- package/lib/sections/shared/rowState.d.ts.map +1 -0
- package/lib/sections/shared/rowState.js +52 -0
- package/lib/sections/shared/sanitizeUtils.d.ts +5 -0
- package/lib/sections/shared/sanitizeUtils.d.ts.map +1 -0
- package/lib/sections/shared/sanitizeUtils.js +22 -0
- package/lib/sections/shared/sectionCardHelpers.d.ts +11 -0
- package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -0
- package/lib/sections/shared/sectionCardHelpers.js +105 -0
- package/lib/sections/shared/types.d.ts +7 -0
- package/lib/sections/shared/types.d.ts.map +1 -0
- package/lib/sections/shared/types.js +5 -0
- package/lib/sections/skills/SkillsEditDialog.d.ts +7 -0
- package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -0
- package/lib/sections/skills/SkillsEditDialog.js +340 -0
- package/lib/sections/skills/SkillsSection.d.ts +5 -0
- package/lib/sections/skills/SkillsSection.d.ts.map +1 -0
- package/lib/sections/skills/SkillsSection.js +169 -0
- package/lib/sections/skills/mutations.d.ts +6 -0
- package/lib/sections/skills/mutations.d.ts.map +1 -0
- package/lib/sections/skills/mutations.js +110 -0
- package/lib/sections/skills/selectors.d.ts +6 -0
- package/lib/sections/skills/selectors.d.ts.map +1 -0
- package/lib/sections/skills/selectors.js +37 -0
- package/lib/sections/skills/types.d.ts +14 -0
- package/lib/sections/skills/types.d.ts.map +1 -0
- package/lib/sections/skills/types.js +5 -0
- package/lib/sections/social/SocialEditDialog.d.ts +7 -0
- package/lib/sections/social/SocialEditDialog.d.ts.map +1 -0
- package/lib/sections/social/SocialEditDialog.js +362 -0
- package/lib/sections/social/SocialSection.d.ts +8 -0
- package/lib/sections/social/SocialSection.d.ts.map +1 -0
- package/lib/sections/social/SocialSection.js +201 -0
- package/lib/sections/social/constants.d.ts +3 -0
- package/lib/sections/social/constants.d.ts.map +1 -0
- package/lib/sections/social/constants.js +16 -0
- package/lib/sections/social/helpers.d.ts +15 -0
- package/lib/sections/social/helpers.d.ts.map +1 -0
- package/lib/sections/social/helpers.js +316 -0
- package/lib/sections/social/mutations.d.ts +4 -0
- package/lib/sections/social/mutations.d.ts.map +1 -0
- package/lib/sections/social/mutations.js +298 -0
- package/lib/sections/social/selectors.d.ts +4 -0
- package/lib/sections/social/selectors.d.ts.map +1 -0
- package/lib/sections/social/selectors.js +43 -0
- package/lib/sections/social/types.d.ts +19 -0
- package/lib/sections/social/types.d.ts.map +1 -0
- package/lib/sections/social/types.js +5 -0
- package/lib/styles/BioSection.css +77 -0
- package/lib/styles/CVCard.css +107 -2
- package/lib/styles/ContactInfoEditDialog.css +153 -0
- package/lib/styles/EditDialogs.css +1028 -0
- package/lib/styles/EducationCard.css +103 -0
- package/lib/styles/HeadingSection.css +309 -0
- package/lib/styles/ProfileCard.css +10 -42
- package/lib/styles/ProfileView.css +53 -8
- package/lib/styles/ProjectsCard.css +206 -0
- package/lib/styles/QRCodeCard.css +29 -10
- package/lib/styles/SocialCard.css +41 -13
- package/lib/styles/dialog.css +209 -0
- package/lib/styles/utilities.css +638 -256
- package/lib/textUtils.d.ts +6 -0
- package/lib/textUtils.d.ts.map +1 -0
- package/lib/textUtils.js +44 -0
- package/lib/texts.d.ts +45 -4
- package/lib/texts.d.ts.map +1 -1
- package/lib/texts.js +46 -5
- package/lib/types.d.ts +2 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +5 -0
- package/lib/ui/dialog.d.ts +29 -0
- package/lib/ui/dialog.d.ts.map +1 -0
- package/lib/ui/dialog.js +269 -0
- package/lib/ui/errors.d.ts +2 -0
- package/lib/ui/errors.d.ts.map +1 -0
- package/lib/ui/errors.js +10 -0
- package/package.json +8 -6
- package/lib/CVCard.d.ts +0 -4
- package/lib/CVCard.d.ts.map +0 -1
- package/lib/CVCard.js +0 -114
- package/lib/CVPresenter.d.ts +0 -25
- package/lib/CVPresenter.d.ts.map +0 -1
- package/lib/CVPresenter.js +0 -119
- package/lib/FriendList.d.ts +0 -6
- package/lib/FriendList.d.ts.map +0 -1
- package/lib/FriendList.js +0 -27
- package/lib/ProfileCard.d.ts +0 -6
- package/lib/ProfileCard.d.ts.map +0 -1
- package/lib/ProfileCard.js +0 -62
- package/lib/SocialCard.d.ts +0 -5
- package/lib/SocialCard.d.ts.map +0 -1
- package/lib/SocialCard.js +0 -51
- package/lib/SocialPresenter.d.ts +0 -11
- package/lib/SocialPresenter.d.ts.map +0 -1
- package/lib/SocialPresenter.js +0 -117
- package/lib/StuffCard.d.ts +0 -10
- package/lib/StuffCard.d.ts.map +0 -1
- package/lib/StuffCard.js +0 -52
- package/lib/StuffPresenter.d.ts +0 -14
- package/lib/StuffPresenter.d.ts.map +0 -1
- package/lib/StuffPresenter.js +0 -53
- package/lib/presenter.d.ts +0 -14
- package/lib/presenter.d.ts.map +0 -1
- package/lib/presenter.js +0 -68
- package/lib/styles/FriendList.css +0 -12
- package/lib/styles/StuffCard.css +0 -23
- package/lib/styles/editProfile.css +0 -62
- 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,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
|