solid-ui 2.6.1 → 3.0.0-63a1640

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 (369) hide show
  1. package/LICENSE.md +3 -1
  2. package/README.md +236 -30
  3. package/dist/acl/access-controller.js +238 -0
  4. package/dist/acl/access-controller.js.map +1 -0
  5. package/{lib → dist}/acl/access-groups.d.ts +2 -2
  6. package/{lib → dist}/acl/access-groups.d.ts.map +1 -1
  7. package/dist/acl/access-groups.js +323 -0
  8. package/dist/acl/access-groups.js.map +1 -0
  9. package/dist/acl/acl-control.js +173 -0
  10. package/dist/acl/acl-control.js.map +1 -0
  11. package/dist/acl/acl.js +495 -0
  12. package/dist/acl/acl.js.map +1 -0
  13. package/dist/acl/add-agent-buttons.js +217 -0
  14. package/dist/acl/add-agent-buttons.js.map +1 -0
  15. package/dist/acl/index.js +32 -0
  16. package/dist/acl/index.js.map +1 -0
  17. package/dist/acl/types.js +6 -0
  18. package/dist/acl/types.js.map +1 -0
  19. package/dist/chat/keys.js +106 -0
  20. package/dist/chat/keys.js.map +1 -0
  21. package/dist/chat/signature.js +63 -0
  22. package/dist/chat/signature.js.map +1 -0
  23. package/dist/create/create.js +249 -0
  24. package/dist/create/create.js.map +1 -0
  25. package/dist/create/index.js +5 -0
  26. package/dist/create/index.js.map +1 -0
  27. package/dist/create/types.js +2 -0
  28. package/dist/create/types.js.map +1 -0
  29. package/dist/debug.d.ts.map +1 -0
  30. package/dist/debug.js +13 -0
  31. package/dist/debug.js.map +1 -0
  32. package/dist/footer/index.js +67 -0
  33. package/dist/footer/index.js.map +1 -0
  34. package/dist/header/empty-profile.js +11 -0
  35. package/dist/header/empty-profile.js.map +1 -0
  36. package/dist/header/index.js +260 -0
  37. package/dist/header/index.js.map +1 -0
  38. package/dist/iconBase.js +37 -0
  39. package/dist/iconBase.js.map +1 -0
  40. package/dist/icons/solid_logo.js.map +1 -0
  41. package/{lib → dist}/index.d.ts +7 -9
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +102 -0
  44. package/dist/index.js.map +1 -0
  45. package/{lib → dist}/log.d.ts.map +1 -1
  46. package/dist/log.js +182 -0
  47. package/dist/log.js.map +1 -0
  48. package/dist/login/login.js +858 -0
  49. package/dist/login/login.js.map +1 -0
  50. package/dist/matrix/index.js +5 -0
  51. package/dist/matrix/index.js.map +1 -0
  52. package/dist/matrix/matrix.js +217 -0
  53. package/dist/matrix/matrix.js.map +1 -0
  54. package/dist/matrix/types.js +2 -0
  55. package/dist/matrix/types.js.map +1 -0
  56. package/dist/media/index.js +6 -0
  57. package/dist/media/index.js.map +1 -0
  58. package/dist/media/media-capture.js +161 -0
  59. package/dist/media/media-capture.js.map +1 -0
  60. package/dist/pad.js +775 -0
  61. package/dist/pad.js.map +1 -0
  62. package/{lib → dist}/participation.d.ts.map +1 -1
  63. package/dist/participation.js +184 -0
  64. package/dist/participation.js.map +1 -0
  65. package/dist/solid-ui.esm.js +25531 -0
  66. package/dist/solid-ui.esm.js.map +1 -0
  67. package/dist/solid-ui.esm.min.js +43 -0
  68. package/dist/solid-ui.esm.min.js.map +1 -0
  69. package/dist/solid-ui.js +23479 -68931
  70. package/dist/solid-ui.js.map +1 -1
  71. package/dist/solid-ui.min.js +40 -2
  72. package/dist/solid-ui.min.js.map +1 -1
  73. package/dist/tabs.js +388 -0
  74. package/dist/tabs.js.map +1 -0
  75. package/{lib → dist}/utils/headerFooterHelpers.d.ts.map +1 -1
  76. package/dist/utils/headerFooterHelpers.js +114 -0
  77. package/dist/utils/headerFooterHelpers.js.map +1 -0
  78. package/dist/utils/keyHelpers/accessData.js +64 -0
  79. package/dist/utils/keyHelpers/accessData.js.map +1 -0
  80. package/dist/utils/keyHelpers/acl.js +74 -0
  81. package/dist/utils/keyHelpers/acl.js.map +1 -0
  82. package/dist/utils/keyHelpers/otherHelpers.js +13 -0
  83. package/dist/utils/keyHelpers/otherHelpers.js.map +1 -0
  84. package/dist/utils/label.js +111 -0
  85. package/dist/utils/label.js.map +1 -0
  86. package/dist/versionInfo.js +30 -0
  87. package/dist/versionInfo.js.map +1 -0
  88. package/dist/widgets/buttons/iconLinks.js +44 -0
  89. package/dist/widgets/buttons/iconLinks.js.map +1 -0
  90. package/dist/widgets/buttons.js +1280 -0
  91. package/dist/widgets/buttons.js.map +1 -0
  92. package/dist/widgets/error.d.ts +14 -0
  93. package/dist/widgets/error.d.ts.map +1 -0
  94. package/dist/widgets/error.js +35 -0
  95. package/dist/widgets/error.js.map +1 -0
  96. package/dist/widgets/forms/autocomplete/autocompleteBar.js +123 -0
  97. package/dist/widgets/forms/autocomplete/autocompleteBar.js.map +1 -0
  98. package/dist/widgets/forms/autocomplete/autocompleteField.js +199 -0
  99. package/dist/widgets/forms/autocomplete/autocompleteField.js.map +1 -0
  100. package/dist/widgets/forms/autocomplete/autocompletePicker.js +256 -0
  101. package/dist/widgets/forms/autocomplete/autocompletePicker.js.map +1 -0
  102. package/dist/widgets/forms/autocomplete/language.js +104 -0
  103. package/dist/widgets/forms/autocomplete/language.js.map +1 -0
  104. package/dist/widgets/forms/autocomplete/publicData.js +460 -0
  105. package/dist/widgets/forms/autocomplete/publicData.js.map +1 -0
  106. package/dist/widgets/forms/basic.js +241 -0
  107. package/dist/widgets/forms/basic.js.map +1 -0
  108. package/dist/widgets/forms/comment.js +46 -0
  109. package/dist/widgets/forms/comment.js.map +1 -0
  110. package/dist/widgets/forms/fieldFunction.js +44 -0
  111. package/dist/widgets/forms/fieldFunction.js.map +1 -0
  112. package/dist/widgets/forms/fieldParams.js +89 -0
  113. package/dist/widgets/forms/fieldParams.js.map +1 -0
  114. package/{lib → dist}/widgets/forms/formStyle.d.ts.map +1 -1
  115. package/dist/widgets/forms/formStyle.js +36 -0
  116. package/dist/widgets/forms/formStyle.js.map +1 -0
  117. package/{lib → dist}/widgets/widgetHelpers.d.ts.map +1 -1
  118. package/{lib → dist}/widgets/widgetHelpers.js +14 -25
  119. package/dist/widgets/widgetHelpers.js.map +1 -0
  120. package/package.json +48 -52
  121. package/dist/789.solid-ui.min.js +0 -1
  122. package/dist/841.solid-ui.min.js +0 -3
  123. package/dist/841.solid-ui.min.js.LICENSE.txt +0 -58
  124. package/dist/841.solid-ui.min.js.map +0 -1
  125. package/dist/_2b19.solid-ui.js +0 -14
  126. package/dist/_2b19.solid-ui.js.map +0 -1
  127. package/dist/index.html +0 -1
  128. package/dist/solid-ui.min.js.LICENSE.txt +0 -57
  129. package/dist/vendors-node_modules_jsonld_lib_jsonld_js.solid-ui.js +0 -12247
  130. package/dist/vendors-node_modules_jsonld_lib_jsonld_js.solid-ui.js.map +0 -1
  131. package/lib/acl/access-controller.js +0 -391
  132. package/lib/acl/access-controller.js.map +0 -1
  133. package/lib/acl/access-groups.js +0 -507
  134. package/lib/acl/access-groups.js.map +0 -1
  135. package/lib/acl/acl-control.js +0 -237
  136. package/lib/acl/acl-control.js.map +0 -1
  137. package/lib/acl/acl.js +0 -517
  138. package/lib/acl/acl.js.map +0 -1
  139. package/lib/acl/add-agent-buttons.js +0 -434
  140. package/lib/acl/add-agent-buttons.js.map +0 -1
  141. package/lib/acl/index.js +0 -39
  142. package/lib/acl/index.js.map +0 -1
  143. package/lib/acl/types.js +0 -6
  144. package/lib/acl/types.js.map +0 -1
  145. package/lib/chat/bookmarks.js +0 -303
  146. package/lib/chat/bookmarks.js.map +0 -1
  147. package/lib/chat/chatLogic.js +0 -420
  148. package/lib/chat/chatLogic.js.map +0 -1
  149. package/lib/chat/dateFolder.js +0 -328
  150. package/lib/chat/dateFolder.js.map +0 -1
  151. package/lib/chat/infinite.js +0 -994
  152. package/lib/chat/infinite.js.map +0 -1
  153. package/lib/chat/keys.js +0 -232
  154. package/lib/chat/keys.js.map +0 -1
  155. package/lib/chat/message.js +0 -715
  156. package/lib/chat/message.js.map +0 -1
  157. package/lib/chat/messageTools.js +0 -538
  158. package/lib/chat/messageTools.js.map +0 -1
  159. package/lib/chat/signature.js +0 -109
  160. package/lib/chat/signature.js.map +0 -1
  161. package/lib/chat/thread.js +0 -535
  162. package/lib/chat/thread.js.map +0 -1
  163. package/lib/create/create.js +0 -242
  164. package/lib/create/create.js.map +0 -1
  165. package/lib/create/index.js +0 -11
  166. package/lib/create/index.js.map +0 -1
  167. package/lib/create/types.js +0 -6
  168. package/lib/create/types.js.map +0 -1
  169. package/lib/debug.d.ts.map +0 -1
  170. package/lib/debug.js +0 -30
  171. package/lib/debug.js.map +0 -1
  172. package/lib/folders.js +0 -132
  173. package/lib/folders.js.map +0 -1
  174. package/lib/footer/index.js +0 -123
  175. package/lib/footer/index.js.map +0 -1
  176. package/lib/header/empty-profile.js +0 -8
  177. package/lib/header/empty-profile.js.map +0 -1
  178. package/lib/header/index.js +0 -375
  179. package/lib/header/index.js.map +0 -1
  180. package/lib/iconBase.js +0 -44
  181. package/lib/iconBase.js.map +0 -1
  182. package/lib/icons/solid_logo.js.map +0 -1
  183. package/lib/index.d.ts.map +0 -1
  184. package/lib/index.js +0 -223
  185. package/lib/index.js.map +0 -1
  186. package/lib/log.js +0 -213
  187. package/lib/log.js.map +0 -1
  188. package/lib/login/login.js +0 -1241
  189. package/lib/login/login.js.map +0 -1
  190. package/lib/matrix/index.js +0 -11
  191. package/lib/matrix/index.js.map +0 -1
  192. package/lib/matrix/matrix.js +0 -216
  193. package/lib/matrix/matrix.js.map +0 -1
  194. package/lib/matrix/types.js +0 -6
  195. package/lib/matrix/types.js.map +0 -1
  196. package/lib/media/index.js +0 -12
  197. package/lib/media/index.js.map +0 -1
  198. package/lib/media/media-capture.js +0 -194
  199. package/lib/media/media-capture.js.map +0 -1
  200. package/lib/messageArea.js +0 -319
  201. package/lib/messageArea.js.map +0 -1
  202. package/lib/noun_Camera_1618446_000000.js +0 -8
  203. package/lib/noun_Camera_1618446_000000.js.map +0 -1
  204. package/lib/ns.js +0 -17
  205. package/lib/ns.js.map +0 -1
  206. package/lib/pad.js +0 -805
  207. package/lib/pad.js.map +0 -1
  208. package/lib/participation.js +0 -219
  209. package/lib/participation.js.map +0 -1
  210. package/lib/preferences.js +0 -215
  211. package/lib/preferences.js.map +0 -1
  212. package/lib/signup/config-default.js +0 -43
  213. package/lib/signup/config-default.js.map +0 -1
  214. package/lib/signup/signup.js +0 -74
  215. package/lib/signup/signup.js.map +0 -1
  216. package/lib/stories/decorators.js +0 -10
  217. package/lib/stories/decorators.js.map +0 -1
  218. package/lib/style.js +0 -158
  219. package/lib/style.js.map +0 -1
  220. package/lib/styleConstants.js +0 -35
  221. package/lib/styleConstants.js.map +0 -1
  222. package/lib/style_multiSelect.js +0 -62
  223. package/lib/style_multiSelect.js.map +0 -1
  224. package/lib/table.js +0 -1573
  225. package/lib/table.js.map +0 -1
  226. package/lib/tabs.js +0 -448
  227. package/lib/tabs.js.map +0 -1
  228. package/lib/typings.d.js +0 -2
  229. package/lib/typings.d.js.map +0 -1
  230. package/lib/utils/headerFooterHelpers.js +0 -165
  231. package/lib/utils/headerFooterHelpers.js.map +0 -1
  232. package/lib/utils/index.js +0 -527
  233. package/lib/utils/index.js.map +0 -1
  234. package/lib/utils/keyHelpers/accessData.js +0 -131
  235. package/lib/utils/keyHelpers/accessData.js.map +0 -1
  236. package/lib/utils/keyHelpers/acl.js +0 -90
  237. package/lib/utils/keyHelpers/acl.js.map +0 -1
  238. package/lib/utils/keyHelpers/otherHelpers.js +0 -21
  239. package/lib/utils/keyHelpers/otherHelpers.js.map +0 -1
  240. package/lib/utils/label.js +0 -103
  241. package/lib/utils/label.js.map +0 -1
  242. package/lib/versionInfo.d.ts +0 -32
  243. package/lib/versionInfo.d.ts.map +0 -1
  244. package/lib/versionInfo.js +0 -37
  245. package/lib/versionInfo.js.map +0 -1
  246. package/lib/widgets/buttons/iconLinks.js +0 -53
  247. package/lib/widgets/buttons/iconLinks.js.map +0 -1
  248. package/lib/widgets/buttons.js +0 -1306
  249. package/lib/widgets/buttons.js.map +0 -1
  250. package/lib/widgets/dragAndDrop.js +0 -194
  251. package/lib/widgets/dragAndDrop.js.map +0 -1
  252. package/lib/widgets/error.d.ts +0 -2
  253. package/lib/widgets/error.d.ts.map +0 -1
  254. package/lib/widgets/error.js +0 -46
  255. package/lib/widgets/error.js.map +0 -1
  256. package/lib/widgets/forms/autocomplete/autocompleteBar.js +0 -271
  257. package/lib/widgets/forms/autocomplete/autocompleteBar.js.map +0 -1
  258. package/lib/widgets/forms/autocomplete/autocompleteField.js +0 -258
  259. package/lib/widgets/forms/autocomplete/autocompleteField.js.map +0 -1
  260. package/lib/widgets/forms/autocomplete/autocompletePicker.js +0 -436
  261. package/lib/widgets/forms/autocomplete/autocompletePicker.js.map +0 -1
  262. package/lib/widgets/forms/autocomplete/language.js +0 -189
  263. package/lib/widgets/forms/autocomplete/language.js.map +0 -1
  264. package/lib/widgets/forms/autocomplete/publicData.js +0 -636
  265. package/lib/widgets/forms/autocomplete/publicData.js.map +0 -1
  266. package/lib/widgets/forms/basic.js +0 -254
  267. package/lib/widgets/forms/basic.js.map +0 -1
  268. package/lib/widgets/forms/comment.js +0 -54
  269. package/lib/widgets/forms/comment.js.map +0 -1
  270. package/lib/widgets/forms/fieldFunction.js +0 -52
  271. package/lib/widgets/forms/fieldFunction.js.map +0 -1
  272. package/lib/widgets/forms/fieldParams.js +0 -77
  273. package/lib/widgets/forms/fieldParams.js.map +0 -1
  274. package/lib/widgets/forms/formStyle.js +0 -44
  275. package/lib/widgets/forms/formStyle.js.map +0 -1
  276. package/lib/widgets/forms.js +0 -2045
  277. package/lib/widgets/forms.js.map +0 -1
  278. package/lib/widgets/index.js +0 -110
  279. package/lib/widgets/index.js.map +0 -1
  280. package/lib/widgets/multiSelect.js +0 -658
  281. package/lib/widgets/multiSelect.js.map +0 -1
  282. package/lib/widgets/peoplePicker.js +0 -467
  283. package/lib/widgets/peoplePicker.js.map +0 -1
  284. package/lib/widgets/widgetHelpers.js.map +0 -1
  285. /package/{lib → dist}/acl/access-controller.d.ts +0 -0
  286. /package/{lib → dist}/acl/access-controller.d.ts.map +0 -0
  287. /package/{lib → dist}/acl/acl-control.d.ts +0 -0
  288. /package/{lib → dist}/acl/acl-control.d.ts.map +0 -0
  289. /package/{lib → dist}/acl/acl.d.ts +0 -0
  290. /package/{lib → dist}/acl/acl.d.ts.map +0 -0
  291. /package/{lib → dist}/acl/add-agent-buttons.d.ts +0 -0
  292. /package/{lib → dist}/acl/add-agent-buttons.d.ts.map +0 -0
  293. /package/{lib → dist}/acl/index.d.ts +0 -0
  294. /package/{lib → dist}/acl/index.d.ts.map +0 -0
  295. /package/{lib → dist}/acl/types.d.ts +0 -0
  296. /package/{lib → dist}/acl/types.d.ts.map +0 -0
  297. /package/{lib → dist}/chat/keys.d.ts +0 -0
  298. /package/{lib → dist}/chat/keys.d.ts.map +0 -0
  299. /package/{lib → dist}/chat/signature.d.ts +0 -0
  300. /package/{lib → dist}/chat/signature.d.ts.map +0 -0
  301. /package/{lib → dist}/create/create.d.ts +0 -0
  302. /package/{lib → dist}/create/create.d.ts.map +0 -0
  303. /package/{lib → dist}/create/index.d.ts +0 -0
  304. /package/{lib → dist}/create/index.d.ts.map +0 -0
  305. /package/{lib → dist}/create/types.d.ts +0 -0
  306. /package/{lib → dist}/create/types.d.ts.map +0 -0
  307. /package/{lib → dist}/debug.d.ts +0 -0
  308. /package/{lib → dist}/footer/index.d.ts +0 -0
  309. /package/{lib → dist}/footer/index.d.ts.map +0 -0
  310. /package/{lib → dist}/header/empty-profile.d.ts +0 -0
  311. /package/{lib → dist}/header/empty-profile.d.ts.map +0 -0
  312. /package/{lib → dist}/header/index.d.ts +0 -0
  313. /package/{lib → dist}/header/index.d.ts.map +0 -0
  314. /package/{lib → dist}/iconBase.d.ts +0 -0
  315. /package/{lib → dist}/iconBase.d.ts.map +0 -0
  316. /package/{lib → dist}/icons/solid_logo.d.ts +0 -0
  317. /package/{lib → dist}/icons/solid_logo.d.ts.map +0 -0
  318. /package/{lib → dist}/icons/solid_logo.js +0 -0
  319. /package/{lib → dist}/log.d.ts +0 -0
  320. /package/{lib → dist}/login/login.d.ts +0 -0
  321. /package/{lib → dist}/login/login.d.ts.map +0 -0
  322. /package/{lib → dist}/matrix/index.d.ts +0 -0
  323. /package/{lib → dist}/matrix/index.d.ts.map +0 -0
  324. /package/{lib → dist}/matrix/matrix.d.ts +0 -0
  325. /package/{lib → dist}/matrix/matrix.d.ts.map +0 -0
  326. /package/{lib → dist}/matrix/types.d.ts +0 -0
  327. /package/{lib → dist}/matrix/types.d.ts.map +0 -0
  328. /package/{lib → dist}/media/index.d.ts +0 -0
  329. /package/{lib → dist}/media/index.d.ts.map +0 -0
  330. /package/{lib → dist}/media/media-capture.d.ts +0 -0
  331. /package/{lib → dist}/media/media-capture.d.ts.map +0 -0
  332. /package/{lib → dist}/pad.d.ts +0 -0
  333. /package/{lib → dist}/pad.d.ts.map +0 -0
  334. /package/{lib → dist}/participation.d.ts +0 -0
  335. /package/{lib → dist}/tabs.d.ts +0 -0
  336. /package/{lib → dist}/tabs.d.ts.map +0 -0
  337. /package/{lib → dist}/utils/headerFooterHelpers.d.ts +0 -0
  338. /package/{lib → dist}/utils/keyHelpers/accessData.d.ts +0 -0
  339. /package/{lib → dist}/utils/keyHelpers/accessData.d.ts.map +0 -0
  340. /package/{lib → dist}/utils/keyHelpers/acl.d.ts +0 -0
  341. /package/{lib → dist}/utils/keyHelpers/acl.d.ts.map +0 -0
  342. /package/{lib → dist}/utils/keyHelpers/otherHelpers.d.ts +0 -0
  343. /package/{lib → dist}/utils/keyHelpers/otherHelpers.d.ts.map +0 -0
  344. /package/{lib → dist}/utils/label.d.ts +0 -0
  345. /package/{lib → dist}/utils/label.d.ts.map +0 -0
  346. /package/{lib → dist}/widgets/buttons/iconLinks.d.ts +0 -0
  347. /package/{lib → dist}/widgets/buttons/iconLinks.d.ts.map +0 -0
  348. /package/{lib → dist}/widgets/buttons.d.ts +0 -0
  349. /package/{lib → dist}/widgets/buttons.d.ts.map +0 -0
  350. /package/{lib → dist}/widgets/forms/autocomplete/autocompleteBar.d.ts +0 -0
  351. /package/{lib → dist}/widgets/forms/autocomplete/autocompleteBar.d.ts.map +0 -0
  352. /package/{lib → dist}/widgets/forms/autocomplete/autocompleteField.d.ts +0 -0
  353. /package/{lib → dist}/widgets/forms/autocomplete/autocompleteField.d.ts.map +0 -0
  354. /package/{lib → dist}/widgets/forms/autocomplete/autocompletePicker.d.ts +0 -0
  355. /package/{lib → dist}/widgets/forms/autocomplete/autocompletePicker.d.ts.map +0 -0
  356. /package/{lib → dist}/widgets/forms/autocomplete/language.d.ts +0 -0
  357. /package/{lib → dist}/widgets/forms/autocomplete/language.d.ts.map +0 -0
  358. /package/{lib → dist}/widgets/forms/autocomplete/publicData.d.ts +0 -0
  359. /package/{lib → dist}/widgets/forms/autocomplete/publicData.d.ts.map +0 -0
  360. /package/{lib → dist}/widgets/forms/basic.d.ts +0 -0
  361. /package/{lib → dist}/widgets/forms/basic.d.ts.map +0 -0
  362. /package/{lib → dist}/widgets/forms/comment.d.ts +0 -0
  363. /package/{lib → dist}/widgets/forms/comment.d.ts.map +0 -0
  364. /package/{lib → dist}/widgets/forms/fieldFunction.d.ts +0 -0
  365. /package/{lib → dist}/widgets/forms/fieldFunction.d.ts.map +0 -0
  366. /package/{lib → dist}/widgets/forms/fieldParams.d.ts +0 -0
  367. /package/{lib → dist}/widgets/forms/fieldParams.d.ts.map +0 -0
  368. /package/{lib → dist}/widgets/forms/formStyle.d.ts +0 -0
  369. /package/{lib → dist}/widgets/widgetHelpers.d.ts +0 -0
@@ -0,0 +1,1280 @@
1
+ /* Buttons
2
+ */
3
+ import { st, sym, uri, Util } from 'rdflib';
4
+ import { icons } from '../iconBase';
5
+ import ns from '../ns';
6
+ import { style } from '../style';
7
+ import * as debug from '../debug';
8
+ import { info } from '../log';
9
+ import { uploadFiles, makeDraggable, makeDropTarget } from './dragAndDrop';
10
+ import { store } from 'solid-logic';
11
+ import * as utils from '../utils';
12
+ import { errorMessageBlock } from './error';
13
+ import { addClickListenerToElement, createImageDiv, wrapDivInATR } from './widgetHelpers';
14
+ import { linkIcon, createLinkForURI } from './buttons/iconLinks';
15
+ /**
16
+ * UI Widgets such as buttons
17
+ * @packageDocumentation
18
+ */
19
+ /* global alert */
20
+ const { iconBase } = icons;
21
+ const cancelIconURI = iconBase + 'noun_1180156.svg'; // black X
22
+ const checkIconURI = iconBase + 'noun_1180158.svg'; // green checkmark; Continue
23
+ function getStatusArea(context) {
24
+ let box = (context && context.statusArea) || (context && context.div) || null;
25
+ if (box)
26
+ return box;
27
+ let dom = context && context.dom;
28
+ if (!dom && typeof document !== 'undefined') {
29
+ dom = document;
30
+ }
31
+ if (dom) {
32
+ const body = dom.getElementsByTagName('body')[0];
33
+ box = dom.createElement('div');
34
+ body.insertBefore(box, body.firstElementChild);
35
+ if (context) {
36
+ context.statusArea = box;
37
+ }
38
+ return box;
39
+ }
40
+ return null;
41
+ }
42
+ /**
43
+ * Display an error message block
44
+ */
45
+ export function complain(context, err) {
46
+ if (!err)
47
+ return; // only if error
48
+ const ele = getStatusArea(context);
49
+ debug.log('Complaint: ' + err);
50
+ if (ele)
51
+ ele.appendChild(errorMessageBlock((context && context.dom) || document, err));
52
+ else
53
+ alert(err);
54
+ }
55
+ /**
56
+ * Remove all the children of an HTML element
57
+ */
58
+ export function clearElement(ele) {
59
+ while (ele.firstChild) {
60
+ ele.removeChild(ele.firstChild);
61
+ }
62
+ return ele;
63
+ }
64
+ /**
65
+ * To figure out the log URI from the full URI used to invoke the reasoner
66
+ */
67
+ export function extractLogURI(fullURI) {
68
+ const logPos = fullURI.search(/logFile=/);
69
+ const rulPos = fullURI.search(/&rulesFile=/);
70
+ return fullURI.substring(logPos + 8, rulPos);
71
+ }
72
+ /**
73
+ * By default, converts e.g. '2020-02-19T19:35:28.557Z' to '19:35'
74
+ * if today is 19 Feb 2020, and to 'Feb 19' if not.
75
+ * @@@ TODO This needs to be changed to local time
76
+ * @param noTime Return a string like 'Feb 19' even if it's today.
77
+ */
78
+ export function shortDate(str, noTime) {
79
+ if (!str)
80
+ return '???';
81
+ const month = [
82
+ 'Jan',
83
+ 'Feb',
84
+ 'Mar',
85
+ 'Apr',
86
+ 'May',
87
+ 'Jun',
88
+ 'Jul',
89
+ 'Aug',
90
+ 'Sep',
91
+ 'Oct',
92
+ 'Nov',
93
+ 'Dec'
94
+ ];
95
+ try {
96
+ const nowZ = new Date().toISOString();
97
+ // var nowZ = $rdf.term(now).value
98
+ // var n = now.getTimezoneOffset() // Minutes
99
+ if (str.slice(0, 10) === nowZ.slice(0, 10) && !noTime) {
100
+ return str.slice(11, 16);
101
+ }
102
+ if (str.slice(0, 4) === nowZ.slice(0, 4)) {
103
+ return (month[parseInt(str.slice(5, 7), 10) - 1] +
104
+ ' ' +
105
+ parseInt(str.slice(8, 10), 10));
106
+ }
107
+ return str.slice(0, 10);
108
+ }
109
+ catch (e) {
110
+ return 'shortdate:' + e;
111
+ }
112
+ }
113
+ /**
114
+ * Format a date and time
115
+ * @param date for instance `new Date()`
116
+ * @param format for instance '{FullYear}-{Month}-{Date}T{Hours}:{Minutes}:{Seconds}.{Milliseconds}'
117
+ * @returns for instance '2000-01-15T23:14:23.002'
118
+ */
119
+ export function formatDateTime(date, format) {
120
+ return format
121
+ .split('{')
122
+ .map(function (s) {
123
+ const k = s.split('}')[0];
124
+ const width = { Milliseconds: 3, FullYear: 4 };
125
+ const d = { Month: 1 };
126
+ return s
127
+ ? ('000' + (date['get' + k]() + (d[k] || 0))).slice(-(width[k] || 2)) + s.split('}')[1]
128
+ : '';
129
+ })
130
+ .join('');
131
+ }
132
+ /**
133
+ * Get a string representation of the current time
134
+ * @returns for instance '2000-01-15T23:14:23.002'
135
+ */
136
+ export function timestamp() {
137
+ return formatDateTime(new Date(), '{FullYear}-{Month}-{Date}T{Hours}:{Minutes}:{Seconds}.{Milliseconds}');
138
+ }
139
+ /**
140
+ * Get a short string representation of the current time
141
+ * @returns for instance '23:14:23.002'
142
+ */
143
+ export function shortTime() {
144
+ return formatDateTime(new Date(), '{Hours}:{Minutes}:{Seconds}.{Milliseconds}');
145
+ }
146
+ // ///////////////////// Handy UX widgets
147
+ /**
148
+ * Sets the best name we have and looks up a better one
149
+ */
150
+ export function setName(element, x) {
151
+ const kb = store;
152
+ const findName = function (x) {
153
+ const name = kb.any(x, ns.vcard('fn')) ||
154
+ kb.any(x, ns.foaf('name')) ||
155
+ kb.any(x, ns.vcard('organization-name'));
156
+ return name ? name.value : null;
157
+ };
158
+ const name = x.sameTerm(ns.foaf('Agent')) ? 'Everyone' : findName(x);
159
+ element.textContent = name || utils.label(x);
160
+ if (!name && x.uri) {
161
+ if (!kb.fetcher) {
162
+ throw new Error('kb has no fetcher');
163
+ }
164
+ // Note this is only a fetch, not a lookUP of all sameAs etc
165
+ kb.fetcher.nowOrWhenFetched(x.doc(), undefined, function (_ok) {
166
+ element.textContent = findName(x) || utils.label(x); // had: (ok ? '' : '? ') +
167
+ });
168
+ }
169
+ }
170
+ /**
171
+ * Set of suitable images
172
+ * See also [[findImage]]
173
+ * @param x The thing for which we want to find an image
174
+ * @param kb The RDF store to look in
175
+ * @returns It goes looking for triples in `kb`,
176
+ * `(subject: x), (predicate: see list below) (object: image-url)`
177
+ * to find any image linked from the thing with one of the following
178
+ * predicates (in order):
179
+ * * ns.sioc('avatar')
180
+ * * ns.foaf('img')
181
+ * * ns.vcard('logo')
182
+ * * ns.vcard('hasPhoto')
183
+ * * ns.vcard('photo')
184
+ * * ns.foaf('depiction')
185
+
186
+ */
187
+ export function imagesOf(x, kb) {
188
+ return kb
189
+ .each(x, ns.sioc('avatar'))
190
+ .concat(kb.each(x, ns.foaf('img')))
191
+ .concat(kb.each(x, ns.vcard('logo')))
192
+ .concat(kb.each(x, ns.vcard('hasPhoto')))
193
+ .concat(kb.each(x, ns.vcard('photo')))
194
+ .concat(kb.each(x, ns.foaf('depiction')));
195
+ }
196
+ /**
197
+ * Best logo or avatar or photo etc to represent someone or some group etc
198
+ */
199
+ export const iconForClass = {
200
+ // Potentially extendable by other apps, panes, etc
201
+ // Relative URIs to the iconBase
202
+ 'solid:AppProviderClass': 'noun_144.svg', // @@ classs name should not contain 'Class'
203
+ 'solid:AppProvider': 'noun_15177.svg', // @@
204
+ 'solid:Pod': 'noun_Cabinet_1434380.svg',
205
+ 'vcard:Group': 'noun_339237.svg',
206
+ 'vcard:Organization': 'noun_143899.svg',
207
+ 'vcard:Individual': 'noun_15059.svg',
208
+ 'schema:Person': 'noun_15059.svg',
209
+ 'foaf:Person': 'noun_15059.svg',
210
+ 'foaf:Agent': 'noun_98053.svg',
211
+ 'acl:AuthenticatedAgent': 'noun_99101.svg',
212
+ 'prov:SoftwareAgent': 'noun_Robot_849764.svg', // Bot
213
+ 'vcard:AddressBook': 'noun_15695.svg',
214
+ 'trip:Trip': 'noun_581629.svg',
215
+ 'meeting:LongChat': 'noun_1689339.svg',
216
+ 'meeting:Meeting': 'noun_66617.svg',
217
+ 'meeting:Project': 'noun_1036577.svg',
218
+ 'ui:Form': 'noun_122196.svg',
219
+ 'rdfs:Class': 'class-rectangle.svg', // For RDF developers
220
+ 'rdf:Property': 'property-diamond.svg',
221
+ 'owl:Ontology': 'noun_classification_1479198.svg',
222
+ 'wf:Tracker': 'noun_122196.svg',
223
+ 'wf:Task': 'noun_17020_gray-tick.svg',
224
+ 'wf:Open': 'noun_17020_sans-tick.svg',
225
+ 'wf:Closed': 'noun_17020.svg'
226
+ };
227
+ /**
228
+ * Returns the origin of the URI of a NamedNode
229
+ */
230
+ function tempSite(x) {
231
+ // use only while one in rdflib fails with origins 2019
232
+ const str = x.uri.split('#')[0];
233
+ const p = str.indexOf('//');
234
+ if (p < 0)
235
+ throw new Error('This URI does not have a web site part (origin)');
236
+ const q = str.indexOf('/', p + 2);
237
+ if (q < 0) {
238
+ // no third slash?
239
+ return str.slice(0) + '/'; // Add slash to a bare origin
240
+ }
241
+ else {
242
+ return str.slice(0, q + 1);
243
+ }
244
+ }
245
+ /**
246
+ * Find an image for this thing as a class
247
+ */
248
+ export function findImageFromURI(x) {
249
+ const iconDir = iconBase;
250
+ // Special cases from URI scheme:
251
+ if (typeof x !== 'string' && x.uri) {
252
+ if (x.uri.split('/').length === 4 &&
253
+ !x.uri.split('/')[1] &&
254
+ !x.uri.split('/')[3]) {
255
+ return iconDir + 'noun_15177.svg'; // App -- this is an origin
256
+ }
257
+ // Non-HTTP URI types imply types
258
+ if (x.uri.startsWith('message:') || x.uri.startsWith('mid:')) {
259
+ // message: is apple bug-- should be mid:
260
+ return iconDir + 'noun_480183.svg'; // envelope noun_567486
261
+ }
262
+ if (x.uri.startsWith('mailto:')) {
263
+ return iconDir + 'noun_567486.svg'; // mailbox - an email desitination
264
+ }
265
+ // For HTTP(s) documents, we could look at the MIME type if we know it.
266
+ if (x.uri.startsWith('https:') && x.uri.indexOf('#') < 0) {
267
+ return tempSite(x) + 'favicon.ico'; // was x.site().uri + ...
268
+ // Todo: make the document icon a fallback for if the favicon does not exist
269
+ // todo: pick up a possible favicon for the web page itself from a link
270
+ // was: return iconDir + 'noun_681601.svg' // document - under solid assumptions
271
+ }
272
+ return null;
273
+ }
274
+ return iconDir + 'noun_10636_grey.svg'; // Grey Circle - some thing
275
+ }
276
+ /**
277
+ * Find something we have as explicit image data for the thing
278
+ * See also [[imagesOf]]
279
+ * @param thing The thing for which we want to find an image
280
+ * @returns The URL of a globe icon if thing equals `ns.foaf('Agent')`
281
+ * or `ns.rdf('Resource')`. Otherwise, it goes looking for
282
+ * triples in `store`,
283
+ * `(subject: thing), (predicate: see list below) (object: image-url)`
284
+ * to find any image linked from the thing with one of the following
285
+ * predicates (in order):
286
+ * * ns.sioc('avatar')
287
+ * * ns.foaf('img')
288
+ * * ns.vcard('logo')
289
+ * * ns.vcard('hasPhoto')
290
+ * * ns.vcard('photo')
291
+ * * ns.foaf('depiction')
292
+ */
293
+ export function findImage(thing) {
294
+ const kb = store;
295
+ const iconDir = iconBase;
296
+ if (thing.sameTerm(ns.foaf('Agent')) || thing.sameTerm(ns.rdf('Resource'))) {
297
+ return iconDir + 'noun_98053.svg'; // Globe
298
+ }
299
+ const image = kb.any(thing, ns.sioc('avatar')) ||
300
+ kb.any(thing, ns.foaf('img')) ||
301
+ kb.any(thing, ns.vcard('logo')) ||
302
+ kb.any(thing, ns.vcard('hasPhoto')) ||
303
+ kb.any(thing, ns.vcard('photo')) ||
304
+ kb.any(thing, ns.foaf('depiction'));
305
+ return image ? image.uri : null;
306
+ }
307
+ /**
308
+ * Do the best you can with the data available
309
+ *
310
+ * @return {Boolean} Are we happy with this icon?
311
+ * Sets src AND STYLE of the image.
312
+ */
313
+ function trySetImage(element, thing, iconForClassMap) {
314
+ const kb = store;
315
+ const explitImage = findImage(thing);
316
+ if (explitImage) {
317
+ element.setAttribute('src', explitImage);
318
+ return true;
319
+ }
320
+ // This is one of the classes we know about - the class itself?
321
+ const typeIcon = iconForClassMap[thing.uri];
322
+ if (typeIcon) {
323
+ element.setAttribute('src', typeIcon);
324
+ element.style = style.classIconStyle;
325
+ // element.style.border = '0.1em solid green;'
326
+ // element.style.backgroundColor = '#eeffee' // pale green
327
+ return true;
328
+ }
329
+ const schemeIcon = findImageFromURI(thing);
330
+ if (schemeIcon) {
331
+ element.setAttribute('src', schemeIcon);
332
+ return true; // happy with this -- don't look it up
333
+ }
334
+ // Do we have a generic icon for something in any class its in?
335
+ const types = kb.findTypeURIs(thing);
336
+ for (const typeURI in types) {
337
+ if (iconForClassMap[typeURI]) {
338
+ element.setAttribute('src', iconForClassMap[typeURI]);
339
+ return false; // maybe we can do better
340
+ }
341
+ }
342
+ element.setAttribute('src', iconBase + 'noun_10636_grey.svg'); // Grey Circle - some thing
343
+ return false; // we can do better
344
+ }
345
+ /**
346
+ * ToDo: Also add icons for *properties* like home, work, email, range, domain, comment,
347
+ */
348
+ export function setImage(element, thing) {
349
+ const kb = store;
350
+ const iconForClassMap = {};
351
+ for (const k in iconForClass) {
352
+ const pref = k.split(':')[0];
353
+ const id = k.split(':')[1];
354
+ const theClass = ns[pref](id);
355
+ iconForClassMap[theClass.uri] = uri.join(iconForClass[k], iconBase);
356
+ }
357
+ const happy = trySetImage(element, thing, iconForClassMap);
358
+ if (!happy && thing.uri) {
359
+ if (!kb.fetcher) {
360
+ throw new Error('kb has no fetcher');
361
+ }
362
+ kb.fetcher.nowOrWhenFetched(thing.doc(), undefined, (ok) => {
363
+ if (ok) {
364
+ trySetImage(element, thing, iconForClassMap);
365
+ }
366
+ });
367
+ }
368
+ }
369
+ // If a web page, then a favicon, with a fallback to ???
370
+ // See, e.g., http://stackoverflow.com/questions/980855/inputting-a-default-image
371
+ export function faviconOrDefault(dom, x) {
372
+ const image = dom.createElement('img');
373
+ image.style = style.iconStyle;
374
+ const isOrigin = function (x) {
375
+ if (!x.uri)
376
+ return false;
377
+ const parts = x.uri.split('/');
378
+ return parts.length === 3 || (parts.length === 4 && parts[3] === '');
379
+ };
380
+ image.setAttribute('src', iconBase + (isOrigin(x) ? 'noun_15177.svg' : 'noun_681601.svg') // App symbol vs document
381
+ );
382
+ if (x.uri && x.uri.startsWith('https:') && x.uri.indexOf('#') < 0) {
383
+ const res = dom.createElement('object'); // favico with a fallback of a default image if no favicon
384
+ res.setAttribute('data', tempSite(x) + 'favicon.ico');
385
+ res.setAttribute('type', 'image/x-icon');
386
+ res.appendChild(image); // fallback
387
+ return res;
388
+ }
389
+ else {
390
+ setImage(image, x);
391
+ return image;
392
+ }
393
+ }
394
+ /* Two-option dialog pop-up
395
+ */
396
+ function renderDeleteConfirmPopup(dom, refererenceElement, prompt, deleteFunction) {
397
+ function removePopup() {
398
+ refererenceElement.parentElement.removeChild(refererenceElement);
399
+ }
400
+ function removePopupAndDoDeletion() {
401
+ removePopup();
402
+ deleteFunction();
403
+ }
404
+ const popup = dom.createElement('div');
405
+ popup.style = style.confirmPopupStyle;
406
+ popup.style.position = 'absolute';
407
+ popup.style.top = '-1em'; // try leaving original button clear
408
+ popup.style.display = 'grid';
409
+ popup.style.gridTemplateColumns = 'auto auto';
410
+ const affirm = dom.createElement('div');
411
+ affirm.style.gridColumn = '1/2';
412
+ affirm.style.gridRow = '1'; // @@ sigh; TS. could pass number in fact
413
+ const cancel = dom.createElement('div');
414
+ cancel.style.gridColumn = '1/2';
415
+ cancel.style.gridRow = '2';
416
+ const xButton = cancelButton(dom, removePopup);
417
+ popup.appendChild(xButton);
418
+ xButton.style.gridColumn = '1';
419
+ xButton.style.gridRow = '2';
420
+ const cancelPrompt = popup.appendChild(dom.createElement('button'));
421
+ cancelPrompt.style = style.buttonStyle;
422
+ cancelPrompt.style.gridRow = '2';
423
+ cancelPrompt.style.gridColumn = '2';
424
+ cancelPrompt.textContent = 'Cancel'; // @@ I18n
425
+ const affirmIcon = button(dom, icons.iconBase + 'noun_925021.svg', 'Delete it'); // trashcan
426
+ popup.appendChild(affirmIcon);
427
+ affirmIcon.style.gridRow = '1';
428
+ affirmIcon.style.gridColumn = '1';
429
+ const sureButtonElt = popup.appendChild(dom.createElement('button'));
430
+ sureButtonElt.style = style.buttonStyle;
431
+ sureButtonElt.style.gridRow = '1';
432
+ sureButtonElt.style.gridColumn = '2';
433
+ sureButtonElt.textContent = prompt;
434
+ popup.appendChild(sureButtonElt);
435
+ affirmIcon.addEventListener('click', removePopupAndDoDeletion);
436
+ sureButtonElt.addEventListener('click', removePopupAndDoDeletion);
437
+ // xButton.addEventListener('click', removePopup)
438
+ cancelPrompt.addEventListener('click', removePopup);
439
+ return popup;
440
+ }
441
+ /**
442
+ * Delete button with a check you really mean it
443
+ * @@ Supress check if command key held down?
444
+ */
445
+ export function deleteButtonWithCheck(dom, container, noun, deleteFunction) {
446
+ function createPopup() {
447
+ const refererenceElement = dom.createElement('div');
448
+ container.insertBefore(refererenceElement, deleteButton);
449
+ refererenceElement.style.position = 'relative'; // Needed as reference for popup
450
+ refererenceElement.appendChild(renderDeleteConfirmPopup(dom, refererenceElement, prompt, deleteFunction));
451
+ }
452
+ const minusIconURI = iconBase + 'noun_2188_red.svg'; // white minus in red #cc0000 circle
453
+ const deleteButton = dom.createElement('img');
454
+ deleteButton.setAttribute('src', minusIconURI);
455
+ deleteButton.setAttribute('style', style.smallButtonStyle); // @@tsc - would set deleteButton.style
456
+ deleteButton.style.float = 'right'; // Historically this has alwaus floated right
457
+ const prompt = 'Remove this ' + noun;
458
+ deleteButton.title = prompt;
459
+ // @@ In an ideal world, make use of hover an accessibility option
460
+ deleteButton.classList.add('hoverControlHide');
461
+ deleteButton.addEventListener('click', createPopup);
462
+ container.classList.add('hoverControl');
463
+ container.appendChild(deleteButton);
464
+ deleteButton.setAttribute('data-testid', 'deleteButtonWithCheck');
465
+ return deleteButton; // or button div? caller may change size of image
466
+ }
467
+ /* Make a button
468
+ *
469
+ * @param dom - the DOM document object
470
+ * @Param iconURI - the URI of the icon to use (if any)
471
+ * @param text - the tooltip text or possibly button contents text
472
+ * @param handler <function> - A handler to called when button is clicked
473
+ *
474
+ * @returns <dDomElement> - the button
475
+ */
476
+ export function button(dom, iconURI, text, handler, options = { buttonColor: 'Primary', needsBorder: false }) {
477
+ const button = dom.createElement('button');
478
+ button.setAttribute('type', 'button');
479
+ // button.innerHTML = text // later, user preferences may make text preferred for some
480
+ if (iconURI) {
481
+ const img = button.appendChild(dom.createElement('img'));
482
+ img.setAttribute('src', iconURI);
483
+ img.setAttribute('style', 'width: 2em; height: 2em;'); // trial and error. 2em disappears
484
+ img.title = text;
485
+ button.setAttribute('style', style.buttonStyle);
486
+ }
487
+ else {
488
+ button.textContent = text.toLocaleUpperCase();
489
+ button.onmouseover = function () {
490
+ if (options.buttonColor === 'Secondary') {
491
+ if (options.needsBorder) {
492
+ button.setAttribute('style', style.secondaryButtonNoBorderHover);
493
+ }
494
+ else {
495
+ button.setAttribute('style', style.secondaryButtonHover);
496
+ }
497
+ }
498
+ else {
499
+ if (options.needsBorder) {
500
+ button.setAttribute('style', style.primaryButtonNoBorderHover);
501
+ }
502
+ else {
503
+ button.setAttribute('style', style.primaryButtonHover);
504
+ }
505
+ }
506
+ };
507
+ button.onmouseout = function () {
508
+ if (options.buttonColor === 'Secondary') {
509
+ if (options.needsBorder) {
510
+ button.setAttribute('style', style.secondaryButtonNoBorder);
511
+ }
512
+ else {
513
+ button.setAttribute('style', style.secondaryButton);
514
+ }
515
+ }
516
+ else {
517
+ if (options.needsBorder) {
518
+ button.setAttribute('style', style.primaryButtonNoBorder);
519
+ }
520
+ else {
521
+ button.setAttribute('style', style.primaryButton);
522
+ }
523
+ }
524
+ };
525
+ if (options.buttonColor === 'Secondary') {
526
+ if (options.needsBorder) {
527
+ button.setAttribute('style', style.secondaryButtonNoBorder);
528
+ }
529
+ else {
530
+ button.setAttribute('style', style.secondaryButton);
531
+ }
532
+ }
533
+ else {
534
+ if (options.needsBorder) {
535
+ button.setAttribute('style', style.primaryButtonNoBorder);
536
+ }
537
+ else {
538
+ button.setAttribute('style', style.primaryButton);
539
+ }
540
+ }
541
+ }
542
+ if (handler) {
543
+ button.addEventListener('click', handler, false);
544
+ }
545
+ return button;
546
+ }
547
+ /* Make a cancel button
548
+ *
549
+ * @param dom - the DOM document object
550
+ * @param handler <function> - A handler to called when button is clicked
551
+ *
552
+ * @returns <dDomElement> - the button
553
+ */
554
+ export function cancelButton(dom, handler) {
555
+ const b = button(dom, cancelIconURI, 'Cancel', handler);
556
+ if (b.firstChild) { // sigh for tsc
557
+ b.firstChild.style.opacity = '0.3'; // Black X is too harsh: current language is grey X
558
+ }
559
+ return b;
560
+ }
561
+ /* Make a continue button
562
+ *
563
+ * @param dom - the DOM document object
564
+ * @param handler <function> - A handler to called when button is clicked
565
+ *
566
+ * @returns <dDomElement> - the button
567
+ */
568
+ export function continueButton(dom, handler) {
569
+ return button(dom, checkIconURI, 'Continue', handler);
570
+ }
571
+ /* Grab a name for a new thing
572
+ *
573
+ * Form to get the name of a new thing before we create it
574
+ * @params theClass Misspelt to avoid clashing with the JavaScript keyword
575
+ * @returns: a promise of (a name or null if cancelled)
576
+ */
577
+ export function askName(dom, kb, container, predicate, theClass, noun) {
578
+ return new Promise(function (resolve, _reject) {
579
+ const form = dom.createElement('div'); // form is broken as HTML behaviour can resurface on js error
580
+ // classLabel = utils.label(ns.vcard('Individual'))
581
+ predicate = predicate || ns.foaf('name'); // eg 'name' in user's language
582
+ noun = noun || (theClass ? utils.label(theClass) : ' '); // eg 'folder' in users's language
583
+ const prompt = noun + ' ' + utils.label(predicate) + ': ';
584
+ form.appendChild(dom.createElement('p')).textContent = prompt;
585
+ const namefield = dom.createElement('input');
586
+ namefield.setAttribute('type', 'text');
587
+ namefield.setAttribute('size', '100');
588
+ namefield.setAttribute('maxLength', '2048'); // No arbitrary limits
589
+ namefield.setAttribute('style', style.textInputStyle);
590
+ namefield.select(); // focus next user input
591
+ form.appendChild(namefield);
592
+ container.appendChild(form);
593
+ // namefield.focus()
594
+ function gotName() {
595
+ form.parentNode.removeChild(form);
596
+ resolve(namefield.value.trim());
597
+ }
598
+ namefield.addEventListener('keyup', function (e) {
599
+ if (e.keyCode === 13) {
600
+ gotName();
601
+ }
602
+ }, false);
603
+ form.appendChild(dom.createElement('br'));
604
+ form.appendChild(cancelButton(dom, function (_event) {
605
+ form.parentNode.removeChild(form);
606
+ resolve(null);
607
+ }));
608
+ form.appendChild(continueButton(dom, function (_event) {
609
+ gotName();
610
+ }));
611
+ namefield.focus();
612
+ }); // Promise
613
+ }
614
+ /**
615
+ * A TR to represent a draggable person, etc in a list
616
+ *
617
+ * pred is unused param at the moment
618
+ */
619
+ export const personTR = renderAsRow; // The legacy name is used in a lot of places
620
+ export function renderAsRow(dom, pred, obj, options) {
621
+ const tr = dom.createElement('tr');
622
+ options = options || {};
623
+ // tr.predObj = [pred.uri, obj.uri] moved to acl-control
624
+ const td1 = tr.appendChild(dom.createElement('td'));
625
+ const td2 = tr.appendChild(dom.createElement('td'));
626
+ const td3 = tr.appendChild(dom.createElement('td'));
627
+ // const image = td1.appendChild(dom.createElement('img'))
628
+ const image = options.image || faviconOrDefault(dom, obj);
629
+ td1.setAttribute('style', 'vertical-align: middle; width:2.5em; padding:0.5em; height: 2.5em;');
630
+ td2.setAttribute('style', 'vertical-align: middle; text-align:left;');
631
+ td3.setAttribute('style', 'vertical-align: middle; width:2em; padding:0.5em; height: 4em;');
632
+ td1.appendChild(image);
633
+ if (options.title) {
634
+ td2.textContent = options.title;
635
+ }
636
+ else {
637
+ setName(td2, obj); // This is async
638
+ }
639
+ if (options.deleteFunction) {
640
+ deleteButtonWithCheck(dom, td3, options.noun || 'one', options.deleteFunction);
641
+ }
642
+ if (obj.uri) {
643
+ // blank nodes need not apply
644
+ if (options.link !== false) {
645
+ const anchor = td3.appendChild(linkIcon(dom, obj));
646
+ anchor.classList.add('HoverControlHide');
647
+ td3.appendChild(dom.createElement('br'));
648
+ }
649
+ if (options.draggable !== false) {
650
+ // default is on
651
+ image.setAttribute('draggable', 'false'); // Stop the image being dragged instead - just the TR
652
+ makeDraggable(tr, obj);
653
+ }
654
+ }
655
+ ;
656
+ tr.subject = obj;
657
+ return tr;
658
+ }
659
+ /* A helper function for renderAsDiv
660
+ * creates the NameDiv for the person
661
+ * Note: could not move it to the helper file because they call exported functions
662
+ * from buttons
663
+ * @internal exporting this only for unit tests
664
+ */
665
+ export function createNameDiv(dom, div, title, obj) {
666
+ const nameDiv = div.appendChild(dom.createElement('div'));
667
+ if (title) {
668
+ nameDiv.textContent = title;
669
+ }
670
+ else {
671
+ setName(nameDiv, obj); // This is async
672
+ }
673
+ }
674
+ /* A helper function for renderAsDiv
675
+ * creates the linkDiv for the person
676
+ * Note: could not move it to the helper file because they call exported functions
677
+ * from buttons
678
+ * @internal exporting this only for unit tests
679
+ */
680
+ export function createLinkDiv(dom, div, obj, options) {
681
+ const linkDiv = div.appendChild(dom.createElement('div'));
682
+ linkDiv.setAttribute('style', style.linkDivStyle);
683
+ if (options.deleteFunction) {
684
+ deleteButtonWithCheck(dom, linkDiv, options.noun || 'one', options.deleteFunction);
685
+ }
686
+ if (obj.uri) {
687
+ // blank nodes need not apply
688
+ if (options.link !== false) {
689
+ createLinkForURI(dom, linkDiv, obj);
690
+ }
691
+ makeDraggable(div, obj);
692
+ }
693
+ }
694
+ /**
695
+ * A Div to represent a draggable person, etc in a list
696
+ * configurable to add an onClick listener
697
+ */
698
+ export function renderAsDiv(dom, obj, options) {
699
+ const div = dom.createElement('div');
700
+ div.setAttribute('style', style.renderAsDivStyle);
701
+ options = options || {};
702
+ const image = options.image || faviconOrDefault(dom, obj);
703
+ createImageDiv(dom, div, image);
704
+ createNameDiv(dom, div, options.title, obj);
705
+ createLinkDiv(dom, div, obj, options);
706
+ if (options.clickable && options.onClickFunction) {
707
+ addClickListenerToElement(div, options.onClickFunction);
708
+ }
709
+ // to be compatible with the SolidOS table layout
710
+ if (options.wrapInATR) {
711
+ const tr = wrapDivInATR(dom, div, obj);
712
+ return tr;
713
+ }
714
+ return div;
715
+ }
716
+ /**
717
+ * Refresh a DOM tree recursively
718
+ */
719
+ export function refreshTree(root) {
720
+ if (root.refresh) {
721
+ root.refresh();
722
+ return;
723
+ }
724
+ for (let i = 0; i < root.children.length; i++) {
725
+ refreshTree(root.children[i]);
726
+ }
727
+ }
728
+ /**
729
+ * Component that displays a list of resources, for instance
730
+ * the attachments of a message, or the various documents related
731
+ * to a meeting.
732
+ * Accepts dropping URLs onto it to add attachments to it.
733
+ */
734
+ export function attachmentList(dom, subject, div, options = {}) {
735
+ // options = options || {}
736
+ const deleteAttachment = function (target) {
737
+ if (!kb.updater) {
738
+ throw new Error('kb has no updater');
739
+ }
740
+ kb.updater.update(st(subject, predicate, target, doc), [], function (uri, ok, errorBody, _xhr) {
741
+ if (ok) {
742
+ refresh();
743
+ }
744
+ else {
745
+ complain(undefined, 'Error deleting one: ' + errorBody);
746
+ }
747
+ });
748
+ };
749
+ function createNewRow(target) {
750
+ const theTarget = target;
751
+ const opt = { noun };
752
+ if (modify) {
753
+ opt.deleteFunction = function () {
754
+ deleteAttachment(theTarget);
755
+ };
756
+ }
757
+ return personTR(dom, predicate, target, opt);
758
+ }
759
+ const refresh = function () {
760
+ const things = kb.each(subject, predicate);
761
+ things.sort();
762
+ utils.syncTableToArray(attachmentTable, things, createNewRow);
763
+ };
764
+ function droppedURIHandler(uris) {
765
+ const ins = [];
766
+ uris.forEach(function (u) {
767
+ const target = sym(u); // Attachment needs text label to disinguish I think not icon.
768
+ debug.log('Dropped on attachemnt ' + u); // icon was: iconBase + 'noun_25830.svg'
769
+ ins.push(st(subject, predicate, target, doc));
770
+ });
771
+ if (!kb.updater) {
772
+ throw new Error('kb has no updater');
773
+ }
774
+ kb.updater.update([], ins, function (uri, ok, errorBody, _xhr) {
775
+ if (ok) {
776
+ refresh();
777
+ }
778
+ else {
779
+ complain(undefined, 'Error adding one: ' + errorBody);
780
+ }
781
+ });
782
+ }
783
+ function droppedFileHandler(files) {
784
+ var _a, _b;
785
+ uploadFiles(kb.fetcher, files, (_a = options.uploadFolder) === null || _a === void 0 ? void 0 : _a.uri, // Files
786
+ (_b = options.uploadFolder) === null || _b === void 0 ? void 0 : _b.uri, // Pictures
787
+ function (theFile, destURI) {
788
+ const ins = [st(subject, predicate, kb.sym(destURI), doc)];
789
+ if (!kb.updater) {
790
+ throw new Error('kb has no updater');
791
+ }
792
+ kb.updater.update([], ins, function (uri, ok, errorBody, _xhr) {
793
+ if (ok) {
794
+ refresh();
795
+ }
796
+ else {
797
+ complain(undefined, 'Error adding link to uploaded file: ' + errorBody);
798
+ }
799
+ });
800
+ });
801
+ }
802
+ const doc = options.doc || subject.doc();
803
+ if (options.modify === undefined)
804
+ options.modify = true;
805
+ const modify = options.modify;
806
+ const promptIcon = options.promptIcon || iconBase + 'noun_748003.svg'; // target
807
+ // const promptIcon = options.promptIcon || (iconBase + 'noun_25830.svg') // paperclip
808
+ const predicate = options.predicate || ns.wf('attachment');
809
+ const noun = options.noun || 'attachment';
810
+ const kb = store;
811
+ const attachmentOuter = div.appendChild(dom.createElement('table'));
812
+ attachmentOuter.setAttribute('style', 'margin-top: 1em; margin-bottom: 1em;');
813
+ const attachmentOne = attachmentOuter.appendChild(dom.createElement('tr'));
814
+ const attachmentLeft = attachmentOne.appendChild(dom.createElement('td'));
815
+ const attachmentRight = attachmentOne.appendChild(dom.createElement('td'));
816
+ const attachmentTable = attachmentRight.appendChild(dom.createElement('table'));
817
+ attachmentTable.appendChild(dom.createElement('tr')) // attachmentTableTop
818
+ ;
819
+ attachmentOuter.refresh = refresh; // Participate in downstream changes
820
+ // ;(attachmentTable as any).refresh = refresh <- outer should be best?
821
+ refresh();
822
+ if (modify) {
823
+ // const buttonStyle = 'width; 2em; height: 2em; margin: 0.5em; padding: 0.1em;'
824
+ const paperclip = button(dom, promptIcon, 'Drop attachments here');
825
+ // paperclip.style = buttonStyle // @@ needed? default has white background
826
+ attachmentLeft.appendChild(paperclip);
827
+ const fhandler = options.uploadFolder ? droppedFileHandler : null;
828
+ makeDropTarget(paperclip, droppedURIHandler, fhandler); // beware missing the wire of the paparclip!
829
+ makeDropTarget(attachmentLeft, droppedURIHandler, fhandler); // just the outer won't do it
830
+ if (options.uploadFolder) { // Addd an explicit file upload button as well
831
+ const buttonDiv = fileUploadButtonDiv(dom, droppedFileHandler);
832
+ attachmentLeft.appendChild(buttonDiv);
833
+ // buttonDiv.children[1].style = buttonStyle
834
+ }
835
+ }
836
+ return attachmentOuter;
837
+ }
838
+ // /////////////////////////////////////////////////////////////////////////////
839
+ /**
840
+ * Event Handler for links within solid apps.
841
+ *
842
+ * Note that native links have constraints in Firefox, they
843
+ * don't work with local files for instance (2011)
844
+ */
845
+ export function openHrefInOutlineMode(e) {
846
+ e.preventDefault();
847
+ e.stopPropagation();
848
+ const target = utils.getTarget(e);
849
+ const uri = target.getAttribute('href');
850
+ if (!uri)
851
+ return debug.log('openHrefInOutlineMode: No href found!\n');
852
+ const dom = window.document;
853
+ if (dom.outlineManager) {
854
+ // @@ TODO Remove the use of document as a global object
855
+ // TODO fix dependency cycle to solid-panes by calling outlineManager
856
+ ;
857
+ dom.outlineManager.GotoSubject(store.sym(uri), true, undefined, true, undefined);
858
+ }
859
+ else if (window && window.panes && window.panes.getOutliner) {
860
+ // @@ TODO Remove the use of window as a global object
861
+ ;
862
+ window.panes
863
+ .getOutliner()
864
+ .GotoSubject(store.sym(uri), true, undefined, true, undefined);
865
+ }
866
+ else {
867
+ debug.log('ERROR: Can\'t access outline manager in this config');
868
+ }
869
+ // dom.outlineManager.GotoSubject(store.sym(uri), true, undefined, true, undefined)
870
+ }
871
+ /**
872
+ * Make a URI in the Tabulator.org annotation store out of the URI of the thing to be annotated.
873
+ *
874
+ * @@ Todo: make it a personal preference.
875
+ */
876
+ export function defaultAnnotationStore(subject) {
877
+ if (subject.uri === undefined)
878
+ return undefined;
879
+ let s = subject.uri;
880
+ if (s.slice(0, 7) !== 'http://')
881
+ return undefined;
882
+ s = s.slice(7); // Remove
883
+ const hash = s.indexOf('#');
884
+ if (hash >= 0)
885
+ s = s.slice(0, hash);
886
+ // Strip trailing
887
+ else {
888
+ const slash = s.lastIndexOf('/');
889
+ if (slash < 0)
890
+ return undefined;
891
+ s = s.slice(0, slash);
892
+ }
893
+ return store.sym('http://tabulator.org/wiki/annnotation/' + s);
894
+ }
895
+ /**
896
+ * Retrieve all RDF class URIs from solid-ui's RDF store
897
+ * @returns an object `ret` such that `Object.keys(ret)` is
898
+ * the list of all class URIs.
899
+ */
900
+ export function allClassURIs() {
901
+ const set = {};
902
+ store
903
+ .statementsMatching(undefined, ns.rdf('type'), undefined)
904
+ .forEach(function (st) {
905
+ if (st.object.value)
906
+ set[st.object.value] = true;
907
+ });
908
+ store
909
+ .statementsMatching(undefined, ns.rdfs('subClassOf'), undefined)
910
+ .forEach(function (st) {
911
+ if (st.object.value)
912
+ set[st.object.value] = true;
913
+ if (st.subject.value)
914
+ set[st.subject.value] = true;
915
+ });
916
+ store
917
+ .each(undefined, ns.rdf('type'), ns.rdfs('Class'))
918
+ .forEach(function (c) {
919
+ if (c.value)
920
+ set[c.value] = true;
921
+ });
922
+ return set;
923
+ }
924
+ /**
925
+ * Figuring which properties we know about
926
+ *
927
+ * When the user inputs an RDF property, like for a form field
928
+ * or when specifying the relationship between two arbitrary things,
929
+ * then er can prompt them with properties the session knows about
930
+ *
931
+ * TODO: Look again by catching this somewhere. (On the kb?)
932
+ * TODO: move to diff module? Not really a button.
933
+ * @param {Store} kb The quadstore to be searched.
934
+ */
935
+ export function propertyTriage(kb) {
936
+ const possibleProperties = {};
937
+ // if (possibleProperties === undefined) possibleProperties = {}
938
+ // const kb = store
939
+ const dp = {};
940
+ const op = {};
941
+ let no = 0;
942
+ let nd = 0;
943
+ let nu = 0;
944
+ const pi = kb.predicateIndex; // One entry for each pred
945
+ for (const p in pi) {
946
+ const object = pi[p][0].object;
947
+ if (object.termType === 'Literal') {
948
+ dp[p] = true;
949
+ nd++;
950
+ }
951
+ else {
952
+ op[p] = true;
953
+ no++;
954
+ }
955
+ } // If nothing discovered, then could be either:
956
+ const ps = kb.each(undefined, ns.rdf('type'), ns.rdf('Property'));
957
+ for (let i = 0; i < ps.length; i++) {
958
+ const p = ps[i].toNT();
959
+ if (!op[p] && !dp[p]) {
960
+ dp[p] = true;
961
+ op[p] = true;
962
+ nu++;
963
+ }
964
+ }
965
+ possibleProperties.op = op;
966
+ possibleProperties.dp = dp;
967
+ info(`propertyTriage: ${no} non-lit, ${nd} literal. ${nu} unknown.`);
968
+ return possibleProperties;
969
+ }
970
+ /**
971
+ * General purpose widgets
972
+ */
973
+ /**
974
+ * A button for jumping
975
+ */
976
+ export function linkButton(dom, object) {
977
+ const b = dom.createElement('button');
978
+ b.setAttribute('type', 'button');
979
+ b.textContent = 'Goto ' + utils.label(object);
980
+ b.addEventListener('click', function (_event) {
981
+ // b.parentNode.removeChild(b)
982
+ // TODO fix dependency cycle to solid-panes by calling outlineManager
983
+ ;
984
+ dom.outlineManager.GotoSubject(object, true, undefined, true, undefined);
985
+ }, true);
986
+ return b;
987
+ }
988
+ /**
989
+ * A button to remove some other element from the page
990
+ */
991
+ export function removeButton(dom, element) {
992
+ const b = dom.createElement('button');
993
+ b.setAttribute('type', 'button');
994
+ b.textContent = '✕'; // MULTIPLICATION X
995
+ b.addEventListener('click', function (_event) {
996
+ ;
997
+ element.parentNode.removeChild(element);
998
+ }, true);
999
+ return b;
1000
+ }
1001
+ // Description text area
1002
+ //
1003
+ // Make a box to demand a description or display existing one
1004
+ //
1005
+ // @param dom - the document DOM for the user interface
1006
+ // @param kb - the graph which is the knowledge base we are working with
1007
+ // @param subject - a term, the subject of the statement(s) being edited.
1008
+ // @param predicate - a term, the predicate of the statement(s) being edited
1009
+ // @param store - The web document being edited
1010
+ // @param callbackFunction - takes (boolean ok, string errorBody)
1011
+ // /////////////////////////////////////// Random I/O widgets /////////////
1012
+ // //// Column Header Buttons
1013
+ //
1014
+ // These are for selecting different modes, sources,styles, etc.
1015
+ //
1016
+ /*
1017
+ buttons.headerButtons = function (dom, kb, name, words) {
1018
+ const box = dom.createElement('table')
1019
+ var i, word, s = '<tr>'
1020
+ box.setAttribute('style', 'width: 90%; height: 1.5em')
1021
+ for (i=0; i<words.length; i++) {
1022
+ s += '<td><input type="radio" name="' + name + '" id="' + words[i] + '" value='
1023
+ }
1024
+ box.innerHTML = s + '</tr>'
1025
+
1026
+ }
1027
+ */
1028
+ // ////////////////////////////////////////////////////////////
1029
+ //
1030
+ // selectorPanel
1031
+ //
1032
+ // A vertical panel for selecting connections to left or right.
1033
+ //
1034
+ // @param inverse means this is the object rather than the subject
1035
+ //
1036
+ export function selectorPanel(dom, kb, type, predicate, inverse, possible, options, callbackFunction, linkCallback) {
1037
+ return selectorPanelRefresh(dom.createElement('div'), dom, kb, type, predicate, inverse, possible, options, callbackFunction, linkCallback);
1038
+ }
1039
+ export function selectorPanelRefresh(list, dom, kb, type, predicate, inverse, possible, options, callbackFunction, linkCallback) {
1040
+ const style0 = 'border: 0.1em solid #ddd; border-bottom: none; width: 95%; height: 2em; padding: 0.5em;';
1041
+ let selected = null;
1042
+ list.innerHTML = '';
1043
+ const refreshItem = function (box, x) {
1044
+ // Scope to hold item and x
1045
+ let item;
1046
+ // eslint-disable-next-line prefer-const
1047
+ let image;
1048
+ const setStyle = function () {
1049
+ const already = inverse
1050
+ ? kb.each(undefined, predicate, x)
1051
+ : kb.each(x, predicate);
1052
+ iconDiv.setAttribute('class', already.length === 0 ? 'hideTillHover' : ''); // See tabbedtab.css
1053
+ image.setAttribute('src', options.connectIcon || iconBase + 'noun_25830.svg');
1054
+ image.setAttribute('title', already.length ? already.length : 'attach');
1055
+ };
1056
+ const f = index.twoLine.widgetForClass(type);
1057
+ // eslint-disable-next-line prefer-const
1058
+ item = f(dom, x);
1059
+ item.setAttribute('style', style0);
1060
+ const nav = dom.createElement('div');
1061
+ nav.setAttribute('class', 'hideTillHover'); // See tabbedtab.css
1062
+ nav.setAttribute('style', 'float:right; width:10%');
1063
+ const a = dom.createElement('a');
1064
+ a.setAttribute('href', x.uri);
1065
+ a.setAttribute('style', 'float:right');
1066
+ nav.appendChild(a).textContent = '>';
1067
+ box.appendChild(nav);
1068
+ const iconDiv = dom.createElement('div');
1069
+ iconDiv.setAttribute('style', (inverse ? 'float:left;' : 'float:right;') + ' width:30px;');
1070
+ image = dom.createElement('img');
1071
+ setStyle();
1072
+ iconDiv.appendChild(image);
1073
+ box.appendChild(iconDiv);
1074
+ item.addEventListener('click', function (event) {
1075
+ if (selected === item) {
1076
+ // deselect
1077
+ item.setAttribute('style', style0);
1078
+ selected = null;
1079
+ }
1080
+ else {
1081
+ if (selected)
1082
+ selected.setAttribute('style', style0);
1083
+ item.setAttribute('style', style0 + 'background-color: #ccc; color:black;');
1084
+ selected = item;
1085
+ }
1086
+ callbackFunction(x, event, selected === item);
1087
+ setStyle();
1088
+ }, false);
1089
+ image.addEventListener('click', function (event) {
1090
+ linkCallback(x, event, inverse, setStyle);
1091
+ }, false);
1092
+ box.appendChild(item);
1093
+ return box;
1094
+ };
1095
+ for (let i = 0; i < possible.length; i++) {
1096
+ const box = dom.createElement('div');
1097
+ list.appendChild(box);
1098
+ refreshItem(box, possible[i]);
1099
+ }
1100
+ return list;
1101
+ }
1102
+ // ###########################################################################
1103
+ //
1104
+ // Small compact views of things
1105
+ //
1106
+ export let index = {};
1107
+ // ///////////////////////////////////////////////////////////////////////////
1108
+ // We need these for anything which is a subject of an attachment.
1109
+ //
1110
+ // These should be moved to type-dependeent UI code. Related panes maybe
1111
+ function twoLineDefault(dom, x) {
1112
+ // Default
1113
+ const box = dom.createElement('div');
1114
+ box.textContent = utils.label(x);
1115
+ return box;
1116
+ }
1117
+ /**
1118
+ * Find a function that can create a widget for a given class
1119
+ * @param c The RDF class for which we want a widget generator function
1120
+ */
1121
+ function twoLineWidgetForClass(c) {
1122
+ let widget = index.twoLine[c.uri];
1123
+ const kb = store;
1124
+ if (widget)
1125
+ return widget;
1126
+ const sup = kb.findSuperClassesNT(c);
1127
+ for (const cl in sup) {
1128
+ widget = index.twoLine[kb.fromNT(cl).uri];
1129
+ if (widget)
1130
+ return widget;
1131
+ }
1132
+ return index.twoLine[''];
1133
+ }
1134
+ /**
1135
+ * Display a transaction
1136
+ * @param x Should have attributes through triples in store:
1137
+ * * ns.qu('payee') -> a named node
1138
+ * * ns.qu('date) -> a literal
1139
+ * * ns.qu('amount') -> a literal
1140
+ */
1141
+ function twoLineTransaction(dom, x) {
1142
+ let failed = '';
1143
+ const enc = function (p) {
1144
+ const y = store.any(x, ns.qu(p));
1145
+ if (!y)
1146
+ failed += '@@ No value for ' + p + '! ';
1147
+ return y ? utils.escapeForXML(y.value) : '?'; // @@@@
1148
+ };
1149
+ const box = dom.createElement('table');
1150
+ box.innerHTML = `
1151
+ <tr>
1152
+ <td colspan="2"> ${enc('payee')}</td>
1153
+ < /tr>
1154
+ < tr >
1155
+ <td>${enc('date').slice(0, 10)}</td>
1156
+ <td style = "text-align: right;">${enc('amount')}</td>
1157
+ </tr>`;
1158
+ if (failed) {
1159
+ box.innerHTML = `
1160
+ <tr>
1161
+ <td><a href="${utils.escapeForXML(x.uri)}">${utils.escapeForXML(failed)}</a></td>
1162
+ </tr>`;
1163
+ }
1164
+ return box;
1165
+ }
1166
+ /**
1167
+ * Display a trip
1168
+ * @param x Should have attributes through triples in store:
1169
+ * * ns.dc('title') -> a literal
1170
+ * * ns.cal('dtstart') -> a literal
1171
+ * * ns.cal('dtend') -> a literal
1172
+ */
1173
+ function twoLineTrip(dom, x) {
1174
+ const enc = function (p) {
1175
+ const y = store.any(x, p);
1176
+ return y ? utils.escapeForXML(y.value) : '?';
1177
+ };
1178
+ const box = dom.createElement('table');
1179
+ box.innerHTML = `
1180
+ <tr>
1181
+ <td colspan="2">${enc(ns.dc('title'))}</td>
1182
+ </tr>
1183
+ <tr style="color: #777">
1184
+ <td>${enc(ns.cal('dtstart'))}</td>
1185
+ <td>${enc(ns.cal('dtend'))}</td>
1186
+ </tr>`;
1187
+ return box;
1188
+ }
1189
+ /**
1190
+ * Stick a stylesheet link the document if not already there
1191
+ */
1192
+ export function addStyleSheet(dom, href) {
1193
+ const links = dom.querySelectorAll('link');
1194
+ for (let i = 0; i < links.length; i++) {
1195
+ if ((links[i].getAttribute('rel') || '') === 'stylesheet' &&
1196
+ (links[i].getAttribute('href') || '') === href) {
1197
+ return;
1198
+ }
1199
+ }
1200
+ const link = dom.createElement('link');
1201
+ link.setAttribute('rel', 'stylesheet');
1202
+ link.setAttribute('type', 'text/css');
1203
+ link.setAttribute('href', href);
1204
+ dom.getElementsByTagName('head')[0].appendChild(link);
1205
+ }
1206
+ // Figure (or guess) whether this is an image, etc
1207
+ //
1208
+ export function isAudio(file) {
1209
+ return isImage(file, 'audio');
1210
+ }
1211
+ export function isVideo(file) {
1212
+ return isImage(file, 'video');
1213
+ }
1214
+ /**
1215
+ *
1216
+ */
1217
+ export function isImage(file, kind) {
1218
+ const dcCLasses = {
1219
+ audio: 'http://purl.org/dc/dcmitype/Sound',
1220
+ image: 'http://purl.org/dc/dcmitype/Image',
1221
+ video: 'http://purl.org/dc/dcmitype/MovingImage'
1222
+ };
1223
+ const what = kind || 'image';
1224
+ // See https://github.com/linkeddata/rdflib.js/blob/e367d5088c/src/formula.ts#L554
1225
+ //
1226
+ const typeURIs = store.findTypeURIs(file);
1227
+ // See https://github.com/linkeddata/rdflib.js/blob/d5000f/src/utils-js.js#L14
1228
+ // e.g.'http://www.w3.org/ns/iana/media-types/audio'
1229
+ const prefix = Util.mediaTypeClass(what + '/*').uri.split('*')[0];
1230
+ for (const t in typeURIs) {
1231
+ if (t.startsWith(prefix))
1232
+ return true;
1233
+ }
1234
+ if (dcCLasses[what] in typeURIs)
1235
+ return true;
1236
+ return false;
1237
+ }
1238
+ /**
1239
+ * File upload button
1240
+ * @param dom The DOM aka document
1241
+ * @param droppedFileHandler Same handler function as drop, takes array of file objects
1242
+ * @returns {Element} - a div with a button and a inout in it
1243
+ * The input is hidden, as it is uglky - the user clicks on the nice icons and fires the input.
1244
+ */
1245
+ // See https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications
1246
+ export function fileUploadButtonDiv(dom, droppedFileHandler) {
1247
+ const div = dom.createElement('div');
1248
+ const input = div.appendChild(dom.createElement('input'));
1249
+ input.setAttribute('type', 'file');
1250
+ input.setAttribute('multiple', 'true');
1251
+ input.addEventListener('change', (event) => {
1252
+ debug.log('File drop event: ', event);
1253
+ if (event.files) {
1254
+ droppedFileHandler(event.files);
1255
+ }
1256
+ else if (event.target && event.target.files) {
1257
+ droppedFileHandler(event.target.files);
1258
+ }
1259
+ else {
1260
+ alert('Sorry no files .. internal error?');
1261
+ }
1262
+ }, false);
1263
+ input.style = 'display:none';
1264
+ const buttonElt = div.appendChild(button(dom, iconBase + 'noun_Upload_76574_000000.svg', 'Upload files', _event => {
1265
+ input.click();
1266
+ }));
1267
+ makeDropTarget(buttonElt, null, droppedFileHandler); // Can also just drop on button
1268
+ return div;
1269
+ }
1270
+ index = {
1271
+ line: { // Approx 80em
1272
+ },
1273
+ twoLine: {
1274
+ '': twoLineDefault,
1275
+ 'http://www.w3.org/2000/10/swap/pim/qif#Transaction': twoLineTransaction,
1276
+ 'http://www.w3.org/ns/pim/trip#Trip': twoLineTrip,
1277
+ widgetForClass: twoLineWidgetForClass
1278
+ }
1279
+ };
1280
+ //# sourceMappingURL=buttons.js.map