profile-pane 3.2.0 → 3.2.2-test.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 +50 -0
- package/icons-png/discord.png +0 -0
- package/icons-png/dribbble.png +0 -0
- package/icons-png/facebook.png +0 -0
- package/icons-png/instagram.png +0 -0
- package/icons-png/linkedin.png +0 -0
- package/icons-png/pinterest.png +0 -0
- package/icons-png/sharechat.png +0 -0
- package/icons-png/signup.png +0 -0
- package/icons-png/snapchat.png +0 -0
- package/icons-png/spotify.png +0 -0
- package/icons-png/telegram.png +0 -0
- package/icons-png/tiktok.png +0 -0
- package/icons-png/whatsapp.png +0 -0
- package/icons-png/x.png +0 -0
- package/icons-png/youtube.png +0 -0
- package/lib/303.profile-pane.js +1362 -0
- package/lib/303.profile-pane.js.map +1 -0
- package/lib/303.profile-pane.min.js +2 -0
- package/lib/303.profile-pane.min.js.map +1 -0
- package/lib/ProfileView.css +1090 -0
- package/lib/ProfileView.d.ts +2 -1
- package/lib/ProfileView.d.ts.map +1 -1
- package/lib/ProfileView.js +64 -36
- package/lib/buttonsHelper.d.ts +1 -1
- package/lib/buttonsHelper.d.ts.map +1 -1
- package/lib/buttonsHelper.js +2 -1
- package/lib/editProfilePane/EditCVCard.js +1 -1
- package/lib/editProfilePane/EditCommunitiesCard.js +1 -1
- package/lib/editProfilePane/EditFriendsCard.js +1 -1
- package/lib/editProfilePane/EditProfileView.d.ts +1 -1
- package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
- package/lib/editProfilePane/EditProfileView.js +4 -5
- package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
- package/lib/editProfilePane/editProfilePresenter.js +5 -4
- package/lib/icons-svg/profileIcons.d.ts +1 -1
- package/lib/icons-svg/profileIcons.d.ts.map +1 -1
- package/lib/icons-svg/profileIcons.js +9 -17
- package/lib/index.d.ts +1 -8
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +74 -40
- package/lib/ontology/otherPreferencesForm.ttl +32 -0
- package/lib/ontology/resumeForm.ttl +349 -0
- package/lib/ontology/socialMedia.ttl +433 -0
- package/lib/profile-pane.js +32266 -13247
- package/lib/profile-pane.js.map +1 -1
- package/lib/profile-pane.min.js +2315 -935
- package/lib/profile-pane.min.js.map +1 -1
- package/lib/rdfFormsHelper.d.ts +13 -1
- package/lib/rdfFormsHelper.d.ts.map +1 -1
- package/lib/rdfFormsHelper.js +13 -1
- package/lib/sections/bio/BioEditDialog.d.ts.map +1 -1
- package/lib/sections/bio/BioEditDialog.js +7 -7
- package/lib/sections/bio/BioSection.css +300 -0
- package/lib/sections/bio/BioSection.d.ts +3 -2
- package/lib/sections/bio/BioSection.d.ts.map +1 -1
- package/lib/sections/bio/BioSection.js +26 -19
- package/lib/sections/bio/mutations.d.ts.map +1 -1
- package/lib/sections/bio/mutations.js +14 -3
- package/lib/sections/contactInfo/ContactInfoEditDialog.css +354 -0
- package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +3 -1
- package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -1
- package/lib/sections/contactInfo/ContactInfoEditDialog.js +183 -98
- package/lib/sections/contactInfo/ContactInfoSection.css +125 -0
- package/lib/sections/contactInfo/ContactInfoSection.d.ts +2 -0
- package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -1
- package/lib/sections/contactInfo/ContactInfoSection.js +64 -41
- package/lib/sections/contactInfo/mutations.d.ts.map +1 -1
- package/lib/sections/contactInfo/mutations.js +51 -16
- package/lib/sections/education/EducationEditDialog.d.ts +3 -1
- package/lib/sections/education/EducationEditDialog.d.ts.map +1 -1
- package/lib/sections/education/EducationEditDialog.js +170 -92
- package/lib/sections/education/EducationSection.css +133 -0
- package/lib/sections/education/EducationSection.d.ts +3 -2
- package/lib/sections/education/EducationSection.d.ts.map +1 -1
- package/lib/sections/education/EducationSection.js +32 -25
- package/lib/sections/education/mutations.d.ts.map +1 -1
- package/lib/sections/education/mutations.js +14 -3
- package/lib/sections/heading/HeadingEditDialog.d.ts +4 -1
- package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -1
- package/lib/sections/heading/HeadingEditDialog.js +287 -162
- package/lib/sections/heading/HeadingSection.css +862 -0
- package/lib/sections/heading/HeadingSection.d.ts +3 -2
- package/lib/sections/heading/HeadingSection.d.ts.map +1 -1
- package/lib/sections/heading/HeadingSection.js +63 -32
- package/lib/sections/heading/imageHelpers.d.ts +1 -0
- package/lib/sections/heading/imageHelpers.d.ts.map +1 -1
- package/lib/sections/heading/imageHelpers.js +40 -1
- package/lib/sections/heading/mutations.d.ts.map +1 -1
- package/lib/sections/heading/mutations.js +86 -23
- package/lib/sections/heading/selectors.d.ts.map +1 -1
- package/lib/sections/heading/selectors.js +14 -3
- package/lib/sections/heading/types.d.ts +1 -2
- package/lib/sections/heading/types.d.ts.map +1 -1
- package/lib/sections/languages/LanguageEditDialog.d.ts +3 -1
- package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -1
- package/lib/sections/languages/LanguageEditDialog.js +202 -119
- package/lib/sections/languages/LanguageSection.css +53 -0
- package/lib/sections/languages/LanguageSection.d.ts +2 -0
- package/lib/sections/languages/LanguageSection.d.ts.map +1 -1
- package/lib/sections/languages/LanguageSection.js +42 -31
- package/lib/sections/languages/mutations.d.ts.map +1 -1
- package/lib/sections/languages/mutations.js +60 -161
- package/lib/sections/languages/selectors.d.ts.map +1 -1
- package/lib/sections/languages/selectors.js +1 -2
- package/lib/sections/projects/ProjectEditDialog.d.ts +2 -1
- package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -1
- package/lib/sections/projects/ProjectEditDialog.js +13 -24
- package/lib/sections/projects/ProjectSection.css +368 -0
- package/lib/sections/projects/ProjectSection.d.ts +2 -1
- package/lib/sections/projects/ProjectSection.d.ts.map +1 -1
- package/lib/sections/projects/ProjectSection.js +116 -34
- package/lib/sections/projects/mutations.d.ts.map +1 -1
- package/lib/sections/projects/mutations.js +109 -132
- package/lib/sections/projects/selectors.d.ts.map +1 -1
- package/lib/sections/projects/selectors.js +4 -45
- package/lib/{QRCodeCard.d.ts → sections/qrcode/QRCodeCard.d.ts} +2 -1
- package/lib/sections/qrcode/QRCodeCard.d.ts.map +1 -0
- package/lib/{QRCodeCard.js → sections/qrcode/QRCodeCard.js} +59 -11
- package/lib/sections/qrcode/QRCodeSection.css +108 -0
- package/lib/sections/qrcode/QRCodeSection.d.ts +4 -0
- package/lib/sections/qrcode/QRCodeSection.d.ts.map +1 -0
- package/lib/sections/qrcode/QRCodeSection.js +17 -0
- package/lib/sections/resume/ResumeEditDialog.d.ts +10 -1
- package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -1
- package/lib/sections/resume/ResumeEditDialog.js +531 -149
- package/lib/sections/resume/ResumeSection.css +350 -0
- package/lib/sections/resume/ResumeSection.d.ts +3 -2
- package/lib/sections/resume/ResumeSection.d.ts.map +1 -1
- package/lib/sections/resume/ResumeSection.js +78 -49
- package/lib/sections/resume/mutations.d.ts.map +1 -1
- package/lib/sections/resume/mutations.js +17 -3
- package/lib/sections/resume/selectors.d.ts.map +1 -1
- package/lib/sections/resume/selectors.js +1 -0
- package/lib/sections/resume/types.d.ts +1 -0
- package/lib/sections/resume/types.d.ts.map +1 -1
- package/lib/sections/shared/collapsibleSection.d.ts.map +1 -1
- package/lib/sections/shared/collapsibleSection.js +1 -0
- package/lib/sections/shared/phoneCountries.d.ts +1 -1
- package/lib/sections/shared/phoneCountries.d.ts.map +1 -1
- package/lib/sections/shared/phoneCountries.js +2 -2
- package/lib/sections/shared/projectCommunityNodes.d.ts +6 -0
- package/lib/sections/shared/projectCommunityNodes.d.ts.map +1 -0
- package/lib/sections/shared/projectCommunityNodes.js +56 -0
- package/lib/sections/shared/rdfMutationHelpers.d.ts +35 -2
- package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -1
- package/lib/sections/shared/rdfMutationHelpers.js +290 -14
- package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -1
- package/lib/sections/shared/sectionCardHelpers.js +80 -11
- package/lib/sections/shared/types.d.ts +24 -0
- package/lib/sections/shared/types.d.ts.map +1 -1
- package/lib/sections/skills/SkillsEditDialog.d.ts +3 -1
- package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -1
- package/lib/sections/skills/SkillsEditDialog.js +136 -115
- package/lib/sections/skills/SkillsSection.css +173 -0
- package/lib/sections/skills/SkillsSection.d.ts +2 -0
- package/lib/sections/skills/SkillsSection.d.ts.map +1 -1
- package/lib/sections/skills/SkillsSection.js +107 -47
- package/lib/sections/skills/mutations.d.ts.map +1 -1
- package/lib/sections/skills/mutations.js +25 -21
- package/lib/sections/skills/selectors.d.ts.map +1 -1
- package/lib/sections/skills/selectors.js +5 -3
- package/lib/sections/social/SocialEditDialog.d.ts +3 -1
- package/lib/sections/social/SocialEditDialog.d.ts.map +1 -1
- package/lib/sections/social/SocialEditDialog.js +170 -62
- package/lib/sections/social/SocialSection.css +194 -0
- package/lib/sections/social/SocialSection.d.ts +4 -3
- package/lib/sections/social/SocialSection.d.ts.map +1 -1
- package/lib/sections/social/SocialSection.js +59 -43
- package/lib/sections/social/mutations.d.ts.map +1 -1
- package/lib/sections/social/mutations.js +23 -132
- package/lib/specialButtons/AddMeToYourFriends.css +54 -0
- package/lib/specialButtons/addContact/AddMeToYourContacts.css +1118 -0
- package/lib/specialButtons/addContact/ContactCreationDialog.d.ts +10 -0
- package/lib/specialButtons/addContact/ContactCreationDialog.d.ts.map +1 -0
- package/lib/specialButtons/addContact/ContactCreationDialog.js +1123 -0
- package/lib/specialButtons/addContact/addMeToYourContacts.d.ts +16 -0
- package/lib/specialButtons/addContact/addMeToYourContacts.d.ts.map +1 -0
- package/lib/specialButtons/addContact/addMeToYourContacts.js +136 -0
- package/lib/specialButtons/addContact/contactsErrors.d.ts +8 -0
- package/lib/specialButtons/addContact/contactsErrors.d.ts.map +1 -0
- package/lib/specialButtons/addContact/contactsErrors.js +106 -0
- package/lib/specialButtons/addContact/contactsTypes.d.ts +43 -0
- package/lib/specialButtons/addContact/contactsTypes.d.ts.map +1 -0
- package/lib/specialButtons/addContact/contactsTypes.js +5 -0
- package/lib/specialButtons/addContact/helpers.d.ts +7 -0
- package/lib/specialButtons/addContact/helpers.d.ts.map +1 -0
- package/lib/specialButtons/addContact/helpers.js +103 -0
- package/lib/specialButtons/addContact/mutations.d.ts +16 -0
- package/lib/specialButtons/addContact/mutations.d.ts.map +1 -0
- package/lib/specialButtons/addContact/mutations.js +300 -0
- package/lib/specialButtons/addContact/selectors.d.ts +10 -0
- package/lib/specialButtons/addContact/selectors.d.ts.map +1 -0
- package/lib/specialButtons/addContact/selectors.js +163 -0
- package/lib/{addMeToYourFriends.d.ts → specialButtons/addMeToYourFriends.d.ts} +6 -4
- package/lib/specialButtons/addMeToYourFriends.d.ts.map +1 -0
- package/lib/{addMeToYourFriends.js → specialButtons/addMeToYourFriends.js} +46 -11
- package/lib/styles/CollapsibleSection.css +519 -0
- package/lib/styles/EditDialogs.css +506 -686
- package/lib/styles/EditDialogs.responsive.css +989 -0
- package/lib/texts/buttonTexts.d.ts +9 -0
- package/lib/texts/buttonTexts.d.ts.map +1 -0
- package/lib/texts/buttonTexts.js +14 -0
- package/lib/texts/dialogTexts.d.ts +14 -0
- package/lib/texts/dialogTexts.d.ts.map +1 -0
- package/lib/texts/dialogTexts.js +19 -0
- package/lib/texts/messageTexts.d.ts +42 -0
- package/lib/texts/messageTexts.d.ts.map +1 -0
- package/lib/texts/messageTexts.js +47 -0
- package/lib/texts/profileTexts.d.ts +14 -0
- package/lib/texts/profileTexts.d.ts.map +1 -0
- package/lib/texts/profileTexts.js +19 -0
- package/lib/texts/qrCodeTexts.d.ts +2 -0
- package/lib/texts/qrCodeTexts.d.ts.map +1 -0
- package/lib/texts/qrCodeTexts.js +7 -0
- package/lib/texts.d.ts +5 -60
- package/lib/texts.d.ts.map +1 -1
- package/lib/texts.js +55 -70
- package/lib/ui/dialog.css +233 -0
- package/lib/ui/dialog.d.ts +15 -1
- package/lib/ui/dialog.d.ts.map +1 -1
- package/lib/ui/dialog.js +245 -45
- package/lib/ui/dialog.responsive.css +195 -0
- package/lib/ui/errors.d.ts.map +1 -1
- package/lib/ui/errors.js +2 -1
- package/lib/ui/spinner.d.ts +3 -0
- package/lib/ui/spinner.d.ts.map +1 -0
- package/lib/ui/spinner.js +13 -0
- package/lib/utils/debug.d.ts +5 -0
- package/lib/utils/debug.d.ts.map +1 -0
- package/lib/utils/debug.js +23 -0
- package/lib/utils/errorDisplay.d.ts +2 -0
- package/lib/utils/errorDisplay.d.ts.map +1 -0
- package/lib/utils/errorDisplay.js +19 -0
- package/package.json +34 -26
- package/lib/ChatWithMe.d.ts +0 -7
- package/lib/ChatWithMe.d.ts.map +0 -1
- package/lib/ChatWithMe.js +0 -90
- package/lib/QRCodeCard.d.ts.map +0 -1
- package/lib/addMeToYourFriends.d.ts.map +0 -1
- package/lib/sections/heading/camera.d.ts +0 -19
- package/lib/sections/heading/camera.d.ts.map +0 -1
- package/lib/sections/heading/camera.js +0 -199
- package/lib/styles/BioSection.css +0 -77
- package/lib/styles/CVCard.css +0 -142
- package/lib/styles/ChatWithMe.css +0 -6
- package/lib/styles/ContactInfoEditDialog.css +0 -153
- package/lib/styles/EducationCard.css +0 -103
- package/lib/styles/HeadingSection.css +0 -309
- package/lib/styles/ProfileCard.css +0 -66
- package/lib/styles/ProfileView.css +0 -65
- package/lib/styles/ProjectsCard.css +0 -206
- package/lib/styles/QRCodeCard.css +0 -43
- package/lib/styles/SocialCard.css +0 -89
- package/lib/styles/dialog.css +0 -209
- package/lib/styles/utilities.css +0 -740
|
@@ -0,0 +1,1123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createAddressBookContactCreationDialog = void 0;
|
|
7
|
+
exports.createAddressBookContactCreationFooter = createAddressBookContactCreationFooter;
|
|
8
|
+
exports.createAddressBookUriSelectorDialog = void 0;
|
|
9
|
+
exports.getButtonContainer = getButtonContainer;
|
|
10
|
+
exports.handleContactExistsByName = void 0;
|
|
11
|
+
require("solid-ui/components/actions/button");
|
|
12
|
+
var _helpers = require("./helpers");
|
|
13
|
+
var _selectors = require("./selectors");
|
|
14
|
+
var _mutations = require("./mutations");
|
|
15
|
+
var _litHtml = require("lit-html");
|
|
16
|
+
var _buttonsHelper = require("../../buttonsHelper");
|
|
17
|
+
var _texts = require("../../texts");
|
|
18
|
+
var _contactsErrors = require("./contactsErrors");
|
|
19
|
+
var _rdflib = require("rdflib");
|
|
20
|
+
var _profileIcons = require("../../icons-svg/profileIcons");
|
|
21
|
+
var _solidUi = require("solid-ui");
|
|
22
|
+
var _dialog = require("../../ui/dialog");
|
|
23
|
+
var _rdfMutationHelpers = require("../../sections/shared/rdfMutationHelpers");
|
|
24
|
+
var _debug = require("../../utils/debug");
|
|
25
|
+
const CONTACTS_POPUP_OVERLAY_ID = 'contacts-popup-overlay';
|
|
26
|
+
const CONTACTS_OVERLAY_ACTIVE_CLASS = 'contacts-dialog--overlay-active';
|
|
27
|
+
function setContactsListButtonSelected(button, isSelected) {
|
|
28
|
+
const listButton = button;
|
|
29
|
+
listButton.selected = isSelected;
|
|
30
|
+
if (isSelected) {
|
|
31
|
+
listButton.setAttribute('selected', '');
|
|
32
|
+
} else {
|
|
33
|
+
listButton.removeAttribute('selected');
|
|
34
|
+
}
|
|
35
|
+
listButton.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
|
|
36
|
+
}
|
|
37
|
+
function isContactsListButtonSelected(button) {
|
|
38
|
+
if (!(button instanceof HTMLElement)) return false;
|
|
39
|
+
const listButton = button;
|
|
40
|
+
return listButton.selected || button.hasAttribute('selected');
|
|
41
|
+
}
|
|
42
|
+
function createContactsButtonElement(context, options) {
|
|
43
|
+
const button = context.dom.createElement('solid-ui-button');
|
|
44
|
+
button.setAttribute('type', options.type || 'button');
|
|
45
|
+
button.setAttribute('variant', options.variant || 'secondary');
|
|
46
|
+
button.setAttribute('size', options.size || 'sm');
|
|
47
|
+
if (options.id) button.setAttribute('id', options.id);
|
|
48
|
+
if (options.ariaLabel) button.setAttribute('aria-label', options.ariaLabel);
|
|
49
|
+
button.setAttribute('aria-pressed', 'false');
|
|
50
|
+
if (options.contentAlign) button.setAttribute('content-align', options.contentAlign);
|
|
51
|
+
if (options.classes?.length) button.classList.add(...options.classes);
|
|
52
|
+
if (options.label) button.textContent = options.label;
|
|
53
|
+
return button;
|
|
54
|
+
}
|
|
55
|
+
const createAddressBookContactCreationDialog = (context, contactsModule, contactData, addressBooksData) => {
|
|
56
|
+
const addressBookContactCreationDialog = context.dom.createElement('form');
|
|
57
|
+
addressBookContactCreationDialog.classList.add('contacts-dialog__frame', 'contacts-dialog__content', 'flex-column');
|
|
58
|
+
addressBookContactCreationDialog.setAttribute('id', 'contacts-addressbook-picker-dialog');
|
|
59
|
+
const dialogDescription = context.dom.createElement('p');
|
|
60
|
+
dialogDescription.setAttribute('id', 'contacts-dialog-description');
|
|
61
|
+
dialogDescription.classList.add('contacts-dialog__description');
|
|
62
|
+
dialogDescription.textContent = 'Choose an address book and group for this contact, or create them first.';
|
|
63
|
+
addressBookContactCreationDialog.setAttribute('aria-describedby', 'contacts-dialog-description');
|
|
64
|
+
const mainContent = context.dom.createElement('div');
|
|
65
|
+
mainContent.classList.add('contacts-dialog__main');
|
|
66
|
+
const addressBookContactCreationDiv = context.dom.createElement('section');
|
|
67
|
+
addressBookContactCreationDiv.setAttribute('aria-label', 'Contact creation options');
|
|
68
|
+
addressBookContactCreationDiv.classList.add('contacts-dialog__body', 'contacts-dialog__creation', 'flex-column');
|
|
69
|
+
const addressBookDetailsSection = createAddressBookDetailsSection(context);
|
|
70
|
+
const statusRegion = createContactsStatusRegion(context);
|
|
71
|
+
const addressBookListDiv = createAddressBookListSection(context, contactsModule, contactData, addressBooksData);
|
|
72
|
+
const inlinePanelRegion = createInlinePanelRegion(context);
|
|
73
|
+
addressBookDetailsSection.appendChild(addressBookListDiv);
|
|
74
|
+
addressBookDetailsSection.appendChild(inlinePanelRegion);
|
|
75
|
+
addressBookContactCreationDiv.appendChild(addressBookDetailsSection);
|
|
76
|
+
mainContent.appendChild(dialogDescription);
|
|
77
|
+
mainContent.appendChild(addressBookContactCreationDiv);
|
|
78
|
+
addressBookContactCreationDialog.appendChild(mainContent);
|
|
79
|
+
addressBookContactCreationDialog.appendChild(statusRegion);
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
const firstAction = addressBookContactCreationDialog.querySelector('#addressbook-list button, #contacts-create-addressbook-button, #contacts-addressbook-uri-entry-button');
|
|
82
|
+
if (firstAction) firstAction.focus();
|
|
83
|
+
}, 0);
|
|
84
|
+
return addressBookContactCreationDialog;
|
|
85
|
+
};
|
|
86
|
+
exports.createAddressBookContactCreationDialog = createAddressBookContactCreationDialog;
|
|
87
|
+
function createAddressBookContactCreationFooter(context, contactsModule, addressBooksData, contactData) {
|
|
88
|
+
const footer = context.dom.createElement('div');
|
|
89
|
+
footer.classList.add('contacts-dialog__footer');
|
|
90
|
+
const cancelButton = createDialogCancelButton(context);
|
|
91
|
+
const submitButton = createNewContactCreationButton(context, contactsModule, addressBooksData, contactData);
|
|
92
|
+
footer.appendChild(cancelButton);
|
|
93
|
+
footer.appendChild(submitButton);
|
|
94
|
+
return footer;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Backward-compatible export name used by consumers and tests.
|
|
98
|
+
const createAddressBookUriSelectorDialog = exports.createAddressBookUriSelectorDialog = createAddressBookContactCreationDialog;
|
|
99
|
+
function createPopupHeader(context, title, titleId, closeButton) {
|
|
100
|
+
const header = context.dom.createElement('div');
|
|
101
|
+
header.classList.add('contacts-dialog__header', 'contacts-dialog__header--popup');
|
|
102
|
+
const heading = context.dom.createElement('h3');
|
|
103
|
+
heading.setAttribute('id', titleId);
|
|
104
|
+
heading.classList.add('contacts-dialog__title');
|
|
105
|
+
heading.textContent = title;
|
|
106
|
+
header.appendChild(heading);
|
|
107
|
+
header.appendChild(closeButton);
|
|
108
|
+
return header;
|
|
109
|
+
}
|
|
110
|
+
const createAddressBookDetailsSection = context => {
|
|
111
|
+
const addressBookDetailsSection = context.dom.createElement('section');
|
|
112
|
+
addressBookDetailsSection.setAttribute('id', 'addressbook-details-section');
|
|
113
|
+
addressBookDetailsSection.classList.add('contacts-dialog__details', 'flex-row');
|
|
114
|
+
return addressBookDetailsSection;
|
|
115
|
+
};
|
|
116
|
+
const createAddressBookCreationButton = (context, contactsModule, addressBooksData, contactData) => {
|
|
117
|
+
const setButtonOnClickHandler = async event => {
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
resetSelectedAddressBookState(context);
|
|
120
|
+
const newAddressBookForm = createNewAddressBookForm(context, addressBooksData, contactsModule, contactData);
|
|
121
|
+
renderInlinePanel(context, newAddressBookForm);
|
|
122
|
+
};
|
|
123
|
+
const addressBookCreationButton = createContactsButtonElement(context, {
|
|
124
|
+
id: 'contacts-create-addressbook-button',
|
|
125
|
+
type: 'button',
|
|
126
|
+
label: 'Create Address Book',
|
|
127
|
+
variant: 'primary',
|
|
128
|
+
size: 'md',
|
|
129
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary']
|
|
130
|
+
});
|
|
131
|
+
addressBookCreationButton.addEventListener('click', setButtonOnClickHandler);
|
|
132
|
+
return addressBookCreationButton;
|
|
133
|
+
};
|
|
134
|
+
const createAddressBookUriEntryDialog = (context, contactsModule, addressBooksData, contactData) => {
|
|
135
|
+
const addressBookUriEntryDialog = context.dom.createElement('section');
|
|
136
|
+
addressBookUriEntryDialog.setAttribute('aria-labelledby', 'contacts-addressbook-uri-entry-title');
|
|
137
|
+
addressBookUriEntryDialog.setAttribute('id', 'contacts-addressbook-uri-entry');
|
|
138
|
+
addressBookUriEntryDialog.classList.add('contacts-dialog__popup', 'contacts-dialog__uri-entry', 'flex-column');
|
|
139
|
+
const closeButton = createCloseButton(context, addressBookUriEntryDialog);
|
|
140
|
+
addressBookUriEntryDialog.appendChild(createPopupHeader(context, 'Enter address book URI', 'contacts-addressbook-uri-entry-title', closeButton));
|
|
141
|
+
addressBookUriEntryDialog.appendChild(createAddressBookUriEntryForm(context, contactsModule, addressBooksData, contactData));
|
|
142
|
+
return addressBookUriEntryDialog;
|
|
143
|
+
};
|
|
144
|
+
const createAddressBookUriEntryButton = (context, contactsModule, addressBooksData, contactData) => {
|
|
145
|
+
const setButtonOnClickHandler = async event => {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
resetSelectedAddressBookState(context);
|
|
148
|
+
const addressBookUriEntryDialog = createAddressBookUriEntryDialog(context, contactsModule, addressBooksData, contactData);
|
|
149
|
+
renderInlinePanel(context, addressBookUriEntryDialog);
|
|
150
|
+
};
|
|
151
|
+
const addressBookCreationButton = createContactsButtonElement(context, {
|
|
152
|
+
id: 'contacts-addressbook-uri-entry-button',
|
|
153
|
+
type: 'button',
|
|
154
|
+
label: 'Enter Address Book URI',
|
|
155
|
+
variant: 'primary',
|
|
156
|
+
size: 'md',
|
|
157
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary']
|
|
158
|
+
});
|
|
159
|
+
addressBookCreationButton.addEventListener('click', setButtonOnClickHandler);
|
|
160
|
+
return addressBookCreationButton;
|
|
161
|
+
};
|
|
162
|
+
const createAddressBookUriEntryForm = (context, contactsModule, addressBooksData, contactData) => {
|
|
163
|
+
let submitButton = null;
|
|
164
|
+
const setButtonOnSubmitHandler = async event => {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
await runWithButtonLoading(context, submitButton, 'Adding...', async () => {
|
|
167
|
+
try {
|
|
168
|
+
const addressBookUriField = context.dom.querySelector('#addressBookUriInput');
|
|
169
|
+
const enteredAddressBookUri = sanitizeInput(addressBookUriField?.value || '');
|
|
170
|
+
if (addressBookUriField) addressBookUriField.value = enteredAddressBookUri;
|
|
171
|
+
if (!enteredAddressBookUri) {
|
|
172
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, _texts.errorNotExistsAddressBookUri);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const uriCheck = enteredAddressBookUri.substring(enteredAddressBookUri.length - 5, enteredAddressBookUri.length);
|
|
176
|
+
const normalizedUri = uriCheck === '#this' ? enteredAddressBookUri : enteredAddressBookUri + '#this';
|
|
177
|
+
const books = await (0, _mutations.addANewAddressBookUriToAddressBooks)(context, contactsModule, addressBooksData, normalizedUri);
|
|
178
|
+
const addressBookListDiv = context.dom.querySelector('#addressbook-list');
|
|
179
|
+
if (addressBookListDiv) {
|
|
180
|
+
clearInlinePanel(context);
|
|
181
|
+
removePopupOverlayIfNoPopup(context);
|
|
182
|
+
const addressBookCreationButton = context.dom.getElementById('contacts-create-addressbook-button');
|
|
183
|
+
const addressBookUriEntryButton = context.dom.getElementById('contacts-addressbook-uri-entry-button');
|
|
184
|
+
addressBookCreationButton.remove();
|
|
185
|
+
addressBookUriEntryButton.remove();
|
|
186
|
+
addressBookListDiv.appendChild(createAddressBookButton(context, contactsModule, books.addressBooksData, books.addressBook, enteredAddressBookUri, contactData));
|
|
187
|
+
addressBookListDiv.appendChild(createAddressBookCreationButton(context, contactsModule, books.addressBooksData, contactData));
|
|
188
|
+
addressBookListDiv.appendChild(createAddressBookUriEntryButton(context, contactsModule, books.addressBooksData, contactData));
|
|
189
|
+
announceContactsStatus(context, 'Address book added to the list.');
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
(0, _debug.error)('Contacts address book URI processing failed', error);
|
|
193
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, (0, _contactsErrors.formatContactsDialogError)(_texts.errorProcessingUriAddressBook, error));
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
const inputAddressUriEventListener = event => {
|
|
198
|
+
const input = event.target;
|
|
199
|
+
input.value = sanitizeInput(input.value);
|
|
200
|
+
(0, _contactsErrors.checkAndRemoveErrorDisplay)(context);
|
|
201
|
+
};
|
|
202
|
+
const addressBookUriEntryForm = context.dom.createElement('form');
|
|
203
|
+
addressBookUriEntryForm.setAttribute('id', 'contacts-address-uri-entry-form');
|
|
204
|
+
addressBookUriEntryForm.classList.add('contacts-dialog__uri-entry-form', 'flex-column');
|
|
205
|
+
addressBookUriEntryForm.method = 'post';
|
|
206
|
+
addressBookUriEntryForm.addEventListener('submit', setButtonOnSubmitHandler);
|
|
207
|
+
const popupBody = createPopupSection(context, 'contacts-dialog__popup-body', 'flex-column-center', 'text-center');
|
|
208
|
+
const popupFooter = createPopupSection(context, 'contacts-dialog__popup-footer');
|
|
209
|
+
const addressBookUriEntryLabel = context.dom.createElement('label');
|
|
210
|
+
addressBookUriEntryLabel.setAttribute('for', 'addressBookUriInput');
|
|
211
|
+
const addressBookUriEntryLabelText = context.dom.createElement('span');
|
|
212
|
+
addressBookUriEntryLabelText.classList.add('sr-only');
|
|
213
|
+
addressBookUriEntryLabelText.textContent = 'Address book URI';
|
|
214
|
+
addressBookUriEntryLabel.appendChild(addressBookUriEntryLabelText);
|
|
215
|
+
const addressBookNameInputBox = context.dom.createElement('input');
|
|
216
|
+
addressBookNameInputBox.type = 'text';
|
|
217
|
+
addressBookNameInputBox.name = 'addressBookUri';
|
|
218
|
+
addressBookNameInputBox.id = 'addressBookUriInput';
|
|
219
|
+
addressBookNameInputBox.placeholder = 'Enter address book URI to find your address book';
|
|
220
|
+
addressBookNameInputBox.classList.add('input', 'contacts-dialog__uri-input');
|
|
221
|
+
addressBookNameInputBox.addEventListener('input', inputAddressUriEventListener);
|
|
222
|
+
popupBody.appendChild(addressBookUriEntryLabel);
|
|
223
|
+
popupBody.appendChild(addressBookNameInputBox);
|
|
224
|
+
submitButton = createAddressBookUriEntryAddButton(context);
|
|
225
|
+
popupFooter.appendChild(submitButton);
|
|
226
|
+
addressBookUriEntryForm.appendChild(popupBody);
|
|
227
|
+
addressBookUriEntryForm.appendChild(popupFooter);
|
|
228
|
+
return addressBookUriEntryForm;
|
|
229
|
+
};
|
|
230
|
+
const createAddressBookUriEntryAddButton = context => {
|
|
231
|
+
const setButtonOnClickHandler = async event => {
|
|
232
|
+
event.preventDefault();
|
|
233
|
+
const addressBookUriEntryForm = context.dom.querySelector('#contacts-address-uri-entry-form');
|
|
234
|
+
// @ts-ignore
|
|
235
|
+
if (addressBookUriEntryForm) addressBookUriEntryForm.requestSubmit();
|
|
236
|
+
};
|
|
237
|
+
const entryButton = createContactsButtonElement(context, {
|
|
238
|
+
id: 'contacts-addressbook-entry-button',
|
|
239
|
+
type: 'submit',
|
|
240
|
+
ariaLabel: 'Submit new address book URI',
|
|
241
|
+
variant: 'primary',
|
|
242
|
+
size: 'md',
|
|
243
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary', 'contacts-dialog__uri-submit', 'inline-flex-row', 'justify-center']
|
|
244
|
+
});
|
|
245
|
+
entryButton.addEventListener('click', setButtonOnClickHandler);
|
|
246
|
+
entryButton.textContent = 'Add';
|
|
247
|
+
return entryButton;
|
|
248
|
+
};
|
|
249
|
+
const createAddressBookListSection = (context, contactsModule, contactData, addressBooksData) => {
|
|
250
|
+
const addressBookListSection = context.dom.createElement('section');
|
|
251
|
+
addressBookListSection.setAttribute('class', 'contacts-dialog__address-book-list');
|
|
252
|
+
addressBookListSection.setAttribute('aria-label', 'Select an address book for this contact.');
|
|
253
|
+
addressBookListSection.setAttribute('aria-describedby', 'addressbook-list');
|
|
254
|
+
addressBookListSection.setAttribute('id', 'addressbook-list');
|
|
255
|
+
const heading = context.dom.createElement('h3');
|
|
256
|
+
heading.classList.add('contacts-dialog__column-title');
|
|
257
|
+
heading.textContent = 'Address Books';
|
|
258
|
+
addressBookListSection.appendChild(heading);
|
|
259
|
+
addressBooksData.public.forEach((addressBook, addressBookUri) => {
|
|
260
|
+
addressBookListSection.appendChild(createAddressBookButton(context, contactsModule, addressBooksData, addressBook, addressBookUri, contactData));
|
|
261
|
+
});
|
|
262
|
+
addressBooksData.private.forEach((addressBook, addressBookUri) => {
|
|
263
|
+
addressBookListSection.appendChild(createAddressBookButton(context, contactsModule, addressBooksData, addressBook, addressBookUri, contactData));
|
|
264
|
+
});
|
|
265
|
+
const addressBookCreationButton = createAddressBookCreationButton(context, contactsModule, addressBooksData, contactData);
|
|
266
|
+
const addressBookUriEntryButton = createAddressBookUriEntryButton(context, contactsModule, addressBooksData, contactData);
|
|
267
|
+
addressBookListSection.appendChild(addressBookCreationButton);
|
|
268
|
+
addressBookListSection.appendChild(addressBookUriEntryButton);
|
|
269
|
+
return addressBookListSection;
|
|
270
|
+
};
|
|
271
|
+
const createAddressBookGroupCreationButton = (context, contactsModule, addressBooksData, contactData) => {
|
|
272
|
+
const setButtonOnClickHandler = async event => {
|
|
273
|
+
event.preventDefault();
|
|
274
|
+
const groupNameForm = context.dom.getElementById('new-group-form');
|
|
275
|
+
if (!groupNameForm) {
|
|
276
|
+
const newGroupForm = createGroupNameForm(context, contactsModule, addressBooksData, contactData);
|
|
277
|
+
renderInlinePanel(context, newGroupForm);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const groupCreationButton = createContactsButtonElement(context, {
|
|
281
|
+
id: 'contacts-create-group-button',
|
|
282
|
+
type: 'button',
|
|
283
|
+
label: 'Create Group',
|
|
284
|
+
variant: 'primary',
|
|
285
|
+
size: 'md',
|
|
286
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary']
|
|
287
|
+
});
|
|
288
|
+
groupCreationButton.addEventListener('click', setButtonOnClickHandler);
|
|
289
|
+
return groupCreationButton;
|
|
290
|
+
};
|
|
291
|
+
const createGroupListSection = (context, contactsModule, addressBooksData, addressBook, contactData) => {
|
|
292
|
+
const groupListSection = context.dom.createElement('section');
|
|
293
|
+
groupListSection.setAttribute('class', 'contacts-dialog__group-list flex-column');
|
|
294
|
+
groupListSection.setAttribute('aria-label', 'Select a group to add your contact to.');
|
|
295
|
+
groupListSection.setAttribute('aria-describedby', 'group-list');
|
|
296
|
+
groupListSection.setAttribute('id', 'group-list');
|
|
297
|
+
const heading = context.dom.createElement('h3');
|
|
298
|
+
heading.classList.add('contacts-dialog__column-title');
|
|
299
|
+
heading.textContent = 'Groups';
|
|
300
|
+
groupListSection.appendChild(heading);
|
|
301
|
+
if (addressBook) {
|
|
302
|
+
addressBook.groups.map(group => {
|
|
303
|
+
groupListSection.appendChild(createGroupButton(context, group));
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
groupListSection.appendChild(createAddressBookGroupCreationButton(context, contactsModule, addressBooksData, contactData));
|
|
307
|
+
return groupListSection;
|
|
308
|
+
};
|
|
309
|
+
const createNewContactCreationButton = (context, contactsModule, addressBooksData, contactData) => {
|
|
310
|
+
let button;
|
|
311
|
+
const setButtonOnClickHandler = async event => {
|
|
312
|
+
event.preventDefault();
|
|
313
|
+
await runWithButtonLoading(context, button, 'Adding...', async () => {
|
|
314
|
+
const contactExistsByWebID = (0, _selectors.checkIfContactExistsByWebID)(addressBooksData, contactData.webID);
|
|
315
|
+
const contactExistsByNameUri = (0, _selectors.checkIfContactExistsByName)(addressBooksData, contactData.name);
|
|
316
|
+
const contactExistsHandled = handleContactExistsFromNonRegisteredAddressBook(context, addressBooksData, contactData, contactExistsByWebID, contactExistsByNameUri);
|
|
317
|
+
if (contactExistsHandled) return;
|
|
318
|
+
let selectedAddressBookUri = null;
|
|
319
|
+
const selectedGroupUris = [];
|
|
320
|
+
const selectedAddressBookElements = context.dom.querySelectorAll('#addressbook-list .contacts-dialog__list-button[selected]');
|
|
321
|
+
selectedAddressBookElements.forEach(addressBookButton => {
|
|
322
|
+
selectedAddressBookUri = addressBookButton.getAttribute('id');
|
|
323
|
+
});
|
|
324
|
+
const selectedGroupElements = context.dom.querySelectorAll('#group-list .contacts-dialog__list-button[selected]');
|
|
325
|
+
selectedGroupElements.forEach(groupButtons => {
|
|
326
|
+
selectedGroupUris.push(groupButtons.getAttribute('id'));
|
|
327
|
+
});
|
|
328
|
+
if (selectedGroupUris.length) {
|
|
329
|
+
const selectedAddressBookUris = {
|
|
330
|
+
addressBookUri: selectedAddressBookUri,
|
|
331
|
+
groupUris: selectedGroupUris
|
|
332
|
+
};
|
|
333
|
+
try {
|
|
334
|
+
const contactUri = await (0, _mutations.createContactInAddressBook)(context, contactsModule, contactData, selectedAddressBookUris);
|
|
335
|
+
finalizeContactEntry(context, addressBooksData, contactData, contactUri);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
(0, _debug.error)('Contacts contact creation failed', error);
|
|
338
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, (0, _contactsErrors.formatContactsDialogError)(_texts.errorContactCreation, error));
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, _texts.groupIsRequired);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
};
|
|
345
|
+
button = createContactsButtonElement(context, {
|
|
346
|
+
id: 'contacts-submit-contact-button',
|
|
347
|
+
type: 'submit',
|
|
348
|
+
variant: 'primary',
|
|
349
|
+
size: 'md',
|
|
350
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary', 'contacts-dialog__submit-contact']
|
|
351
|
+
});
|
|
352
|
+
button.disabled = true;
|
|
353
|
+
button.setAttribute('aria-disabled', 'true');
|
|
354
|
+
button.addEventListener('click', setButtonOnClickHandler);
|
|
355
|
+
button.textContent = 'Add Contact';
|
|
356
|
+
return button;
|
|
357
|
+
};
|
|
358
|
+
const createAddressBookButton = (context, contactsModule, addressBooksData, addressBook, addressBookUri, contactData) => {
|
|
359
|
+
const setButtonOnClickHandler = event => {
|
|
360
|
+
event.preventDefault();
|
|
361
|
+
const selectedAddressBookButton = event.currentTarget;
|
|
362
|
+
const previouslySelected = isContactsListButtonSelected(selectedAddressBookButton);
|
|
363
|
+
const addressBookDetailsSection = context.dom.getElementById('addressbook-details-section');
|
|
364
|
+
let addressBook = null;
|
|
365
|
+
// remove the previous groups
|
|
366
|
+
const groupDivToRemove = context.dom.getElementById('group-list');
|
|
367
|
+
if (groupDivToRemove) groupDivToRemove.remove();
|
|
368
|
+
|
|
369
|
+
// remove presious address book selection bc you can only have one
|
|
370
|
+
const selectedAddressBookElements = context.dom.querySelectorAll('#addressbook-list .contacts-dialog__list-button[selected]');
|
|
371
|
+
selectedAddressBookElements.forEach(addressBookButton => {
|
|
372
|
+
setContactsListButtonSelected(addressBookButton, false);
|
|
373
|
+
});
|
|
374
|
+
if (previouslySelected) {
|
|
375
|
+
setContactsListButtonSelected(selectedAddressBookButton, false);
|
|
376
|
+
clearInlinePanel(context);
|
|
377
|
+
} else {
|
|
378
|
+
clearInlinePanel(context);
|
|
379
|
+
setContactsListButtonSelected(selectedAddressBookButton, true);
|
|
380
|
+
// selected address book code
|
|
381
|
+
const selectedAddressBookUri = selectedAddressBookButton.id;
|
|
382
|
+
// can check for the class on private
|
|
383
|
+
addressBook = addressBooksData.public.get(selectedAddressBookUri);
|
|
384
|
+
if (!addressBook) addressBook = addressBooksData.private.get(selectedAddressBookUri);
|
|
385
|
+
|
|
386
|
+
// remove the previous groups
|
|
387
|
+
const groupDivToRemove = context.dom.getElementById('group-list');
|
|
388
|
+
if (groupDivToRemove) groupDivToRemove.remove();
|
|
389
|
+
// add groups for addressbook
|
|
390
|
+
const groupListSection = createGroupListSection(context, contactsModule, addressBooksData, addressBook, contactData);
|
|
391
|
+
addressBookDetailsSection.appendChild(groupListSection);
|
|
392
|
+
}
|
|
393
|
+
selectedAddressBookButton.blur();
|
|
394
|
+
syncAddContactActionState(context);
|
|
395
|
+
};
|
|
396
|
+
const button = createContactsButtonElement(context, {
|
|
397
|
+
id: addressBookUri,
|
|
398
|
+
type: 'button',
|
|
399
|
+
ariaLabel: 'Select address book ' + addressBook.name,
|
|
400
|
+
variant: 'secondary',
|
|
401
|
+
size: 'sm',
|
|
402
|
+
contentAlign: 'start',
|
|
403
|
+
classes: ['contacts-dialog__list-button']
|
|
404
|
+
});
|
|
405
|
+
button.setAttribute('value', addressBook.name);
|
|
406
|
+
button.addEventListener('click', setButtonOnClickHandler);
|
|
407
|
+
button.textContent = addressBook.name;
|
|
408
|
+
return button;
|
|
409
|
+
};
|
|
410
|
+
const createNewAddressBookForm = (context, addressBooksData, contactsModule, contactData) => {
|
|
411
|
+
let submitButton = null;
|
|
412
|
+
const newAddressBookEventListener = async event => {
|
|
413
|
+
event.preventDefault();
|
|
414
|
+
await runWithButtonLoading(context, submitButton, 'Creating...', async () => {
|
|
415
|
+
try {
|
|
416
|
+
let enteredAddressBookUri = null;
|
|
417
|
+
let newGroupNode = null;
|
|
418
|
+
const addressNameField = context.dom.querySelector('#addressBookNameInput');
|
|
419
|
+
|
|
420
|
+
// @ts-ignore
|
|
421
|
+
const enteredAddressName = sanitizeInput(addressNameField.value);
|
|
422
|
+
// @ts-ignore
|
|
423
|
+
addressNameField.value = enteredAddressName;
|
|
424
|
+
const addressContainerField = context.dom.querySelector('#addressBookContainerInput');
|
|
425
|
+
|
|
426
|
+
// @ts-ignore
|
|
427
|
+
const enteredAddressContainer = sanitizeInput(addressContainerField.value);
|
|
428
|
+
// @ts-ignore
|
|
429
|
+
addressContainerField.value = enteredAddressContainer;
|
|
430
|
+
const groupNameField = context.dom.querySelector('#groupNameInput');
|
|
431
|
+
// @ts-ignore
|
|
432
|
+
const enteredGroupName = sanitizeInput(groupNameField.value);
|
|
433
|
+
// @ts-ignore
|
|
434
|
+
groupNameField.value = enteredGroupName;
|
|
435
|
+
if (!enteredAddressName) return;
|
|
436
|
+
enteredAddressBookUri = await (0, _mutations.handleAddressBookCreation)(context, enteredAddressContainer, enteredAddressName);
|
|
437
|
+
if (!enteredAddressBookUri) {
|
|
438
|
+
throw new Error(_texts.errorNotExistsAddressBookUri);
|
|
439
|
+
}
|
|
440
|
+
const resolvedAddressBookUri = enteredAddressBookUri;
|
|
441
|
+
if (enteredGroupName) {
|
|
442
|
+
const selectedAddressBookNode = new _rdflib.NamedNode(resolvedAddressBookUri);
|
|
443
|
+
newGroupNode = await saveNewGroupToAddressBook(context, selectedAddressBookNode, enteredGroupName);
|
|
444
|
+
}
|
|
445
|
+
const nextAddressBooksData = (0, _helpers.addAddressBookToAddressBooksData)(addressBooksData, resolvedAddressBookUri, {
|
|
446
|
+
name: enteredAddressName,
|
|
447
|
+
groups: newGroupNode ? [{
|
|
448
|
+
name: enteredGroupName,
|
|
449
|
+
uri: newGroupNode.value
|
|
450
|
+
}] : [],
|
|
451
|
+
contacts: []
|
|
452
|
+
}, 'private');
|
|
453
|
+
refreshAddressBookDialogContents(context, contactsModule, contactData, nextAddressBooksData, resolvedAddressBookUri, newGroupNode?.value || null);
|
|
454
|
+
clearInlinePanel(context);
|
|
455
|
+
removePopupOverlayIfNoPopup(context);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
(0, _debug.error)('Contacts address book creation failed', error);
|
|
458
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, (0, _contactsErrors.formatContactsDialogError)(_texts.errorAddressBookCreation, error));
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
};
|
|
462
|
+
const submitFormEventListener = event => {
|
|
463
|
+
event.preventDefault();
|
|
464
|
+
newAddressBookForm.requestSubmit();
|
|
465
|
+
};
|
|
466
|
+
const newAddressBookForm = context.dom.createElement('form');
|
|
467
|
+
newAddressBookForm.setAttribute('aria-labelledby', 'new-addressbook-form-title');
|
|
468
|
+
newAddressBookForm.method = 'post';
|
|
469
|
+
newAddressBookForm.setAttribute('id', 'new-addressbook-form');
|
|
470
|
+
newAddressBookForm.classList.add('contacts-dialog__popup', 'contacts-dialog__address-form', 'flex-column');
|
|
471
|
+
const addressBookNameLabel = context.dom.createElement('label');
|
|
472
|
+
addressBookNameLabel.setAttribute('for', 'addressBookNameInput');
|
|
473
|
+
const addressBookNameLabelText = context.dom.createElement('span');
|
|
474
|
+
addressBookNameLabelText.classList.add('sr-only');
|
|
475
|
+
addressBookNameLabelText.textContent = 'Address book name';
|
|
476
|
+
addressBookNameLabel.appendChild(addressBookNameLabelText);
|
|
477
|
+
const addressBookNameInputBox = context.dom.createElement('input');
|
|
478
|
+
addressBookNameInputBox.type = 'text';
|
|
479
|
+
addressBookNameInputBox.name = 'addressBookName';
|
|
480
|
+
addressBookNameInputBox.id = 'addressBookNameInput';
|
|
481
|
+
addressBookNameInputBox.placeholder = 'New address book name';
|
|
482
|
+
addressBookNameInputBox.classList.add('input');
|
|
483
|
+
addressBookNameInputBox.required = true;
|
|
484
|
+
const addressBookContainerLabel = context.dom.createElement('label');
|
|
485
|
+
addressBookContainerLabel.setAttribute('for', 'addressBookContainerInput');
|
|
486
|
+
const addressBookContainerLabelText = context.dom.createElement('span');
|
|
487
|
+
addressBookContainerLabelText.classList.add('sr-only');
|
|
488
|
+
addressBookContainerLabelText.textContent = 'Address book container';
|
|
489
|
+
addressBookContainerLabel.appendChild(addressBookContainerLabelText);
|
|
490
|
+
const addressBookContainerInputBox = context.dom.createElement('input');
|
|
491
|
+
addressBookContainerInputBox.type = 'text';
|
|
492
|
+
addressBookContainerInputBox.name = 'addressBookContainer';
|
|
493
|
+
addressBookContainerInputBox.id = 'addressBookContainerInput';
|
|
494
|
+
addressBookContainerInputBox.placeholder = 'Address book container';
|
|
495
|
+
addressBookContainerInputBox.classList.add('input');
|
|
496
|
+
addressBookContainerInputBox.required = true;
|
|
497
|
+
const groupNameLabel = context.dom.createElement('label');
|
|
498
|
+
groupNameLabel.setAttribute('for', 'groupNameInput');
|
|
499
|
+
const groupNameLabelText = context.dom.createElement('span');
|
|
500
|
+
groupNameLabelText.classList.add('sr-only');
|
|
501
|
+
groupNameLabelText.textContent = 'Group name';
|
|
502
|
+
groupNameLabel.appendChild(groupNameLabelText);
|
|
503
|
+
const groupNameInputBox = context.dom.createElement('input');
|
|
504
|
+
groupNameInputBox.type = 'text';
|
|
505
|
+
groupNameInputBox.name = 'groupName';
|
|
506
|
+
groupNameInputBox.id = 'groupNameInput';
|
|
507
|
+
groupNameInputBox.placeholder = 'New group name';
|
|
508
|
+
groupNameInputBox.classList.add('input');
|
|
509
|
+
groupNameInputBox.required = true;
|
|
510
|
+
const validationMessage = createValidationMessage(context);
|
|
511
|
+
validationMessage.setAttribute('id', 'contacts-addressbook-validation-message');
|
|
512
|
+
addressBookNameInputBox.setAttribute('aria-describedby', 'contacts-addressbook-validation-message');
|
|
513
|
+
addressBookContainerInputBox.setAttribute('aria-describedby', 'contacts-addressbook-validation-message');
|
|
514
|
+
groupNameInputBox.setAttribute('aria-describedby', 'contacts-addressbook-validation-message');
|
|
515
|
+
attachSanitizingValidation(addressBookNameInputBox, validationMessage);
|
|
516
|
+
attachSanitizingValidation(addressBookContainerInputBox, validationMessage);
|
|
517
|
+
attachSanitizingValidation(groupNameInputBox, validationMessage);
|
|
518
|
+
submitButton = createContactsButtonElement(context, {
|
|
519
|
+
type: 'submit',
|
|
520
|
+
variant: 'primary',
|
|
521
|
+
size: 'md',
|
|
522
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary', 'contacts-dialog__address-submit']
|
|
523
|
+
});
|
|
524
|
+
submitButton.addEventListener('click', submitFormEventListener);
|
|
525
|
+
submitButton.textContent = 'Add';
|
|
526
|
+
const closeButton = createCloseButton(context, newAddressBookForm);
|
|
527
|
+
const popupBody = createPopupSection(context, 'contacts-dialog__popup-body', 'flex-column');
|
|
528
|
+
const popupFooter = createPopupSection(context, 'contacts-dialog__popup-footer');
|
|
529
|
+
newAddressBookForm.appendChild(createPopupHeader(context, 'Create a new address book', 'new-addressbook-form-title', closeButton));
|
|
530
|
+
popupBody.appendChild(addressBookNameLabel);
|
|
531
|
+
popupBody.appendChild(addressBookNameInputBox);
|
|
532
|
+
popupBody.appendChild(addressBookContainerLabel);
|
|
533
|
+
popupBody.appendChild(addressBookContainerInputBox);
|
|
534
|
+
popupBody.appendChild(groupNameLabel);
|
|
535
|
+
popupBody.appendChild(groupNameInputBox);
|
|
536
|
+
popupBody.appendChild(validationMessage);
|
|
537
|
+
popupFooter.appendChild(submitButton);
|
|
538
|
+
newAddressBookForm.appendChild(popupBody);
|
|
539
|
+
newAddressBookForm.appendChild(popupFooter);
|
|
540
|
+
newAddressBookForm.addEventListener('submit', newAddressBookEventListener);
|
|
541
|
+
return newAddressBookForm;
|
|
542
|
+
};
|
|
543
|
+
function removeDialogElement(context, element) {
|
|
544
|
+
if (element && element.classList.contains('contacts-dialog__inline-panel')) {
|
|
545
|
+
clearInlinePanel(context);
|
|
546
|
+
} else if (element) {
|
|
547
|
+
element.remove();
|
|
548
|
+
removePopupOverlayIfNoPopup(context);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
const createCloseButton = (context, element) => {
|
|
552
|
+
const buttonID = `${element.id}-close-button`;
|
|
553
|
+
const setButtonOnClickHandler = event => {
|
|
554
|
+
event.preventDefault();
|
|
555
|
+
removeDialogElement(context, element);
|
|
556
|
+
};
|
|
557
|
+
const closeButton = createContactsButtonElement(context, {
|
|
558
|
+
id: buttonID,
|
|
559
|
+
type: 'button',
|
|
560
|
+
ariaLabel: 'Close dialog',
|
|
561
|
+
variant: 'icon',
|
|
562
|
+
size: 'sm',
|
|
563
|
+
classes: ['contacts-dialog__close']
|
|
564
|
+
});
|
|
565
|
+
closeButton.addEventListener('click', setButtonOnClickHandler);
|
|
566
|
+
const iconSlot = context.dom.createElement('span');
|
|
567
|
+
iconSlot.setAttribute('slot', 'icon');
|
|
568
|
+
(0, _litHtml.render)(_profileIcons.closeIcon, iconSlot);
|
|
569
|
+
closeButton.appendChild(iconSlot);
|
|
570
|
+
return closeButton;
|
|
571
|
+
};
|
|
572
|
+
function createDialogCancelButton(context) {
|
|
573
|
+
const cancelButton = createContactsButtonElement(context, {
|
|
574
|
+
type: 'button',
|
|
575
|
+
label: _texts.dialogCancelLabelText,
|
|
576
|
+
variant: 'secondary',
|
|
577
|
+
size: 'md',
|
|
578
|
+
classes: ['contacts-dialog__cancel', 'contacts-dialog__cancel--footer']
|
|
579
|
+
});
|
|
580
|
+
cancelButton.addEventListener('click', event => {
|
|
581
|
+
event.preventDefault();
|
|
582
|
+
const sharedCancelButton = (0, _dialog.getSharedDialogCancelButton)(context.dom);
|
|
583
|
+
if (sharedCancelButton) {
|
|
584
|
+
sharedCancelButton.click();
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
return cancelButton;
|
|
588
|
+
}
|
|
589
|
+
function createPopupSection(context, className, ...extraClasses) {
|
|
590
|
+
const section = context.dom.createElement('div');
|
|
591
|
+
section.classList.add(className, ...extraClasses);
|
|
592
|
+
return section;
|
|
593
|
+
}
|
|
594
|
+
function createInlinePanelRegion(context) {
|
|
595
|
+
const region = context.dom.createElement('section');
|
|
596
|
+
region.setAttribute('id', 'contacts-inline-panel-region');
|
|
597
|
+
region.classList.add('contacts-dialog__inline-panel-region');
|
|
598
|
+
region.setAttribute('aria-live', 'polite');
|
|
599
|
+
return region;
|
|
600
|
+
}
|
|
601
|
+
function refreshAddressBookDialogContents(context, contactsModule, contactData, addressBooksData, selectedAddressBookUri, selectedGroupUri) {
|
|
602
|
+
const detailsSection = context.dom.getElementById('addressbook-details-section');
|
|
603
|
+
if (!detailsSection || !addressBooksData) return;
|
|
604
|
+
const addressBookListSection = createAddressBookListSection(context, contactsModule, contactData, addressBooksData);
|
|
605
|
+
const inlinePanelRegion = createInlinePanelRegion(context);
|
|
606
|
+
detailsSection.replaceChildren();
|
|
607
|
+
detailsSection.appendChild(addressBookListSection);
|
|
608
|
+
if (selectedAddressBookUri) {
|
|
609
|
+
const selectedAddressBook = addressBooksData.public.get(selectedAddressBookUri) || addressBooksData.private.get(selectedAddressBookUri);
|
|
610
|
+
if (selectedAddressBook) {
|
|
611
|
+
const groupListSection = createGroupListSection(context, contactsModule, addressBooksData, selectedAddressBook, contactData);
|
|
612
|
+
detailsSection.appendChild(groupListSection);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
detailsSection.appendChild(inlinePanelRegion);
|
|
616
|
+
if (selectedAddressBookUri) {
|
|
617
|
+
const selectedAddressBookButton = context.dom.getElementById(selectedAddressBookUri);
|
|
618
|
+
if (selectedAddressBookButton) {
|
|
619
|
+
setContactsListButtonSelected(selectedAddressBookButton, true);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (selectedGroupUri) {
|
|
623
|
+
const selectedGroupButton = context.dom.getElementById(selectedGroupUri);
|
|
624
|
+
if (selectedGroupButton) {
|
|
625
|
+
setContactsListButtonSelected(selectedGroupButton, true);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
syncAddContactActionState(context);
|
|
629
|
+
}
|
|
630
|
+
function resetSelectedAddressBookState(context) {
|
|
631
|
+
const selectedAddressBookElements = context.dom.querySelectorAll('#addressbook-list .contacts-dialog__list-button[selected]');
|
|
632
|
+
selectedAddressBookElements.forEach(addressBookButton => {
|
|
633
|
+
setContactsListButtonSelected(addressBookButton, false);
|
|
634
|
+
});
|
|
635
|
+
const groupListSection = context.dom.getElementById('group-list');
|
|
636
|
+
if (groupListSection) groupListSection.remove();
|
|
637
|
+
syncAddContactActionState(context);
|
|
638
|
+
}
|
|
639
|
+
function clearInlinePanel(context) {
|
|
640
|
+
const region = context.dom.getElementById('contacts-inline-panel-region');
|
|
641
|
+
if (!region) return;
|
|
642
|
+
region.replaceChildren();
|
|
643
|
+
region.classList.remove('contacts-dialog__inline-panel-region--active');
|
|
644
|
+
syncAddContactActionState(context);
|
|
645
|
+
}
|
|
646
|
+
function renderInlinePanel(context, element) {
|
|
647
|
+
const region = context.dom.getElementById('contacts-inline-panel-region');
|
|
648
|
+
if (!region) return;
|
|
649
|
+
region.replaceChildren();
|
|
650
|
+
element.classList.add('contacts-dialog__inline-panel');
|
|
651
|
+
region.appendChild(element);
|
|
652
|
+
region.classList.add('contacts-dialog__inline-panel-region--active');
|
|
653
|
+
syncAddContactActionState(context);
|
|
654
|
+
focusFirstInputInPopup(element);
|
|
655
|
+
}
|
|
656
|
+
function syncAddContactActionState(context) {
|
|
657
|
+
const selectedAddressBook = context.dom.querySelector('#addressbook-list .contacts-dialog__list-button[selected]');
|
|
658
|
+
const selectedGroup = context.dom.querySelector('#group-list .contacts-dialog__list-button[selected]');
|
|
659
|
+
const inlinePanelRegion = context.dom.getElementById('contacts-inline-panel-region');
|
|
660
|
+
const hasActiveInlinePanel = inlinePanelRegion?.classList.contains('contacts-dialog__inline-panel-region--active') ?? false;
|
|
661
|
+
setAddContactActionDisabled(context, !(selectedAddressBook && selectedGroup) || hasActiveInlinePanel);
|
|
662
|
+
}
|
|
663
|
+
function setAddContactActionDisabled(context, disabled) {
|
|
664
|
+
const actionButton = context.dom.getElementById('contacts-submit-contact-button');
|
|
665
|
+
if (!actionButton) return;
|
|
666
|
+
actionButton.disabled = disabled;
|
|
667
|
+
actionButton.setAttribute('aria-disabled', String(disabled));
|
|
668
|
+
}
|
|
669
|
+
const createGroupNameForm = (context, contactsModule, addressBooksData, contactData) => {
|
|
670
|
+
let submitButton = null;
|
|
671
|
+
const addGroupEventListener = async event => {
|
|
672
|
+
event.preventDefault();
|
|
673
|
+
await runWithButtonLoading(context, submitButton, 'Creating...', async () => {
|
|
674
|
+
try {
|
|
675
|
+
let selectedAddressBookUri = null;
|
|
676
|
+
const selectedAddressBookElements = context.dom.querySelectorAll('#addressbook-list .contacts-dialog__list-button[selected]');
|
|
677
|
+
selectedAddressBookElements.forEach(addressBookButton => {
|
|
678
|
+
selectedAddressBookUri = addressBookButton.getAttribute('id');
|
|
679
|
+
});
|
|
680
|
+
const groupNameField = context.dom.querySelector('#groupNameInput');
|
|
681
|
+
// @ts-ignore
|
|
682
|
+
const enteredGroupName = sanitizeInput(groupNameField.value);
|
|
683
|
+
// @ts-ignore
|
|
684
|
+
groupNameField.value = enteredGroupName;
|
|
685
|
+
if (!selectedAddressBookUri) {
|
|
686
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, _texts.errorNotExistsAddressBookUri);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (enteredGroupName) {
|
|
690
|
+
const selectedAddressBookNode = new _rdflib.NamedNode(selectedAddressBookUri);
|
|
691
|
+
const newGroupNode = await saveNewGroupToAddressBook(context, selectedAddressBookNode, enteredGroupName);
|
|
692
|
+
const newGroup = {
|
|
693
|
+
name: enteredGroupName,
|
|
694
|
+
uri: newGroupNode.value
|
|
695
|
+
};
|
|
696
|
+
const wasUpdated = (0, _helpers.addGroupToAddressBookData)(addressBooksData, selectedAddressBookUri, newGroup);
|
|
697
|
+
if (!wasUpdated) {
|
|
698
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, _texts.errorNotExistsAddressBookUri);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const removeGroupAddButton = context.dom.getElementById('contacts-create-group-button');
|
|
702
|
+
if (removeGroupAddButton) removeGroupAddButton.remove();
|
|
703
|
+
const groupListDiv = context.dom.querySelector('#group-list');
|
|
704
|
+
if (groupListDiv) {
|
|
705
|
+
groupListDiv.appendChild(createGroupButton(context, newGroup));
|
|
706
|
+
groupListDiv.appendChild(createAddressBookGroupCreationButton(context, contactsModule, addressBooksData, contactData));
|
|
707
|
+
announceContactsStatus(context, 'Group added to the list.');
|
|
708
|
+
}
|
|
709
|
+
clearInlinePanel(context);
|
|
710
|
+
removePopupOverlayIfNoPopup(context);
|
|
711
|
+
}
|
|
712
|
+
} catch (error) {
|
|
713
|
+
(0, _debug.error)('Contacts group creation failed', error);
|
|
714
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, (0, _contactsErrors.formatContactsDialogError)(_texts.errorGroupCreation, error));
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
};
|
|
718
|
+
const newGroupForm = context.dom.createElement('form');
|
|
719
|
+
newGroupForm.setAttribute('aria-labelledby', 'new-group-form-title');
|
|
720
|
+
newGroupForm.addEventListener('submit', addGroupEventListener);
|
|
721
|
+
newGroupForm.setAttribute('id', 'new-group-form');
|
|
722
|
+
newGroupForm.classList.add('contacts-dialog__popup', 'contacts-dialog__group-form', 'flex-column');
|
|
723
|
+
const groupNameLabel = context.dom.createElement('label');
|
|
724
|
+
groupNameLabel.setAttribute('for', 'groupNameInput');
|
|
725
|
+
const groupNameLabelText = context.dom.createElement('span');
|
|
726
|
+
groupNameLabelText.classList.add('sr-only');
|
|
727
|
+
groupNameLabelText.textContent = 'Group name';
|
|
728
|
+
groupNameLabel.appendChild(groupNameLabelText);
|
|
729
|
+
const groupNameInputBox = context.dom.createElement('input');
|
|
730
|
+
groupNameInputBox.type = 'text';
|
|
731
|
+
groupNameInputBox.name = 'groupName';
|
|
732
|
+
groupNameInputBox.id = 'groupNameInput';
|
|
733
|
+
groupNameInputBox.placeholder = 'New group name';
|
|
734
|
+
groupNameInputBox.classList.add('input');
|
|
735
|
+
const validationMessage = createValidationMessage(context);
|
|
736
|
+
validationMessage.setAttribute('id', 'contacts-group-validation-message');
|
|
737
|
+
groupNameInputBox.setAttribute('aria-describedby', 'contacts-group-validation-message');
|
|
738
|
+
attachSanitizingValidation(groupNameInputBox, validationMessage);
|
|
739
|
+
submitButton = createAddGroupButton(context, newGroupForm);
|
|
740
|
+
const closeButton = createCloseButton(context, newGroupForm);
|
|
741
|
+
const popupBody = createPopupSection(context, 'contacts-dialog__popup-body', 'flex-column');
|
|
742
|
+
const popupFooter = createPopupSection(context, 'contacts-dialog__popup-footer');
|
|
743
|
+
newGroupForm.appendChild(createPopupHeader(context, 'Create a new group', 'new-group-form-title', closeButton));
|
|
744
|
+
popupBody.appendChild(groupNameLabel);
|
|
745
|
+
popupBody.appendChild(groupNameInputBox);
|
|
746
|
+
popupBody.appendChild(validationMessage);
|
|
747
|
+
popupFooter.appendChild(submitButton);
|
|
748
|
+
newGroupForm.appendChild(popupBody);
|
|
749
|
+
newGroupForm.appendChild(popupFooter);
|
|
750
|
+
return newGroupForm;
|
|
751
|
+
};
|
|
752
|
+
const createAddGroupButton = (context, form) => {
|
|
753
|
+
const setButtonOnClickHandler = async event => {
|
|
754
|
+
event.preventDefault();
|
|
755
|
+
form.requestSubmit();
|
|
756
|
+
};
|
|
757
|
+
const button = createContactsButtonElement(context, {
|
|
758
|
+
id: 'contacts-create-group-button',
|
|
759
|
+
type: 'button',
|
|
760
|
+
label: 'Add',
|
|
761
|
+
variant: 'primary',
|
|
762
|
+
size: 'md',
|
|
763
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__action-button--primary', 'contacts-dialog__group-submit']
|
|
764
|
+
});
|
|
765
|
+
button.addEventListener('click', setButtonOnClickHandler);
|
|
766
|
+
return button;
|
|
767
|
+
};
|
|
768
|
+
const handleContactExistsFromNonRegisteredAddressBook = (context, addressBooksData, contactData, contactExistsByWebID, contactExistsByNameUri) => {
|
|
769
|
+
if (contactExistsByWebID) {
|
|
770
|
+
(0, _contactsErrors.addErrorToErrorDisplay)(context, _texts.contactExistsMessage);
|
|
771
|
+
return true;
|
|
772
|
+
} else if (contactExistsByNameUri) {
|
|
773
|
+
const fromRegisteredAddressBook = false;
|
|
774
|
+
const handled = handleContactExistsByName(context, addressBooksData, contactData, contactExistsByNameUri, fromRegisteredAddressBook);
|
|
775
|
+
return handled;
|
|
776
|
+
}
|
|
777
|
+
return false;
|
|
778
|
+
};
|
|
779
|
+
const handleContactExistsByName = (context, addressBooksData, contactData, contactExistsByNameUri, fromRegisteredAddressBook) => {
|
|
780
|
+
const selectorDialog = context.dom.getElementById('contacts-addressbook-picker-dialog');
|
|
781
|
+
const useSharedDialog = fromRegisteredAddressBook || !selectorDialog;
|
|
782
|
+
if (useSharedDialog) {
|
|
783
|
+
void openSharedContactExistsDialog(context, addressBooksData, contactData, contactExistsByNameUri);
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
const contactExistsDialog = context.dom.createElement('section');
|
|
787
|
+
contactExistsDialog.setAttribute('role', 'alertdialog');
|
|
788
|
+
contactExistsDialog.setAttribute('aria-modal', 'true');
|
|
789
|
+
contactExistsDialog.setAttribute('aria-labelledby', 'contacts-contact-exists-title');
|
|
790
|
+
contactExistsDialog.setAttribute('aria-describedby', 'contacts-contact-exists-message');
|
|
791
|
+
contactExistsDialog.setAttribute('tabindex', '-1');
|
|
792
|
+
contactExistsDialog.classList.add('contacts-dialog__popup', 'contacts-dialog__contact-exists', 'flex-column');
|
|
793
|
+
const popupBody = createPopupSection(context, 'contacts-dialog__popup-body', 'flex-column');
|
|
794
|
+
const popupFooter = createPopupSection(context, 'contacts-dialog__popup-footer');
|
|
795
|
+
const heading = context.dom.createElement('h3');
|
|
796
|
+
heading.setAttribute('id', 'contacts-contact-exists-title');
|
|
797
|
+
heading.classList.add('contacts-dialog__title');
|
|
798
|
+
heading.textContent = 'Contact already exists';
|
|
799
|
+
const message = context.dom.createElement('p');
|
|
800
|
+
message.setAttribute('id', 'contacts-contact-exists-message');
|
|
801
|
+
message.textContent = `${contactData.name} already exists. Do you want to add their WebID?`;
|
|
802
|
+
const confirmButton = createContactsButtonElement(context, {
|
|
803
|
+
type: 'button',
|
|
804
|
+
label: 'Yes',
|
|
805
|
+
variant: 'primary',
|
|
806
|
+
size: 'md',
|
|
807
|
+
classes: ['contacts-dialog__action-button', 'contacts-dialog__confirm', 'inline-flex-row', 'justify-center']
|
|
808
|
+
});
|
|
809
|
+
confirmButton.addEventListener('click', async event => {
|
|
810
|
+
event.preventDefault();
|
|
811
|
+
await runWithButtonLoading(context, confirmButton, 'Adding...', async () => {
|
|
812
|
+
await (0, _mutations.addWebIDToExistingContact)(context, contactData, contactExistsByNameUri);
|
|
813
|
+
contactExistsDialog.remove();
|
|
814
|
+
finalizeContactEntry(context, addressBooksData, contactData, addressBooksData.contactWebIDs.get(contactData.webID));
|
|
815
|
+
(0, _helpers.refreshButton)(context, addressBooksData, contactData);
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
const cancelButton = createContactsButtonElement(context, {
|
|
819
|
+
type: 'button',
|
|
820
|
+
label: 'No',
|
|
821
|
+
variant: 'secondary',
|
|
822
|
+
size: 'md',
|
|
823
|
+
classes: ['contacts-dialog__cancel', 'inline-flex-row', 'justify-center']
|
|
824
|
+
});
|
|
825
|
+
cancelButton.addEventListener('click', event => {
|
|
826
|
+
event.preventDefault();
|
|
827
|
+
if (!fromRegisteredAddressBook) {
|
|
828
|
+
selectorDialog.remove();
|
|
829
|
+
}
|
|
830
|
+
contactExistsDialog.remove();
|
|
831
|
+
(0, _buttonsHelper.complain)(getButtonContainer(context), context, 'Contact was not added');
|
|
832
|
+
setTimeout(() => {
|
|
833
|
+
(0, _buttonsHelper.clearPreviousMessage)(getButtonContainer(context));
|
|
834
|
+
}, 2000);
|
|
835
|
+
(0, _helpers.refreshButton)(context, addressBooksData, contactData);
|
|
836
|
+
});
|
|
837
|
+
popupBody.appendChild(heading);
|
|
838
|
+
popupBody.appendChild(message);
|
|
839
|
+
popupFooter.appendChild(confirmButton);
|
|
840
|
+
popupFooter.appendChild(cancelButton);
|
|
841
|
+
contactExistsDialog.appendChild(popupBody);
|
|
842
|
+
contactExistsDialog.appendChild(popupFooter);
|
|
843
|
+
showPopupOverlay(context);
|
|
844
|
+
if (selectorDialog) selectorDialog.appendChild(contactExistsDialog);
|
|
845
|
+
setTimeout(() => contactExistsDialog.focus(), 0);
|
|
846
|
+
return true;
|
|
847
|
+
};
|
|
848
|
+
exports.handleContactExistsByName = handleContactExistsByName;
|
|
849
|
+
async function openSharedContactExistsDialog(context, addressBooksData, contactData, contactExistsByNameUri) {
|
|
850
|
+
const form = context.dom.createElement('form');
|
|
851
|
+
form.classList.add('contacts-dialog__shared-confirm-form');
|
|
852
|
+
const message = context.dom.createElement('p');
|
|
853
|
+
message.classList.add('contacts-dialog__shared-confirm-message');
|
|
854
|
+
const name = context.dom.createElement('span');
|
|
855
|
+
name.classList.add('contacts-dialog__shared-confirm-name');
|
|
856
|
+
name.textContent = contactData.name;
|
|
857
|
+
message.appendChild(name);
|
|
858
|
+
message.appendChild(context.dom.createTextNode(' already exists. Do you want to add their WebID?'));
|
|
859
|
+
form.appendChild(message);
|
|
860
|
+
const result = await (0, _dialog.openInputDialog)({
|
|
861
|
+
title: 'Contact already exists',
|
|
862
|
+
dom: context.dom,
|
|
863
|
+
form,
|
|
864
|
+
cancelLabel: 'No',
|
|
865
|
+
submitLabel: 'Yes',
|
|
866
|
+
onSave: async () => {
|
|
867
|
+
await (0, _mutations.addWebIDToExistingContact)(context, contactData, contactExistsByNameUri);
|
|
868
|
+
finalizeContactEntry(context, addressBooksData, contactData, addressBooksData.contactWebIDs.get(contactData.webID));
|
|
869
|
+
(0, _helpers.refreshButton)(context, addressBooksData, contactData);
|
|
870
|
+
},
|
|
871
|
+
formatSaveError: error => {
|
|
872
|
+
return error instanceof Error ? error.message : _texts.errorAddingContactWebIDToAddressBook;
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
if (result) return;
|
|
876
|
+
(0, _buttonsHelper.complain)(getButtonContainer(context), context, 'Contact was not added');
|
|
877
|
+
setTimeout(() => {
|
|
878
|
+
(0, _buttonsHelper.clearPreviousMessage)(getButtonContainer(context));
|
|
879
|
+
}, 2000);
|
|
880
|
+
(0, _helpers.refreshButton)(context, addressBooksData, contactData);
|
|
881
|
+
}
|
|
882
|
+
const finalizeContactEntry = (context, addressBooksData, contactData, contactUri) => {
|
|
883
|
+
const sharedCancelButton = (0, _dialog.getSharedDialogCancelButton)(context.dom);
|
|
884
|
+
if (sharedCancelButton) {
|
|
885
|
+
sharedCancelButton.click();
|
|
886
|
+
} else {
|
|
887
|
+
(0, _dialog.closeSharedDialog)();
|
|
888
|
+
}
|
|
889
|
+
addressBooksData.contactWebIDs.set(contactData.webID, contactUri);
|
|
890
|
+
const selectorDialog = context.dom.getElementById('contacts-addressbook-picker-dialog');
|
|
891
|
+
if (selectorDialog) {
|
|
892
|
+
selectorDialog.remove();
|
|
893
|
+
}
|
|
894
|
+
(0, _helpers.refreshButton)(context, addressBooksData, contactData);
|
|
895
|
+
};
|
|
896
|
+
const createGroupButton = (context, group) => {
|
|
897
|
+
const setButtonOnClickHandler = async event => {
|
|
898
|
+
event.preventDefault();
|
|
899
|
+
const selectedGroupButton = event.currentTarget;
|
|
900
|
+
const previouslySelected = isContactsListButtonSelected(selectedGroupButton);
|
|
901
|
+
if (previouslySelected) {
|
|
902
|
+
setContactsListButtonSelected(selectedGroupButton, false);
|
|
903
|
+
(0, _contactsErrors.checkAndAddErrorToDisplay)(context, _texts.groupIsRequired);
|
|
904
|
+
} else {
|
|
905
|
+
setContactsListButtonSelected(selectedGroupButton, true);
|
|
906
|
+
(0, _contactsErrors.checkAndRemoveErrorDisplay)(context);
|
|
907
|
+
}
|
|
908
|
+
selectedGroupButton.blur();
|
|
909
|
+
syncAddContactActionState(context);
|
|
910
|
+
};
|
|
911
|
+
const button = createContactsButtonElement(context, {
|
|
912
|
+
id: group.uri,
|
|
913
|
+
type: 'button',
|
|
914
|
+
ariaLabel: 'Select group ' + group.name,
|
|
915
|
+
variant: 'secondary',
|
|
916
|
+
size: 'sm',
|
|
917
|
+
contentAlign: 'start',
|
|
918
|
+
classes: ['contacts-dialog__list-button']
|
|
919
|
+
});
|
|
920
|
+
button.setAttribute('value', group.name);
|
|
921
|
+
button.addEventListener('click', setButtonOnClickHandler);
|
|
922
|
+
button.textContent = group.name;
|
|
923
|
+
return button;
|
|
924
|
+
};
|
|
925
|
+
function getButtonContainer(context) {
|
|
926
|
+
const buttonContainer = context.dom.getElementById('add-to-contacts-button-container');
|
|
927
|
+
return buttonContainer;
|
|
928
|
+
}
|
|
929
|
+
const setSelectorDialogBackgroundAccessibility = (selectorDialog, isPopupActive) => {
|
|
930
|
+
const popupManagedAriaHiddenAttribute = 'data-popup-managed-aria-hidden';
|
|
931
|
+
const popupManagedInertAttribute = 'data-popup-managed-inert';
|
|
932
|
+
Array.from(selectorDialog.children).forEach(child => {
|
|
933
|
+
if (!(child instanceof HTMLElement)) return;
|
|
934
|
+
if (child.id === CONTACTS_POPUP_OVERLAY_ID || child.classList.contains('contacts-dialog__contact-exists')) return;
|
|
935
|
+
if (isPopupActive) {
|
|
936
|
+
child.setAttribute('aria-hidden', 'true');
|
|
937
|
+
child.setAttribute('inert', '');
|
|
938
|
+
const nestedRegions = child.matches('.contacts-dialog__main') ? Array.from(child.querySelectorAll('.contacts-dialog__description, .contacts-dialog__body')) : [];
|
|
939
|
+
nestedRegions.forEach(region => {
|
|
940
|
+
if (region.getAttribute('aria-hidden') !== 'true') {
|
|
941
|
+
region.setAttribute('aria-hidden', 'true');
|
|
942
|
+
region.setAttribute(popupManagedAriaHiddenAttribute, 'true');
|
|
943
|
+
}
|
|
944
|
+
if (region.matches('.contacts-dialog__body') && !region.hasAttribute('inert')) {
|
|
945
|
+
region.setAttribute('inert', '');
|
|
946
|
+
region.setAttribute(popupManagedInertAttribute, 'true');
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
} else {
|
|
950
|
+
child.removeAttribute('aria-hidden');
|
|
951
|
+
child.removeAttribute('inert');
|
|
952
|
+
Array.from(child.querySelectorAll(`[${popupManagedAriaHiddenAttribute}="true"]`)).forEach(descendant => {
|
|
953
|
+
descendant.removeAttribute('aria-hidden');
|
|
954
|
+
descendant.removeAttribute(popupManagedAriaHiddenAttribute);
|
|
955
|
+
});
|
|
956
|
+
Array.from(child.querySelectorAll(`[${popupManagedInertAttribute}="true"]`)).forEach(descendant => {
|
|
957
|
+
descendant.removeAttribute('inert');
|
|
958
|
+
descendant.removeAttribute(popupManagedInertAttribute);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
};
|
|
963
|
+
const showPopupOverlay = context => {
|
|
964
|
+
const selectorDialog = context.dom.getElementById('contacts-addressbook-picker-dialog');
|
|
965
|
+
if (!selectorDialog) return;
|
|
966
|
+
selectorDialog.classList.add(CONTACTS_OVERLAY_ACTIVE_CLASS);
|
|
967
|
+
setSelectorDialogBackgroundAccessibility(selectorDialog, true);
|
|
968
|
+
const existingOverlay = selectorDialog.querySelector(`#${CONTACTS_POPUP_OVERLAY_ID}`);
|
|
969
|
+
if (existingOverlay) return;
|
|
970
|
+
const overlay = context.dom.createElement('div');
|
|
971
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
972
|
+
overlay.setAttribute('id', CONTACTS_POPUP_OVERLAY_ID);
|
|
973
|
+
overlay.classList.add('contacts-dialog__popup-overlay');
|
|
974
|
+
selectorDialog.appendChild(overlay);
|
|
975
|
+
};
|
|
976
|
+
const removePopupOverlayIfNoPopup = context => {
|
|
977
|
+
const selectorDialog = context.dom.getElementById('contacts-addressbook-picker-dialog');
|
|
978
|
+
if (!selectorDialog) return;
|
|
979
|
+
const activePopup = selectorDialog.querySelector('.contacts-dialog__contact-exists');
|
|
980
|
+
if (activePopup) return;
|
|
981
|
+
const overlay = selectorDialog.querySelector(`#${CONTACTS_POPUP_OVERLAY_ID}`);
|
|
982
|
+
if (overlay) overlay.remove();
|
|
983
|
+
selectorDialog.classList.remove(CONTACTS_OVERLAY_ACTIVE_CLASS);
|
|
984
|
+
setSelectorDialogBackgroundAccessibility(selectorDialog, false);
|
|
985
|
+
};
|
|
986
|
+
/* Sanitization and validation */
|
|
987
|
+
function sanitizeInput(input) {
|
|
988
|
+
return (input || '').replace(/[^a-zA-Z0-9 ]+/g, '').replace(/\s+/g, ' ').trim();
|
|
989
|
+
}
|
|
990
|
+
function sanitizeInputForTyping(input) {
|
|
991
|
+
return (input || '').replace(/[^a-zA-Z0-9 ]+/g, '');
|
|
992
|
+
}
|
|
993
|
+
function attachSanitizingValidation(input, feedbackElement) {
|
|
994
|
+
input.addEventListener('input', () => {
|
|
995
|
+
const rawValue = input.value;
|
|
996
|
+
const sanitizedValue = sanitizeInputForTyping(rawValue);
|
|
997
|
+
if (rawValue !== sanitizedValue) {
|
|
998
|
+
input.value = sanitizedValue;
|
|
999
|
+
input.setAttribute('aria-invalid', 'true');
|
|
1000
|
+
feedbackElement.textContent = 'Only letters, numbers, and spaces are allowed.';
|
|
1001
|
+
feedbackElement.classList.add('contacts-dialog__validation--visible');
|
|
1002
|
+
feedbackElement.setAttribute('aria-hidden', 'false');
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
input.removeAttribute('aria-invalid');
|
|
1006
|
+
feedbackElement.textContent = '';
|
|
1007
|
+
feedbackElement.classList.remove('contacts-dialog__validation--visible');
|
|
1008
|
+
feedbackElement.setAttribute('aria-hidden', 'true');
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
function createValidationMessage(context) {
|
|
1012
|
+
const validationMessage = context.dom.createElement('p');
|
|
1013
|
+
validationMessage.setAttribute('role', 'status');
|
|
1014
|
+
validationMessage.setAttribute('aria-live', 'polite');
|
|
1015
|
+
validationMessage.classList.add('contacts-dialog__validation');
|
|
1016
|
+
validationMessage.setAttribute('aria-hidden', 'true');
|
|
1017
|
+
return validationMessage;
|
|
1018
|
+
}
|
|
1019
|
+
function createContactsStatusRegion(context) {
|
|
1020
|
+
const statusRegion = context.dom.createElement('p');
|
|
1021
|
+
statusRegion.setAttribute('id', 'contacts-list-status');
|
|
1022
|
+
statusRegion.setAttribute('role', 'status');
|
|
1023
|
+
statusRegion.setAttribute('aria-live', 'polite');
|
|
1024
|
+
statusRegion.classList.add('sr-only');
|
|
1025
|
+
return statusRegion;
|
|
1026
|
+
}
|
|
1027
|
+
function announceContactsStatus(context, message) {
|
|
1028
|
+
const statusRegion = context.dom.getElementById('contacts-list-status');
|
|
1029
|
+
if (!statusRegion) return;
|
|
1030
|
+
statusRegion.textContent = '';
|
|
1031
|
+
setTimeout(() => {
|
|
1032
|
+
statusRegion.textContent = message;
|
|
1033
|
+
}, 0);
|
|
1034
|
+
}
|
|
1035
|
+
function focusFirstInputInPopup(container) {
|
|
1036
|
+
setTimeout(() => {
|
|
1037
|
+
const firstInput = container.querySelector('input, textarea, select');
|
|
1038
|
+
if (firstInput) firstInput.focus();
|
|
1039
|
+
}, 0);
|
|
1040
|
+
}
|
|
1041
|
+
function setButtonLoadingState(button, isLoading, loadingLabel) {
|
|
1042
|
+
if (!button) return;
|
|
1043
|
+
const originalLabel = button.dataset.originalLabel || button.textContent || '';
|
|
1044
|
+
if (!button.dataset.originalLabel) button.dataset.originalLabel = originalLabel;
|
|
1045
|
+
if (isLoading) {
|
|
1046
|
+
button.disabled = true;
|
|
1047
|
+
button.setAttribute('aria-busy', 'true');
|
|
1048
|
+
button.textContent = loadingLabel || originalLabel;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
button.disabled = false;
|
|
1052
|
+
button.removeAttribute('aria-busy');
|
|
1053
|
+
button.textContent = button.dataset.originalLabel || originalLabel;
|
|
1054
|
+
}
|
|
1055
|
+
async function runWithButtonLoading(context, button, loadingLabel, action) {
|
|
1056
|
+
const sharedModal = context.dom.getElementById('profile-modal');
|
|
1057
|
+
const useDialogOverlay = Boolean(sharedModal?.hasAttribute('open'));
|
|
1058
|
+
if (useDialogOverlay) {
|
|
1059
|
+
if (button) {
|
|
1060
|
+
button.disabled = true;
|
|
1061
|
+
button.setAttribute('aria-busy', 'true');
|
|
1062
|
+
}
|
|
1063
|
+
(0, _dialog.setSharedDialogSavingState)(context.dom, true, loadingLabel);
|
|
1064
|
+
} else {
|
|
1065
|
+
setButtonLoadingState(button, true, loadingLabel);
|
|
1066
|
+
}
|
|
1067
|
+
try {
|
|
1068
|
+
return await action();
|
|
1069
|
+
} finally {
|
|
1070
|
+
if (useDialogOverlay) {
|
|
1071
|
+
(0, _dialog.setSharedDialogSavingState)(context.dom, false, loadingLabel);
|
|
1072
|
+
if (button) {
|
|
1073
|
+
button.disabled = false;
|
|
1074
|
+
button.removeAttribute('aria-busy');
|
|
1075
|
+
}
|
|
1076
|
+
} else {
|
|
1077
|
+
setButtonLoadingState(button, false);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
function sanitizeGroupFileName(name) {
|
|
1082
|
+
return name.replace(/\W/gu, '_').replace(/_+/g, '_');
|
|
1083
|
+
}
|
|
1084
|
+
function getDocumentKey(statementDocument) {
|
|
1085
|
+
return 'value' in statementDocument ? statementDocument.value : '__default__';
|
|
1086
|
+
}
|
|
1087
|
+
async function updateAcrossDocuments(context, deletions, insertions = []) {
|
|
1088
|
+
const store = context.session.store;
|
|
1089
|
+
(0, _rdfMutationHelpers.ensureStandardMutationPrefixes)(store);
|
|
1090
|
+
const docs = deletions.concat(insertions).map(statement => statement.why);
|
|
1091
|
+
const uniqueDocKeys = new Set();
|
|
1092
|
+
const uniqueDocs = docs.filter(doc => {
|
|
1093
|
+
const key = getDocumentKey(doc);
|
|
1094
|
+
if (uniqueDocKeys.has(key)) return false;
|
|
1095
|
+
uniqueDocKeys.add(key);
|
|
1096
|
+
return true;
|
|
1097
|
+
});
|
|
1098
|
+
await Promise.all(uniqueDocs.map(doc => (0, _rdfMutationHelpers.runDirectUpdaterUpdate)(store, deletions.filter(statement => getDocumentKey(statement.why) === getDocumentKey(doc)), insertions.filter(statement => getDocumentKey(statement.why) === getDocumentKey(doc)), _texts.errorGroupCreation)));
|
|
1099
|
+
}
|
|
1100
|
+
async function saveNewGroupToAddressBook(context, addressBookNode, name) {
|
|
1101
|
+
const store = context.session.store;
|
|
1102
|
+
await store.fetcher.load(addressBookNode.doc());
|
|
1103
|
+
const groupIndex = store.any(addressBookNode, _solidUi.ns.vcard('groupIndex'));
|
|
1104
|
+
if (!groupIndex) {
|
|
1105
|
+
throw new Error('Error loading group index for the selected address book.');
|
|
1106
|
+
}
|
|
1107
|
+
const groupFileName = sanitizeGroupFileName(name);
|
|
1108
|
+
const groupNode = (0, _rdflib.sym)(`${addressBookNode.dir().uri}Group/${groupFileName}.ttl#this`);
|
|
1109
|
+
const groupDocument = groupNode.doc();
|
|
1110
|
+
try {
|
|
1111
|
+
await store.fetcher.load(groupIndex);
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
throw new Error(`Error loading group index ${groupIndex.value}: ${error}`);
|
|
1114
|
+
}
|
|
1115
|
+
if (store.holds(addressBookNode, _solidUi.ns.vcard('includesGroup'), groupNode, groupIndex)) {
|
|
1116
|
+
return groupNode;
|
|
1117
|
+
}
|
|
1118
|
+
const indexInsertions = [(0, _rdflib.st)(addressBookNode, _solidUi.ns.vcard('includesGroup'), groupNode, groupIndex), (0, _rdflib.st)(groupNode, _solidUi.ns.rdf('type'), _solidUi.ns.vcard('Group'), groupIndex), (0, _rdflib.st)(groupNode, _solidUi.ns.vcard('fn'), (0, _rdflib.literal)(name), groupIndex)];
|
|
1119
|
+
const groupInsertions = [(0, _rdflib.st)(addressBookNode, _solidUi.ns.vcard('includesGroup'), groupNode, groupDocument), (0, _rdflib.st)(groupNode, _solidUi.ns.rdf('type'), _solidUi.ns.vcard('Group'), groupDocument), (0, _rdflib.st)(groupNode, _solidUi.ns.vcard('fn'), (0, _rdflib.literal)(name), groupDocument)];
|
|
1120
|
+
await updateAcrossDocuments(context, [], indexInsertions);
|
|
1121
|
+
await updateAcrossDocuments(context, [], groupInsertions);
|
|
1122
|
+
return groupNode;
|
|
1123
|
+
}
|