2024-08-12 14:53:19 +12:00
< script >
2024-08-26 17:00:21 +12:00
// get the data from the JSON Webservices feed in +page.js
export let data;
const { webservices } = data;
2024-09-04 15:53:51 +12:00
import { references } from '$lib/references.js';
import { colours } from '$lib/colours.js';
//console.log('colours: ', colours);
//
//function
// digest and return useful info from the Webservices JSON feed
function processData(webservices) {
let instances = 0;
let current = [];
let future = [];
// properties of technologies
let category_list = [];
let analogue_list = [];
let license_list = [];
// properties of instances
let status_list = [];
let affiliate_list = [];
let host_list = [];
// actual objects
let hosts = [];
let affiliates = [];
//
// just a trivial reassignment
//let hosts = webservices.hosts;
//
// pull out relevant info in useful chunks.
for (let key in webservices.technologies) {
let tech = webservices.technologies[key];
if (tech.hasOwnProperty('categories') && tech.categories.constructor === Array) {
tech.categories.forEach(function (category, index) {
if (category_list.hasOwnProperty(category)) category_list[category]++;
else category_list[category] = 1;
});
}
if (tech.hasOwnProperty('analogues') && tech.analogues.constructor === Array) {
tech.analogues.forEach(function (analogue, index) {
if (analogue_list.hasOwnProperty(analogue)) analogue_list[analogue]++;
else analogue_list[analogue] = 1;
});
}
if (tech.hasOwnProperty('license')) {
let license = tech.license;
if (license_list.hasOwnProperty(license)) license_list[license]++;
else license_list[license] = 1;
}
if (hasInstances(tech)) {
tech['name'] = key;
current.push(tech);
//console.log(tech.name + ': ' + tech.instances.length + ' instances...');
tech.instances.forEach(function (instance, i) {
instances++;
if (instance.hasOwnProperty('status')) {
let tag = instance.status;
if (status_list.hasOwnProperty(tag)) status_list[tag]++;
else status_list[tag] = 1;
}
if (instance.hasOwnProperty('affiliation')) {
let tag = instance.affiliation;
2024-09-05 11:07:29 +12:00
2024-09-04 15:53:51 +12:00
if (affiliate_list.hasOwnProperty(tag)) affiliate_list[tag]++;
else affiliate_list[tag] = 1;
}
if (instance.hasOwnProperty('host')) {
let tag = instance.host;
if (host_list.hasOwnProperty(tag)) host_list[tag]++;
else host_list[tag] = 1;
}
});
} else {
future[key] = tech;
}
}
for (let key in webservices.hosts) {
//console.log('key: ', key);
let host = webservices.hosts[key];
host['name'] = key;
//console.log('host: ', host);
if (
host.hasOwnProperty('domain') & &
!(host.hasOwnProperty('status') & & host.status == 'retired')
) {
hosts[key] = host;
}
}
//console.log('webservices.affiliates: ', webservices.affiliates);
for (let key in webservices.affiliates) {
//console.log('key: ', key);
let affiliate = webservices.affiliates[key];
//console.log('affiliate assignment: ', affiliate);
affiliates[key] = affiliate;
// if (affiliate.hasOwnProperty('name')) {
// affiliate_data[key] = affiliate;
// }
}
return {
total_instances: instances,
active_services: current,
candidate_services: future,
tech_lists: {
category_list: category_list,
analogue_list: analogue_list,
license_list: license_list
},
instance_lists: {
status_list: status_list,
affiliate_list: affiliate_list,
host_list: host_list
},
hosts: hosts,
affiliates: affiliates
};
}
2024-08-26 17:00:21 +12:00
// console.log(technologies);
// return true if a tech object includes valid instances
function hasInstances(tech) {
if (
tech.hasOwnProperty('instances') & &
tech.instances.constructor === Array & &
tech.instances.length
)
return true;
return false;
}
// return an array of keys from an object
function getKeys(ob) {
let keys = [];
for (let key in ob) {
//keys.push(key.replace(/ /g, '\u00a0'));
keys.push(key);
}
return keys;
}
// get intersection: ref https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
function getIntersection(a, b) {
const set1 = new Set(a);
const set2 = new Set(b);
const intersection = [...set1].filter((element) => set2.has(element));
return intersection;
}
// combine an array of terms into a sentence with proper Oxford commas, dealing with the special cases
// of one or two elements.
function toOxfordCommaString(arr) {
if (arr.length == 1) return arr;
if (arr.length == 2) return arr.join(' and ');
else {
var last = arr.pop();
return arr.join(', ') + ', and ' + last;
}
}
// return a singular or plural term depending on the value of 'count'
function pluraliser(singular, plural, count) {
if (count > 1) return plural;
return singular;
}
// assign colours from a set of differentiated colours to a list of tags...
// this one is for 'hosts'
function hostColours(host_list, colours, hosts) {
let host_array = {} ;
let i = 0;
//console.log('hosts:', hosts);
host_list.forEach(function (host) {
//console.log(host);
if (hosts[host].hasOwnProperty('domain') && hosts[host].hasOwnProperty('affiliation')) {
host_array[host] = {
colour: colours[i++],
domain: hosts[host].domain,
affiliation: hosts[host].affiliation
};
}
});
return host_array;
}
// assign colours from a set of differentiated colours to a list of tags...
// this one is for 'affiliates'
function affiliateColours(affiliate_list, colours, affiliates) {
let affiliate_result = {} ;
let i = 0;
//console.log('affiliates:', affiliates);
console.log('affiliate_list:', affiliate_list);
for (const affiliate of affiliate_list) {
//console.log('affiliate:', affiliate);
if (
affiliates[affiliate].hasOwnProperty('name') & &
affiliates[affiliate].hasOwnProperty('website')
) {
affiliate_result[affiliate] = {
colour: colours[i++],
name: affiliates[affiliate].name,
website: affiliates[affiliate].website
};
}
}
return affiliate_result;
}
// sort technologies alphabetically by name
function sortTechnologies(technologies) {
return technologies.sort((a, b) => a.name.localeCompare(b.name));
}
// generic function to find the intersection of two arrays
// approach ref: https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
function inCommon(a, b) {
const set1 = new Set(a);
const set2 = new Set(b);
const intersection = [...set1].filter((element) => set2.has(element));
console.log('intersection = ', intersection);
return intersection;
}
// filter technologies based on a list of Categories
function filterTechnologiesByCategoryList(technologies, list) {
console.log('looking for tech in categories: ', list);
const included = [];
technologies.forEach(function (tech, index) {
//console.log('tech(' + index + '): ', tech);
if (hasInstances(tech)) {
const intersection = inCommon(tech.categories, list);
console.log('categories: ', tech.categories);
//console.log('list: ', list);
console.log('intersection: ', intersection);
if (intersection && intersection.constructor === Array) {
//console.log('intersection length: '. intersection.length);
if (intersection.length > 0) {
console.log('including tech: ', tech);
included.push(tech);
}
} else {
console.log('intersection not array');
}
}
});
console.log('found ' + included.length + ' technologies.');
return included;
}
const results = processData(webservices);
//console.log('results: ', results);
//const technologies = webservices.technologies;
//console.log(technologies);
const category_list = getKeys(results.tech_lists.category_list).sort();
const analogue_list = getKeys(results.tech_lists.analogue_list).sort();
const license_list = getKeys(results.tech_lists.license_list).sort();
const status_list = getKeys(results.instance_lists.status_list).sort();
const affiliate_list = getKeys(results.instance_lists.affiliate_list).sort();
const host_list = getKeys(results.instance_lists.host_list).sort();
const hosts = results.hosts;
//console.log('host_data: ', results.hosts);
const affiliates = results.affiliates;
//console.log('affiliate_data: ', results.affiliates);
2024-08-30 15:23:00 +12:00
const host_colours = hostColours(host_list, colours, hosts);
2024-08-26 17:00:21 +12:00
//console.log('host_colours:', host_colours);
2024-08-30 15:23:00 +12:00
colours.sort();
const affiliate_colours = affiliateColours(affiliate_list, colours, affiliates);
2024-08-26 17:00:21 +12:00
//console.log('affiliate_colours:',affiliate_colours);
//console.log('categories array: ', results.tech_tags.categories);
//console.log('categories keys: ', categories);
2024-09-04 15:53:51 +12:00
console.log('references: ', references);
2024-08-26 17:00:21 +12:00
console.log('category_list: ', category_list);
//console.log('analogue_list: ', analogue_list);
console.log('license_list: ', license_list);
console.log('status_list: ', status_list);
console.log('affiliate_list: ', affiliate_list);
console.log('hosts_list: ', host_list);
const filtered_technologies = filterTechnologiesByCategoryList(
results.active_services,
2024-09-04 15:53:51 +12:00
references.full_category_list,
// references.category_filter_list
2024-08-26 17:00:21 +12:00
);
const technologies = sortTechnologies(filtered_technologies);
2024-08-12 14:53:19 +12:00
< / script >
< div class = "webservices" >
2024-08-26 17:00:21 +12:00
< h1 > Web Services< / h1 >
< div class = "introduction" >
2024-09-04 15:53:51 +12:00
< p > This sites exists to provide an 'always-up-to-date', in-depth description of the < a
2024-08-26 17:00:21 +12:00
href="https://tech.oeru.org/foss-libresoftware-its-about-clarity-and-values"
title="What do I mean by 'libre' software?">libre software< / a > web services < a href = "https://davelane.nz" title = "Who is this Dave Lane character?" > I< / a > have set
up and maintain.
< / p >
2024-09-04 15:53:51 +12:00
2024-08-26 17:00:21 +12:00
< / div >
< div class = "summary" >
< ul >
< li > Total number of services: { results . total_instances } </ li >
< / ul >
< / div >
< div class = "filters" >
< div class = "tag-list tech" >
< div class = "tags tech categories" >
2024-09-05 11:07:29 +12:00
Categories< br /> { #each category_list as category } < span class = "tag on category" style = "white-space: nowrap; word-break: normal;" > { category } </ span >< wbr /> { /each }
2024-08-26 17:00:21 +12:00
< / div >
<!-- <div class="tags tech analogues">{#each analogues as analogue}<span class="tag analogue">{analogue}</span> {/each}</div> -->
< div class = "tags tech licenses" >
2024-09-05 11:07:29 +12:00
Licenses< br /> { #each license_list as license } < span class = "tag on license" > { license } </ span >< wbr /> { /each }
2024-08-26 17:00:21 +12:00
< / div >
< / div >
< div class = "tag-list instance" >
< div class = "tags instance statuses" >
2024-09-05 11:07:29 +12:00
Statuses< br /> { #each status_list as status } < span class = "tag on status" > { status } </ span >< wbr /> { /each }
2024-08-26 17:00:21 +12:00
< / div >
< div class = "tags instance affiliates" >
2024-09-05 11:07:29 +12:00
Affiliates< br /> { #each affiliate_list as affiliate } < span class = "tag on affiliate" >< span class = "marker circle" style = "background-color: { affiliate_colours [ affiliate ]. colour } " ></ span > { affiliate } </ span >< wbr /> { /each }
2024-08-26 17:00:21 +12:00
< / div >
< div class = "tags instance hosts" >
2024-09-05 11:07:29 +12:00
Hosts< br /> { #each host_list as host } < span class = "tag on host" >< span class = "marker square" style = "background-color: { host_colours [ host ]. colour } " ></ span > { host } </ span >< wbr /> { /each }
2024-08-26 17:00:21 +12:00
< / div >
< / div >
< / div >
< div class = "tiles" >
{ #each filtered_technologies as technology }
< div class = "tile technology" >
< div class = "links" >
{ #if technology . repository } < span class = "repository"
>< a
href={ technology . repository }
title="The source code repository for { technology . name } ">R< /a
>< /span
>{ /if }
{ #if technology . wikipedia } < span class = "wikipedia"
>< a href = { technology . wikipedia } title="Wikipedia Page for { technology . name } " > W< /a
>< /span
>{ /if }
< / div >
< h2 >< a href = { technology . website } > { technology . name } </a ></ h2 >
{ #if technology . license } < p
class="license"
title="The libre license for this project is { technology . license } "
>
License: < span class = "value" > { technology . license } </ span >
</ p > { /if }
{ #if technology . categories } < p class = "categories" >
{ pluraliser ( 'Category' , 'Categories' , technology . categories . length )} :
< span class = "value" > { toOxfordCommaString ( technology . categories )} </ span >
</ p > { /if }
{ #if technology . analogues } < p class = "analogues" >
Alternative to < span class = "value" > { toOxfordCommaString ( technology . analogues )} </ span >
</ p > { /if }
< p class = "description" >
{ technology . description }{ #if technology . extended_description } < span
title={ technology . extended_description } >i< /span
>{ /if }
< / p >
{ #if hasInstances ( technology )}
< div class = "instances" >
< p >
{ #each technology . instances as instance }
< a
href="https://{ instance . domain } "
title="{ technology . name } instance { instance . domain } hosted on '{ instance . host } ' by { instance . affiliation } "
>< span
class="marker circle"
style="background-color: { affiliate_colours [ instance . affiliation ]. colour } "
>< / span > < /a
>{ /each }
< / p >
< / div >
{ : else }
< div class = "instances" > Nothing here yet...< / div >
{ /if }
< / div >
{ /each }
< / div >
2024-08-12 14:53:19 +12:00
< / div >
2024-08-16 17:01:16 +12:00
< style >
2024-08-26 17:00:21 +12:00
.webservices {
display: grid;
margin: 0 auto 3em auto;
padding: 0;
}
.summary {
background-color: #ccc;
display: block;
}
.filters {
/*background-color: #f1ff94;
2024-08-18 13:01:02 +12:00
padding: 0.5em;
border: 3px solid #cbea77;
2024-08-18 13:56:25 +12:00
margin: 1em 0;*/
2024-08-26 17:00:21 +12:00
margin-bottom: 1em;
}
.filters .tags {
/*padding: 0.5em;*/
margin: 1em 0;
display: block;
}
.tag-list {
/* white-space: normal;
word-break: normal;
display: inline;*/
}
.tags {
/* white-space: normal;
word-break: normal;
display: inline;*/
}
.tag {
font-size: 80%;
margin-right: 0.5em;
line-height: 2.5;
padding: 6px 8px;
2024-09-05 11:07:29 +12:00
border-radius: 10px;
2024-08-26 17:00:21 +12:00
white-space: nowrap;
word-break: normal;
2024-09-05 11:07:29 +12:00
box-shadow: 3px 3px 3px #6a6d6a;
2024-08-26 17:00:21 +12:00
}
2024-09-05 11:07:29 +12:00
.tag:hover { box - shadow : 4px 4 px 3 px # 727372 ;}
2024-08-26 17:00:21 +12:00
.tag.category {
background-color: #9aa34d;
color: #fff;
}
.tag.license {
background-color: #6498a3;
color: #fff;
}
.tag.status {
background-color: #a369a2;
color: #fff;
}
.tag.affiliate {
background-color: #fff;
color: #000;
}
.tag.host {
background-color: #fff;
color: #000;
}
2024-09-05 11:07:29 +12:00
.tag.on {
padding-right: 25px;
background-image: url('images/check-black-in-white-20px.png');
background-position: right center;
background-repeat: no-repeat;
}
.tag.off {
color: #ccc;
opacity: 0.5;
}
2024-08-26 17:00:21 +12:00
.tiles {
display: grid;
grid-gap: 15px;
2024-09-04 15:53:51 +12:00
grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
2024-08-26 17:00:21 +12:00
}
/* flip card stuff: https://www.w3schools.com/howto/howto_css_flip_card.asp */
.tile {
height: 515px;
2024-09-04 15:53:51 +12:00
min-width: 240px;
max-width: 300px;
2024-08-29 08:28:04 +12:00
/*width: 290px;*/
2024-08-26 17:00:21 +12:00
overflow: hidden;
box-sizing: border-box;
box-shadow: 5px 5px 3px #71ba71;
border: solid 3px #1e6831;
text-overflow: ellipsis;
overflow: hidden;
position: relative;
background-color: #eee;
}
.tile .links {
position: absolute;
top: 0;
right: 0;
padding: 2px 6px;
font-size: 90%;
}
.tile:hover {
box-shadow: 10px 10px 6px #71ba71;
}
.tile .links h2 a {
color: #e6c4fc;
}
.tile .links a:visited {
color: #ced0ff;
}
.tile .links a:hover,
.tile:hover h2 a {
color: #fff !important;
}
.tile h2 {
background-color: #999;
text-align: center;
padding: 0.5em;
margin: 0;
}
.tile h2 a {
color: #e6c4fc;
}
.tile h2 a:visited {
color: #ced0ff;
}
.tile h2 a:hover {
color: #fff;
}
.tile .description {
height: 260px;
text-overflow: ellipsis;
overflow: hidden;
}
.tile p {
padding: 0 1em 0.2em 1em;
font-size: 80%;
color: #555;
}
.instances {
background-color: #ddd;
position: absolute;
bottom: 0;
height: 3em;
width: 100%;
}
.instances .marker {
margin-right: 3px;
}
.webservices li {
list-style-type: none;
}
.value {
font-weight: bold;
color: #000;
}
.marker {
vertical-align: middle;
}
.circle {
height: 20px;
width: 20px;
background-color: #555;
border-radius: 50%;
display: inline-block;
}
.square {
height: 20px;
width: 20px;
background-color: #555;
display: inline-block;
}
2024-08-12 14:53:19 +12:00
< / style >