solid-panes 4.4.0 → 4.4.1-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/RDFXMLPane.css +70 -0
- package/dist/RDFXMLPane.d.ts +13 -0
- package/dist/RDFXMLPane.d.ts.map +1 -0
- package/dist/RDFXMLPane.js +46 -5
- package/dist/dataContentPane.css +271 -0
- package/dist/dataContentPane.d.ts +14 -0
- package/dist/dataContentPane.d.ts.map +1 -0
- package/dist/dataContentPane.js +68 -101
- package/dist/defaultPane.css +97 -0
- package/dist/defaultPane.d.ts +14 -0
- package/dist/defaultPane.d.ts.map +1 -0
- package/dist/defaultPane.js +9 -2
- package/dist/form/formPane.css +120 -0
- package/dist/form/pane.d.ts +4 -0
- package/dist/form/pane.d.ts.map +1 -0
- package/dist/form/pane.js +120 -54
- package/dist/humanReadablePane.css +129 -0
- package/dist/humanReadablePane.d.ts +13 -0
- package/dist/humanReadablePane.d.ts.map +1 -0
- package/dist/humanReadablePane.js +29 -18
- package/dist/icons/signUp.svg +9 -0
- package/dist/imagePane.css +4 -0
- package/dist/imagePane.d.ts +12 -0
- package/dist/imagePane.d.ts.map +1 -0
- package/dist/imagePane.js +19 -21
- package/dist/internal/internalPane.css +14 -0
- package/dist/internal/internalPane.d.ts +1 -0
- package/dist/internal/internalPane.d.ts.map +1 -1
- package/dist/internal/internalPane.js +5 -6
- package/dist/mainPage/header.js +2 -2
- package/dist/mainPage/index.d.ts +2 -1
- package/dist/mainPage/index.d.ts.map +1 -1
- package/dist/mainPage/index.js +23 -0
- package/dist/mainPage/menu.d.ts.map +1 -1
- package/dist/mainPage/menu.js +29 -2
- package/dist/n3Pane.css +49 -0
- package/dist/n3Pane.d.ts +13 -0
- package/dist/n3Pane.d.ts.map +1 -0
- package/dist/n3Pane.js +36 -5
- package/dist/outline/manager.js +20 -1
- package/dist/pad/padPane.css +6 -2
- package/dist/pad/padPane.js +1 -1
- package/dist/registerPanes.js +8 -8
- package/dist/schedule/schedulePane.css +294 -0
- package/dist/schedule/schedulePane.d.ts +23 -0
- package/dist/schedule/schedulePane.d.ts.map +1 -0
- package/dist/schedule/schedulePane.js +161 -61
- package/dist/social/editProfileDetails.d.ts +3 -3
- package/dist/social/editProfileDetails.d.ts.map +1 -1
- package/dist/social/editProfileDetails.js +222 -127
- package/dist/social/icons.d.ts +2 -0
- package/dist/social/icons.d.ts.map +1 -1
- package/dist/social/icons.js +39 -4
- package/dist/social/socialPane.css +838 -178
- package/dist/social/socialPane.d.ts.map +1 -1
- package/dist/social/socialPane.js +136 -43
- package/dist/social/socialSections.d.ts +11 -0
- package/dist/social/socialSections.d.ts.map +1 -1
- package/dist/social/socialSections.js +138 -62
- package/dist/social/spinner.d.ts +3 -0
- package/dist/social/spinner.d.ts.map +1 -0
- package/dist/social/spinner.js +13 -0
- package/dist/social/triage.d.ts +17 -0
- package/dist/social/triage.d.ts.map +1 -0
- package/dist/social/triage.js +79 -0
- package/dist/solid-panes.js +25772 -9576
- package/dist/solid-panes.js.map +1 -1
- package/dist/solid-panes.min.js +2583 -927
- package/dist/solid-panes.min.js.map +1 -1
- package/dist/{style → styles}/tabbedtab.css +0 -157
- package/dist/styles/utilities.css +5 -0
- package/dist/versionInfo.js +13 -13
- package/package.json +27 -26
- package/dist/icons/signup.png +0 -0
package/dist/form/pane.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.formPane = void 0;
|
|
|
7
7
|
var UI = _interopRequireWildcard(require("solid-ui"));
|
|
8
8
|
var _solidLogic = require("solid-logic");
|
|
9
9
|
var $rdf = _interopRequireWildcard(require("rdflib"));
|
|
10
|
+
require("./formPane.css");
|
|
10
11
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
11
12
|
/*
|
|
12
13
|
** Pane for running existing forms for any object
|
|
@@ -14,12 +15,63 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
const ns = UI.ns;
|
|
18
|
+
function isNamedNode(term) {
|
|
19
|
+
return term?.termType === 'NamedNode';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* The following helper was generated by AI GPT-5.4 Model */
|
|
23
|
+
/* Prompt: Add a compatibility shim in the form pane for mixed `ui:Group` plus field typing. */
|
|
24
|
+
function normalizeAmbiguousFieldTypes(store, form) {
|
|
25
|
+
const formDoc = form.doc ? form.doc() : undefined;
|
|
26
|
+
const types = store.each(form, ns.rdf('type'), undefined, formDoc).filter(isNamedNode);
|
|
27
|
+
const hasGroupType = types.some(type => type.sameTerm(ns.ui('Group')));
|
|
28
|
+
const hasOtherFieldType = types.some(type => !type.sameTerm(ns.ui('Group')) && !type.sameTerm(ns.ui('Form')));
|
|
29
|
+
const hasProperty = !!store.any(form, ns.ui('property'), undefined, formDoc);
|
|
30
|
+
const partsList = store.any(form, ns.ui('parts'), undefined, formDoc);
|
|
31
|
+
const hasParts = !!partsList?.elements?.length || store.each(form, ns.ui('part'), undefined, formDoc).length > 0;
|
|
32
|
+
|
|
33
|
+
// Some legacy forms mark a leaf field as both ui:Group and a concrete input type.
|
|
34
|
+
// solid-ui may then choose the Group renderer and produce an empty nested box.
|
|
35
|
+
if (hasGroupType && hasOtherFieldType && hasProperty && !hasParts) {
|
|
36
|
+
store.removeMany(form, ns.rdf('type'), ns.ui('Group'), formDoc);
|
|
37
|
+
}
|
|
38
|
+
const listParts = partsList?.elements ?? [];
|
|
39
|
+
for (const part of listParts) {
|
|
40
|
+
if (isNamedNode(part)) {
|
|
41
|
+
normalizeAmbiguousFieldTypes(store, part);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const unorderedParts = store.each(form, ns.ui('part'), undefined, formDoc);
|
|
45
|
+
for (const part of unorderedParts) {
|
|
46
|
+
if (isNamedNode(part)) {
|
|
47
|
+
normalizeAmbiguousFieldTypes(store, part);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function tagMobileTextareaRows(renderedForm) {
|
|
52
|
+
const textareas = Array.from(renderedForm.querySelectorAll('textarea'));
|
|
53
|
+
for (const textarea of textareas) {
|
|
54
|
+
let row = textarea.parentElement;
|
|
55
|
+
while (row) {
|
|
56
|
+
const firstChild = row.firstElementChild;
|
|
57
|
+
const hasLabelColumn = !!firstChild && (firstChild.classList.contains('formFieldName') || firstChild.querySelector('a') !== null);
|
|
58
|
+
if (hasLabelColumn && row.children.length >= 2) {
|
|
59
|
+
row.classList.add('formPane__mobileTextareaRow');
|
|
60
|
+
firstChild.classList.add('formPane__mobileTextareaLabel');
|
|
61
|
+
const valueColumn = row.children[1];
|
|
62
|
+
valueColumn.classList.add('formPane__mobileTextareaValue');
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
row = row.parentElement;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
17
69
|
const formPane = exports.formPane = {
|
|
18
70
|
icon: UI.icons.iconBase + 'noun_122196.svg',
|
|
19
71
|
name: 'form',
|
|
20
72
|
audience: [ns.solid('PowerUser')],
|
|
21
73
|
// Does the subject deserve this pane?
|
|
22
|
-
label: function (subject) {
|
|
74
|
+
label: function (subject, _context) {
|
|
23
75
|
const n = UI.widgets.formsFor(subject).length;
|
|
24
76
|
UI.log.debug('Form pane: forms for ' + subject + ': ' + n);
|
|
25
77
|
if (!n) return null;
|
|
@@ -28,14 +80,21 @@ const formPane = exports.formPane = {
|
|
|
28
80
|
render: function (subject, context) {
|
|
29
81
|
const kb = context.session.store;
|
|
30
82
|
const dom = context.dom;
|
|
31
|
-
const
|
|
83
|
+
const box = dom.createElement('div');
|
|
84
|
+
box.setAttribute('class', 'formPane');
|
|
85
|
+
function applyEnvironmentAttributes(element) {
|
|
86
|
+
const environment = context.environment ?? {};
|
|
87
|
+
element.dataset.layout = environment.layout ?? 'desktop';
|
|
88
|
+
}
|
|
89
|
+
applyEnvironmentAttributes(box);
|
|
90
|
+
const mention = function (message, modifier = 'info') {
|
|
32
91
|
const pre = dom.createElement('p');
|
|
33
|
-
pre.
|
|
92
|
+
pre.className = `formPane__message formPane__message--${modifier}`;
|
|
34
93
|
box.appendChild(pre).textContent = message;
|
|
35
94
|
return pre;
|
|
36
95
|
};
|
|
37
|
-
const complain = function
|
|
38
|
-
mention(message, '
|
|
96
|
+
const complain = function (message) {
|
|
97
|
+
return mention(message, 'error');
|
|
39
98
|
};
|
|
40
99
|
const complainIfBad = function (ok, body) {
|
|
41
100
|
if (ok) {
|
|
@@ -51,8 +110,6 @@ const formPane = exports.formPane = {
|
|
|
51
110
|
// const t = kb.findTypeURIs(subject)
|
|
52
111
|
|
|
53
112
|
const me = _solidLogic.authn.currentUser();
|
|
54
|
-
const box = dom.createElement('div');
|
|
55
|
-
box.setAttribute('class', 'formPane');
|
|
56
113
|
if (!me) {
|
|
57
114
|
mention('You are not logged in. If you log in and have ' + 'workspaces then you would be able to select workspace in which ' + 'to put this new information');
|
|
58
115
|
} else {
|
|
@@ -66,30 +123,33 @@ const formPane = exports.formPane = {
|
|
|
66
123
|
|
|
67
124
|
// Render forms using a given store
|
|
68
125
|
|
|
69
|
-
const renderFormsFor = function (
|
|
70
|
-
kb.fetcher.nowOrWhenFetched(
|
|
71
|
-
if (!ok) return complain('Cannot load store ' +
|
|
126
|
+
const renderFormsFor = function (storeNode, targetSubject) {
|
|
127
|
+
kb.fetcher.nowOrWhenFetched(storeNode.uri, targetSubject, function (ok, body) {
|
|
128
|
+
if (!ok) return complain('Cannot load store ' + storeNode.uri + ': ' + body);
|
|
72
129
|
|
|
73
130
|
// Render the forms
|
|
74
131
|
|
|
75
|
-
const forms = UI.widgets.formsFor(
|
|
132
|
+
const forms = UI.widgets.formsFor(targetSubject);
|
|
76
133
|
|
|
77
134
|
// complain('Form for editing this form:');
|
|
78
|
-
for (
|
|
79
|
-
|
|
135
|
+
for (const form of forms) {
|
|
136
|
+
normalizeAmbiguousFieldTypes(kb, form);
|
|
80
137
|
const heading = dom.createElement('h4');
|
|
138
|
+
heading.classList.add('formPane__heading');
|
|
81
139
|
box.appendChild(heading);
|
|
140
|
+
/* The edit Form is not working in the local environment. it does not find
|
|
141
|
+
the ui FormForm ontology. Need to research further and check in production. */
|
|
82
142
|
if (form.uri) {
|
|
83
143
|
const formStore = $rdf.Util.uri.document(form.uri);
|
|
84
144
|
if (formStore.uri !== form.uri) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
e.setAttribute('style', 'margin-left: auto; display: block;');
|
|
145
|
+
const editButton = box.appendChild(UI.widgets.editFormButton(dom, box, form, formStore, complainIfBad));
|
|
146
|
+
editButton.classList.add('formPane__editButton');
|
|
88
147
|
}
|
|
89
148
|
}
|
|
90
149
|
const anchor = dom.createElement('a');
|
|
150
|
+
anchor.classList.add('formPane__headingLink');
|
|
91
151
|
anchor.setAttribute('href', form.uri);
|
|
92
|
-
heading.
|
|
152
|
+
heading.insertBefore(anchor, heading.firstChild);
|
|
93
153
|
anchor.textContent = UI.utils.label(form, true);
|
|
94
154
|
|
|
95
155
|
/* Keep tis as a reminder to let a New one have its URI given by user
|
|
@@ -103,7 +163,8 @@ const formPane = exports.formPane = {
|
|
|
103
163
|
ele.value = store.uri
|
|
104
164
|
*/
|
|
105
165
|
|
|
106
|
-
UI.widgets.appendForm(dom, box, {},
|
|
166
|
+
UI.widgets.appendForm(dom, box, {}, targetSubject, form, storeNode, complainIfBad);
|
|
167
|
+
tagMobileTextareaRows(box);
|
|
107
168
|
}
|
|
108
169
|
}); // end: when store loded
|
|
109
170
|
}; // renderFormsFor
|
|
@@ -112,64 +173,69 @@ const formPane = exports.formPane = {
|
|
|
112
173
|
|
|
113
174
|
// Which places are editable and have stuff about the subject?
|
|
114
175
|
|
|
115
|
-
let
|
|
176
|
+
let targetStore = null;
|
|
116
177
|
|
|
117
178
|
// 1. The document URI of the subject itself
|
|
118
179
|
const docuri = $rdf.Util.uri.docpart(subject.uri);
|
|
119
|
-
if (
|
|
120
|
-
|
|
180
|
+
if (kb.updater.editable(docuri, kb)) {
|
|
181
|
+
targetStore = subject.doc();
|
|
121
182
|
} // an editable data file with hash
|
|
122
183
|
|
|
123
|
-
|
|
184
|
+
const annotationStore = kb.any(kb.sym(docuri), ns.link('annotationStore'));
|
|
185
|
+
if (!targetStore && isNamedNode(annotationStore)) {
|
|
186
|
+
targetStore = annotationStore;
|
|
187
|
+
}
|
|
124
188
|
|
|
125
189
|
// 2. where stuff is already stored
|
|
126
|
-
if (!
|
|
127
|
-
const docs =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
if (!targetStore) {
|
|
191
|
+
const docs = new Map();
|
|
192
|
+
kb.statementsMatching(subject).forEach(function (st) {
|
|
193
|
+
if (st.why.value) {
|
|
194
|
+
docs.set(st.why.value, 1);
|
|
195
|
+
}
|
|
131
196
|
});
|
|
132
|
-
|
|
133
|
-
|
|
197
|
+
kb.statementsMatching(undefined, undefined, subject).forEach(function (st) {
|
|
198
|
+
if (st.why.value) {
|
|
199
|
+
docs.set(st.why.value, 2);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
const docList = Array.from(docs.entries()).sort(function ([uriA, scoreA], [uriB, scoreB]) {
|
|
203
|
+
return scoreA - scoreB || uriA.localeCompare(uriB);
|
|
134
204
|
});
|
|
135
|
-
for (const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const uri = docList[i][1];
|
|
139
|
-
if (uri && store.updater.editable(uri)) {
|
|
140
|
-
store = store.sym(uri);
|
|
205
|
+
for (const [uri] of docList) {
|
|
206
|
+
if (uri && kb.updater.editable(uri, kb)) {
|
|
207
|
+
targetStore = kb.sym(uri);
|
|
141
208
|
break;
|
|
142
209
|
}
|
|
143
210
|
}
|
|
144
211
|
}
|
|
145
212
|
|
|
146
213
|
// 3. In a workspace store
|
|
147
|
-
// @@ TODO: Can probably remove _followeach (not done this time because the commit is a very safe refactor)
|
|
148
|
-
const _followeach = function (kb, subject, path) {
|
|
149
|
-
if (path.length === 0) return [subject];
|
|
150
|
-
const oo = kb.each(subject, path[0]);
|
|
151
|
-
let res = [];
|
|
152
|
-
for (let i = 0; i < oo.length; i++) {
|
|
153
|
-
res = res.concat(_followeach(kb, oo[i], path.slice(1)));
|
|
154
|
-
}
|
|
155
|
-
return res;
|
|
156
|
-
};
|
|
157
214
|
const date = '2014'; // @@@@@@@@@@@@ pass as parameter
|
|
158
215
|
|
|
159
|
-
if (
|
|
216
|
+
if (targetStore) {
|
|
160
217
|
// mention("@@ Ok, we have a store <" + store.uri + ">.");
|
|
161
|
-
renderFormsFor(
|
|
218
|
+
renderFormsFor(targetStore, subject);
|
|
162
219
|
} else {
|
|
163
220
|
complain('No suitable store is known, to edit <' + subject.uri + '>.');
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
221
|
+
const workspaceDetails = {
|
|
222
|
+
noun: 'form',
|
|
223
|
+
appPathSegment: 'form'
|
|
224
|
+
};
|
|
225
|
+
const foobarbaz = UI.login.selectWorkspace(dom, workspaceDetails, function (workspaceUri) {
|
|
226
|
+
const workspace = workspaceUri ? kb.sym(workspaceUri) : null;
|
|
227
|
+
if (!workspace) {
|
|
228
|
+
complain('Workspace selection was cancelled.');
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
mention('Workspace selected OK: ' + workspace.uri);
|
|
232
|
+
const activities = kb.each(undefined, ns.space('workspace'), workspace).filter(isNamedNode);
|
|
167
233
|
for (let j = 0; j < activities.length; j++) {
|
|
168
234
|
const act = activities[j];
|
|
169
|
-
const subjectDoc2 =
|
|
170
|
-
const start =
|
|
171
|
-
const end =
|
|
172
|
-
if (subjectDoc2 && start && end && start <= date && end > date) {
|
|
235
|
+
const subjectDoc2 = kb.any(act, ns.space('store'));
|
|
236
|
+
const start = kb.any(act, ns.cal('dtstart'))?.value;
|
|
237
|
+
const end = kb.any(act, ns.cal('dtend'))?.value;
|
|
238
|
+
if (isNamedNode(subjectDoc2) && start && end && start <= date && end > date) {
|
|
173
239
|
renderFormsFor(subjectDoc2, subject);
|
|
174
240
|
break;
|
|
175
241
|
} else {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
.human-readable-pane {
|
|
2
|
+
display: block;
|
|
3
|
+
min-width: 0;
|
|
4
|
+
width: 100%;
|
|
5
|
+
max-width: 100%;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.human-readable-pane__container {
|
|
10
|
+
display: block;
|
|
11
|
+
min-width: 0;
|
|
12
|
+
width: 100%;
|
|
13
|
+
max-width: 100%;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
overflow-x: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.human-readable-pane__frame {
|
|
19
|
+
display: block;
|
|
20
|
+
border: 1px solid;
|
|
21
|
+
padding: 1rem;
|
|
22
|
+
height: var(--human-readable-pane-height, 30rem);
|
|
23
|
+
min-width: 0;
|
|
24
|
+
max-width: 100%;
|
|
25
|
+
width: 100%;
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
resize: both;
|
|
28
|
+
overflow: auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.human-readable-pane__frame--iframe {
|
|
32
|
+
padding: 0;
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
width: 100%;
|
|
35
|
+
max-width: 100%;
|
|
36
|
+
min-height: 18rem;
|
|
37
|
+
background: var(--color-background, white);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.human-readable-pane__frame--markdown {
|
|
41
|
+
overflow-wrap: anywhere;
|
|
42
|
+
word-break: break-word;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.human-readable-pane__frame--plain-text {
|
|
46
|
+
font-family: monospace;
|
|
47
|
+
white-space: pre-wrap;
|
|
48
|
+
overflow-wrap: anywhere;
|
|
49
|
+
word-break: break-word;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.human-readable-pane__frame--markdown > * {
|
|
53
|
+
max-width: 100%;
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.human-readable-pane__frame--markdown img,
|
|
58
|
+
.human-readable-pane__frame--markdown video,
|
|
59
|
+
.human-readable-pane__frame--markdown canvas,
|
|
60
|
+
.human-readable-pane__frame--markdown iframe {
|
|
61
|
+
max-width: 100%;
|
|
62
|
+
height: auto;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.human-readable-pane__frame--markdown pre,
|
|
66
|
+
.human-readable-pane__frame--markdown code {
|
|
67
|
+
max-width: 100%;
|
|
68
|
+
overflow-wrap: anywhere;
|
|
69
|
+
word-break: break-word;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.human-readable-pane__frame--markdown pre {
|
|
73
|
+
white-space: pre-wrap;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.human-readable-pane__frame--markdown table {
|
|
77
|
+
display: block;
|
|
78
|
+
width: 100%;
|
|
79
|
+
max-width: 100%;
|
|
80
|
+
overflow-x: auto;
|
|
81
|
+
box-sizing: border-box;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.human-readable-pane__frame--markdown th,
|
|
85
|
+
.human-readable-pane__frame--markdown td {
|
|
86
|
+
white-space: normal;
|
|
87
|
+
overflow-wrap: anywhere;
|
|
88
|
+
word-break: break-word;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame {
|
|
92
|
+
padding: 0.75rem;
|
|
93
|
+
resize: none;
|
|
94
|
+
min-width: 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--markdown,
|
|
98
|
+
.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--plain-text {
|
|
99
|
+
overflow-wrap: anywhere;
|
|
100
|
+
word-break: break-word;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--iframe {
|
|
104
|
+
width: 100%;
|
|
105
|
+
max-width: 100%;
|
|
106
|
+
min-height: 16rem;
|
|
107
|
+
height: min(var(--human-readable-pane-height, 30rem), 75vh);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@media (max-width: 576px) {
|
|
111
|
+
.human-readable-pane__frame {
|
|
112
|
+
padding: 0.75rem;
|
|
113
|
+
resize: none;
|
|
114
|
+
min-width: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.human-readable-pane__frame--markdown,
|
|
118
|
+
.human-readable-pane__frame--plain-text {
|
|
119
|
+
overflow-wrap: anywhere;
|
|
120
|
+
word-break: break-word;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.human-readable-pane__frame--iframe {
|
|
124
|
+
width: 100%;
|
|
125
|
+
max-width: 100%;
|
|
126
|
+
min-height: 16rem;
|
|
127
|
+
height: min(var(--human-readable-pane-height, 30rem), 75vh);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataBrowserContext } from 'pane-registry';
|
|
2
|
+
import type { NamedNode } from 'rdflib';
|
|
3
|
+
import './humanReadablePane.css';
|
|
4
|
+
type HumanReadableIcon = string | Promise<string>;
|
|
5
|
+
type HumanReadablePaneDefinition = {
|
|
6
|
+
icon: (subject: NamedNode, context: DataBrowserContext) => HumanReadableIcon;
|
|
7
|
+
name: string;
|
|
8
|
+
label: (subject: NamedNode, context: DataBrowserContext) => 'view' | 'View' | null;
|
|
9
|
+
render: (subject: NamedNode, context: DataBrowserContext) => HTMLDivElement;
|
|
10
|
+
};
|
|
11
|
+
declare const humanReadablePane: HumanReadablePaneDefinition;
|
|
12
|
+
export default humanReadablePane;
|
|
13
|
+
//# sourceMappingURL=humanReadablePane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"humanReadablePane.d.ts","sourceRoot":"","sources":["../src/humanReadablePane.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAqB,MAAM,eAAe,CAAA;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,yBAAyB,CAAA;AAKhC,KAAK,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AAEjD,KAAK,2BAA2B,GAAG;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAA;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,KAAK,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClF,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,KAAK,cAAc,CAAA;CAC5E,CAAA;AAsBD,QAAA,MAAM,iBAAiB,EAAE,2BAuQxB,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -8,6 +8,7 @@ var _solidUi = require("solid-ui");
|
|
|
8
8
|
var _rdflib = require("rdflib");
|
|
9
9
|
var _marked = require("marked");
|
|
10
10
|
var _dompurify = _interopRequireDefault(require("dompurify"));
|
|
11
|
+
require("./humanReadablePane.css");
|
|
11
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
/* Human-readable Pane
|
|
13
14
|
**
|
|
@@ -16,6 +17,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
// Helper function to check if a URI has a markdown file extension
|
|
20
|
+
|
|
19
21
|
const isMarkdownFile = uri => {
|
|
20
22
|
if (!uri) return false;
|
|
21
23
|
const path = uri.split('?')[0].split('#')[0]; // Remove query string and fragment
|
|
@@ -24,6 +26,12 @@ const isMarkdownFile = uri => {
|
|
|
24
26
|
|
|
25
27
|
// Cache for dokieli detection results (keyed by subject URI)
|
|
26
28
|
const dokieliCache = new Map();
|
|
29
|
+
function applyFrameClasses(frame, modifier, lines) {
|
|
30
|
+
frame.className = '';
|
|
31
|
+
frame.classList.add('human-readable-pane__frame');
|
|
32
|
+
frame.classList.add(`human-readable-pane__frame--${modifier}`);
|
|
33
|
+
frame.style.setProperty('--human-readable-pane-height', `${lines}em`);
|
|
34
|
+
}
|
|
27
35
|
const humanReadablePane = {
|
|
28
36
|
icon: function (subject, context) {
|
|
29
37
|
// Markdown files detected by extension
|
|
@@ -131,6 +139,10 @@ const humanReadablePane = {
|
|
|
131
139
|
const myDocument = context.dom;
|
|
132
140
|
const div = myDocument.createElement('div');
|
|
133
141
|
const kb = context.session.store;
|
|
142
|
+
function applyEnvironmentAttributes(element) {
|
|
143
|
+
const environment = context.environment ?? {};
|
|
144
|
+
element.dataset.layout = environment.layout ?? 'desktop';
|
|
145
|
+
}
|
|
134
146
|
const cts = kb.fetcher.getHeader(subject.doc(), 'content-type');
|
|
135
147
|
const ct = cts ? cts[0].split(';', 1)[0].trim() : null; // remove content-type parameters
|
|
136
148
|
|
|
@@ -144,19 +156,20 @@ const humanReadablePane = {
|
|
|
144
156
|
}
|
|
145
157
|
|
|
146
158
|
// @@ When we can, use CSP to turn off scripts within the iframe
|
|
147
|
-
div.
|
|
148
|
-
div
|
|
159
|
+
div.classList.add('human-readable-pane');
|
|
160
|
+
applyEnvironmentAttributes(div);
|
|
149
161
|
|
|
150
162
|
// render markdown to html in a DIV element
|
|
151
163
|
const renderMarkdownContent = function (frame) {
|
|
152
164
|
kb.fetcher.webOperation('GET', subject.uri).then(response => {
|
|
153
|
-
const markdownText = response.responseText;
|
|
165
|
+
const markdownText = response.responseText ?? '';
|
|
154
166
|
const lines = Math.min(30, markdownText.split(/\n/).length + 5);
|
|
155
|
-
const res = _marked.marked.parse(markdownText
|
|
167
|
+
const res = _marked.marked.parse(markdownText, {
|
|
168
|
+
async: false
|
|
169
|
+
});
|
|
156
170
|
const clean = _dompurify.default.sanitize(res);
|
|
157
171
|
frame.innerHTML = clean;
|
|
158
|
-
frame
|
|
159
|
-
frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto;`);
|
|
172
|
+
applyFrameClasses(frame, 'markdown', lines);
|
|
160
173
|
}).catch(error => {
|
|
161
174
|
console.error('Error fetching markdown content:', error);
|
|
162
175
|
frame.innerHTML = '<p>Error loading content</p>';
|
|
@@ -166,11 +179,10 @@ const humanReadablePane = {
|
|
|
166
179
|
// render plain text in a PRE element
|
|
167
180
|
const renderPlainTextContent = function (frame) {
|
|
168
181
|
kb.fetcher.webOperation('GET', subject.uri).then(response => {
|
|
169
|
-
const plainText = response.responseText;
|
|
182
|
+
const plainText = response.responseText ?? '';
|
|
170
183
|
const lines = Math.min(30, plainText.split(/\n/).length + 5);
|
|
171
184
|
frame.textContent = plainText;
|
|
172
|
-
frame
|
|
173
|
-
frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto; font-family: monospace; white-space: pre-wrap; word-wrap: break-word;`);
|
|
185
|
+
applyFrameClasses(frame, 'plain-text', lines);
|
|
174
186
|
}).catch(error => {
|
|
175
187
|
console.error('Error fetching plain text content:', error);
|
|
176
188
|
frame.textContent = 'Error loading content';
|
|
@@ -178,28 +190,27 @@ const humanReadablePane = {
|
|
|
178
190
|
};
|
|
179
191
|
const setIframeAttributes = (frame, lines) => {
|
|
180
192
|
frame.setAttribute('src', subject.uri);
|
|
181
|
-
frame
|
|
182
|
-
frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto;`);
|
|
193
|
+
applyFrameClasses(frame, 'iframe', lines);
|
|
183
194
|
};
|
|
184
195
|
if (isMarkdown) {
|
|
185
196
|
// For markdown, use a DIV element and render the content
|
|
186
|
-
const frame = myDocument.createElement('
|
|
197
|
+
const frame = myDocument.createElement('div');
|
|
187
198
|
renderMarkdownContent(frame);
|
|
188
199
|
const frameContainer = myDocument.createElement('div');
|
|
189
|
-
frameContainer.
|
|
200
|
+
frameContainer.classList.add('human-readable-pane__container');
|
|
190
201
|
frameContainer.appendChild(frame);
|
|
191
202
|
div.appendChild(frameContainer);
|
|
192
203
|
} else if (isPlainText) {
|
|
193
204
|
// For plain text, use a PRE element and render the content
|
|
194
|
-
const frame = myDocument.createElement('
|
|
205
|
+
const frame = myDocument.createElement('pre');
|
|
195
206
|
renderPlainTextContent(frame);
|
|
196
207
|
const frameContainer = myDocument.createElement('div');
|
|
197
|
-
frameContainer.
|
|
208
|
+
frameContainer.classList.add('human-readable-pane__container');
|
|
198
209
|
frameContainer.appendChild(frame);
|
|
199
210
|
div.appendChild(frameContainer);
|
|
200
211
|
} else {
|
|
201
212
|
// For other content types, use IFRAME
|
|
202
|
-
const frame = myDocument.createElement('
|
|
213
|
+
const frame = myDocument.createElement('iframe');
|
|
203
214
|
|
|
204
215
|
// Apply sandbox for HTML/XHTML
|
|
205
216
|
if (ct === 'text/html' || ct === 'application/xhtml+xml') {
|
|
@@ -208,7 +219,7 @@ const humanReadablePane = {
|
|
|
208
219
|
|
|
209
220
|
// Fetch content to calculate lines dynamically
|
|
210
221
|
kb.fetcher.webOperation('GET', subject.uri).then(response => {
|
|
211
|
-
const blobText = response.responseText;
|
|
222
|
+
const blobText = response.responseText ?? '';
|
|
212
223
|
const newLines = blobText.includes('<script src="https://dokie.li/scripts/dokieli.js">') ? -10 : 5;
|
|
213
224
|
const lines = Math.min(30, blobText.split(/\n/).length + newLines);
|
|
214
225
|
|
|
@@ -222,7 +233,7 @@ const humanReadablePane = {
|
|
|
222
233
|
setIframeAttributes(frame, 30);
|
|
223
234
|
});
|
|
224
235
|
const frameContainer = myDocument.createElement('div');
|
|
225
|
-
frameContainer.
|
|
236
|
+
frameContainer.classList.add('human-readable-pane__container');
|
|
226
237
|
frameContainer.appendChild(frame);
|
|
227
238
|
div.appendChild(frameContainer);
|
|
228
239
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg"
|
|
2
|
+
viewBox="0 0 24 24"
|
|
3
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
4
|
+
class="lucide lucide-square-arrow-right-enter-icon lucide-square-arrow-right-enter">
|
|
5
|
+
|
|
6
|
+
<path d="m10 16 4-4-4-4"/>
|
|
7
|
+
<path d="M3 12h11"/>
|
|
8
|
+
<path d="M3 8V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-3"/>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DataBrowserContext } from 'pane-registry';
|
|
2
|
+
import type { NamedNode } from 'rdflib';
|
|
3
|
+
import './imagePane.css';
|
|
4
|
+
type ImagePane = {
|
|
5
|
+
icon: string;
|
|
6
|
+
name: string;
|
|
7
|
+
label: (subject: NamedNode, context: DataBrowserContext) => string | null;
|
|
8
|
+
render: (subject: NamedNode, context: DataBrowserContext) => HTMLDivElement;
|
|
9
|
+
};
|
|
10
|
+
export declare const imagePane: ImagePane;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=imagePane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imagePane.d.ts","sourceRoot":"","sources":["../src/imagePane.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,iBAAiB,CAAA;AAWxB,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,KAAK,MAAM,GAAG,IAAI,CAAA;IACzE,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,KAAK,cAAc,CAAA;CAC5E,CAAA;AAuBD,eAAO,MAAM,SAAS,EAAE,SA+CvB,CAAA"}
|
package/dist/imagePane.js
CHANGED
|
@@ -5,12 +5,27 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.imagePane = void 0;
|
|
7
7
|
var UI = _interopRequireWildcard(require("solid-ui"));
|
|
8
|
+
require("./imagePane.css");
|
|
8
9
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
9
10
|
/* Image Pane
|
|
10
11
|
**
|
|
11
12
|
** This outline pane contains the document contents for an Image document
|
|
12
13
|
*/
|
|
13
14
|
|
|
15
|
+
function contentTypeMatch(store, subject, contentTypes) {
|
|
16
|
+
const contentTypesForSubject = store.fetcher.getHeader(subject, 'content-type');
|
|
17
|
+
if (!contentTypesForSubject) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
for (const contentType of contentTypesForSubject) {
|
|
21
|
+
for (const candidate of contentTypes) {
|
|
22
|
+
if (contentType.includes(candidate)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
14
29
|
const imagePane = exports.imagePane = {
|
|
15
30
|
icon: UI.icons.originalIconBase + 'tango/22-image-x-generic.png',
|
|
16
31
|
name: 'image',
|
|
@@ -23,19 +38,6 @@ const imagePane = exports.imagePane = {
|
|
|
23
38
|
|
|
24
39
|
// See also the source pane, which has lower precedence.
|
|
25
40
|
|
|
26
|
-
const contentTypeMatch = function (store, x, contentTypes) {
|
|
27
|
-
const cts = store.fetcher.getHeader(x, 'content-type');
|
|
28
|
-
if (cts) {
|
|
29
|
-
for (let j = 0; j < cts.length; j++) {
|
|
30
|
-
for (let k = 0; k < contentTypes.length; k++) {
|
|
31
|
-
if (cts[j].indexOf(contentTypes[k]) >= 0) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
};
|
|
39
41
|
const suppressed = ['application/pdf'];
|
|
40
42
|
if (contentTypeMatch(store, subject, suppressed)) {
|
|
41
43
|
return null;
|
|
@@ -46,8 +48,8 @@ const imagePane = exports.imagePane = {
|
|
|
46
48
|
const myDocument = context.dom;
|
|
47
49
|
const store = context.session.store;
|
|
48
50
|
const div = myDocument.createElement('div');
|
|
49
|
-
div.setAttribute('class', '
|
|
50
|
-
const img = myDocument.createElement('
|
|
51
|
+
div.setAttribute('class', 'image-pane');
|
|
52
|
+
const img = myDocument.createElement('img');
|
|
51
53
|
|
|
52
54
|
// get image with authenticated fetch
|
|
53
55
|
store.fetcher._fetch(subject.uri).then(function (response) {
|
|
@@ -56,12 +58,8 @@ const imagePane = exports.imagePane = {
|
|
|
56
58
|
const objectURL = URL.createObjectURL(myBlob);
|
|
57
59
|
img.setAttribute('src', objectURL); // w640 h480 //
|
|
58
60
|
});
|
|
59
|
-
img.
|
|
60
|
-
|
|
61
|
-
// div.style['max-height'] = '480'
|
|
62
|
-
const tr = myDocument.createElement('TR'); // why need tr?
|
|
63
|
-
tr.appendChild(img);
|
|
64
|
-
div.appendChild(tr);
|
|
61
|
+
img.classList.add('image-pane__image');
|
|
62
|
+
div.appendChild(img);
|
|
65
63
|
return div;
|
|
66
64
|
}
|
|
67
65
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.internalPaneContent {
|
|
2
|
+
background-color: #ddddff;
|
|
3
|
+
padding: var(--spacing-xs, 0.5em);
|
|
4
|
+
border-radius: 1rem;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.internalPaneControls {
|
|
8
|
+
width: 100%;
|
|
9
|
+
margin: var(--spacing-sm, 1em);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.internalPaneDeleteButton {
|
|
13
|
+
height: var(--icon-base, 2em);
|
|
14
|
+
}
|