Commit 8e3aa216 authored by Matthieu Fesselier's avatar Matthieu Fesselier

Merge branch 'master' into dev

parents f6c2575e 997c52b0
Pipeline #7061 passed with stage
in 3 minutes and 7 seconds
......@@ -76,7 +76,7 @@ Filters and searching capabilities can be easily added to interact with the list
- **`highlight-xyz`**: The resources to put at the top of the list. For example, `highlight-date="2019-05-20"` will display first all the resources which have a field date equal to "2019-05-20".
- **`group by`**: The resources will be grouped by the field you give as a parameter. For example, `group-by="date"` will render one `<div>` by date, and put the corresponding resources inside.
- **`next`**: `name` attribute of the `<solid-route>` that should be accessed when a `<solid-display>` element is clicked. See the documentation of `<solid-router>` for more details.
- **`action-xyz`**:
- **`action-xyz`**: name of the route to reach when the widget for the field `xyz` is clicked. By default, a `solid-link` widget is used.
- **`label-xyz`**: Set the label for the field `xyz`
- **`placeholder-xyz`**: Set the placeholder for the field `xyz`
- **`editable-xyz`**: Add an "edit" button next to the `xyz` field to let the user edit it. The changes are saved as soon as the field loses focus.
......
......@@ -7,7 +7,7 @@ describe('simple Startin’blox e2e test', function() {
})
it('check first children content', () => {
cy.get('body > solid-display > div > solid-display:first-child > div > solid-display-value:first-child')
.should('have.attr', 'name', 'firstName')
.should('have.attr', 'name', 'first_name')
.should('have.text', 'Test')
})
})
......@@ -137,4 +137,9 @@ Here is a simplified schema of the organization and the responsibilities of the
## List post-processing
A `solid-display` component is capable of showing a list of resources and applying different filters on this list to filter, sort, group... resources. Here is a schema of the order of these transformations:
![list-post-processing](./images/list-post-processing.png)
\ No newline at end of file
![list-post-processing](./images/list-post-processing.png)
## Not clear enough ?
Help us to improve the documentation! Feel free to ask for clarification or ask questions. This helps us to improve our documentation.
Thanks you!
......@@ -12,7 +12,7 @@
<body>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, username, name(firstName, lastName), email"
fields="@id, username, name(first_name, last_name), email"
child-style="border: 3px dashed purple"
></solid-display>
</body>
......
......@@ -13,7 +13,7 @@
<body>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
search-fields="email"
counter-template="${counter} users here"
></solid-display>
......
{
"@id": "",
"@id": "circles-1.jsonld",
"name": "circle",
"description": "A circle just for testing purpose",
"@context": "https://cdn.happy-dev.fr/owl/hdcontext.jsonld"
......
{
"@id": "",
"@id": "circles-2.jsonld",
"name": "Les poètes disparus",
"description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit!",
"@context": "https://cdn.happy-dev.fr/owl/hdcontext.jsonld"
......
{
"@id": "",
"@id": "circles.jsonld",
"@type": "ldp:Container",
"ldp:contains": [
{
......
{
"@id": "",
"@id": "user-1-skills.jsonld",
"@type": "ldp:Container",
"ldp:contains": [
{
......
{
"@id": "",
"@id": "user-2-skills.jsonld",
"@type": "ldp:Container",
"ldp:contains": [
{
......
{
"@id": "",
"@id": "user-3-skills.jsonld",
"@type": "ldp:Container",
"ldp:contains": [
......
{
"@id": "",
"@id": "user-4-skills.jsonld",
"@type": "ldp:Container",
"ldp:contains": [
{
......
......@@ -10,7 +10,7 @@
<body>
<solid-display
data-src="../data/list/users.jsonld"
fields="firstName, lastName"
fields="first_name, last_name"
></solid-display>
</body>
</html>
\ No newline at end of file
......@@ -14,7 +14,7 @@
<solid-display
id="guineapig"
data-src="data/list/users.jsonld"
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
></solid-display>
</body>
......
......@@ -27,7 +27,7 @@
<h1>HOME</h1>
<solid-display
data-src="https://api.test-paris.happy-dev.fr/users/"
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
next="detail"
extra-context="alpha"
></solid-display>
......@@ -36,7 +36,7 @@
<div id="detail">
<h1>DETAIL</h1>
<solid-display
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
bind-resources
extra-context="alpha"
></solid-display>
......
......@@ -14,7 +14,7 @@
<summary>Highlight:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
highlight-username="pierre"
></solid-display>
</details>
......@@ -23,7 +23,7 @@
<summary>Highlight + order by:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
highlight-username="pierre"
order-by="username"
></solid-display>
......
......@@ -14,7 +14,7 @@
<summary>Order by:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
order-by="username"
></solid-display>
</details>
......@@ -23,7 +23,7 @@
<summary>Order by + pagination:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
order-by="username"
paginate-by="3"
></solid-display>
......@@ -33,7 +33,7 @@
<summary>Order by + pagination + search:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
order-by="username"
paginate-by="3"
search-fields="username"
......
......@@ -14,7 +14,7 @@
<summary>Pagination:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
paginate-by="2"
></solid-display>
</details>
......@@ -23,7 +23,7 @@
<summary>Search + Pagination:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
search-fields="email"
paginate-by="2"
></solid-display>
......
......@@ -20,7 +20,7 @@
<h2>Reduced id</h2>
<solid-display
data-src="user:1/"
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
paginate-by="4"
next="detail"
></solid-display>
......
......@@ -14,7 +14,7 @@
<summary>One field & label:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
search-fields="email"
search-label-email="mail"
></solid-display>
......@@ -24,7 +24,7 @@
<summary>One field & value:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
search-fields="email"
search-value-email="happy"
></solid-display>
......@@ -34,8 +34,8 @@
<summary>Multiple fields:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
search-fields="firstName, lastName"
fields="username, first_name, last_name, email"
search-fields="first_name, last_name"
></solid-display>
</details>
......@@ -43,7 +43,7 @@
<summary>Set:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, nameSet(firstName, lastName), email"
fields="username, nameSet(first_name, last_name), email"
search-fields="nameSet"
></solid-display>
</details>
......@@ -80,7 +80,7 @@
<summary>Widget:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
search-fields="email"
search-widget-email="solid-form-textarea"
></solid-display>
......@@ -90,7 +90,7 @@
<summary>Dotted field:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email, profile.city"
fields="username, first_name, last_name, email, profile.city"
search-fields="profile.city"
></solid-display>
</details>
......@@ -99,7 +99,7 @@
<summary>Set + dotted field:</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="username, firstName, lastName, email, nameSet(profile.city, firstName)"
fields="username, first_name, last_name, email, nameSet(profile.city, first_name)"
search-fields="nameSet"
></solid-display>
</details>
......
......@@ -14,7 +14,7 @@
<summary>Set</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, name(firstName, lastName, username), infos(email, profile.city)"
fields="@id, name(first_name, last_name, username), infos(email, profile.city)"
></solid-display>
</details>
......@@ -22,7 +22,7 @@
<summary>Nested set</summary>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, name(firstName, lastName, username, infos(email, profile.city))"
fields="@id, name(first_name, last_name, username, infos(email, profile.city))"
widget-name="solid-set-ul"
></solid-display>
</details>
......
......@@ -30,7 +30,7 @@
<div id="detail">
<h1>DETAIL</h1>
<solid-display
fields="@id, username, firstName, lastName, email"
fields="@id, username, first_name, last_name, email"
bind-resources
></solid-display>
</div>
......
......@@ -17,7 +17,7 @@
<h2>With fields and sets</h2>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, username, name(firstName, lastName), email, profile.city"
fields="@id, username, name(first_name, last_name), email, profile.city"
default-email="no email yet"
default-profile.city="no city yet"
class-id="id"
......@@ -26,7 +26,7 @@
<h2>Default widget</h2>
<solid-display
data-src="data/list/users.jsonld"
fields="@id, name(firstName, lastName)"
fields="@id, name(first_name, last_name)"
default-widget="solid-display-div"
></solid-display>
<style>
......
......@@ -15,7 +15,7 @@
<summary>Some fields:</summary>
<solid-form
data-src="data/list/user-1.jsonld"
fields="username, firstName, lastName, email"
fields="username, first_name, last_name, email"
submit-button="Enregistrer l'utilisateur"
></solid-form>
</details>
......
......@@ -28,15 +28,21 @@ export const SolidAcChecker = {
const context = await myParser.parse(this.context);
if (this.permission) { // User has permission of ...
displayElement = await asyncSome(
displayElement = this.resource.permissions.some(p => {
return ContextParser.compactIri(p, context) === this.permission;
});
/* displayElement = await asyncSome(
(permission: object) => ContextParser.compactIri(permission.toString(), context) === this.permission,
this.resource.permissions.mode['rdf:type']
)
this.resource.permissions.mode['@type']
)*/
} else if (this.noPermission) { // User has no permission of ...
displayElement = await asyncEvery(
displayElement = this.resource.permissions.every(p => {
return ContextParser.compactIri(p, context) !== this.noPermission;
});
/*displayElement = await asyncEvery(
(permission: object) => ContextParser.compactIri(permission.toString(), context) !== this.noPermission,
this.resource.permissions.mode['rdf:type']
)
this.resource.permissions.mode['@type']
)*/
} else { // No parameter provided
console.warn('solid-ac-checker: you should define at least one of "permission" or "no-permission" attribute.');
return;
......
......@@ -37,8 +37,7 @@ export const SolidCalendar = {
}
},
async appendChildElt(resourceId: string) {
await store.initGraph(resourceId, this.context);
const resource = store.get(resourceId);
const resource = await store.initGraph(resourceId, this.context);
const date = await resource['date'];
const name = await resource['name'];
......
......@@ -33,9 +33,10 @@ export const SolidDelete = {
},
async delete(): Promise<void> {
if (!this.dataSrc) return;
return store.delete(this.dataSrc, this.context).then(() => {
return store.delete(this.dataSrc, this.context).then(response => {
if (!response.ok) return;
this.element.dispatchEvent(
new CustomEvent('resourceDeleted', { detail: { resource: { "@id": this.dataSrc } } }),
new CustomEvent('resourceDeleted', { detail: { resource: { "@id": this.dataSrc } }, bubbles: true }),
);
});
},
......
......@@ -97,7 +97,7 @@ export const SolidForm = {
this.hideError();
const resource = await this.getFormValue();
resource['@context'] = this.context;
let saved: object = {};
let saved;
try {
if (this.partial == null) {
saved = resource['@id'] ?
......
......@@ -61,8 +61,7 @@ export const SolidMap = {
}
},
async appendChildElt(resourceId: string) {
await store.initGraph(resourceId, this.context);
const resource = store.get(resourceId);
const resource = await store.initGraph(resourceId, this.context);
const lat = await resource['lat'];
const lng = await resource['lng'];
......
This diff is collapsed.
This diff is collapsed.
......@@ -16,13 +16,14 @@ const FederationMixin = {
},
async fetchSources(resources: object[], listPostProcessors: Function[], div: HTMLElement, context: string) {
let sources: any[] = [];
for await (let res of resources) { // TODO : test with different response timings
for (let res of resources) { // TODO : test with different response timings
let type = await res['@type'];
if (type && type.toString() == "http://www.w3.org/ns/ldp#Container") {
if (type && type.toString() == "ldp:Container") {
const containerId = res['@id'];
sources = asyncChain(sources, await this.fetchSource(containerId)); // Add content of sources to array...
const resourcesFetched = this.fetchSource(containerId);
if (resourcesFetched) sources.push(...resourcesFetched); // Add content of sources to array...
} else {
sources = asyncChain(sources, [res]); // Or resource directly if not a container
sources.push(res); // Or resource directly if not a container
}
}
......@@ -30,10 +31,9 @@ const FederationMixin = {
if(nextProcessor) await nextProcessor(sources, listPostProcessors, div, context);
},
async fetchSource(containerId: string): Promise<object> {
await store.initGraph(containerId);
fetchSource(containerId: string): Promise<object> {
const container = store.get(containerId);
return container['ldp:contains'];
return container ? container['ldp:contains'] : null;
},
}
......
......@@ -57,7 +57,7 @@ const FilterMixin = {
if (filterValue['@id']) filterValue = filterValue['@id']; // if filter has id (dropdown), use it to filter
// Filter on a container
if (propertyValue.termType && propertyValue.termType !== "Literal" && await propertyValue.isContainer()) {
if (propertyValue.isContainer && await propertyValue.isContainer()) {
return await asyncReduce(
Promise.resolve(false),
async (initial, value) => await initial || await this.matchValue({ "@id": value['@id'] }, filterValue),
......
......@@ -72,12 +72,11 @@ const PaginateMixin = {
const currentPage = this.getCurrentPage(context);
insertNode.insertBefore(nav, div.nextSibling);
nav.querySelector('[data-id="prev"]')!.addEventListener('click', () => {
this.setCurrentPage(currentPage - 1, context);
});
nav.querySelector('[data-id="next"]')!.addEventListener('click', () => {
this.setCurrentPage(currentPage + 1, context);
});
const prevButton = nav.querySelector('[data-id="prev"]') as HTMLElement;
const nextButton = nav.querySelector('[data-id="next"]') as HTMLElement;
// use onclick to override previous listeners
prevButton.onclick = () => this.setCurrentPage(currentPage - 1, context);
nextButton.onclick = () => this.setCurrentPage(currentPage + 1, context);
nav.querySelector('[data-id="current"]')!.textContent = currentPage;
nav.querySelector('[data-id="count"]')!.textContent = String(pageCount);
......
......@@ -18,7 +18,7 @@ const SorterMixin = {
async orderCallback(resources: object[], listPostProcessors: Function[], div: HTMLElement, context: string) {
if (this.orderBy) {
resources = await asyncMap(async (resource) => ({
sortingKey: (await resource[this.orderBy]).toString(), // fetch sorting value
sortingKey: await resource[this.orderBy], // fetch sorting value
proxy: resource // and keep proxy
}), resources);
resources = await asyncToArray(resources); // tranform in array
......
......@@ -10,6 +10,7 @@ const StoreMixin = {
callback: async function (value: string) {
this.empty();
if (!value || value == "undefined") return;
this.resourceId = value;
await store.initGraph(this.resourceId, this.context);
......
......@@ -87,7 +87,7 @@ const WidgetMixin = {
return this.element.getAttribute('value-' + field);
}
let resourceValue = await this.fetchValue(this.resource, field);
if (resourceValue == undefined || resourceValue == "") // If null or empty, return field default value
if (resourceValue === undefined || resourceValue === "") // If null or empty, return field default value
return this.element.hasAttribute('default-' + field) ?
this.element.getAttribute('default-' + field) : undefined;
return resourceValue;
......@@ -115,6 +115,7 @@ const WidgetMixin = {
widgetAttributes(field: string): object {
const attrs = {
name: field,
context: this.context
};
const escapedField = this.getEscapedField(field);
for (let attr of ['range', 'label', 'placeholder', 'class']) {
......@@ -136,7 +137,6 @@ const WidgetMixin = {
}
if (this.getAction(escapedField) && this.resource) attrs['src'] = this.resource['@id'];
attrs['resourceId'] = this.resource ? this.resource['@id'] : null;
attrs['context'] = this.context;
return attrs;
},
......
......@@ -65,8 +65,7 @@ export class BaseWidget extends HTMLElement {
}
set value(value) {
this._value = value; // ... store `value` in the widget
if (!this._value) return;
if (this._value == null || this._value == undefined) return;
if (this.dataHolder && this.dataHolder.length === 1) {
// if one dataHolder in the widget...
......@@ -74,7 +73,7 @@ export class BaseWidget extends HTMLElement {
if (element.type == "checkbox") {
element.checked = value;
} else {
element.value = value || ''; // ... set `value` to the dataHolder element
element.value = value; // ... set `value` to the dataHolder element
}
// remove when https://git.happy-dev.fr/startinblox/framework/sib-core/issues/426 fixed
if (element.dispatchEvent) element.dispatchEvent(new Event('change')); // trigger change manually
......@@ -136,22 +135,36 @@ export class BaseWidget extends HTMLElement {
}
get range(): any {
return this._range ? this._range['ldp:contains'] : null;
return this.fetchSources(this._range);
}
set range(range) {
(async () => {
await store.initGraph(range, this.context);
this._range = store.get(range);
this._range = await store.initGraph(range, this.context);
await this.render();
})();
}
async fetchSources(resource: object) {
if (!resource || !resource['ldp:contains']) return null;
let resources: any[] = [];
for (let res of resource['ldp:contains']) {
if (res.isContainer()) { // if nested container
let resourcesFromContainer = await store.initGraph(res['@id'], this.context); // fetch the datas
if (resourcesFromContainer) resources.push(...resourcesFromContainer['ldp:contains']);
} else {
resources.push(res);
}
}
return resources;
}
get htmlRange(): Promise<string|undefined> {
return (async () => {
let htmlRange = '';
if (!this.range) return;
for await (let element of this.range) {
await store.initGraph(element['@id'], this.context); // fetch the resource to display the name
element = store.get(element['@id']);
const rangeResources = await this.range;
if (!rangeResources) return;
for await (let element of rangeResources) {
element = await store.initGraph(element['@id'], this.context); // fetch the resource to display the name
let selected: boolean;
if (this._value && this._value.isContainer && await this._value.isContainer()) { // selected options for multiple select
......@@ -166,7 +179,7 @@ export class BaseWidget extends HTMLElement {
selected = this._value ? this._value['@id'] == element['@id'] : false;
}
htmlRange += await evalTemplateString(this.childTemplate, {
name: (await element.name).toString(),
name: await element.name,
id: element['@id'],
selected: selected
});
......
......@@ -25,7 +25,7 @@ const SolidDisplayMultiline = widgetFactory(
const SolidDisplayLabelledBoolean = widgetFactory(
'solid-display-labelled-boolean',
`\${value == 'true' ? "<label>" + label + "</label>" : ""}`
`\${value ? "<label>" + label + "</label>" : ""}`
);
const SolidDisplayImg = widgetFactory(
......
......@@ -66,6 +66,7 @@ export default class SolidMultipleForm extends BaseWidget {
const widget = widgetTag ? document.createElement(widgetTag) : null;
if (!widget) return;
widget['context'] = this.context;
for (let name of Object.keys(attributes)) {
widget[name] = attributes[name];
}
......
......@@ -7,7 +7,10 @@ export default class SolidMultipleSelect extends BaseWidget {
}
set range(range: string | null) {
if (range) this.setAttribute('range', range);
if (this.firstChild) this.firstChild['range'] = range;
if (this.firstChild) {
this.firstChild['context'] = this.context;
this.firstChild['range'] = range;
};
}
async render() {
......
import { BaseWidget } from './baseWidget.js';
import { defineComponent } from "../libs/helpers.js";
import { store } from "../libs/store/store.js";
export default class SolidMultiple extends BaseWidget {
async render() {
const fragment = document.createDocumentFragment();
......@@ -14,7 +16,7 @@ export default class SolidMultiple extends BaseWidget {
for await (const resource of this.value['ldp:contains']) {
const elm = this.insertWidget(this.childAttributes, parent);
if (elm) {
elm['value'] = resource;
elm['value'] = await store.initGraph(resource['@id']);
elm.toggleAttribute('data-holder', true);
}
i++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment