contacts-pane 2.5.8 → 2.6.0-fd0082d5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +0 -0
- package/.github/workflows/ci.yml +4 -3
- package/.nvmrc +0 -0
- package/LICENSE.md +0 -0
- package/Makefile +0 -0
- package/README.md +0 -0
- package/card.ai +0 -0
- package/card.png +0 -0
- package/contactLogic.js +21 -20
- package/contactsPane.js +4 -16
- package/diff.txt +0 -0
- package/exampleOfOpenData/mit-wikidata-details.ttl +0 -0
- package/exampleOfOpenData/mit-wikidata-query.sparql +0 -0
- package/exampleOfOpenData/wikidata-get.json +0 -0
- package/groupMembershipControl.js +0 -1
- package/individual.js +10 -9
- package/individualForm.js +0 -0
- package/lib/autocompleteBar.js +5 -5
- package/lib/autocompleteField.js +3 -3
- package/lib/autocompletePicker.js +7 -12
- package/lib/forms.js +0 -0
- package/lib/instituteDetailsQuery.js +0 -0
- package/lib/publicData.js +13 -13
- package/lib/vcard.js +0 -0
- package/mintNewAddressBook.js +3 -20
- package/mugshotGallery.js +21 -19
- package/organizationForm.js +0 -0
- package/organizationForm.ttl +0 -0
- package/package.json +6 -5
- package/shapes/contacts-shapes.ttl +0 -0
- package/src/autocompleteBar.ts +6 -8
- package/src/autocompleteField.ts +3 -9
- package/src/autocompletePicker.ts +8 -8
- package/src/forms.ttl +0 -0
- package/src/instituteDetailsQuery.sparql +0 -0
- package/src/publicData.ts +7 -9
- package/src/vcard.ttl +0 -0
- package/toolsPane.js +41 -40
- package/webidControl.js +11 -10
package/.eslintrc
CHANGED
|
File without changes
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -3,10 +3,11 @@ name: CI
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
|
-
-
|
|
6
|
+
- "**"
|
|
7
7
|
pull_request:
|
|
8
8
|
branches:
|
|
9
|
-
-
|
|
9
|
+
- "**"
|
|
10
|
+
workflow_dispatch:
|
|
10
11
|
|
|
11
12
|
jobs:
|
|
12
13
|
test:
|
|
@@ -16,7 +17,7 @@ jobs:
|
|
|
16
17
|
node-version:
|
|
17
18
|
- 12.x
|
|
18
19
|
- 14.x
|
|
19
|
-
-
|
|
20
|
+
- 16.x
|
|
20
21
|
steps:
|
|
21
22
|
- uses: actions/checkout@v2
|
|
22
23
|
- name: Use Node.js ${{ matrix.node-version }}
|
package/.nvmrc
CHANGED
|
File without changes
|
package/LICENSE.md
CHANGED
|
File without changes
|
package/Makefile
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/card.ai
CHANGED
|
File without changes
|
package/card.png
CHANGED
|
File without changes
|
package/contactLogic.js
CHANGED
|
@@ -7,7 +7,8 @@ import { getPersonas } from './webidControl'
|
|
|
7
7
|
const ns = UI.ns
|
|
8
8
|
const $rdf = UI.rdf
|
|
9
9
|
const utils = UI.utils
|
|
10
|
-
const
|
|
10
|
+
const kb = store
|
|
11
|
+
const updater = kb.updater
|
|
11
12
|
|
|
12
13
|
/** Perform updates on more than one document @@ Move to rdflib!
|
|
13
14
|
*/
|
|
@@ -18,7 +19,7 @@ export async function updateMany (deletions, insertions = []) {
|
|
|
18
19
|
if (!uniqueDocs.find(uniqueDoc => uniqueDoc.equals(doc))) uniqueDocs.push(doc)
|
|
19
20
|
})
|
|
20
21
|
const updates = uniqueDocs.map(doc =>
|
|
21
|
-
|
|
22
|
+
kb.updater.update(deletions.filter(st => st.why.sameTerm(doc)),
|
|
22
23
|
insertions.filter(st => st.why.sameTerm(doc))))
|
|
23
24
|
return Promise.all(updates)
|
|
24
25
|
}
|
|
@@ -29,11 +30,11 @@ export async function updateMany (deletions, insertions = []) {
|
|
|
29
30
|
* @returns {NamedNode} the person
|
|
30
31
|
*/
|
|
31
32
|
export async function saveNewContact (book, name, selectedGroups, klass) {
|
|
32
|
-
await
|
|
33
|
-
const nameEmailIndex =
|
|
33
|
+
await kb.fetcher.load(book.doc())
|
|
34
|
+
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
34
35
|
|
|
35
36
|
const uuid = utils.genUuid()
|
|
36
|
-
const person =
|
|
37
|
+
const person = kb.sym(
|
|
37
38
|
book.dir().uri + 'Person/' + uuid + '/index.ttl#this'
|
|
38
39
|
)
|
|
39
40
|
const doc = person.doc()
|
|
@@ -52,7 +53,7 @@ export async function saveNewContact (book, name, selectedGroups, klass) {
|
|
|
52
53
|
]
|
|
53
54
|
|
|
54
55
|
for (const gu in selectedGroups) {
|
|
55
|
-
const g =
|
|
56
|
+
const g = kb.sym(gu)
|
|
56
57
|
const gd = g.doc()
|
|
57
58
|
agenda.push(
|
|
58
59
|
$rdf.st(g, ns.vcard('hasMember'), person, gd),
|
|
@@ -79,19 +80,19 @@ export function sanitizeToAlpha (name) { // https://mathiasbynens.be/notes/es6-u
|
|
|
79
80
|
* @returns group
|
|
80
81
|
*/
|
|
81
82
|
export async function saveNewGroup (book, name) {
|
|
82
|
-
await
|
|
83
|
-
const gix =
|
|
83
|
+
await kb.fetcher.load(book.doc())
|
|
84
|
+
const gix = kb.any(book, ns.vcard('groupIndex'))
|
|
84
85
|
|
|
85
86
|
const gname = sanitizeToAlpha(name)
|
|
86
|
-
const group =
|
|
87
|
+
const group = kb.sym(book.dir().uri + 'Group/' + gname + '.ttl#this')
|
|
87
88
|
const doc = group.doc()
|
|
88
89
|
console.log(' New group will be: ' + group + '\n')
|
|
89
90
|
try {
|
|
90
|
-
await
|
|
91
|
+
await kb.fetcher.load(gix)
|
|
91
92
|
} catch (err) {
|
|
92
93
|
throw new Error('Error loading group index!' + gix.uri + ': ' + err)
|
|
93
94
|
}
|
|
94
|
-
if (
|
|
95
|
+
if (kb.holds(book, ns.vcard('includesGroup'), group, gix)) {
|
|
95
96
|
return group // Already exists
|
|
96
97
|
}
|
|
97
98
|
const insertTriples = [
|
|
@@ -121,12 +122,12 @@ export async function saveNewGroup (book, name) {
|
|
|
121
122
|
export async function addPersonToGroup (thing, group) {
|
|
122
123
|
const toBeFetched = [thing.doc(), group.doc()]
|
|
123
124
|
try {
|
|
124
|
-
await
|
|
125
|
+
await kb.fetcher.load(toBeFetched)
|
|
125
126
|
} catch (e) {
|
|
126
127
|
throw new Error('addPersonToGroup: ' + e)
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
const types =
|
|
130
|
+
const types = kb.findTypeURIs(thing)
|
|
130
131
|
for (const ty in types) {
|
|
131
132
|
console.log(' drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped?
|
|
132
133
|
}
|
|
@@ -134,10 +135,10 @@ export async function addPersonToGroup (thing, group) {
|
|
|
134
135
|
ns.vcard('Organization').uri in types)) {
|
|
135
136
|
return alert(`Can't add ${thing} to a group: it has to be an individual or another group.`)
|
|
136
137
|
}
|
|
137
|
-
const pname =
|
|
138
|
-
const gname =
|
|
138
|
+
const pname = kb.any(thing, ns.vcard('fn'))
|
|
139
|
+
const gname = kb.any(group, ns.vcard('fn'))
|
|
139
140
|
if (!pname) { return alert('No vcard name known for ' + thing) }
|
|
140
|
-
const already =
|
|
141
|
+
const already = kb.holds(group, ns.vcard('hasMember'), thing, group.doc())
|
|
141
142
|
if (already) {
|
|
142
143
|
return alert(
|
|
143
144
|
'ALREADY added ' + pname + ' to group ' + gname
|
|
@@ -150,15 +151,15 @@ export async function addPersonToGroup (thing, group) {
|
|
|
150
151
|
$rdf.st(thing, ns.vcard('fn'), pname, group.doc())
|
|
151
152
|
]
|
|
152
153
|
// find person webIDs
|
|
153
|
-
const webIDs = getPersonas(
|
|
154
|
+
const webIDs = getPersonas(kb, thing).map(webid => webid.value)
|
|
154
155
|
webIDs.forEach(webid => {
|
|
155
|
-
ins.push($rdf.st(thing, ns.owl('sameAs'),
|
|
156
|
+
ins.push($rdf.st(thing, ns.owl('sameAs'), kb.sym(webid), group.doc()))
|
|
156
157
|
})
|
|
157
158
|
try {
|
|
158
159
|
await updater.update([], ins)
|
|
159
160
|
// to allow refresh of card groupList
|
|
160
|
-
|
|
161
|
-
await
|
|
161
|
+
kb.fetcher.unload(group.doc())
|
|
162
|
+
await kb.fetcher.load(group.doc())
|
|
162
163
|
} catch (e) {
|
|
163
164
|
throw new Error(`Error adding ${pname} to group ${gname}:` + e)
|
|
164
165
|
}
|
package/contactsPane.js
CHANGED
|
@@ -14,12 +14,11 @@ to change its state according to an ontology, comment on it, etc.
|
|
|
14
14
|
*/
|
|
15
15
|
/* global alert, confirm */
|
|
16
16
|
|
|
17
|
+
import { authn, addPersonToGroup, saveNewContact, saveNewGroup } from 'solid-logic'
|
|
17
18
|
import * as UI from 'solid-ui'
|
|
18
|
-
import { authn, solidLogicSingleton } from 'solid-logic'
|
|
19
|
-
import { toolsPane } from './toolsPane'
|
|
20
19
|
import { mintNewAddressBook } from './mintNewAddressBook'
|
|
21
20
|
import { renderIndividual } from './individual'
|
|
22
|
-
import {
|
|
21
|
+
import { toolsPane } from './toolsPane'
|
|
23
22
|
|
|
24
23
|
// const $rdf = UI.rdf
|
|
25
24
|
const ns = UI.ns
|
|
@@ -894,18 +893,7 @@ export default {
|
|
|
894
893
|
console.log(
|
|
895
894
|
'(You do not have your Web Id set. Sign in or sign up to make changes.)'
|
|
896
895
|
)
|
|
897
|
-
|
|
898
|
-
const renderContext = await UI.login.loggedInContext(context)
|
|
899
|
-
// load profile
|
|
900
|
-
me = renderContext.me
|
|
901
|
-
console.log('Logged in as ' + me)
|
|
902
|
-
renderContext.publicProfile = await solidLogicSingleton.loadProfile(me)
|
|
903
|
-
// load preferences
|
|
904
|
-
renderContext.preferencesFile = await solidLogicSingleton.loadPreferences(me)
|
|
905
|
-
} catch (err) {
|
|
906
|
-
div.appendChild(UI.widgets.errorMessageBlock(err))
|
|
907
|
-
}
|
|
908
|
-
/* UI.authn.logInLoadProfile(context).then(
|
|
896
|
+
UI.login.ensureLoadedProfile(context).then(
|
|
909
897
|
context => {
|
|
910
898
|
console.log('Logged in as ' + context.me)
|
|
911
899
|
me = context.me
|
|
@@ -913,7 +901,7 @@ export default {
|
|
|
913
901
|
err => {
|
|
914
902
|
div.appendChild(UI.widgets.errorMessageBlock(err))
|
|
915
903
|
}
|
|
916
|
-
)
|
|
904
|
+
)
|
|
917
905
|
} else {
|
|
918
906
|
// console.log("(Your webid is "+ me +")")
|
|
919
907
|
}
|
package/diff.txt
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/individual.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as UI from 'solid-ui'
|
|
2
|
-
import {
|
|
2
|
+
import { authn, store } from 'solid-logic'
|
|
3
3
|
import { renderMugshotGallery } from './mugshotGallery'
|
|
4
4
|
import { renderWebIdControl, renderPublicIdControl } from './webidControl'
|
|
5
5
|
import { renderGroupMemberships } from './groupMembershipControl.js'
|
|
@@ -8,6 +8,7 @@ import VCARD_ONTOLOGY_TEXT from './lib/vcard.js'
|
|
|
8
8
|
|
|
9
9
|
const $rdf = UI.rdf
|
|
10
10
|
const ns = UI.ns
|
|
11
|
+
const kb = store
|
|
11
12
|
const style = UI.style
|
|
12
13
|
|
|
13
14
|
export function loadTurtleText (kb, thing, text) {
|
|
@@ -40,28 +41,28 @@ export async function renderIndividual (dom, div, subject, dataBrowserContext) {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/// ///////////////////////////
|
|
43
|
-
const t =
|
|
44
|
+
const t = kb.findTypeURIs(subject)
|
|
44
45
|
const isOrganization = !!(t[ns.vcard('Organization').uri] || t[ns.schema('Organization').uri])
|
|
45
|
-
const editable =
|
|
46
|
+
const editable = kb.updater.editable(subject.doc().uri, kb)
|
|
46
47
|
|
|
47
|
-
const individualForm =
|
|
48
|
+
const individualForm = kb.sym(
|
|
48
49
|
'https://solid.github.io/solid-panes/contact/individualForm.ttl#form1'
|
|
49
50
|
)
|
|
50
|
-
loadTurtleText(
|
|
51
|
+
loadTurtleText(kb, individualForm, textOfForms)
|
|
51
52
|
|
|
52
|
-
const orgDetailsForm =
|
|
53
|
+
const orgDetailsForm = kb.sym( // orgDetailsForm organizationForm
|
|
53
54
|
'https://solid.github.io/solid-panes/contact/individualForm.ttl#orgDetailsForm'
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
// Ontology metadata for this pane we bundle with the JS
|
|
57
58
|
const vcardOnt = UI.ns.vcard('Type').doc()
|
|
58
|
-
if (!
|
|
59
|
+
if (!kb.holds(undefined, undefined, undefined, vcardOnt)) {
|
|
59
60
|
// If not loaded already
|
|
60
|
-
$rdf.parse(VCARD_ONTOLOGY_TEXT,
|
|
61
|
+
$rdf.parse(VCARD_ONTOLOGY_TEXT, kb, vcardOnt.uri, 'text/turtle') // Load ontology directly
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
try {
|
|
64
|
-
await
|
|
65
|
+
await kb.fetcher.load(subject.doc())
|
|
65
66
|
} catch (err) {
|
|
66
67
|
complain('Error: Failed to load contact card: ' + err)
|
|
67
68
|
} // end of try catch on load
|
package/individualForm.js
CHANGED
|
File without changes
|
package/lib/autocompleteBar.js
CHANGED
|
@@ -38,16 +38,16 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
38
38
|
};
|
|
39
39
|
exports.__esModule = true;
|
|
40
40
|
exports.renderAutocompleteControl = void 0;
|
|
41
|
+
var solid_logic_1 = require("solid-logic");
|
|
41
42
|
var solid_ui_1 = require("solid-ui");
|
|
42
|
-
var UI = require("solid-ui");
|
|
43
43
|
var autocompletePicker_1 = require("./autocompletePicker"); // dbpediaParameters
|
|
44
44
|
var publicData_1 = require("./publicData");
|
|
45
45
|
var WEBID_NOUN = 'Solid ID';
|
|
46
|
-
var kb =
|
|
46
|
+
var kb = solid_logic_1.store;
|
|
47
47
|
var AUTOCOMPLETE_THRESHOLD = 4; // don't check until this many characters typed
|
|
48
48
|
var AUTOCOMPLETE_ROWS = 12; // 20?
|
|
49
|
-
var GREEN_PLUS =
|
|
50
|
-
var SEARCH_ICON =
|
|
49
|
+
var GREEN_PLUS = solid_ui_1.icons.iconBase + 'noun_34653_green.svg';
|
|
50
|
+
var SEARCH_ICON = solid_ui_1.icons.iconBase + 'noun_Search_875351.svg';
|
|
51
51
|
function renderAutocompleteControl(dom, person, options, addOneIdAndRefresh) {
|
|
52
52
|
return __awaiter(this, void 0, void 0, function () {
|
|
53
53
|
function autoCompleteDone(object, _name) {
|
|
@@ -65,7 +65,7 @@ function renderAutocompleteControl(dom, person, options, addOneIdAndRefresh) {
|
|
|
65
65
|
var webid;
|
|
66
66
|
return __generator(this, function (_a) {
|
|
67
67
|
switch (_a.label) {
|
|
68
|
-
case 0: return [4 /*yield*/, solid_ui_1.widgets.askName(dom,
|
|
68
|
+
case 0: return [4 /*yield*/, solid_ui_1.widgets.askName(dom, solid_logic_1.store, creationArea, solid_ui_1.ns.vcard('url'), null, WEBID_NOUN)];
|
|
69
69
|
case 1:
|
|
70
70
|
webid = _a.sent();
|
|
71
71
|
if (!webid) {
|
package/lib/autocompleteField.js
CHANGED
|
@@ -39,10 +39,10 @@ exports.__esModule = true;
|
|
|
39
39
|
exports.autocompleteField = void 0;
|
|
40
40
|
/* Form field for doing autocompleete
|
|
41
41
|
*/
|
|
42
|
+
var rdflib_1 = require("rdflib");
|
|
43
|
+
var solid_logic_1 = require("solid-logic");
|
|
42
44
|
var solid_ui_1 = require("solid-ui");
|
|
43
45
|
var autocompletePicker_1 = require("./autocompletePicker"); // dbpediaParameters
|
|
44
|
-
var rdflib_1 = require("rdflib");
|
|
45
|
-
var kb = solid_ui_1.store;
|
|
46
46
|
var AUTOCOMPLETE_THRESHOLD = 4; // don't check until this many characters typed
|
|
47
47
|
var AUTOCOMPLETE_ROWS = 12; // 20?
|
|
48
48
|
/**
|
|
@@ -97,7 +97,7 @@ dom, container, already, subject, form, doc, callbackFunction) {
|
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
|
-
var kb =
|
|
100
|
+
var kb = solid_logic_1.store;
|
|
101
101
|
var formDoc = form.doc ? form.doc() : null; // @@ if blank no way to know
|
|
102
102
|
var box = dom.createElement('tr');
|
|
103
103
|
if (container)
|
|
@@ -37,14 +37,9 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
37
37
|
};
|
|
38
38
|
exports.__esModule = true;
|
|
39
39
|
exports.renderAutoComplete = void 0;
|
|
40
|
-
|
|
41
|
-
**
|
|
42
|
-
** organization conveys many distinct types of thing.
|
|
43
|
-
**
|
|
44
|
-
*/
|
|
40
|
+
var solid_logic_1 = require("solid-logic");
|
|
45
41
|
var solid_ui_1 = require("solid-ui");
|
|
46
42
|
var publicData_1 = require("./publicData");
|
|
47
|
-
var kb = solid_ui_1.store;
|
|
48
43
|
var AUTOCOMPLETE_THRESHOLD = 4; // don't check until this many characters typed
|
|
49
44
|
var AUTOCOMPLETE_ROWS = 20; // 20?
|
|
50
45
|
var AUTOCOMPLETE_ROWS_STRETCH = 40;
|
|
@@ -146,8 +141,8 @@ callback) {
|
|
|
146
141
|
}
|
|
147
142
|
}
|
|
148
143
|
if (hits == 1) { // Maybe require green confirmation button be clicked?
|
|
149
|
-
console.log(" auto complete elimination: \""
|
|
150
|
-
gotIt(
|
|
144
|
+
console.log(" auto complete elimination: \"".concat(filter, "\" -> \"").concat(pickedName, "\""));
|
|
145
|
+
gotIt(solid_logic_1.store.sym(pick), pickedName); // uri, name
|
|
151
146
|
}
|
|
152
147
|
}
|
|
153
148
|
function clearList() {
|
|
@@ -174,7 +169,7 @@ callback) {
|
|
|
174
169
|
switch (_a.label) {
|
|
175
170
|
case 0:
|
|
176
171
|
if (inputEventHandlerLock) {
|
|
177
|
-
console.log("Ignoring \""
|
|
172
|
+
console.log("Ignoring \"".concat(searchInput.value, "\" because of lock "));
|
|
178
173
|
return [2 /*return*/];
|
|
179
174
|
}
|
|
180
175
|
inputEventHandlerLock = true;
|
|
@@ -222,7 +217,7 @@ callback) {
|
|
|
222
217
|
numberOfRows = slimmed.length; // stretch if it means we get all items
|
|
223
218
|
}
|
|
224
219
|
allDisplayed = loadedEnough && slimmed.length <= numberOfRows;
|
|
225
|
-
console.log(" Filter:\""
|
|
220
|
+
console.log(" Filter:\"".concat(filter, "\" bindings: ").concat(bindings.length, ", slimmed to ").concat(slimmed.length, "; rows: ").concat(numberOfRows, ", Enough? ").concat(loadedEnough, ", All displayed? ").concat(allDisplayed));
|
|
226
221
|
slimmed.slice(0, numberOfRows).forEach(function (binding) {
|
|
227
222
|
var row = table.appendChild(dom.createElement('tr'));
|
|
228
223
|
solid_ui_1.style.setStyle(row, 'autocompleteRowStyle');
|
|
@@ -236,7 +231,7 @@ callback) {
|
|
|
236
231
|
return __generator(this, function (_a) {
|
|
237
232
|
console.log(' click row textContent: ' + row.textContent);
|
|
238
233
|
console.log(' click name: ' + name);
|
|
239
|
-
gotIt(
|
|
234
|
+
gotIt(solid_logic_1.store.sym(uri), name);
|
|
240
235
|
return [2 /*return*/];
|
|
241
236
|
});
|
|
242
237
|
}); });
|
|
@@ -256,7 +251,7 @@ callback) {
|
|
|
256
251
|
*/
|
|
257
252
|
function sparqlForSearch(name, theType) {
|
|
258
253
|
var clean = name.replace(/\W/g, ''); // Remove non alphanum so as to protect regexp
|
|
259
|
-
var sparql = "select distinct ?subject, ?name where {\n ?subject a <"
|
|
254
|
+
var sparql = "select distinct ?subject, ?name where {\n ?subject a <".concat(theType.uri, ">; rdfs:label ?name\n FILTER regex(?name, \"").concat(clean, "\", \"i\")\n } LIMIT ").concat(publicData_1.AUTOCOMPLETE_LIMIT);
|
|
260
255
|
return sparql;
|
|
261
256
|
}
|
|
262
257
|
var queryParams, OrgClass, candidatesLoaded, runningTimeout, inputEventHandlerLock, allDisplayed, lastFilter, numberOfRows, div, foundName, foundObject, table, head, cell, searchInput, searchInputStyle;
|
package/lib/forms.js
CHANGED
|
File without changes
|
|
File without changes
|
package/lib/publicData.js
CHANGED
|
@@ -42,9 +42,9 @@ exports.getDbpediaDetails = exports.getWikidataLocation = exports.getWikidataDet
|
|
|
42
42
|
* including filtering resut by natural language etc
|
|
43
43
|
*/
|
|
44
44
|
var rdflib_1 = require("rdflib");
|
|
45
|
+
var solid_logic_1 = require("solid-logic");
|
|
45
46
|
var solid_ui_1 = require("solid-ui");
|
|
46
47
|
var instituteDetailsQuery = require("../lib/instituteDetailsQuery.js");
|
|
47
|
-
var kb = solid_ui_1.store;
|
|
48
48
|
exports.AUTOCOMPLETE_LIMIT = 3000; // How many to get from server
|
|
49
49
|
var subjectRegexp = /\$\(subject\)/g;
|
|
50
50
|
// Schema.org seems to suggest NGOs are non-profit and Corporaions are for-profit
|
|
@@ -121,7 +121,7 @@ function filterByLanguage(bindings, languagePrefs) {
|
|
|
121
121
|
sortMe.reverse(); // best at the top
|
|
122
122
|
slimmed.push(sortMe[0][1]);
|
|
123
123
|
} // map u
|
|
124
|
-
console.log(" Filter by language: "
|
|
124
|
+
console.log(" Filter by language: ".concat(bindings.length, " -> ").concat(slimmed.length));
|
|
125
125
|
return slimmed;
|
|
126
126
|
}
|
|
127
127
|
exports.filterByLanguage = filterByLanguage;
|
|
@@ -144,8 +144,8 @@ exports.predMap = {
|
|
|
144
144
|
};
|
|
145
145
|
function loadFromBindings(kb, solidSubject, bindings, doc) {
|
|
146
146
|
var results = {};
|
|
147
|
-
console.log("loadFromBindings: subject: "
|
|
148
|
-
console.log(" doc: "
|
|
147
|
+
console.log("loadFromBindings: subject: ".concat(solidSubject));
|
|
148
|
+
console.log(" doc: ".concat(doc));
|
|
149
149
|
bindings.forEach(function (binding) {
|
|
150
150
|
for (var key in binding) {
|
|
151
151
|
var result = binding[key];
|
|
@@ -156,7 +156,7 @@ function loadFromBindings(kb, solidSubject, bindings, doc) {
|
|
|
156
156
|
});
|
|
157
157
|
var _loop_1 = function (key) {
|
|
158
158
|
var values = results[key];
|
|
159
|
-
console.log(" results "
|
|
159
|
+
console.log(" results ".concat(key, " -> ").concat(values));
|
|
160
160
|
values.forEach(function (combined) {
|
|
161
161
|
var result = JSON.parse(combined);
|
|
162
162
|
var type = result.type, value = result.value;
|
|
@@ -168,7 +168,7 @@ function loadFromBindings(kb, solidSubject, bindings, doc) {
|
|
|
168
168
|
obj = new rdflib_1.Literal(value, result.language, result.datatype);
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
|
-
throw new Error("loadFromBindings: unexpected type: "
|
|
171
|
+
throw new Error("loadFromBindings: unexpected type: ".concat(type));
|
|
172
172
|
}
|
|
173
173
|
if (key == 'type') {
|
|
174
174
|
if (exports.wikidataClassMap[value]) {
|
|
@@ -192,7 +192,7 @@ function loadFromBindings(kb, solidSubject, bindings, doc) {
|
|
|
192
192
|
else if (exports.predMap[key]) {
|
|
193
193
|
var pred = exports.predMap[key] || solid_ui_1.ns.schema(key); // fallback to just using schema.org
|
|
194
194
|
kb.add(solidSubject, pred, obj, doc); // @@ deal with non-string and objects
|
|
195
|
-
console.log(" public data "
|
|
195
|
+
console.log(" public data ".concat(pred, " ").concat(obj, "."));
|
|
196
196
|
}
|
|
197
197
|
});
|
|
198
198
|
};
|
|
@@ -220,7 +220,7 @@ function queryESCODataByName(filter, theClass, queryTarget) {
|
|
|
220
220
|
headers: { 'Accept': 'application/json' }
|
|
221
221
|
} // CORS
|
|
222
222
|
;
|
|
223
|
-
return [4 /*yield*/,
|
|
223
|
+
return [4 /*yield*/, solid_logic_1.store.fetcher.webOperation('GET', queryURI, options)
|
|
224
224
|
//complain('Error querying db of organizations: ' + err)
|
|
225
225
|
];
|
|
226
226
|
case 1:
|
|
@@ -276,7 +276,7 @@ function queryPublicDataSelect(sparql, queryTarget) {
|
|
|
276
276
|
headers: { 'Accept': 'application/json' }
|
|
277
277
|
} // CORS
|
|
278
278
|
;
|
|
279
|
-
return [4 /*yield*/,
|
|
279
|
+
return [4 /*yield*/, solid_logic_1.store.fetcher.webOperation('GET', queryURI, options)
|
|
280
280
|
//complain('Error querying db of organizations: ' + err)
|
|
281
281
|
];
|
|
282
282
|
case 1:
|
|
@@ -308,7 +308,7 @@ function queryPublicDataConstruct(sparql, pubicId, queryTarget) {
|
|
|
308
308
|
options = { credentials: 'omit',
|
|
309
309
|
headers: { 'Accept': 'text/turtle' }
|
|
310
310
|
};
|
|
311
|
-
return [4 /*yield*/,
|
|
311
|
+
return [4 /*yield*/, solid_logic_1.store.fetcher.webOperation('GET', queryURI, options)];
|
|
312
312
|
case 1:
|
|
313
313
|
response = _a.sent();
|
|
314
314
|
text = response.responseText;
|
|
@@ -316,7 +316,7 @@ function queryPublicDataConstruct(sparql, pubicId, queryTarget) {
|
|
|
316
316
|
console.log(' queryPublicDataConstruct result text:' + report);
|
|
317
317
|
if (text.length === 0)
|
|
318
318
|
throw new Error('queryPublicDataConstruct: No text back from construct query:' + queryURI);
|
|
319
|
-
(0, rdflib_1.parse)(text,
|
|
319
|
+
(0, rdflib_1.parse)(text, solid_logic_1.store, pubicId.uri, 'text/turtle');
|
|
320
320
|
return [2 /*return*/];
|
|
321
321
|
}
|
|
322
322
|
});
|
|
@@ -334,7 +334,7 @@ function loadPublicDataThing(kb, subject, publicDataID) {
|
|
|
334
334
|
case 1:
|
|
335
335
|
if (!publicDataID.uri.match(/^https?:\/\/www\.wikidata\.org\/entity\/.*/)) return [3 /*break*/, 3];
|
|
336
336
|
QId = publicDataID.uri.split('/')[4];
|
|
337
|
-
dataURI = "http://www.wikidata.org/wiki/Special:EntityData/"
|
|
337
|
+
dataURI = "http://www.wikidata.org/wiki/Special:EntityData/".concat(QId, ".ttl");
|
|
338
338
|
// In fact loading the data URI gives much to much irrelevant data, from wikidata.
|
|
339
339
|
return [4 /*yield*/, getWikidataDetails(kb, subject, publicDataID)
|
|
340
340
|
// await getWikidataLocation(kb, subject, publicDataID) -- should get that in the details query now
|
|
@@ -416,7 +416,7 @@ function getDbpediaDetails(kb, solidSubject, publicDataID) {
|
|
|
416
416
|
return __generator(this, function (_a) {
|
|
417
417
|
switch (_a.label) {
|
|
418
418
|
case 0:
|
|
419
|
-
sparql = "select distinct ?city, ?state, ?country, ?homepage, ?logo, ?lat, ?long, WHERE {\n OPTIONAL { <"
|
|
419
|
+
sparql = "select distinct ?city, ?state, ?country, ?homepage, ?logo, ?lat, ?long, WHERE {\n OPTIONAL { <".concat(publicDataID, "> <http://dbpedia.org/ontology/city> ?city }\n OPTIONAL { ").concat(publicDataID, " <http://dbpedia.org/ontology/state> ?state }\n OPTIONAL { ").concat(publicDataID, " <http://dbpedia.org/ontology/country> ?country }\n OPTIONAL { ").concat(publicDataID, " foaf:homepage ?homepage }\n OPTIONAL { ").concat(publicDataID, " foaf:lat ?lat; foaf:long ?long }\n OPTIONAL { ").concat(publicDataID, " <http://dbpedia.org/ontology/country> ?country }\n }");
|
|
420
420
|
predMap = {
|
|
421
421
|
city: solid_ui_1.ns.vcard('locality'),
|
|
422
422
|
state: solid_ui_1.ns.vcard('region'),
|
package/lib/vcard.js
CHANGED
|
File without changes
|
package/mintNewAddressBook.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as UI from 'solid-ui'
|
|
2
|
-
import {
|
|
2
|
+
import { setACLUserPublic } from 'solid-logic'
|
|
3
3
|
|
|
4
4
|
// const mime = require('mime-types')
|
|
5
5
|
// const toolsPane0 = require('./toolsPane')
|
|
@@ -13,23 +13,7 @@ const $rdf = UI.rdf
|
|
|
13
13
|
|
|
14
14
|
export function mintNewAddressBook (dataBrowserContext, context) {
|
|
15
15
|
return new Promise(function (resolve, reject) {
|
|
16
|
-
|
|
17
|
-
let loggedInContext
|
|
18
|
-
try {
|
|
19
|
-
loggedInContext = await UI.login.loggedInContext(context)
|
|
20
|
-
// load profile
|
|
21
|
-
loggedInContext.publicProfile = await solidLogicSingleton.loadProfile(loggedInContext.me)
|
|
22
|
-
// load preferences
|
|
23
|
-
loggedInContext.preferencesFile = await solidLogicSingleton.loadPreferences(loggedInContext.me)
|
|
24
|
-
} catch (err) {
|
|
25
|
-
const error = `Could not login and load profile and preferences: ${err}`
|
|
26
|
-
console.log(error)
|
|
27
|
-
context.div.appendChild(UI.widgets.errorMessageBlock(error))
|
|
28
|
-
}
|
|
29
|
-
return loggedInContext
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
loadPreference(context).then(
|
|
16
|
+
UI.login.ensureLoadedProfile(context).then(
|
|
33
17
|
context => {
|
|
34
18
|
// 20180713
|
|
35
19
|
console.log('Logged in as ' + context.me)
|
|
@@ -137,8 +121,7 @@ export function mintNewAddressBook (dataBrowserContext, context) {
|
|
|
137
121
|
return reject(new Error('Error writing new file ' + task.to))
|
|
138
122
|
}
|
|
139
123
|
|
|
140
|
-
|
|
141
|
-
.setACLUserPublic(dest, me, aclOptions)
|
|
124
|
+
setACLUserPublic(dest, me, aclOptions)
|
|
142
125
|
.then(() => doNextTask())
|
|
143
126
|
.catch(err => {
|
|
144
127
|
const message =
|
package/mugshotGallery.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as mime from 'mime-types'
|
|
|
5
5
|
const $rdf = UI.rdf
|
|
6
6
|
const ns = UI.ns
|
|
7
7
|
const utils = UI.utils
|
|
8
|
+
const kb = store
|
|
8
9
|
|
|
9
10
|
/* Mugshot Gallery
|
|
10
11
|
*
|
|
@@ -23,9 +24,9 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
23
24
|
]
|
|
24
25
|
try {
|
|
25
26
|
if (remove) {
|
|
26
|
-
await
|
|
27
|
+
await kb.updater.update(link, [])
|
|
27
28
|
} else {
|
|
28
|
-
await
|
|
29
|
+
await kb.updater.update([], link)
|
|
29
30
|
}
|
|
30
31
|
} catch (err) {
|
|
31
32
|
const msg = ' Write back image link FAIL ' + pic + ', Error: ' + err
|
|
@@ -35,16 +36,16 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
function handleDroppedThing (thing) {
|
|
38
|
-
|
|
39
|
+
kb.fetcher.nowOrWhenFetched(thing.doc(), function (ok, mess) {
|
|
39
40
|
if (!ok) {
|
|
40
41
|
console.log('Error looking up dropped thing ' + thing + ': ' + mess)
|
|
41
42
|
} else {
|
|
42
|
-
const types =
|
|
43
|
+
const types = kb.findTypeURIs(thing)
|
|
43
44
|
for (const ty in types) {
|
|
44
45
|
console.log(' drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped?
|
|
45
46
|
}
|
|
46
47
|
console.log('Default: assume web page ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'
|
|
47
|
-
|
|
48
|
+
kb.add(subject, ns.wf('attachment'), thing, subject.doc())
|
|
48
49
|
// @@ refresh UI
|
|
49
50
|
}
|
|
50
51
|
})
|
|
@@ -70,8 +71,8 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
70
71
|
let n, pic
|
|
71
72
|
for (n = 0; ; n++) {
|
|
72
73
|
// Check filename is not used or invent new one
|
|
73
|
-
pic =
|
|
74
|
-
if (!
|
|
74
|
+
pic = kb.sym(subject.dir().uri + filename)
|
|
75
|
+
if (!kb.holds(subject, ns.vcard('hasPhoto'), pic)) {
|
|
75
76
|
break
|
|
76
77
|
}
|
|
77
78
|
filename = prefix + n + '.' + extension
|
|
@@ -84,7 +85,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
84
85
|
' to ' +
|
|
85
86
|
pic
|
|
86
87
|
)
|
|
87
|
-
|
|
88
|
+
kb.fetcher
|
|
88
89
|
.webOperation('PUT', pic.uri, {
|
|
89
90
|
data: data,
|
|
90
91
|
contentType: contentType
|
|
@@ -95,8 +96,8 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
95
96
|
return
|
|
96
97
|
}
|
|
97
98
|
console.log(' Upload: put OK: ' + pic)
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
kb.add(subject, predicate, pic, subject.doc())
|
|
100
|
+
kb.fetcher
|
|
100
101
|
.putBack(subject.doc(), { contentType: 'text/turtle' })
|
|
101
102
|
.then(
|
|
102
103
|
function (_response) {
|
|
@@ -116,7 +117,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
116
117
|
// When a set of URIs are dropped on
|
|
117
118
|
async function handleURIsDroppedOnMugshot (uris) {
|
|
118
119
|
for (const u of uris) {
|
|
119
|
-
|
|
120
|
+
let thing = $rdf.sym(u) // Attachment needs text label to disinguish I think not icon.
|
|
120
121
|
console.log('Dropped on mugshot thing ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'
|
|
121
122
|
if (u.startsWith('http') && u.indexOf('#') < 0) {
|
|
122
123
|
// Plain document
|
|
@@ -125,8 +126,9 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
125
126
|
thing = $rdf.sym('https:' + u.slice(5))
|
|
126
127
|
}
|
|
127
128
|
const options = { withCredentials: false, credentials: 'omit' }
|
|
129
|
+
let result
|
|
128
130
|
try {
|
|
129
|
-
|
|
131
|
+
result = await kb.fetcher.webOperation('GET', thing.uri, options)
|
|
130
132
|
} catch (err) {
|
|
131
133
|
complain(
|
|
132
134
|
`Gallery: fetch error trying to read picture ${thing} data: ${err}`
|
|
@@ -205,7 +207,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
function syncMugshots () {
|
|
208
|
-
let images =
|
|
210
|
+
let images = kb.each(subject, ns.vcard('hasPhoto')) // Priviledge vcard ones
|
|
209
211
|
images.sort() // arbitrary consistency
|
|
210
212
|
images = images.slice(0, 5) // max number for the space
|
|
211
213
|
if (images.length === 0) {
|
|
@@ -220,7 +222,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
220
222
|
|
|
221
223
|
// Good URI for a Camera picture
|
|
222
224
|
function getImageDoc () {
|
|
223
|
-
const imageDoc =
|
|
225
|
+
const imageDoc = kb.sym(
|
|
224
226
|
subject.dir().uri + 'Image_' + Date.now() + '.png'
|
|
225
227
|
)
|
|
226
228
|
return imageDoc
|
|
@@ -240,7 +242,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
240
242
|
'Drag here to delete'
|
|
241
243
|
)
|
|
242
244
|
async function droppedURIHandler (uris) {
|
|
243
|
-
const images =
|
|
245
|
+
const images = kb
|
|
244
246
|
.each(subject, ns.vcard('hasPhoto'))
|
|
245
247
|
.map(x => x.uri)
|
|
246
248
|
for (const uri of uris) {
|
|
@@ -250,10 +252,10 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
250
252
|
}
|
|
251
253
|
if (confirm(`Permanently DELETE image ${uri} completely?`)) {
|
|
252
254
|
console.log('Unlinking image file ' + uri)
|
|
253
|
-
await linkToPicture(subject,
|
|
255
|
+
await linkToPicture(subject, kb.sym(uri), true)
|
|
254
256
|
try {
|
|
255
257
|
console.log('Deleting image file ' + uri)
|
|
256
|
-
await
|
|
258
|
+
await kb.fetcher.webOperation('DELETE', uri)
|
|
257
259
|
} catch (err) {
|
|
258
260
|
alert('Unable to delete picture! ' + err)
|
|
259
261
|
}
|
|
@@ -273,7 +275,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
273
275
|
const right = row.appendChild(dom.createElement('td'))
|
|
274
276
|
|
|
275
277
|
left.appendChild(
|
|
276
|
-
UI.media.cameraButton(dom,
|
|
278
|
+
UI.media.cameraButton(dom, kb, getImageDoc, tookPicture)
|
|
277
279
|
) // 20190812
|
|
278
280
|
try {
|
|
279
281
|
middle.appendChild(
|
|
@@ -288,7 +290,7 @@ export function renderMugshotGallery (dom, subject) {
|
|
|
288
290
|
|
|
289
291
|
// Body of renderMugshotGallery
|
|
290
292
|
|
|
291
|
-
const editable =
|
|
293
|
+
const editable = kb.updater.editable(subject.doc().uri, kb)
|
|
292
294
|
const galleryDiv = dom.createElement('div')
|
|
293
295
|
const mugshotDiv = galleryDiv.appendChild(dom.createElement('div'))
|
|
294
296
|
const placeholder = elementForImage()
|
package/organizationForm.js
CHANGED
|
File without changes
|
package/organizationForm.ttl
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contacts-pane",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0-fd0082d5",
|
|
4
4
|
"description": "Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.",
|
|
5
5
|
"main": "./contactsPane.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"lint": "eslint '*.js'",
|
|
11
11
|
"lint-fix": "eslint '*.js' --fix",
|
|
12
12
|
"test": "npm run lint",
|
|
13
|
-
"prepublishOnly": "npm test && npm run build",
|
|
14
|
-
"postpublish": "git push origin master --follow-tags"
|
|
13
|
+
"ignore:prepublishOnly": "npm test && npm run build",
|
|
14
|
+
"ignore:postpublish": "git push origin master --follow-tags"
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
@@ -37,9 +37,10 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/solid/contacts-pane",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"pane-registry": "
|
|
40
|
+
"pane-registry": "2.4.6-7ecb64b0",
|
|
41
41
|
"rdflib": "^2.2.17",
|
|
42
|
-
"solid-
|
|
42
|
+
"solid-logic": "1.3.13-60e05a84",
|
|
43
|
+
"solid-ui": "^2.4.16-4ab5f1f1"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"eslint": "^7.32.0",
|
|
File without changes
|
package/src/autocompleteBar.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
// The Control with decorations
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import
|
|
3
|
+
import { NamedNode } from 'rdflib'
|
|
4
|
+
import { store } from 'solid-logic'
|
|
5
|
+
import { ns, widgets, icons } from 'solid-ui'
|
|
6
6
|
import { renderAutoComplete } from './autocompletePicker' // dbpediaParameters
|
|
7
|
+
import { wikidataParameters } from './publicData'
|
|
7
8
|
|
|
8
|
-
import { NamedNode, Store, st } from 'rdflib'
|
|
9
|
-
import { queryPublicDataByName, filterByLanguage, wikidataParameters,
|
|
10
|
-
AUTOCOMPLETE_LIMIT, QueryParameters, getPreferredLanguages } from './publicData'
|
|
11
9
|
|
|
12
10
|
const WEBID_NOUN = 'Solid ID'
|
|
13
11
|
|
|
@@ -16,8 +14,8 @@ const kb = store
|
|
|
16
14
|
const AUTOCOMPLETE_THRESHOLD = 4 // don't check until this many characters typed
|
|
17
15
|
const AUTOCOMPLETE_ROWS = 12 // 20?
|
|
18
16
|
|
|
19
|
-
const GREEN_PLUS =
|
|
20
|
-
const SEARCH_ICON =
|
|
17
|
+
const GREEN_PLUS = icons.iconBase + 'noun_34653_green.svg'
|
|
18
|
+
const SEARCH_ICON = icons.iconBase + 'noun_Search_875351.svg'
|
|
21
19
|
|
|
22
20
|
export async function renderAutocompleteControl (dom:HTMLDocument,
|
|
23
21
|
person:NamedNode, options, addOneIdAndRefresh): Promise<HTMLElement> {
|
package/src/autocompleteField.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
/* Form field for doing autocompleete
|
|
2
2
|
*/
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { BlankNode, NamedNode, st, Variable } from 'rdflib'
|
|
4
|
+
import { store } from 'solid-logic'
|
|
5
|
+
import { ns, style, widgets } from 'solid-ui'
|
|
5
6
|
import { renderAutoComplete } from './autocompletePicker' // dbpediaParameters
|
|
6
7
|
|
|
7
|
-
import { NamedNode, BlankNode, Variable, Store, st } from 'rdflib'
|
|
8
|
-
import { queryPublicDataByName, filterByLanguage, wikidataParameters,
|
|
9
|
-
AUTOCOMPLETE_LIMIT, QueryParameters, getPreferredLanguages } from './publicData'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const kb = store
|
|
13
|
-
|
|
14
8
|
const AUTOCOMPLETE_THRESHOLD = 4 // don't check until this many characters typed
|
|
15
9
|
const AUTOCOMPLETE_ROWS = 12 // 20?
|
|
16
10
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
** organization conveys many distinct types of thing.
|
|
4
4
|
**
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import { NamedNode } from 'rdflib'
|
|
7
|
+
import { store } from 'solid-logic'
|
|
8
|
+
import { style, widgets } from 'solid-ui'
|
|
9
|
+
import {
|
|
10
|
+
AUTOCOMPLETE_LIMIT, filterByLanguage, getPreferredLanguages, QueryParameters, queryPublicDataByName
|
|
11
|
+
} from './publicData'
|
|
12
12
|
|
|
13
13
|
const AUTOCOMPLETE_THRESHOLD = 4 // don't check until this many characters typed
|
|
14
14
|
const AUTOCOMPLETE_ROWS = 20 // 20?
|
|
@@ -120,7 +120,7 @@ export async function renderAutoComplete (dom: HTMLDocument, options:Autocomplet
|
|
|
120
120
|
}
|
|
121
121
|
if (hits == 1) { // Maybe require green confirmation button be clicked?
|
|
122
122
|
console.log(` auto complete elimination: "${filter}" -> "${pickedName}"`)
|
|
123
|
-
gotIt(
|
|
123
|
+
gotIt(store.sym(pick), pickedName) // uri, name
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -190,7 +190,7 @@ export async function renderAutoComplete (dom: HTMLDocument, options:Autocomplet
|
|
|
190
190
|
row.addEventListener('click', async _event => {
|
|
191
191
|
console.log(' click row textContent: ' + row.textContent)
|
|
192
192
|
console.log(' click name: ' + name)
|
|
193
|
-
gotIt(
|
|
193
|
+
gotIt(store.sym(uri), name)
|
|
194
194
|
})
|
|
195
195
|
})
|
|
196
196
|
}
|
package/src/forms.ttl
CHANGED
|
File without changes
|
|
File without changes
|
package/src/publicData.ts
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
*
|
|
3
3
|
* including filtering resut by natural language etc
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import {
|
|
5
|
+
import { Literal, NamedNode, parse } from 'rdflib'
|
|
6
|
+
import { store } from 'solid-logic'
|
|
7
|
+
import { ns } from 'solid-ui'
|
|
8
8
|
import * as instituteDetailsQuery from '../lib/instituteDetailsQuery.js'
|
|
9
9
|
|
|
10
|
-
const kb = store
|
|
11
|
-
|
|
12
10
|
export const AUTOCOMPLETE_LIMIT = 3000 // How many to get from server
|
|
13
11
|
|
|
14
12
|
const subjectRegexp = /\$\(subject\)/g
|
|
@@ -228,7 +226,7 @@ export async function queryESCODataByName (filter: string, theClass:NamedNode, q
|
|
|
228
226
|
headers: { 'Accept': 'application/json'}
|
|
229
227
|
} // CORS
|
|
230
228
|
var response
|
|
231
|
-
response = await
|
|
229
|
+
response = await store.fetcher.webOperation('GET', queryURI, options)
|
|
232
230
|
//complain('Error querying db of organizations: ' + err)
|
|
233
231
|
const text = response.responseText
|
|
234
232
|
console.log(' Query result text' + text.slice(0,500) + '...')
|
|
@@ -268,7 +266,7 @@ export async function queryPublicDataSelect (sparql: string, queryTarget: QueryP
|
|
|
268
266
|
headers: { 'Accept': 'application/json'}
|
|
269
267
|
} // CORS
|
|
270
268
|
var response
|
|
271
|
-
response = await
|
|
269
|
+
response = await store.fetcher.webOperation('GET', queryURI, options)
|
|
272
270
|
//complain('Error querying db of organizations: ' + err)
|
|
273
271
|
const text = response.responseText
|
|
274
272
|
// console.log(' Query result text' + text.slice(0,100) + '...')
|
|
@@ -288,12 +286,12 @@ export async function queryPublicDataConstruct (sparql: string, pubicId: NamedNo
|
|
|
288
286
|
const options = { credentials: 'omit', // CORS
|
|
289
287
|
headers: { 'Accept': 'text/turtle'}
|
|
290
288
|
}
|
|
291
|
-
const response = await
|
|
289
|
+
const response = await store.fetcher.webOperation('GET', queryURI, options)
|
|
292
290
|
const text = response.responseText
|
|
293
291
|
const report = text.lenth > 500 ? text.slice(0,200) + ' ... ' + text.slice(-200) : text
|
|
294
292
|
console.log(' queryPublicDataConstruct result text:' + report)
|
|
295
293
|
if (text.length === 0) throw new Error('queryPublicDataConstruct: No text back from construct query:' + queryURI)
|
|
296
|
-
parse(text,
|
|
294
|
+
parse(text, store, pubicId.uri, 'text/turtle')
|
|
297
295
|
return
|
|
298
296
|
}
|
|
299
297
|
|
package/src/vcard.ttl
CHANGED
|
File without changes
|
package/toolsPane.js
CHANGED
|
@@ -14,6 +14,7 @@ export function toolsPane (
|
|
|
14
14
|
me
|
|
15
15
|
) {
|
|
16
16
|
const dom = dataBrowserContext.dom
|
|
17
|
+
const kb = store
|
|
17
18
|
const ns = UI.ns
|
|
18
19
|
const VCARD = ns.vcard
|
|
19
20
|
|
|
@@ -59,7 +60,7 @@ export function toolsPane (
|
|
|
59
60
|
book.dir(),
|
|
60
61
|
dataBrowserContext,
|
|
61
62
|
'book',
|
|
62
|
-
|
|
63
|
+
kb,
|
|
63
64
|
function (ok, body) {
|
|
64
65
|
if (!ok) box.innerHTML = 'ACL control box Failed: ' + body
|
|
65
66
|
}
|
|
@@ -82,9 +83,9 @@ export function toolsPane (
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
function stats () {
|
|
85
|
-
const totalCards =
|
|
86
|
+
const totalCards = kb.each(undefined, VCARD('inAddressBook'), book).length
|
|
86
87
|
log('' + totalCards + ' cards loaded. ')
|
|
87
|
-
const groups =
|
|
88
|
+
const groups = kb.each(book, VCARD('includesGroup'))
|
|
88
89
|
log('' + groups.length + ' total groups. ')
|
|
89
90
|
const gg = []
|
|
90
91
|
for (const g in selectedGroups) {
|
|
@@ -95,9 +96,9 @@ export function toolsPane (
|
|
|
95
96
|
|
|
96
97
|
async function loadIndexHandler (_event) {
|
|
97
98
|
loadIndexButton.setAttribute('style', 'background-color: #ffc;')
|
|
98
|
-
const nameEmailIndex =
|
|
99
|
+
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
99
100
|
try {
|
|
100
|
-
await
|
|
101
|
+
await kb.fetcher.load(nameEmailIndex)
|
|
101
102
|
} catch (e) {
|
|
102
103
|
loadIndexButton.setAttribute('style', 'background-color: #fcc;')
|
|
103
104
|
log('Error: People index has NOT been loaded' + e + '\n')
|
|
@@ -135,8 +136,8 @@ export function toolsPane (
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
for (let i = 0; i < gg.length; i++) {
|
|
138
|
-
const g =
|
|
139
|
-
const a =
|
|
139
|
+
const g = kb.sym(gg[i])
|
|
140
|
+
const a = kb.each(g, ns.vcard('hasMember'))
|
|
140
141
|
log(UI.utils.label(g) + ': ' + a.length + ' members')
|
|
141
142
|
for (let j = 0; j < a.length; j++) {
|
|
142
143
|
const card = a[j]
|
|
@@ -157,7 +158,7 @@ export function toolsPane (
|
|
|
157
158
|
const stats = {} // global god context
|
|
158
159
|
|
|
159
160
|
stats.book = book
|
|
160
|
-
stats.nameEmailIndex =
|
|
161
|
+
stats.nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
161
162
|
log('Loading name index...')
|
|
162
163
|
|
|
163
164
|
store.fetcher.nowOrWhenFetched(
|
|
@@ -235,8 +236,8 @@ export function toolsPane (
|
|
|
235
236
|
} // erase one
|
|
236
237
|
*/
|
|
237
238
|
// Check actual records to see which are exact matches - slow
|
|
238
|
-
stats.nameDupLog =
|
|
239
|
-
stats.exactDupLog =
|
|
239
|
+
stats.nameDupLog = kb.sym(book.dir().uri + 'dedup-nameDupLog.ttl')
|
|
240
|
+
stats.exactDupLog = kb.sym(book.dir().uri + 'dedup-exactDupLog.ttl')
|
|
240
241
|
/*
|
|
241
242
|
function checkOne (card) {
|
|
242
243
|
return new Promise(function (resolve, reject) {
|
|
@@ -322,7 +323,7 @@ export function toolsPane (
|
|
|
322
323
|
|
|
323
324
|
function checkOneNameless (card) {
|
|
324
325
|
return new Promise(function (resolve) {
|
|
325
|
-
|
|
326
|
+
kb.fetcher
|
|
326
327
|
.load(card)
|
|
327
328
|
.then(function (_xhr) {
|
|
328
329
|
log(' Nameless check ' + card)
|
|
@@ -331,7 +332,7 @@ export function toolsPane (
|
|
|
331
332
|
exclude[ns.dc('created').uri] = true
|
|
332
333
|
exclude[ns.dc('modified').uri] = true
|
|
333
334
|
function filtered (x) {
|
|
334
|
-
return
|
|
335
|
+
return kb
|
|
335
336
|
.statementsMatching(null, null, null, x.doc())
|
|
336
337
|
.filter(function (st) {
|
|
337
338
|
return !exclude[st.predicate.uri]
|
|
@@ -350,14 +351,14 @@ export function toolsPane (
|
|
|
350
351
|
// Cheat: serialize and compare
|
|
351
352
|
// var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')
|
|
352
353
|
// var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')
|
|
353
|
-
const cardText = new $rdf.Serializer(
|
|
354
|
+
const cardText = new $rdf.Serializer(kb)
|
|
354
355
|
.setBase(card.doc().uri)
|
|
355
356
|
.statementsToN3(desc)
|
|
356
357
|
const other = stats.nameLessIndex[cardText]
|
|
357
358
|
if (other) {
|
|
358
359
|
log(' Matches with ' + other)
|
|
359
|
-
const cardGroups =
|
|
360
|
-
const otherGroups =
|
|
360
|
+
const cardGroups = kb.each(null, ns.vcard('hasMember'), card)
|
|
361
|
+
const otherGroups = kb.each(null, ns.vcard('hasMember'), other)
|
|
361
362
|
for (let j = 0; j < cardGroups.length; j++) {
|
|
362
363
|
let found = false
|
|
363
364
|
for (let k = 0; k < otherGroups.length; k++) {
|
|
@@ -431,7 +432,7 @@ export function toolsPane (
|
|
|
431
432
|
for (let i = 0; i < stats.uniques.length; i++) {
|
|
432
433
|
stats.uniquesSet[stats.uniques[i].uri] = true
|
|
433
434
|
}
|
|
434
|
-
stats.groupMembers =
|
|
435
|
+
stats.groupMembers = kb
|
|
435
436
|
.statementsMatching(null, ns.vcard('hasMember'))
|
|
436
437
|
.map(st => st.object)
|
|
437
438
|
log(' Naive group members ' + stats.groupMembers.length)
|
|
@@ -472,13 +473,13 @@ export function toolsPane (
|
|
|
472
473
|
|
|
473
474
|
function scanForDuplicates () {
|
|
474
475
|
return new Promise(function (resolve) {
|
|
475
|
-
stats.cards =
|
|
476
|
+
stats.cards = kb.each(undefined, VCARD('inAddressBook'), stats.book)
|
|
476
477
|
log('' + stats.cards.length + ' total cards')
|
|
477
478
|
|
|
478
479
|
let c, card, name
|
|
479
480
|
for (c = 0; c < stats.cards.length; c++) {
|
|
480
481
|
card = stats.cards[c]
|
|
481
|
-
name =
|
|
482
|
+
name = kb.anyValue(card, ns.vcard('fn'))
|
|
482
483
|
if (!name) {
|
|
483
484
|
stats.nameless.push(card)
|
|
484
485
|
continue
|
|
@@ -532,18 +533,18 @@ export function toolsPane (
|
|
|
532
533
|
|
|
533
534
|
return Promise.resolve()
|
|
534
535
|
.then(() => {
|
|
535
|
-
cleanPeople =
|
|
536
|
+
cleanPeople = kb.sym(stats.book.dir().uri + 'clean-people.ttl')
|
|
536
537
|
let sts = []
|
|
537
538
|
for (let i = 0; i < stats.uniques.length; i++) {
|
|
538
539
|
sts = sts.concat(
|
|
539
|
-
|
|
540
|
+
kb.connectedStatements(stats.uniques[i], stats.nameEmailIndex)
|
|
540
541
|
)
|
|
541
542
|
}
|
|
542
|
-
const sz = new $rdf.Serializer(
|
|
543
|
+
const sz = new $rdf.Serializer(kb).setBase(stats.nameEmailIndex.uri)
|
|
543
544
|
log('Serializing index of uniques...')
|
|
544
545
|
const data = sz.statementsToN3(sts)
|
|
545
546
|
|
|
546
|
-
return
|
|
547
|
+
return kb.fetcher.webOperation('PUT', cleanPeople, {
|
|
547
548
|
data: data,
|
|
548
549
|
contentType: 'text/turtle'
|
|
549
550
|
})
|
|
@@ -563,18 +564,18 @@ export function toolsPane (
|
|
|
563
564
|
return Promise.resolve()
|
|
564
565
|
.then(() => {
|
|
565
566
|
const s = g.uri.replace('/Group/', '/NewGroup/')
|
|
566
|
-
cleanGroup =
|
|
567
|
+
cleanGroup = kb.sym(s)
|
|
567
568
|
let sts = []
|
|
568
569
|
for (let i = 0; i < stats.uniques.length; i++) {
|
|
569
570
|
sts = sts.concat(
|
|
570
|
-
|
|
571
|
+
kb.connectedStatements(stats.uniques[i], g.doc())
|
|
571
572
|
)
|
|
572
573
|
}
|
|
573
|
-
const sz = new $rdf.Serializer(
|
|
574
|
+
const sz = new $rdf.Serializer(kb).setBase(g.uri)
|
|
574
575
|
log(' Regenerating group of uniques...' + cleanGroup)
|
|
575
576
|
const data = sz.statementsToN3(sts)
|
|
576
577
|
|
|
577
|
-
return
|
|
578
|
+
return kb.fetcher.webOperation('PUT', cleanGroup, { data })
|
|
578
579
|
})
|
|
579
580
|
.then(() => {
|
|
580
581
|
log(' Done uniques group ' + cleanGroup)
|
|
@@ -595,9 +596,9 @@ export function toolsPane (
|
|
|
595
596
|
if (stats.book) {
|
|
596
597
|
const books = [stats.book]
|
|
597
598
|
books.forEach(function (book) {
|
|
598
|
-
const gs = book ?
|
|
599
|
+
const gs = book ? kb.each(book, ns.vcard('includesGroup')) : []
|
|
599
600
|
const gs2 = gs.map(function (g) {
|
|
600
|
-
return [book,
|
|
601
|
+
return [book, kb.any(g, ns.vcard('fn')), g]
|
|
601
602
|
})
|
|
602
603
|
groups = groups.concat(gs2)
|
|
603
604
|
})
|
|
@@ -609,7 +610,7 @@ export function toolsPane (
|
|
|
609
610
|
|
|
610
611
|
stats.groupObjects = groups.map(gstr => gstr[2])
|
|
611
612
|
log('Loading ' + stats.groupObjects.length + ' groups... ')
|
|
612
|
-
|
|
613
|
+
kb.fetcher
|
|
613
614
|
.load(stats.groupObjects)
|
|
614
615
|
.then(scanForDuplicates)
|
|
615
616
|
.then(checkGroupMembers)
|
|
@@ -647,34 +648,34 @@ export function toolsPane (
|
|
|
647
648
|
}
|
|
648
649
|
|
|
649
650
|
async function getGroupless (book) {
|
|
650
|
-
const groupIndex =
|
|
651
|
-
const nameEmailIndex =
|
|
651
|
+
const groupIndex = kb.any(book, ns.vcard('groupIndex'))
|
|
652
|
+
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
652
653
|
try {
|
|
653
|
-
await
|
|
654
|
-
const groups =
|
|
655
|
-
await
|
|
654
|
+
await kb.fetcher.load([nameEmailIndex, groupIndex])
|
|
655
|
+
const groups = kb.each(book, ns.vcard('includesGroup'))
|
|
656
|
+
await kb.fetcher.load(groups)
|
|
656
657
|
} catch (e) {
|
|
657
658
|
complain('Error loading stuff:' + e)
|
|
658
659
|
}
|
|
659
660
|
|
|
660
661
|
const reverseIndex = {}
|
|
661
662
|
const groupless = []
|
|
662
|
-
const groups =
|
|
663
|
+
const groups = kb.each(book, VCARD('includesGroup'))
|
|
663
664
|
|
|
664
665
|
log('' + groups.length + ' total groups. ')
|
|
665
666
|
|
|
666
667
|
for (let i = 0; i < groups.length; i++) {
|
|
667
668
|
const g = groups[i]
|
|
668
|
-
const a =
|
|
669
|
+
const a = kb.each(g, ns.vcard('hasMember'))
|
|
669
670
|
log(UI.utils.label(g) + ': ' + a.length + ' members')
|
|
670
671
|
for (let j = 0; j < a.length; j++) {
|
|
671
|
-
|
|
672
|
+
kb.allAliases(a[j]).forEach(function (y) {
|
|
672
673
|
reverseIndex[y.uri] = g
|
|
673
674
|
})
|
|
674
675
|
}
|
|
675
676
|
}
|
|
676
677
|
|
|
677
|
-
const cards =
|
|
678
|
+
const cards = kb.each(undefined, VCARD('inAddressBook'), book)
|
|
678
679
|
log('' + cards.length + ' total cards')
|
|
679
680
|
for (let c = 0; c < cards.length; c++) {
|
|
680
681
|
if (!reverseIndex[cards[c].uri]) {
|
|
@@ -697,9 +698,9 @@ export function toolsPane (
|
|
|
697
698
|
return
|
|
698
699
|
}
|
|
699
700
|
|
|
700
|
-
const nameEmailIndex =
|
|
701
|
+
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
701
702
|
try {
|
|
702
|
-
await
|
|
703
|
+
await kb.fetcher.load(nameEmailIndex)
|
|
703
704
|
} catch (e) {
|
|
704
705
|
complain(e)
|
|
705
706
|
}
|
package/webidControl.js
CHANGED
|
@@ -11,6 +11,7 @@ const $rdf = UI.rdf
|
|
|
11
11
|
const ns = UI.ns
|
|
12
12
|
const widgets = UI.widgets
|
|
13
13
|
const utils = UI.utils
|
|
14
|
+
const kb = store
|
|
14
15
|
const style = UI.style
|
|
15
16
|
|
|
16
17
|
const wikidataClasses = widgets.publicData.wikidataClasses // @@ move to solid-logic
|
|
@@ -134,8 +135,8 @@ export function vcardWebIDs (kb, person, urlType) {
|
|
|
134
135
|
|
|
135
136
|
export function isOrganization (agent) {
|
|
136
137
|
const doc = agent.doc()
|
|
137
|
-
return
|
|
138
|
-
|
|
138
|
+
return kb.holds(agent, ns.rdf('type'), ns.vcard('Organization'), doc) ||
|
|
139
|
+
kb.holds(agent, ns.rdf('type'), ns.schema('Organization'), doc)
|
|
139
140
|
}
|
|
140
141
|
/// ////////////////////////////////////////////////////////////// UI
|
|
141
142
|
|
|
@@ -163,11 +164,11 @@ export async function renderWebIdControl (person, dataBrowserContext) {
|
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
export async function renderPublicIdControl (person, dataBrowserContext) {
|
|
166
|
-
let orgClass =
|
|
167
|
+
let orgClass = kb.sym('http://www.wikidata.org/wiki/Q43229')
|
|
167
168
|
let orgClassId = 'Organization'
|
|
168
169
|
for (const classId in wikidataClasses) {
|
|
169
|
-
if (
|
|
170
|
-
orgClass =
|
|
170
|
+
if (kb.holds(person, ns.rdf('type'), ns.schema(classId), person.doc())) {
|
|
171
|
+
orgClass = kb.sym(wikidataClasses[classId])
|
|
171
172
|
orgClassId = classId
|
|
172
173
|
console.log(` renderPublicIdControl bingo: ${classId} -> ${orgClass}`)
|
|
173
174
|
}
|
|
@@ -266,14 +267,14 @@ export async function renderIdControl (person, dataBrowserContext, options) {
|
|
|
266
267
|
} // renderPersona
|
|
267
268
|
|
|
268
269
|
async function refreshWebIDTable () {
|
|
269
|
-
const personas = getPersonas(
|
|
270
|
+
const personas = getPersonas(kb, person)
|
|
270
271
|
console.log('WebId personas: ' + person + ' -> ' + personas.map(p => p.uri).join(',\n '))
|
|
271
272
|
prompt.style.display = personas.length ? 'none' : ''
|
|
272
|
-
utils.syncTableToArrayReOrdered(profileArea, personas, persona => renderPersona(dom, persona,
|
|
273
|
+
utils.syncTableToArrayReOrdered(profileArea, personas, persona => renderPersona(dom, persona, kb))
|
|
273
274
|
}
|
|
274
275
|
async function addOneIdAndRefresh (person, webid) {
|
|
275
276
|
try {
|
|
276
|
-
await addWebIDToContacts(person, webid, options.urlType,
|
|
277
|
+
await addWebIDToContacts(person, webid, options.urlType, kb)
|
|
277
278
|
} catch (err) {
|
|
278
279
|
div.appendChild(widgets.errorMessageBlock(dom, `Error adding Id ${webid} to ${person}: ${err}`))
|
|
279
280
|
}
|
|
@@ -282,11 +283,11 @@ export async function renderIdControl (person, dataBrowserContext, options) {
|
|
|
282
283
|
|
|
283
284
|
const { dom } = dataBrowserContext
|
|
284
285
|
options = options || {}
|
|
285
|
-
options.editable =
|
|
286
|
+
options.editable = kb.updater.editable(person.doc().uri, kb)
|
|
286
287
|
const div = dom.createElement('div')
|
|
287
288
|
div.style = 'border-radius:0.3em; border: 0.1em solid #888;' // padding: 0.8em;
|
|
288
289
|
|
|
289
|
-
if (getPersonas(
|
|
290
|
+
if (getPersonas(kb, person).length === 0 && !options.editable) {
|
|
290
291
|
div.style.display = 'none'
|
|
291
292
|
return div // No point listing an empty list you can't change
|
|
292
293
|
}
|