Commit 1e7d2dc2 authored by Laurent Wouters's avatar Laurent Wouters
Browse files

[doc] Added documentation

parent 0b2550c54b19
......@@ -8,28 +8,27 @@ The promise is then that the data(sets) about these entities can be fetched at t
Therefore, in the same way that a browser for the web of documents can navigate from pages to pages through links using URLs,
a browser for the web of (linked) data could navigate within and between datasets through the URIs of the entities referred to and find new datasets about them.
For this ideal scenario, the web servers that in the end serve the content, in this case the data, should *play nice*, i.e. be compliant with the web of data.
For this ideal scenario, the web servers that in the end serve the content, in this case the data, should _play nice_, i.e. be compliant with the web of data.
In this context, this mainly mean that when asked about an URI in its scope, a web server should answer with data about the requested URI, at least if explicitely asked to using HTTP headers related to content negotiation.
For example, a compliant server of linked data handling resources for `example.com` should readily (or through content negotiation) answers with the data related to `http://example.com/some_resource`.
Example of compliance issues:
* The server always answers HTML, or redirect to an HTML page, despite content negotiation requesting RDF data.
* Possible fix: Rely on content negotiation to answer with RDF content. HTML can still be returned by default.
* Instead of replying with data, the server redirects to `http://example.com/some_resource.rdf`.
* Possible dix: Do not redirect to different URIs depending on RDF syntaxes (.n3, .nt, .rdf, etc.) but directly return the content in the appropriate syntax, as requested through content negotiation.
* The datasets returned by the server make use of multiple writings for the same logical entity, for example using unicode escape sequences `\uxxxx` in URIs.
* Possible fix: Try to canonicalize data to a single URI writing.
* Multiple datasets have been located for different writing of the same URI and they have different content.
* The provided datasets use language specific URIs with different data for different languages.
* Possible fix: Unify the datasets in a language-neutral naming scheme for the entities and use language-tag on language-specific RDF literals.
- The server always answers HTML, or redirect to an HTML page, despite content negotiation requesting RDF data.
- Possible fix: Rely on content negotiation to answer with RDF content. HTML can still be returned by default.
- Instead of replying with data, the server redirects to `http://example.com/some_resource.rdf`.
- Possible dix: Do not redirect to different URIs depending on RDF syntaxes (.n3, .nt, .rdf, etc.) but directly return the content in the appropriate syntax, as requested through content negotiation.
- The datasets returned by the server make use of multiple writings for the same logical entity, for example using unicode escape sequences `\uxxxx` in URIs.
- Possible fix: Try to canonicalize data to a single URI writing.
- Multiple datasets have been located for different writing of the same URI and they have different content.
- The provided datasets use language specific URIs with different data for different languages.
- Possible fix: Unify the datasets in a language-neutral naming scheme for the entities and use language-tag on language-specific RDF literals.
The [CubicWeb Linked Data Browser]() still tries to cooperate with servers that are not already compliant.
It does the following to try to detect datasets:
* Simple content negotiation by requesting RDF data at the URI for the resource (case for compliant servers).
* Follow redirections to URIs for datasets serialized in specific syntaxes.
* Try to detect datasets linked to from HTTP `Link` header.
* When HTML was obtained, try to detect datasets linked to from HTML `Link` headers.
* When HTML was obtained, try to detect links to corresponding datasets, i.e. links starting with the URI of the requested resource and ending with a file extension for a known RDF syntax (.n3, .nt, .rdf, etc.).
\ No newline at end of file
- Simple content negotiation by requesting RDF data at the URI for the resource (case for compliant servers).
- Follow redirections to URIs for datasets serialized in specific syntaxes.
- Try to detect datasets linked to from HTTP `Link` header.
- When HTML was obtained, try to detect datasets linked to from HTML `Link` headers.
- When HTML was obtained, try to detect links to corresponding datasets, i.e. links starting with the URI of the requested resource and ending with a file extension for a known RDF syntax (.n3, .nt, .rdf, etc.).
......@@ -8,9 +8,9 @@ This document explains the basics of writing new views.
At its core, a view is simply a piece of Javascipt code (or any language that compiles to it) that implements a simple interface.
There are a few other requirements, as listed below:
* The view implementation must conform to the [`ViewImplementation`]() interface.
* The Javascript resource containing the implementation must contain an entrypoint for the browser.
* The view implementation must be referred to by a endpoint serving a descriptor of the implementation.
- The view implementation must conform to the [`ViewImplementation`]() interface.
- The Javascript resource containing the implementation must contain an entrypoint for the browser.
- The view implementation must be referred to by a endpoint serving a descriptor of the implementation.
This document go through all these requirements and explain how to fulfill them.
In the end, the implementation of a view does not require any special behavior from the server it.
......@@ -60,13 +60,13 @@ class MyView implements implementation.ViewImplementation {
This interface is basically three members:
* `descriptor` is a public attribute that must contain the descriptor (metadata for the view).
* `priorityFor` is a method that, given a RDF dataset and a target resource (URI) to be rendered, must return the self-evaluated priority of the view.
This value is used by the browser to select an appropriate view for the dataset.
A higher (positive) number indicates a higher priority.
A negative number can be return to indicate that the view *must not* be selected by the browser.
As of this writing, the browser primarily relies on these self-evaluation by the views, unless the user explicitely select a particular view.
* `render` is the single entrypoint for the view implementation used by the browser. Given a rendered, a contact and a target resource (URI) to be rendered, it must return a rendering that may or may not include an HTML DOM sub-tree.
- `descriptor` is a public attribute that must contain the descriptor (metadata for the view).
- `priorityFor` is a method that, given a RDF dataset and a target resource (URI) to be rendered, must return the self-evaluated priority of the view.
This value is used by the browser to select an appropriate view for the dataset.
A higher (positive) number indicates a higher priority.
A negative number can be return to indicate that the view _must not_ be selected by the browser.
As of this writing, the browser primarily relies on these self-evaluation by the views, unless the user explicitely select a particular view.
- `render` is the single entrypoint for the view implementation used by the browser. Given a rendered, a contact and a target resource (URI) to be rendered, it must return a rendering that may or may not include an HTML DOM sub-tree.
The basic idea for a view implementation is for the browser to specify the RDF dataset and the main resource to render and for the view to provide an HTML DOM tree.
How the DOM tree is produced is left to the discretion of the view implementation.
......@@ -75,15 +75,15 @@ Any framework may be used, such as React, Angular, Vue, etc.; or no framework at
### Descriptor
The view descriptor is an object that conform the `ViewDescriptor` interface.
It *must* have the following fields:
It _must_ have the following fields:
* `identifier`, a unique identifier for the view.
* `name`, a short human-readable name for the view.
* `description`, a more lengthier description for the view. It may expands of the kind of RDF data that the view is able to handle.
* `entrypoint`, the name of an exported variable that contains an instance of the view implemention. See Step 2.
* `resourceCss`, an array of potentially remote CSS resources that should be loaded by the browser for this view.
* `resourceJs`, an array of potentially remote additional Javascript resources that should be loaded by the browser for this view.
* `resourceMain`, points to the potentially remote Javascript resource that contains the view implementation.
- `identifier`, a unique identifier for the view.
- `name`, a short human-readable name for the view.
- `description`, a more lengthier description for the view. It may expands of the kind of RDF data that the view is able to handle.
- `entrypoint`, the name of an exported variable that contains an instance of the view implemention. See Step 2.
- `resourceCss`, an array of potentially remote CSS resources that should be loaded by the browser for this view.
- `resourceJs`, an array of potentially remote additional Javascript resources that should be loaded by the browser for this view.
- `resourceMain`, points to the potentially remote Javascript resource that contains the view implementation.
Example:
......@@ -91,7 +91,8 @@ Example:
const MY_VIEW_DESCRIPTOR: definition.ViewDescriptor = {
identifier: "::SeriousBusiness::MyView",
name: "A short human-readable name",
description: "A lengthier description of this view. What kind of RDF data does it handle?",
description:
"A lengthier description of this view. What kind of RDF data does it handle?",
entrypoint: "VIEW_ENTRYPOINT", // name of the entrypoint object
resourceCss: [
{
......@@ -112,7 +113,7 @@ const MY_VIEW_DESCRIPTOR: definition.ViewDescriptor = {
When computing the priority of a view, the raw and complete RDF dataset is passed to the `priorityFor` method of the view implementation, along with the target of rendering, i.e. the primary entity to be rendered by this view.
It is the responsability of the view implementation to determine its priority regarding the dataset and the target entity.
For example, a view specific to books *should* try to detect the type of the target resource and *should* deactivate itself if it does not look like a book.
For example, a view specific to books _should_ try to detect the type of the target resource and _should_ deactivate itself if it does not look like a book.
In the case the view desires to deactivate itself, the `VIEW_PRIORITY_INAPPROPRIATE` constant can be returned.
The strategy to be used to determine whether the view is appropriate and what is its priority is left to the view itself.
......@@ -152,11 +153,117 @@ priorityFor(store: $rdf.Formula, target: application.Resource): number {
### Rendering
The renderer.
Once a view has been selected, it can be rendered by the browser, by calling the `render` method on the view implementation.
This method takes 3 parameters:
The rendering context.
- `renderer`, an object that can be used to interact with the rendering process.
- `context`, an object that holds all the contextual information for this call.
- `target`, the target RDF resource (URI) to be used as the primary entity to be rendered.
The resulting rendering.
The renderer, of type `ViewRenderer` makes available a few methods for the view implementation to interact with the rendering process.
```ts
/**
* A renderer for an application
*/
interface ViewRenderer {
/**
* Selects the languages to use for a target resource
* @param context The current rendering context
* @param target The target resource for this view
*/
getLanguagesFor(context: RenderingContext, target: Resource): Language[];
/**
* Renders a resource belonging to an RDF store
* @param context The context for the rendering
* @param target The target resource for this view
*/
render(context: RenderingContext, target: Resource): RenderingResult;
}
```
- The `getLanguagesFor` method can be used to compute the list of languages, from the highest priority down, that should be used for a specific RDF resource.
The methods takes into account the user preferences in the form of the rendering context.
- Moreover, the `render` method can be used by a view implementation to recursively perform the rendering of (probably another) RDF resource, so that it can be included into its own rendering.
This mechanism can be used by a view to include snippets about other resources as rendered by other view implementations.
The rendering context, of type `RenderingContext`, holds various data related to the rendering.
```ts
/**
* Represents the context of a rendering
*/
interface RenderingContext {
/**
* The RDF store holding the data to be rendered
*/
store: $rdf.Formula;
/**
* The root resource
*/
root: Resource;
/**
* The current rendering options
*/
options: RenderingOptions;
/**
* The handler of user events
*/
event: UserEvents;
/**
* The language used by the browser
*/
browserLanguage: Language;
}
```
- Most notable, the `store` field gives access to the current RDF dataset.
- The `root` field is set to the root RDF resource that is being rendered.
- The `options` field is a dictionary that holds the preferences (view, language, etc.) selected by the user for various RDF resources.
- The `browserLanguage` field simply holds the language that has been detected for the browser.
- The `events` field contains an object that holds methods that can be invoked for certain events related to the user interection with the rendered view.
The `onRequestNavigateTo` method can be used to trigger the navigation of the browser to a RDF resource when a user click on a link to another resource in the rendered view.
The `onSelectAsPrimaryTopic` method can be used to update the primary topic (root resource) of the current dataset.
This method is notably used by the built-in RDF triples view to enable the user to select the primary topic.
In the end, the view implementation _must_ produce a `RenderingResult` object to be returned.
```ts
/**
* Represents the rendering result of a resource
*/
interface RenderingResult {
/**
* The DOM elements representing the rendering
*/
dom: HTMLElement | null;
/**
* The identifier of the selected view
*/
viewId: string;
/**
* The URI of resources that could be of interest to the view that produced this rendering
*/
suggestedResources: Resource[];
/**
* The evaluations of the possible views
*/
evaluations: RenderingEvaluation[];
/**
* The used languages
*/
languages: Language[];
}
```
This object contains the rendering itself as a DOM tree with the field `dom`, as well as some metadata.
Note that returning a rendering object without a DOM tree can be used to indicate a failure to render.
The second field of interest is `suggestedResources`.
This is a list of RDF resources that have been identifier of importance by the view implementation (probably because they are linked to by the resource being rendered).
They can be used to indicate of resource of interest to the browser so that it can be loaded as well.
An example of use case is that the browser asks to render the resource A.
Resource A links to resource B, but the data about B is not in the same dataset.
The view implementation can suggest B so that data about it can be loaded.
When the browser finally loads data about B, a second rendering pass is invoked.
This time the view implementation can use the data about B, for example to render a user-friendly label instead of just an URI.
The `RenderingResult` object possesses other fields, such as the identifier of the view implementation that produced the rendering.
Those are automatically re-written by the renderer (so that they cannot be faked) ans therefore can be safely let empty.
### Facilities to manipulate RDF data
......@@ -164,7 +271,6 @@ RDF entities and entity store.
Load objects from RDF data.
## Step 2 - Entrypoint
When the resource (file) in which a view implementation is defined is loaded by the browser, it needs to known what is the main object that represents the actual view implementation.
......@@ -176,13 +282,12 @@ Continuing on the example, the entrypoint may be defined as follow:
export const VIEW_ENTRYPOINT: MyView = new MyView();
```
The name of the entrypoint, `VIEW_ENTRYPOINT` in the excerpt above, *must* be the same as the name given in the view descriptor.
The name of the entrypoint, `VIEW_ENTRYPOINT` in the excerpt above, _must_ be the same as the name given in the view descriptor.
## Step 3 - Serve the view
The last step consists in setting-up a JSON file containing a list of one or more view descriptors.
The descriptors in the file *must be* identical to the ones provided by the view implementations themselves.
The descriptors in the file _must be_ identical to the ones provided by the view implementations themselves.
For example:
```json
......@@ -203,11 +308,11 @@ For example:
"location": "remote",
"uri": "http://views.example.com/myview.js"
}
},
}
]
```
In this descriptor, the uri provided for the main resource *must* point to the Javascript file that contains the view implementation.
In this descriptor, the uri provided for the main resource _must_ point to the Javascript file that contains the view implementation.
The JSON file can then be served and the browser can points to it as a source of view so that the implementations can be loaded.
The `@logilab/libview` library contains a ready-to-use `index.html` that can be used as a companion to the JSON file to provide a more human-readable landing page for users.
......
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