Moved images from wekan.github.io to docs

This commit is contained in:
Lauri Ojansivu 2025-06-28 11:50:55 +03:00
parent b52d1ca6c4
commit c5e5bb613e
136 changed files with 9159 additions and 3 deletions

View file

@ -0,0 +1,26 @@
Title,Description,Stage,Owner,Members,Labels,Due Date,start date,finish date,created at,updated at
Test card 1,Test description 1,Stage 1,testuser1,testuser1 testuser2,Marketing-blue,05/06/2020,03/20/2020,05/03/2020,03/20/2020,05/03/2020
Test card 2,Test description 2,Stage 3,testuser1,testuser1 testuser2,Engineering ,05/11/2020,04/15/2020,05/12/2020,04/14/2020,04/14/2020
Test card 3,Test description 3,Stage 2,testuser1,testuser1,Marketing,,03/23/2020,04/24/2020,03/21/2020,03/21/2020
Test card 4,Test description 4,Stage 4,testuser1,testuser3 bryanmutai,Sales,05/08/2020,03/04/2020,,02/24/2020,02/24/2020
Test card 5,Test description 5,Stage 1,testuser1,,Marketing,,03/10/2020,,03/11/2020,03/13/2020
Test card 6,Test description 6,Stage 3,testuser1,,Sales,,03/06/2020,04/03/2020,03/02/2020,03/02/2020
Test card 7,Test description 7,Stage 4,testuser1,testuser1,Accounting,05/20/2020,04/13/2020,05/06/2020,04/03/2020,05/03/2020
Test card 8,Test description 8,Stage 2,testuser1,testuser2 testuser3,Sales,05/09/2020,03/13/2020,05/10/2020,02/23/2020,02/23/2020
Test card 9,Test description 9,Stage 4,testuser1,,Sales,,03/17/2020,04/01/2020,03/07/2020,03/07/2020
Test card 10,Test description 10,Stage 1,testuser1,testuser3,Engineering-red,05/10/2020,03/14/2020,,03/14/2020,03/14/2020
Test card 11,Test description 11,Stage 4,testuser1,,,05/21/2020,03/24/2020,,03/24/2020,03/24/2020
Test card 12,Test description 12,Stage 3,testuser1,testuser2,Sales Support,05/17/2020,03/19/2020,05/04/2020,03/19/2020,03/19/2020
Test card 13,Test description 13,Stage 1,testuser1,,Sales Support,05/27/2020,03/25/2020,06/04/2020,03/25/2020,03/28/2020
Test card 14,Test description 14,Stage 3,testuser1,testuser1 testuser3,,05/22/2020,03/03/2020,,03/03/2020,03/03/2020
Test card 15,Test description 15,Stage 4,testuser1,,Marketing,,03/05/2020,,03/05/2020,03/05/2020
Test card 16,Test description 16,Stage 3,testuser1,testuser3 testuser2,Engineering Support,05/13/2020,04/08/2020,05/04/2020,03/28/2020,04/28/2020
Test card 17,Test description 17,Stage 2,testuser1,testuser1,,05/16/2020,03/18/2020,05/10/2020,03/18/2020,03/18/2020
Test card 18,Test description 18,Stage 1,testuser1,,Support,,03/07/2020,04/06/2020,03/07/2020,03/07/2020
Test card 19,Test description 19,Stage 3,testuser1,,Marketing,05/25/2020,03/11/2020,,03/10/2020,03/10/2020
Test card 20,Test description 20,Stage 1,testuser1,,Sales,,03/21/2020,,03/11/2020,03/11/2020
Test card 21,Test description 21,Stage 3,testuser1,testuser3,Engineering,05/12/2020,04/02/2020,,04/02/2020,04/12/2020
Test card 22,Test description 22,Stage 2,testuser1,,Sales,05/15/2020,03/09/2020,05/03/2020,03/09/2020,03/09/2020
Test card 23,Test description 23,Stage 2,testuser1,testuser2,,,02/04/2020,04/05/2020,02/03/2020,03/03/2020
Test card 24,Test description 24,Stage 4,testuser1,testuser1 testuser2 testuser3,Support-yellow,05/14/2020,01/03/2020,04/04/2020,01/03/2020,01/03/2020
Test card 25,Test description 25,Stage 2,testuser1,testuser1 testuser2 testuser3,Support-yellow,05/18/2020,03/16/2020,05/19/2020,03/11/2020,04/11/2020
1 Title Description Stage Owner Members Labels Due Date start date finish date created at updated at
2 Test card 1 Test description 1 Stage 1 testuser1 testuser1 testuser2 Marketing-blue 05/06/2020 03/20/2020 05/03/2020 03/20/2020 05/03/2020
3 Test card 2 Test description 2 Stage 3 testuser1 testuser1 testuser2 Engineering 05/11/2020 04/15/2020 05/12/2020 04/14/2020 04/14/2020
4 Test card 3 Test description 3 Stage 2 testuser1 testuser1 Marketing 03/23/2020 04/24/2020 03/21/2020 03/21/2020
5 Test card 4 Test description 4 Stage 4 testuser1 testuser3 bryanmutai Sales 05/08/2020 03/04/2020 02/24/2020 02/24/2020
6 Test card 5 Test description 5 Stage 1 testuser1 Marketing 03/10/2020 03/11/2020 03/13/2020
7 Test card 6 Test description 6 Stage 3 testuser1 Sales 03/06/2020 04/03/2020 03/02/2020 03/02/2020
8 Test card 7 Test description 7 Stage 4 testuser1 testuser1 Accounting 05/20/2020 04/13/2020 05/06/2020 04/03/2020 05/03/2020
9 Test card 8 Test description 8 Stage 2 testuser1 testuser2 testuser3 Sales 05/09/2020 03/13/2020 05/10/2020 02/23/2020 02/23/2020
10 Test card 9 Test description 9 Stage 4 testuser1 Sales 03/17/2020 04/01/2020 03/07/2020 03/07/2020
11 Test card 10 Test description 10 Stage 1 testuser1 testuser3 Engineering-red 05/10/2020 03/14/2020 03/14/2020 03/14/2020
12 Test card 11 Test description 11 Stage 4 testuser1 05/21/2020 03/24/2020 03/24/2020 03/24/2020
13 Test card 12 Test description 12 Stage 3 testuser1 testuser2 Sales Support 05/17/2020 03/19/2020 05/04/2020 03/19/2020 03/19/2020
14 Test card 13 Test description 13 Stage 1 testuser1 Sales Support 05/27/2020 03/25/2020 06/04/2020 03/25/2020 03/28/2020
15 Test card 14 Test description 14 Stage 3 testuser1 testuser1 testuser3 05/22/2020 03/03/2020 03/03/2020 03/03/2020
16 Test card 15 Test description 15 Stage 4 testuser1 Marketing 03/05/2020 03/05/2020 03/05/2020
17 Test card 16 Test description 16 Stage 3 testuser1 testuser3 testuser2 Engineering Support 05/13/2020 04/08/2020 05/04/2020 03/28/2020 04/28/2020
18 Test card 17 Test description 17 Stage 2 testuser1 testuser1 05/16/2020 03/18/2020 05/10/2020 03/18/2020 03/18/2020
19 Test card 18 Test description 18 Stage 1 testuser1 Support 03/07/2020 04/06/2020 03/07/2020 03/07/2020
20 Test card 19 Test description 19 Stage 3 testuser1 Marketing 05/25/2020 03/11/2020 03/10/2020 03/10/2020
21 Test card 20 Test description 20 Stage 1 testuser1 Sales 03/21/2020 03/11/2020 03/11/2020
22 Test card 21 Test description 21 Stage 3 testuser1 testuser3 Engineering 05/12/2020 04/02/2020 04/02/2020 04/12/2020
23 Test card 22 Test description 22 Stage 2 testuser1 Sales 05/15/2020 03/09/2020 05/03/2020 03/09/2020 03/09/2020
24 Test card 23 Test description 23 Stage 2 testuser1 testuser2 02/04/2020 04/05/2020 02/03/2020 03/03/2020
25 Test card 24 Test description 24 Stage 4 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/14/2020 01/03/2020 04/04/2020 01/03/2020 01/03/2020
26 Test card 25 Test description 25 Stage 2 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/18/2020 03/16/2020 05/19/2020 03/11/2020 04/11/2020

View file

@ -0,0 +1,26 @@
Title Description Stage Owner Members Labels Due Date start date finish date created at updated at
Test card 1 Test description 1 Stage 1 testuser1 testuser1 testuser2 Marketing-blue 05/06/2020 03/20/2020 05/03/2020 03/20/2020 05/03/2020
Test card 2 Test description 2 Stage 3 testuser1 testuser1 testuser2 Engineering 05/11/2020 04/15/2020 05/12/2020 04/14/2020 04/14/2020
Test card 3 Test description 3 Stage 2 testuser1 testuser1 Marketing 03/23/2020 04/24/2020 03/21/2020 03/21/2020
Test card 4 Test description 4 Stage 4 testuser1 testuser3 bryanmutai Sales 05/08/2020 03/04/2020 02/24/2020 02/24/2020
Test card 5 Test description 5 Stage 1 testuser1 Marketing 03/10/2020 03/11/2020 03/13/2020
Test card 6 Test description 6 Stage 3 testuser1 Sales 03/06/2020 04/03/2020 03/02/2020 03/02/2020
Test card 7 Test description 7 Stage 4 testuser1 testuser1 Accounting 05/20/2020 04/13/2020 05/06/2020 04/03/2020 05/03/2020
Test card 8 Test description 8 Stage 2 testuser1 testuser2 testuser3 Sales 05/09/2020 03/13/2020 05/10/2020 02/23/2020 02/23/2020
Test card 9 Test description 9 Stage 4 testuser1 Sales 03/17/2020 04/01/2020 03/07/2020 03/07/2020
Test card 10 Test description 10 Stage 1 testuser1 testuser3 Engineering-red 05/10/2020 03/14/2020 03/14/2020 03/14/2020
Test card 11 Test description 11 Stage 4 testuser1 05/21/2020 03/24/2020 03/24/2020 03/24/2020
Test card 12 Test description 12 Stage 3 testuser1 testuser2 Sales Support 05/17/2020 03/19/2020 05/04/2020 03/19/2020 03/19/2020
Test card 13 Test description 13 Stage 1 testuser1 Sales Support 05/27/2020 03/25/2020 06/04/2020 03/25/2020 03/28/2020
Test card 14 Test description 14 Stage 3 testuser1 testuser1 testuser3 05/22/2020 03/03/2020 03/03/2020 03/03/2020
Test card 15 Test description 15 Stage 4 testuser1 Marketing 03/05/2020 03/05/2020 03/05/2020
Test card 16 Test description 16 Stage 3 testuser1 testuser3 testuser2 Engineering Support 05/13/2020 04/08/2020 05/04/2020 03/28/2020 04/28/2020
Test card 17 Test description 17 Stage 2 testuser1 testuser1 05/16/2020 03/18/2020 05/10/2020 03/18/2020 03/18/2020
Test card 18 Test description 18 Stage 1 testuser1 Support 03/07/2020 04/06/2020 03/07/2020 03/07/2020
Test card 19 Test description 19 Stage 3 testuser1 Marketing 05/25/2020 03/11/2020 03/10/2020 03/10/2020
Test card 20 Test description 20 Stage 1 testuser1 Sales 03/21/2020 03/11/2020 03/11/2020
Test card 21 Test description 21 Stage 3 testuser1 testuser3 Engineering 05/12/2020 04/02/2020 04/02/2020 04/12/2020
Test card 22 Test description 22 Stage 2 testuser1 Sales 05/15/2020 03/09/2020 05/03/2020 03/09/2020 03/09/2020
Test card 23 Test description 23 Stage 2 testuser1 testuser2 02/04/2020 04/05/2020 02/03/2020 03/03/2020
Test card 24 Test description 24 Stage 4 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/14/2020 01/03/2020 04/04/2020 01/03/2020 01/03/2020
Test card 25 Test description 25 Stage 2 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/18/2020 03/16/2020 05/19/2020 03/11/2020 04/11/2020
1 Title Description Stage Owner Members Labels Due Date start date finish date created at updated at
2 Test card 1 Test description 1 Stage 1 testuser1 testuser1 testuser2 Marketing-blue 05/06/2020 03/20/2020 05/03/2020 03/20/2020 05/03/2020
3 Test card 2 Test description 2 Stage 3 testuser1 testuser1 testuser2 Engineering 05/11/2020 04/15/2020 05/12/2020 04/14/2020 04/14/2020
4 Test card 3 Test description 3 Stage 2 testuser1 testuser1 Marketing 03/23/2020 04/24/2020 03/21/2020 03/21/2020
5 Test card 4 Test description 4 Stage 4 testuser1 testuser3 bryanmutai Sales 05/08/2020 03/04/2020 02/24/2020 02/24/2020
6 Test card 5 Test description 5 Stage 1 testuser1 Marketing 03/10/2020 03/11/2020 03/13/2020
7 Test card 6 Test description 6 Stage 3 testuser1 Sales 03/06/2020 04/03/2020 03/02/2020 03/02/2020
8 Test card 7 Test description 7 Stage 4 testuser1 testuser1 Accounting 05/20/2020 04/13/2020 05/06/2020 04/03/2020 05/03/2020
9 Test card 8 Test description 8 Stage 2 testuser1 testuser2 testuser3 Sales 05/09/2020 03/13/2020 05/10/2020 02/23/2020 02/23/2020
10 Test card 9 Test description 9 Stage 4 testuser1 Sales 03/17/2020 04/01/2020 03/07/2020 03/07/2020
11 Test card 10 Test description 10 Stage 1 testuser1 testuser3 Engineering-red 05/10/2020 03/14/2020 03/14/2020 03/14/2020
12 Test card 11 Test description 11 Stage 4 testuser1 05/21/2020 03/24/2020 03/24/2020 03/24/2020
13 Test card 12 Test description 12 Stage 3 testuser1 testuser2 Sales Support 05/17/2020 03/19/2020 05/04/2020 03/19/2020 03/19/2020
14 Test card 13 Test description 13 Stage 1 testuser1 Sales Support 05/27/2020 03/25/2020 06/04/2020 03/25/2020 03/28/2020
15 Test card 14 Test description 14 Stage 3 testuser1 testuser1 testuser3 05/22/2020 03/03/2020 03/03/2020 03/03/2020
16 Test card 15 Test description 15 Stage 4 testuser1 Marketing 03/05/2020 03/05/2020 03/05/2020
17 Test card 16 Test description 16 Stage 3 testuser1 testuser3 testuser2 Engineering Support 05/13/2020 04/08/2020 05/04/2020 03/28/2020 04/28/2020
18 Test card 17 Test description 17 Stage 2 testuser1 testuser1 05/16/2020 03/18/2020 05/10/2020 03/18/2020 03/18/2020
19 Test card 18 Test description 18 Stage 1 testuser1 Support 03/07/2020 04/06/2020 03/07/2020 03/07/2020
20 Test card 19 Test description 19 Stage 3 testuser1 Marketing 05/25/2020 03/11/2020 03/10/2020 03/10/2020
21 Test card 20 Test description 20 Stage 1 testuser1 Sales 03/21/2020 03/11/2020 03/11/2020
22 Test card 21 Test description 21 Stage 3 testuser1 testuser3 Engineering 05/12/2020 04/02/2020 04/02/2020 04/12/2020
23 Test card 22 Test description 22 Stage 2 testuser1 Sales 05/15/2020 03/09/2020 05/03/2020 03/09/2020 03/09/2020
24 Test card 23 Test description 23 Stage 2 testuser1 testuser2 02/04/2020 04/05/2020 02/03/2020 03/03/2020
25 Test card 24 Test description 24 Stage 4 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/14/2020 01/03/2020 04/04/2020 01/03/2020 01/03/2020
26 Test card 25 Test description 25 Stage 2 testuser1 testuser1 testuser2 testuser3 Support-yellow 05/18/2020 03/16/2020 05/19/2020 03/11/2020 04/11/2020

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View file

@ -0,0 +1,21 @@
At this article:
https://news.ycombinator.com/item?id=36047861
This comment:
https://news.ycombinator.com/item?id=36053916
Quote:
> dools 6 hours ago
> I can no longer edit, but it's worth noting that I went through my Trellinator libs and updated for use with WeKan, throwing exceptions where functionality doesn't yet exist:
> https://github.com/iaindooley/trellinator-libs
> https://github.com/iaindooley/trellinator
> I made a list of things that would need to be implemented in WeKan and/or the WeKan API to make it on-par with Trello (screenshot here of my checklist in Trello for this :)
> https://wekan.github.io/trellinator/WekanPriorities.png
Forks:
- https://github.com/wekan/trellinator
- https://github.com/wekan/trellinator-libs

View file

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON Viewer</title>
<style>
#jsonInput {
width: 45%;
height: 300px;
margin-bottom: 10px;
}
#jsonOutput {
width: 45%;
height: 300px;
margin-bottom: 10px;
}
#updateButton {
display: block;
margin-top: 10px;
}
</style>
<script defer src="pretty-json-custom-element.js"></script>
</head>
<body>
<h1>JSON Viewer</h1>
<p><a href="https://github.com/wekan/wekan/issues/4877#issuecomment-2105688702">Source</a></p>
<textarea id="jsonInput" placeholder="Enter Trello-JSON here: (Ctrl+V)&#10;&#10;In Trello go to ... menu and select 'Print, Export and Share'&#10;Select 'Export as JSON'&#10;Copy the whole text (Ctrl+A, Ctrl+C)"></textarea><br>
<button id="updateButton">Convert from Trello to Wekan</button><br>
<textarea id="jsonOutput" placeholder="Copy JSON for Wekan from here: (Ctrl+A, Ctrl+C)&#10;&#10;In Wekan go to 'all Boards', 'Add Board', 'Import', 'From Trello'" readonly></textarea>
<script>
document.getElementById("updateButton").addEventListener("click", function() {
try {
var jsonInput = document.getElementById("jsonInput").value;
// replace colors with replaceAll
jsonInput = jsonInput.replaceAll("green_dark", "green");
jsonInput = jsonInput.replaceAll("red_dark", "red");
// alter the json file structure
var parsedJson = JSON.parse(jsonInput);
// Iterate through the actions array
parsedJson.actions.forEach(function(action) {
// Check if the type is "addAttachmentToCard"
if (action.type === "addAttachmentToCard") {
// Store the value of data.attachment
action.data.text = "**" + action.memberCreator.fullName + "**";
action.data.text += "\nAdded: " + action.data.attachment.name + " " + action.data.attachment.url;
action.data.textData = {};
action.data.textData.emoji = {};
delete action.data.attachment;
action.type = "commentCard";
} else if (action.type === "deleteAttachmentFromCard") {
// Store the value of data.attachment
action.data.text = "**" + action.memberCreator.fullName + "**";
action.data.text += "\nRemoved: " + action.data.attachment.name;
action.data.textData = {};
action.data.textData.emoji = {};
delete action.data.attachment;
action.type = "commentCard";
} else if (action.type === "commentCard") {
action.data.text = "**" + action.memberCreator.fullName + "**\n" + action.data.text;
}
});
// Iterate through the actions array
parsedJson.cards.forEach(function(card) {
for (var i=0; i<card.badges.attachments; i++) {
card.desc += "\nAttachment: " + card.attachments[i].name + " " + card.attachments[i].url;
}
});
var formattedJson = JSON.stringify(parsedJson, null, 4);
document.getElementById("jsonOutput").value = formattedJson;
} catch (error) {
document.getElementById("jsonOutput").value = "Invalid JSON format!";
}
});
</script>
</body>
</html>

View file

@ -0,0 +1,451 @@
// @ts-check
/**
* @typedef {string | number | null | undefined | bigint | boolean | symbol} Primitive
* @typedef {(...args: any[]) => any} AnyFunction
*/
class PrettyJSONError extends Error {
/**
*
* @param {string} message
*/
constructor(message) {
super(message);
this.name = "PrettyJSONError";
}
}
class PrettyJSON extends HTMLElement {
/**
* @type {any}
*/
#input;
/**
* @type {boolean}
*/
#isExpanded;
static get observedAttributes() {
return ["expand", "key", "truncate-string"];
}
static styles = `/* css */
:host {
--key-color: #cc0000;
--arrow-color: #737373;
--brace-color: #0030f0;
--bracket-color: #0030f0;
--string-color: #009900;
--number-color: #0000ff;
--null-color: #666666;
--boolean-color: #d23c91;
--comma-color: #666666;
--ellipsis-color: #666666;
--indent: 2rem;
}
@media (prefers-color-scheme: dark) {
:host {
--key-color: #f73d3d;
--arrow-color: #6c6c6c;
--brace-color: #0690bc;
--bracket-color: #0690bc;
--string-color: #21c521;
--number-color: #0078b3;
--null-color: #8c8888;
--boolean-color: #c737b3;
--comma-color: #848181;
--ellipsis-color: #c2c2c2;
}
}
button {
border: none;
background: transparent;
cursor: pointer;
font-family: inherit;
font-size: 1rem;
vertical-align: text-bottom;
}
.container {
font-family: monospace;
font-size: 1rem;
}
.key {
color: var(--key-color);
margin-right: 0.5rem;
padding: 0;
}
.key .arrow {
width: 1rem;
height: 0.75rem;
margin-left: -1.25rem;
padding-right: 0.25rem;
vertical-align: baseline;
}
.arrow .triangle {
fill: var(--arrow-color);
}
.comma {
color: var(--comma-color);
}
.brace {
color: var(--brace-color);
}
.string,
.url {
color: var(--string-color);
}
.number,
.bigint {
color: var(--number-color);
}
.null {
color: var(--null-color);
}
.boolean {
color: var(--boolean-color);
}
.ellipsis {
width: 1rem;
padding: 0;
color: var(--ellipsis-color);
}
.ellipsis::after {
content: "…";
}
.string .ellipsis::after {
color: var(--string-color);
}
.triangle {
fill: black;
stroke: black;
stroke-width: 0;
}
.row {
padding-left: var(--indent);
}
.row .row {
display: block;
}
.row > div,
.row > span {
display: inline-block;
}
`;
constructor() {
super();
this.#isExpanded = true;
this.attachShadow({ mode: "open" });
}
get #expandAttributeValue() {
const expandAttribute = this.getAttribute("expand");
if (expandAttribute === null) {
return 1;
}
const expandValue = Number.parseInt(expandAttribute);
return isNaN(expandValue) || expandValue < 0 ? 0 : expandValue;
}
get #truncateStringAttributeValue() {
const DEFAULT_TRUNCATE_STRING = 500;
const truncateStringAttribute = this.getAttribute("truncate-string");
if (truncateStringAttribute === null) {
return DEFAULT_TRUNCATE_STRING;
}
const truncateStringValue = Number.parseInt(truncateStringAttribute);
return isNaN(truncateStringValue) || truncateStringValue < 0
? 0
: truncateStringValue;
}
#toggle() {
this.#isExpanded = !this.#isExpanded;
this.setAttribute(
"expand",
this.#isExpanded ? String(this.#expandAttributeValue + 1) : "0"
);
this.#render();
}
/**
* @param {Record<any, any> | any[] | Primitive | AnyFunction} input
* @param {number} expand
* @param {string} [key]
* @returns {HTMLElement}
*/
#createChild(input, expand, key) {
if (this.#isPrimitiveValue(input)) {
const container = this.#createContainer();
container.appendChild(this.#createPrimitiveValueElement(input));
return container;
}
return this.#createObjectOrArray(input);
}
/**
* @param {any} input
* @returns {input is Primitive}
*/
#isPrimitiveValue(input) {
return typeof input !== "object" || input === null;
}
#isValidStringURL() {
try {
new URL(this.#input);
return true;
} catch (error) {
return false;
}
}
/**
* @param {Primitive} input
* @returns {HTMLElement}
*/
#createPrimitiveValueElement(input) {
const container = document.createElement("div");
const type = typeof input === "object" ? "null" : typeof input;
container.className = `primitive value ${type}`;
if (typeof input === "string") {
if (this.#isValidStringURL()) {
const anchor = document.createElement("a");
anchor.className = "url";
anchor.href = this.#input;
anchor.target = "_blank";
anchor.textContent = input;
container.append('"', anchor, '"');
} else if (input.length > this.#truncateStringAttributeValue) {
container.appendChild(this.#createTruncatedStringElement(input));
} else {
container.textContent = JSON.stringify(input);
}
} else {
container.textContent = JSON.stringify(input);
}
return container;
}
/**
* @param {string} input
*/
#createTruncatedStringElement(input) {
const container = document.createElement("div");
container.dataset.expandedTimes = "1";
container.className = "truncated string";
const ellipsis = document.createElement("button");
ellipsis.className = "ellipsis";
ellipsis.addEventListener("click", () => {
const expandedTimes = Number.parseInt(
container.dataset.expandedTimes ?? "1"
);
container.dataset.expandedTimes = String(expandedTimes + 1);
const expandedString = input.slice(
0,
(expandedTimes + 1) * this.#truncateStringAttributeValue
);
const textChild = container.childNodes[1];
container.replaceChild(
document.createTextNode(expandedString),
textChild
);
});
container.append(
'"',
input.slice(0, this.#truncateStringAttributeValue),
ellipsis,
'"'
);
return container;
}
/**
* @returns {HTMLElement}
*/
#createContainer() {
const container = document.createElement("div");
container.className = "container";
return container;
}
/**
* @param {Record<any, any> | any[]} object
* @returns {HTMLElement}
*/
#createObjectOrArray(object) {
const isArray = Array.isArray(object);
const objectKeyName = this.getAttribute("key");
const expand = this.#expandAttributeValue;
const container = this.#createContainer();
container.classList.add(isArray ? "array" : "object");
if (objectKeyName) {
// if objectKeyName is provided, then it is a row
container.classList.add("row");
const keyElement = this.#createKeyElement(objectKeyName, {
withArrow: true,
expanded: this.#isExpanded,
});
keyElement.addEventListener("click", this.#toggle.bind(this));
container.appendChild(keyElement);
}
const openingBrace = document.createElement("span");
openingBrace.className = "open brace";
openingBrace.textContent = isArray ? "[" : "{";
container.appendChild(openingBrace);
const closingBrace = document.createElement("span");
closingBrace.className = "close brace";
closingBrace.textContent = isArray ? "]" : "}";
if (!this.#isExpanded) {
const ellipsis = document.createElement("button");
ellipsis.className = "ellipsis";
container.appendChild(ellipsis);
ellipsis.addEventListener("click", this.#toggle.bind(this));
container.appendChild(closingBrace);
return container;
}
Object.entries(object).forEach(([key, value], index) => {
// for primitives we make a row here
if (this.#isPrimitiveValue(value)) {
const rowContainer = document.createElement("div");
rowContainer.className = "row";
if (!isArray) {
const keyElement = this.#createKeyElement(key);
rowContainer.appendChild(keyElement);
}
rowContainer.appendChild(this.#createPrimitiveValueElement(value));
container.appendChild(rowContainer);
const isLast = index === Object.keys(object).length - 1;
if (!isLast) {
const comma = document.createElement("span");
comma.className = "comma";
comma.textContent = ",";
rowContainer.appendChild(comma);
}
return;
}
// for objects and arrays we make a "container row"
const prettyJsonElement = document.createElement("pretty-json");
prettyJsonElement.textContent = JSON.stringify(value);
prettyJsonElement.setAttribute("expand", String(expand - 1));
prettyJsonElement.setAttribute("key", key);
container.appendChild(prettyJsonElement);
});
container.appendChild(closingBrace);
return container;
}
/**
* @param {{ expanded?: boolean }} [options]
* @returns {SVGElement}
*/
#createArrowElement({ expanded = false } = {}) {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("width", "100");
svg.setAttribute("height", "100");
svg.setAttribute("viewBox", "0 0 100 100");
svg.setAttribute("class", "arrow");
const polygon = document.createElementNS(
"http://www.w3.org/2000/svg",
"polygon"
);
polygon.setAttribute("class", "triangle");
polygon.setAttribute("points", "0,0 100,50 0,100");
if (expanded) {
polygon.setAttribute("transform", "rotate(90 50 50)");
}
svg.appendChild(polygon);
return svg;
}
/**
* @param {string} key
* @param {{ withArrow?: boolean, expanded?: boolean }} [options]
* @returns {HTMLElement}
*/
#createKeyElement(key, { withArrow = false, expanded = false } = {}) {
const keyElement = document.createElement(withArrow ? "button" : "span");
keyElement.className = "key";
if (withArrow) {
const arrow = this.#createArrowElement({ expanded });
keyElement.appendChild(arrow);
}
const keyName = document.createElement("span");
keyName.className = "key-name";
keyName.textContent = JSON.stringify(key);
keyElement.appendChild(keyName);
const colon = document.createElement("span");
colon.className = "colon";
colon.textContent = ":";
keyElement.appendChild(colon);
return keyElement;
}
#render() {
if (!this.shadowRoot) {
throw new PrettyJSONError("Shadow root not available");
}
this.shadowRoot.innerHTML = "";
this.shadowRoot.appendChild(
this.#createChild(this.#input, this.#expandAttributeValue)
);
if (this.shadowRoot.querySelector("[data-pretty-json]")) {
return;
}
const styles = document.createElement("style");
styles.setAttribute("data-pretty-json", "");
styles.textContent = PrettyJSON.styles;
this.shadowRoot.appendChild(styles);
}
/**
* Handle when attributes change
* @param {string} name
* @param {string} _oldValue
* @param {string | null} newValue
*/
attributeChangedCallback(name, _oldValue, newValue) {
if (name === "expand") {
if (newValue === null) {
this.#isExpanded = false;
} else {
const expandValue = Number.parseInt(newValue);
this.#isExpanded = !isNaN(expandValue) && expandValue > 0;
}
this.#render();
}
}
connectedCallback() {
try {
this.#input = JSON.parse(this.textContent ?? "");
} catch (jsonParseError) {
const message = `Error parsing JSON: ${jsonParseError instanceof Error ? jsonParseError.message : "Unknown error"}`;
throw new PrettyJSONError(message);
}
this.#render();
}
}
// Define pretty-json custom element
customElements.define("pretty-json", PrettyJSON);

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB