////////////////////
- Shighl, is for S-olid high L-evel
- a tool that let you write simple html/js to interact with a Solid POD
- Session, Profile, Inbox, Chat...
- Shighl, c'est pour S-olid high L-evel
- un outil qui vous permet d'écrire du simple html/js pour interagir avec un POD Solid
- Session, Profil, Messagerie, Chat...
////////////////////
Why High Level ? Because Shighl is based on other libs like solid-auth-client, mostly @solid/query-ldflex, (solid-file-client, tripledoc in the next future)... to give you the most common used functionnalities to deal with session, pod, chat, inbox... using the Solid Project. If you have any question, feel free to ask on the Solid Community Forum
- see /dist folder for examples or https://scenaristeur.github.io/shighl/
- An example of this chat functionnalities is running on show INSTANCE EXAMPLE
Shighl can be integrated in any gh-page, POD or static WebPage !
use cdn.jsdelivr.net
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/vendor/solid-auth-client.bundle.js"> </script>
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/vendor/solid-query-ldflex.bundle.js"> </script>
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/window/shighl.bundle.js"> </script>
or shighl.bundle.js, solid-query-ldflex.bundle.js, solid-auth-client.bundle.js that you can find in the /dist/ folder.
<script src="./vendor/solid-auth-client.bundle.js"></script>
<script src="./vendor/solid-query-ldflex.bundle.js"></script>
<script src="./window/shighl.bundle.js"></script>
install with npm install --save scenaristeur/shighl
and import with
import Shighl from 'shighl'
not tested yet, but there is a node version in the dist folder
You will probably also need to copy the dist/dist-popup folder that provides you the better way to connect to a Solid Pod
const sh = new Shighl()
sh.test() // optional to verify that the lib is loaded
then you must create Objects from Shighl submodules :
Often, you will need to login to your POD. Shighl.session is a simple way to connect to a POD, but you can use the basic solid-auth-client too if you prefer.
const sh = new Shighl()
let session = new sh.session()
function mycallback(webId){
console.log("WebId: ",webId)
if (webId != null){
console.log("logged with ",webId)
}else{
console.log("not logged")
session.login()
}
}
await session.track(mycallback)
Shighl.pod allows you to simply read pods informations.
let sh = new Shighl()
let pod = new sh.pod()
pod.webId = "https://spoggy.solid.community/profile/card#me" // set the webId of the pod you want to read
let name = await pod.name
let photo = await pod.photo
let role = await pod.role
let organization = await pod.organization
let friends = await pod.friends
let pti = await pod.pti
let storage = await pod.storage
console.log("Name: ", name)
console.log("Photo: ", photo)
console.log("Role:", role)
console.log("Organization:", organization)
console.log("Friends: ", friends)
console.log("publicTypeIndex & instances: ", pti)
console.log("Storage: ", storage)
//Loop through friends
friends.forEach(async function(f, i) {
console.log(f.webId)
let f_pod = new sh.pod()
f_pod.webId = f.webId
let f_name = await f_pod.name
let f_role = await f_pod.role
let f_organization = await f_pod.organization
console.log("--"+f_name+" has role "+f_role+" in "+f_organization)
});
Shighl.chat Calendar example Shighl.chat Infinite Scroll example
let pti, chat, webId, user_pod
let sh = new Shighl()
//chat instances
let pod = new sh.pod()
pod.webId = "https://solidarity.inrupt.net/profile/card#me" // set the webId of the POD you want to retrieve the chat channels
pti = await pod.pti // get the publicTypeIndex of that pod
console.log(pti.instances)
// select the first instance with shortClass="LongChat" available in the publictypeIndex
let instance = pti.instances[0]
// create a chat object & initialize it
chat = new sh.chat()
chat.instance = instance
await chat.init
chat.subscribe = on_new_message // subscribe to chat change that launch on_new_message() callback function
// get chat messages of the last day.
let messages = await chat.messages
/* get each message properties and you are free to display them as you want.
use a calendar or a infinite scroll
to display older messages
(see examples above)
*/
for(const message of messages){
console.log(message.makername+" WROTE "+message.content+" AT "+message.date)
}
// Then to interact you will need to connect
let session = new sh.session()
await session.track(mycallback)
async function mycallback(_webId){
webId = _webId
if (webId != null){
user_pod = new sh.pod()
user_pod.webId = webId
}else{
session.login()
}
}
// ... //
//so you can easily send a chat message to the chat previously initialised by
let mess = {content: content, webId: webId, postType: postType, replyTo: replyTo}
chat.message = mess
// and eventually notiy user inbox of a reply/comment on his post (see examples)
// you can create a new channel with
let params = {user_pod: user_pod , url: chat_create_input.value, discoverable: public_check.checked, shortClass: "LongChat"}
console.log(params)
user_pod.pti_new = params
to be able to receive message, you must grant "Authenticated Agent" to "Submitter"
const sh = new Shighl()
let pod = new sh.pod()
let session = new sh.session() // retrieve webId as above
let user_inbox = {}
let inbox = ""
pod.webId = webId // obtained by session callback (see example)
inbox = await pod.inbox
user_inbox = new sh.inbox()
//
inbox_url = inbox // set & get document.getElementById("inbox_input").value in example
let messages = await user_inbox.getMessages(inbox_url)
messages.forEach(function(m){
let text = [ m.senderName, m.senderImg, m.sender, m.label, m.dateSent, m.text, m.url, m.parentItem].join(' || ')
console.log (text)
})
// then you can delete a message with
await user_inbox.delete(m_url)
...
// or send a message to a friend's inbox
async function send(){
let m = {}
m.content = document.getElementById("messageContent").value
m.title = document.getElementById("title").value
m.sender = pod.webId
if (document.getElementById("parentItem").value.length > 0){
m.parentItem = document.getElementById("parentItem").value
}
let w = document.getElementById("writePan").getAttribute("webId")
let p = new sh.pod()
p.webId = w
p_inbox = new sh.inbox(document.getElementById("to").value)
p_inbox.message = m
}
- For example, to get the name of a pod, you need a basic Shighl object that you can get with above
const sh = new Shighl()
. - When you have got that
sh
variable representing Shighl object, you can create a pod object withlet pod = new sh.pod()
- You must then set the webId of the pod that you want to read the name with
pod.webId = "https://[podname].[provider]/profile/card#me"
- And then to get the "name" property or attribute of the pod use
const sh = new Shighl()
let pod = new sh.pod()
pod.webId = "https://[podname].[provider]/profile/card#me"
let name = await pod.name;
console.log(name)
-
That must give you the name of the pod in 5 lines of code
-
You can now easily get the other properties/attributes of the pod with
let photo = await pod.photo
and same with pod.friends, pod.role, pod.storage, pod.pti -
pod.pti is a particular object as it represent the publicTypeIndex of the pod with the instances declared in it
-
An instance is a resource that the pod owner wants you to be able to discover, so that he put a reference to it. A resource could be some text, some image, or any media that is stored on his pod, by him or by someone else. It could also be a resource that is stored on another pod.
-
You can get each of the instances with
for (const inst of pti.instances){
console.log(inst)
}
- Created this way, each instance property/attribute can be obtained by the same way that we used for the pod. To get the instance url use inst.url and to get the instance short class ... inst.shortClass !!! Yeah, yo got it !!!
- And that shortClass could be something like "TextDigitalDocument", "MediaObject", "Bookmark", "Meeting", or ... "LongChat" ...
- A "LongChat" is an interesting thing on a Solid pod, it allows you to create a chat, a space for discussions. You own it, host it on your pod, give it a name, and a path where you want to put it on your pod. You also can manage the right of access (read/write, person/group). This way everyone can "host" every discussion he wants... I let you imagine what you can do with such functionnality...
- For example Solidarity is an UI coded by Julian-Cole and use Shighl to deal with data stored on https://solidarity.inrupt.net/public/Solidarity/ and on https://solidarity.inrupt.net/public/Shighl/ and there is a way to add other Channel that you want...
- If, with the above
console.log(inst)
you find some instance that have a shortClass property you can try to set that instance in a chat object that you first create from our starting "sh" variable. To create that chat object, do as above alet chat = new sh.chat()
then set the instance property of the chat with that instancechat.instance = instance
and initialize the chat with
let chat = new sh.chat()
chat.instance = [instance]
let chat_details = await chat.init
console.log(chat_details)
- Once the chat has been initialized with an instance, you can get the last messages of the last day someone posted something in that instance of chat
let messages = await chat.messages
for(const message of messages){
console.log(message)
}
- Then you can get the details of each message with
message.content, message.makername, message.makerimg, message.date
- If you want to get older messages, or other properties of that instance of chat, you have to look closer at the chat_details object that we created above and that represent stable and mutable propertiesof the instance of chat. _instance, _folder, and _name should be quite stable, opposed to the other.
{"_instance":{
"instance":"https://solidarity.inrupt.net/settings/publicTypeIndex.ttl#id1581799359461",
"url":"https://solidarity.inrupt.net/public/Shighl/Shighl/index.ttl#this",
"classe":"http://www.w3.org/ns/pim/meeting#LongChat",
"shortClass":"LongChat"
},
"_folder":"https://solidarity.inrupt.net/public/Shighl/Shighl/",
"_name":"Shighl",
"_years":["2020"],
"_year":"2020",
"_months":["02"],
"_month":"02",
"_days":["15","16","17"],
"_day":"17"
}
plural :
- _years is an array that gives you the years when someone posted in this instance
- _months an array that represent the months when someone posted in the last year of _years array
- _days an array of days that represent the days when someone posted in the last month of _months array.
singulier: _year, _month, _day represent the "cursor" where you want to get the messages.
So the example above gives you the messages of the 02/17/2020 or 17/02/2020 in french. To get the message of the day before, just set the _day of your chat object to "16" with something like this
chat._day = "16"
and get the messages of the day as we did before with chat.messages
- To create a new "LongChat" use
let params = {user_pod: user_pod , // a pod object of the user that you created with sh variable
url: chat_create_input.value, // the url of the chat
discoverable: public_check.checked, // if it must be in the publictypeindex or not (not implemented yet)
shortClass: "LongChat"} // to build some other things (not implemented yet)
console.log(params)
user_pod.pti_new = params
- [optional] : you can subscribe to a chat instance with
chat.subscribe = on_new_message
where on_new_message is the name of the callback function that is called when a new message arrive is posted in the chat.
What a call back function could be :
function on_new_message(changement){
console.log ("new Message arrived, get it from Websocket", changement)
chatUpdate()
}
An example of this chat functionnalities is running on show INSTANCE EXAMPLE
or codepen (can't log review how to add popuplogin)
- pod.pti (return publicTypeIndex & instances)
- pod.role
- pod.storage
const sh = new Shighl()
let pod = new sh.pod()
pod.webId = "https://spoggy.solid.community/profile/card#me" // set "https://spoggy.solid.community/profile/card#me" to pod.webId
let name = await pod.name //get pod.name
console.log(name)
checked function are implemented
- pod.name
- pod.photo
- pod.friends
- pod.pti (return publicTypeIndex & instances)
- pod.role
- pod.storage
-
pod.name = "New name"
-
pod.photo = "photo_url" (photo must be stored on your pod, todo copy photo to pod/profile)
-
pod.role = "New Role"
-
pod.pti = for creating a new pti instance (bookmark, notes, longchat...)
<html>
<script src="./vendor/solid-auth-client.bundle.js"></script>
<script src="./vendor/solid-query-ldflex.bundle.js"></script>
<script src="./window/shighl.bundle.js"></script>
<script>
async function init(){
let sh = new Shighl()
console.log(sh)
let pod = new sh.pod()
pod.webId = "https://spoggy.solid.community/profile/card#me"
let name = await pod.name
let photo = await pod.photo
let friends = await pod.friends
let pti = await pod.pti
let role = await pod.role
let storage = await pod.storage
console.log("Name: ",name)
console.log("Photo: ",photo)
console.log("Friends: ",friends)
console.log("publicTypeIndex & instances: ",pti)
console.log("Role:",role)
console.log("Storage: ",storage)
}
</script>
<body onload="init()">
Look the web console to see the pod infos (Ctrl+Maj+i)
</body>
</html>
what Shighl does :
let pod = new sh.pod()
pod.webId = "mywebId"
//example : pod = "https://solidarity.inrupt.net/profile/card#me"
let name = await pod.name --> return String
let photo = await pod.photo --> return String of photo url
let friends = await pod.friends --> return Array of webId
let pti = await pod.pti --> read the pod publicTypeIndex & return pti.url & pti.instances (an Array of instances)
then each pti instance has keys :
classe: "http://www.w3.org/ns/pim/meeting#LongChat"
instance: "https://spoggy.solid.community/settings/publicTypeIndex.ttl#id1579184973294"
shortClass: "LongChat"
url: "https://spoggy.solid.community/public/thirdChat/index.ttl#this"
- session.track(callback) listen session changes and then execute callback
- session.login() return webId if logged else open login popup & return webId
- session.logout()
- session.webId return webId/null
<html>
<script src="./vendor/solid-auth-client.bundle.js"></script>
<script src="./vendor/solid-query-ldflex.bundle.js"></script>
<script src="./window/shighl.bundle.js"></script>
<body onload="init()">
Look the web console to see the pod infos (Ctrl+Maj+i)<br><br>
Session : <span id="info"></span>
<button id="login_btn" onclick="session.login()">Login</button>
<button id="logout_btn" onclick="session.logout()">Logout</button>
<script>
const info = document.getElementById("info")
const login_btn = document.getElementById("login_btn")
const logout_btn = document.getElementById("logout_btn")
const sh = new Shighl()
let session = new sh.session()
async function init(){
await session.track(mycallback)
}
function mycallback(webId){
console.log("WebId: ",webId)
if (webId != null){
info.innerHTML = webId
login_btn.style.display = "none"
logout_btn.style.display = "block"
}
else{
info.innerHTML = "No session look at https://solid.inrupt.com/get-a-solid-pod"
login_btn.style.display = "block"
logout_btn.style.display = "none"
session.login()
}
}
</script>
</body>
</html>
when you get an instance (with pod.pti) of shortClass "Notes" and once you are logged with sh.session
- sh.notes.get(instance) return Array
- (sh.notes.subjects.get(instance) return Array) ??
- sh.notes.create(webId) return success/error
- sh.notes.remove(webId) return success/error
- sh.notes.update(webId) return success/error
- sh.notes.delete(webId) return success/error
- see sh.chat live example when you get an instance (with pod.pti) of shortClass "LongChat" and once you are logged with sh.session
let chat = new sh.chat()
chat.instance = instance
let chat_details = await chat.init
info.innerHTML = JSON.stringify(chat_details)
let messages = await chat.messages
messages_liste.innerHTML = JSON.stringify(messages)
-
chat.init
-
chat.messages
-
chat.send({content: content, webId: webId, postType: postType, replyTo: replyTo})
-
sh.chat.messages.get(date) return Array
-
sh.chat.message.send({creator: webId, content:content} )
-
sh.chat.message.reply(parentMessageUrl)
- sh.friends.get() return Array
- sh.friends.create(webId) return success/error
- sh.friends.remove(webId) return success/error
- sh.friends.update(webId) return success/error
- sh.friends.delete(webId) return success/error
- sh.inbox.get(webId)
- sh.inbox.get.messages(inbox)
- sh.inbox.send.message()
- sh.bookmarks.get(instance) return Array
- sh.bookmarks.create(webId) return success/error
- sh.bookmarks.remove(webId) return success/error
- sh.bookmarks.update(webId) return success/error
- sh.bookmarks.delete(webId) return success/error
- sh.hola.tension.create ...
S-olid HIGH L-evel
- Some facilities to interact with a Solid POD
- based on ldflex-query
<script src="./vendor/solid-auth-client.bundle.js"></script>
<script src="./vendor/solid-query-ldflex.bundle.js"></script>
<script src="./window/shighl.bundle.js"></script>
<script>
const sh = new Shighl()
sh.test()
</script>
npm install --save scenaristeur/shighl
import Shighl from 'shighl'
...
const sh = new Shighl()
sh.test()
then you should see the result of this test
async test(){
var name = await data['https://spoggy.solid.community/profile/card#me'].vcard$fn
console.log(`${name}`);
return `${name}`
}
see /dist/index.html
- Hosted on a POD : https://shighl.solid.community/public/demo/demo.html
- Hosted on ges : https://scenaristeur.github.io/shighl/
git clone https://github.com/scenaristeur/shighl.git
cd shighl
npm install
npm run start
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Shighl</title>
<script src="./vendor/solid-auth-client.bundle.js"></script>
<script src="./vendor/solid-query-ldflex.bundle.js"></script>
<script src="./window/shighl.bundle.js"></script>
</head>
<body>
<h1>Shigh</h1>
<ul id="friends">
</ul>
</body>
<script>
const sh = new Shighl()
console.log(sh)
sh.test()
async function run(){
let friends = await sh.getFriends("https://spoggy.solid.community/profile/card#me")
console.log(friends)
const friends_ul = document.getElementById("friends")
friends.forEach(function(f){
var li = document.createElement("LI")
var t = document.createTextNode(f.webId);
li.appendChild(t);
friends_ul.appendChild(li)
})
}
run()
</script>
</html>
```
# Loading from https://cdn.jsdelivr.net
```
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>Shighl</title>
<!-- <link rel="shortcut icon" type="image/png" href="favicon.png">
<link rel="manifest" href="./manifest.json">
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" >
<link href="css/fontawesome/css/all.css" rel="stylesheet">
<script src="vendor/jquery/jquery.slim.min.js"></script>-->
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/vendor/solid-auth-client.bundle.js"> </script>
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/vendor/solid-query-ldflex.bundle.js"> </script>
<script src="https://cdn.jsdelivr.net/gh/scenaristeur/shighl@master/dist/window/shighl.bundle.js"> </script>
</head>
<body>
<h1>Shigh</h1>
<ul id="friends">
</ul>
</body>
<script>
const sh = new Shighl()
console.log(sh)
sh.test()
async function run(){
let friends = await sh.getFriends("https://spoggy.solid.community/profile/card#me")
console.log(friends)
const friends_ul = document.getElementById("friends")
friends.forEach(function(f){
var li = document.createElement("LI")
var t = document.createTextNode(f.webId);
li.appendChild(t);
friends_ul.appendChild(li)
})
}
run()
</script>
</html>
```
# Functionnalities
- General
- [ X ] Session : trackSession() / login() / logout () / getWebId() return webId/null
<a href="https://scenaristeur.github.io/shighl/tracksession-login-logout.html" target="_blank">Session</a>
- Profile
- [ X ] getName(webId) return String
- [ X ] getPhoto(webId) return String
- [ X ] getFriends(webId) return Array of friends (String)
- [ X ] getPublicTypeIndex(webId) return String / Array of instances (Objects) with props subject, predicate, object, classe, shortClass
<a href="https://scenaristeur.github.io/shighl/profile.html" target="_blank">Profile</a>
- publicTypeIndex
- [ ] (? getDetails(webId) return Object)
- LongChat
- [ ] getFolder(publicTypeIndex) return String
- [ ] getPath(folder) return String
- [ ] getMessages(path) return Array of Messages
- [ ] getDetails(messageUrl) return Object
- Inbox
- [ ] getInbox() return String
- [ ] getMessages(inbox) return Array (with basic details ?)
- [ ] getDetails(messageUrl) return Object/Array
- [ ] sendMessage(inbox_dest) return result/error
- Acl
- [ ] getAcl(path) return Array
# chat calendar
show only days when there are messages
https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input/date
templates bootstrap https://bootsnipp.com/tags/chat
# webpack build copied from @jeffz https://jeff-zucker.github.io/solid-file-client
- build & publish to ges
```
npm run build
git subtree push --prefix dist origin gh-pages
```
https://blog.jakoblind.no/webpack-code-splitting-libraries-what-to-do-with-the-files/
- build ldflex-query
https://gist.github.com/bellbind/24d9a5851397d45e4fa83fa8ec30449c
https://git.happy-dev.fr/startinblox/framework/sib-store/blob/master/package.json
TODO infinite scroll : https://www.youtube.com/watch?v=hSsdhUG9rBI
https://googlechrome.github.io/samples/intersectionobserver/