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.
Files changed (256) hide show
  1. package/README.md +50 -0
  2. package/icons-png/discord.png +0 -0
  3. package/icons-png/dribbble.png +0 -0
  4. package/icons-png/facebook.png +0 -0
  5. package/icons-png/instagram.png +0 -0
  6. package/icons-png/linkedin.png +0 -0
  7. package/icons-png/pinterest.png +0 -0
  8. package/icons-png/sharechat.png +0 -0
  9. package/icons-png/signup.png +0 -0
  10. package/icons-png/snapchat.png +0 -0
  11. package/icons-png/spotify.png +0 -0
  12. package/icons-png/telegram.png +0 -0
  13. package/icons-png/tiktok.png +0 -0
  14. package/icons-png/whatsapp.png +0 -0
  15. package/icons-png/x.png +0 -0
  16. package/icons-png/youtube.png +0 -0
  17. package/lib/303.profile-pane.js +1362 -0
  18. package/lib/303.profile-pane.js.map +1 -0
  19. package/lib/303.profile-pane.min.js +2 -0
  20. package/lib/303.profile-pane.min.js.map +1 -0
  21. package/lib/ProfileView.css +1090 -0
  22. package/lib/ProfileView.d.ts +2 -1
  23. package/lib/ProfileView.d.ts.map +1 -1
  24. package/lib/ProfileView.js +64 -36
  25. package/lib/buttonsHelper.d.ts +1 -1
  26. package/lib/buttonsHelper.d.ts.map +1 -1
  27. package/lib/buttonsHelper.js +2 -1
  28. package/lib/editProfilePane/EditCVCard.js +1 -1
  29. package/lib/editProfilePane/EditCommunitiesCard.js +1 -1
  30. package/lib/editProfilePane/EditFriendsCard.js +1 -1
  31. package/lib/editProfilePane/EditProfileView.d.ts +1 -1
  32. package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
  33. package/lib/editProfilePane/EditProfileView.js +4 -5
  34. package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
  35. package/lib/editProfilePane/editProfilePresenter.js +5 -4
  36. package/lib/icons-svg/profileIcons.d.ts +1 -1
  37. package/lib/icons-svg/profileIcons.d.ts.map +1 -1
  38. package/lib/icons-svg/profileIcons.js +9 -17
  39. package/lib/index.d.ts +1 -8
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js +74 -40
  42. package/lib/ontology/otherPreferencesForm.ttl +32 -0
  43. package/lib/ontology/resumeForm.ttl +349 -0
  44. package/lib/ontology/socialMedia.ttl +433 -0
  45. package/lib/profile-pane.js +32266 -13247
  46. package/lib/profile-pane.js.map +1 -1
  47. package/lib/profile-pane.min.js +2315 -935
  48. package/lib/profile-pane.min.js.map +1 -1
  49. package/lib/rdfFormsHelper.d.ts +13 -1
  50. package/lib/rdfFormsHelper.d.ts.map +1 -1
  51. package/lib/rdfFormsHelper.js +13 -1
  52. package/lib/sections/bio/BioEditDialog.d.ts.map +1 -1
  53. package/lib/sections/bio/BioEditDialog.js +7 -7
  54. package/lib/sections/bio/BioSection.css +300 -0
  55. package/lib/sections/bio/BioSection.d.ts +3 -2
  56. package/lib/sections/bio/BioSection.d.ts.map +1 -1
  57. package/lib/sections/bio/BioSection.js +26 -19
  58. package/lib/sections/bio/mutations.d.ts.map +1 -1
  59. package/lib/sections/bio/mutations.js +14 -3
  60. package/lib/sections/contactInfo/ContactInfoEditDialog.css +354 -0
  61. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +3 -1
  62. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -1
  63. package/lib/sections/contactInfo/ContactInfoEditDialog.js +183 -98
  64. package/lib/sections/contactInfo/ContactInfoSection.css +125 -0
  65. package/lib/sections/contactInfo/ContactInfoSection.d.ts +2 -0
  66. package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -1
  67. package/lib/sections/contactInfo/ContactInfoSection.js +64 -41
  68. package/lib/sections/contactInfo/mutations.d.ts.map +1 -1
  69. package/lib/sections/contactInfo/mutations.js +51 -16
  70. package/lib/sections/education/EducationEditDialog.d.ts +3 -1
  71. package/lib/sections/education/EducationEditDialog.d.ts.map +1 -1
  72. package/lib/sections/education/EducationEditDialog.js +170 -92
  73. package/lib/sections/education/EducationSection.css +133 -0
  74. package/lib/sections/education/EducationSection.d.ts +3 -2
  75. package/lib/sections/education/EducationSection.d.ts.map +1 -1
  76. package/lib/sections/education/EducationSection.js +32 -25
  77. package/lib/sections/education/mutations.d.ts.map +1 -1
  78. package/lib/sections/education/mutations.js +14 -3
  79. package/lib/sections/heading/HeadingEditDialog.d.ts +4 -1
  80. package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -1
  81. package/lib/sections/heading/HeadingEditDialog.js +287 -162
  82. package/lib/sections/heading/HeadingSection.css +862 -0
  83. package/lib/sections/heading/HeadingSection.d.ts +3 -2
  84. package/lib/sections/heading/HeadingSection.d.ts.map +1 -1
  85. package/lib/sections/heading/HeadingSection.js +63 -32
  86. package/lib/sections/heading/imageHelpers.d.ts +1 -0
  87. package/lib/sections/heading/imageHelpers.d.ts.map +1 -1
  88. package/lib/sections/heading/imageHelpers.js +40 -1
  89. package/lib/sections/heading/mutations.d.ts.map +1 -1
  90. package/lib/sections/heading/mutations.js +86 -23
  91. package/lib/sections/heading/selectors.d.ts.map +1 -1
  92. package/lib/sections/heading/selectors.js +14 -3
  93. package/lib/sections/heading/types.d.ts +1 -2
  94. package/lib/sections/heading/types.d.ts.map +1 -1
  95. package/lib/sections/languages/LanguageEditDialog.d.ts +3 -1
  96. package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -1
  97. package/lib/sections/languages/LanguageEditDialog.js +202 -119
  98. package/lib/sections/languages/LanguageSection.css +53 -0
  99. package/lib/sections/languages/LanguageSection.d.ts +2 -0
  100. package/lib/sections/languages/LanguageSection.d.ts.map +1 -1
  101. package/lib/sections/languages/LanguageSection.js +42 -31
  102. package/lib/sections/languages/mutations.d.ts.map +1 -1
  103. package/lib/sections/languages/mutations.js +60 -161
  104. package/lib/sections/languages/selectors.d.ts.map +1 -1
  105. package/lib/sections/languages/selectors.js +1 -2
  106. package/lib/sections/projects/ProjectEditDialog.d.ts +2 -1
  107. package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -1
  108. package/lib/sections/projects/ProjectEditDialog.js +13 -24
  109. package/lib/sections/projects/ProjectSection.css +368 -0
  110. package/lib/sections/projects/ProjectSection.d.ts +2 -1
  111. package/lib/sections/projects/ProjectSection.d.ts.map +1 -1
  112. package/lib/sections/projects/ProjectSection.js +116 -34
  113. package/lib/sections/projects/mutations.d.ts.map +1 -1
  114. package/lib/sections/projects/mutations.js +109 -132
  115. package/lib/sections/projects/selectors.d.ts.map +1 -1
  116. package/lib/sections/projects/selectors.js +4 -45
  117. package/lib/{QRCodeCard.d.ts → sections/qrcode/QRCodeCard.d.ts} +2 -1
  118. package/lib/sections/qrcode/QRCodeCard.d.ts.map +1 -0
  119. package/lib/{QRCodeCard.js → sections/qrcode/QRCodeCard.js} +59 -11
  120. package/lib/sections/qrcode/QRCodeSection.css +108 -0
  121. package/lib/sections/qrcode/QRCodeSection.d.ts +4 -0
  122. package/lib/sections/qrcode/QRCodeSection.d.ts.map +1 -0
  123. package/lib/sections/qrcode/QRCodeSection.js +17 -0
  124. package/lib/sections/resume/ResumeEditDialog.d.ts +10 -1
  125. package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -1
  126. package/lib/sections/resume/ResumeEditDialog.js +531 -149
  127. package/lib/sections/resume/ResumeSection.css +350 -0
  128. package/lib/sections/resume/ResumeSection.d.ts +3 -2
  129. package/lib/sections/resume/ResumeSection.d.ts.map +1 -1
  130. package/lib/sections/resume/ResumeSection.js +78 -49
  131. package/lib/sections/resume/mutations.d.ts.map +1 -1
  132. package/lib/sections/resume/mutations.js +17 -3
  133. package/lib/sections/resume/selectors.d.ts.map +1 -1
  134. package/lib/sections/resume/selectors.js +1 -0
  135. package/lib/sections/resume/types.d.ts +1 -0
  136. package/lib/sections/resume/types.d.ts.map +1 -1
  137. package/lib/sections/shared/collapsibleSection.d.ts.map +1 -1
  138. package/lib/sections/shared/collapsibleSection.js +1 -0
  139. package/lib/sections/shared/phoneCountries.d.ts +1 -1
  140. package/lib/sections/shared/phoneCountries.d.ts.map +1 -1
  141. package/lib/sections/shared/phoneCountries.js +2 -2
  142. package/lib/sections/shared/projectCommunityNodes.d.ts +6 -0
  143. package/lib/sections/shared/projectCommunityNodes.d.ts.map +1 -0
  144. package/lib/sections/shared/projectCommunityNodes.js +56 -0
  145. package/lib/sections/shared/rdfMutationHelpers.d.ts +35 -2
  146. package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -1
  147. package/lib/sections/shared/rdfMutationHelpers.js +290 -14
  148. package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -1
  149. package/lib/sections/shared/sectionCardHelpers.js +80 -11
  150. package/lib/sections/shared/types.d.ts +24 -0
  151. package/lib/sections/shared/types.d.ts.map +1 -1
  152. package/lib/sections/skills/SkillsEditDialog.d.ts +3 -1
  153. package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -1
  154. package/lib/sections/skills/SkillsEditDialog.js +136 -115
  155. package/lib/sections/skills/SkillsSection.css +173 -0
  156. package/lib/sections/skills/SkillsSection.d.ts +2 -0
  157. package/lib/sections/skills/SkillsSection.d.ts.map +1 -1
  158. package/lib/sections/skills/SkillsSection.js +107 -47
  159. package/lib/sections/skills/mutations.d.ts.map +1 -1
  160. package/lib/sections/skills/mutations.js +25 -21
  161. package/lib/sections/skills/selectors.d.ts.map +1 -1
  162. package/lib/sections/skills/selectors.js +5 -3
  163. package/lib/sections/social/SocialEditDialog.d.ts +3 -1
  164. package/lib/sections/social/SocialEditDialog.d.ts.map +1 -1
  165. package/lib/sections/social/SocialEditDialog.js +170 -62
  166. package/lib/sections/social/SocialSection.css +194 -0
  167. package/lib/sections/social/SocialSection.d.ts +4 -3
  168. package/lib/sections/social/SocialSection.d.ts.map +1 -1
  169. package/lib/sections/social/SocialSection.js +59 -43
  170. package/lib/sections/social/mutations.d.ts.map +1 -1
  171. package/lib/sections/social/mutations.js +23 -132
  172. package/lib/specialButtons/AddMeToYourFriends.css +54 -0
  173. package/lib/specialButtons/addContact/AddMeToYourContacts.css +1118 -0
  174. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts +10 -0
  175. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts.map +1 -0
  176. package/lib/specialButtons/addContact/ContactCreationDialog.js +1123 -0
  177. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts +16 -0
  178. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts.map +1 -0
  179. package/lib/specialButtons/addContact/addMeToYourContacts.js +136 -0
  180. package/lib/specialButtons/addContact/contactsErrors.d.ts +8 -0
  181. package/lib/specialButtons/addContact/contactsErrors.d.ts.map +1 -0
  182. package/lib/specialButtons/addContact/contactsErrors.js +106 -0
  183. package/lib/specialButtons/addContact/contactsTypes.d.ts +43 -0
  184. package/lib/specialButtons/addContact/contactsTypes.d.ts.map +1 -0
  185. package/lib/specialButtons/addContact/contactsTypes.js +5 -0
  186. package/lib/specialButtons/addContact/helpers.d.ts +7 -0
  187. package/lib/specialButtons/addContact/helpers.d.ts.map +1 -0
  188. package/lib/specialButtons/addContact/helpers.js +103 -0
  189. package/lib/specialButtons/addContact/mutations.d.ts +16 -0
  190. package/lib/specialButtons/addContact/mutations.d.ts.map +1 -0
  191. package/lib/specialButtons/addContact/mutations.js +300 -0
  192. package/lib/specialButtons/addContact/selectors.d.ts +10 -0
  193. package/lib/specialButtons/addContact/selectors.d.ts.map +1 -0
  194. package/lib/specialButtons/addContact/selectors.js +163 -0
  195. package/lib/{addMeToYourFriends.d.ts → specialButtons/addMeToYourFriends.d.ts} +6 -4
  196. package/lib/specialButtons/addMeToYourFriends.d.ts.map +1 -0
  197. package/lib/{addMeToYourFriends.js → specialButtons/addMeToYourFriends.js} +46 -11
  198. package/lib/styles/CollapsibleSection.css +519 -0
  199. package/lib/styles/EditDialogs.css +506 -686
  200. package/lib/styles/EditDialogs.responsive.css +989 -0
  201. package/lib/texts/buttonTexts.d.ts +9 -0
  202. package/lib/texts/buttonTexts.d.ts.map +1 -0
  203. package/lib/texts/buttonTexts.js +14 -0
  204. package/lib/texts/dialogTexts.d.ts +14 -0
  205. package/lib/texts/dialogTexts.d.ts.map +1 -0
  206. package/lib/texts/dialogTexts.js +19 -0
  207. package/lib/texts/messageTexts.d.ts +42 -0
  208. package/lib/texts/messageTexts.d.ts.map +1 -0
  209. package/lib/texts/messageTexts.js +47 -0
  210. package/lib/texts/profileTexts.d.ts +14 -0
  211. package/lib/texts/profileTexts.d.ts.map +1 -0
  212. package/lib/texts/profileTexts.js +19 -0
  213. package/lib/texts/qrCodeTexts.d.ts +2 -0
  214. package/lib/texts/qrCodeTexts.d.ts.map +1 -0
  215. package/lib/texts/qrCodeTexts.js +7 -0
  216. package/lib/texts.d.ts +5 -60
  217. package/lib/texts.d.ts.map +1 -1
  218. package/lib/texts.js +55 -70
  219. package/lib/ui/dialog.css +233 -0
  220. package/lib/ui/dialog.d.ts +15 -1
  221. package/lib/ui/dialog.d.ts.map +1 -1
  222. package/lib/ui/dialog.js +245 -45
  223. package/lib/ui/dialog.responsive.css +195 -0
  224. package/lib/ui/errors.d.ts.map +1 -1
  225. package/lib/ui/errors.js +2 -1
  226. package/lib/ui/spinner.d.ts +3 -0
  227. package/lib/ui/spinner.d.ts.map +1 -0
  228. package/lib/ui/spinner.js +13 -0
  229. package/lib/utils/debug.d.ts +5 -0
  230. package/lib/utils/debug.d.ts.map +1 -0
  231. package/lib/utils/debug.js +23 -0
  232. package/lib/utils/errorDisplay.d.ts +2 -0
  233. package/lib/utils/errorDisplay.d.ts.map +1 -0
  234. package/lib/utils/errorDisplay.js +19 -0
  235. package/package.json +34 -26
  236. package/lib/ChatWithMe.d.ts +0 -7
  237. package/lib/ChatWithMe.d.ts.map +0 -1
  238. package/lib/ChatWithMe.js +0 -90
  239. package/lib/QRCodeCard.d.ts.map +0 -1
  240. package/lib/addMeToYourFriends.d.ts.map +0 -1
  241. package/lib/sections/heading/camera.d.ts +0 -19
  242. package/lib/sections/heading/camera.d.ts.map +0 -1
  243. package/lib/sections/heading/camera.js +0 -199
  244. package/lib/styles/BioSection.css +0 -77
  245. package/lib/styles/CVCard.css +0 -142
  246. package/lib/styles/ChatWithMe.css +0 -6
  247. package/lib/styles/ContactInfoEditDialog.css +0 -153
  248. package/lib/styles/EducationCard.css +0 -103
  249. package/lib/styles/HeadingSection.css +0 -309
  250. package/lib/styles/ProfileCard.css +0 -66
  251. package/lib/styles/ProfileView.css +0 -65
  252. package/lib/styles/ProjectsCard.css +0 -206
  253. package/lib/styles/QRCodeCard.css +0 -43
  254. package/lib/styles/SocialCard.css +0 -89
  255. package/lib/styles/dialog.css +0 -209
  256. 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
+ }