-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJSON2Table.js
More file actions
300 lines (233 loc) · 10.4 KB
/
JSON2Table.js
File metadata and controls
300 lines (233 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
'use strict'; /* Used traditional syntax and ES5, except "let". */
/** convertJSON2Table ********************************************************
* Constructing a class "convertJSON2Table" with private and public functions.
* This class is ment to generate a html-table from a given JSON-Object.
*
* KNOWN BUG:
* There is a known issue with this script.
* All properties in the JSON must have a unique name,
* or the properties with the same name,
* must be in exactly the same nested order.
*
* If there are two or more properties with the same name,
* and different nested order
* the script fails to place them to the right position.
*
*/
/* BUG-Details:
// This fails, due to the different nested depth of properties with same name
{
"myProp1": {
,"samePropertyName": {
"prop1": 1
}
,"notWorking": {
"samePropertyName": {
"prop1": 1
}
}
}
}
// This still works, due to the same nested depth
{
"myProp1": {
,"workingOne": {
,"samePropertyName": {
"prop1": 1
}
}
,"workingTwo": {
"samePropertyName": {
"prop1": 1
}
}
}
}
*/
let convertJSON2Table = function (){
/**
* PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
* PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
*/
// Common settings needed inside this class
let internalSettings = {
myURLTogetJSON: "./mvc/model/example-content.json",
rowNumber: 1,
columnNumber: 1,
columnsAmount: 1,
tableRowContent: "",
completeTableContentSorted: [],
myBIGJSONPrototype: ""
};
// Retrieve DOM-elements needed inside this class
let DOM = {
root :document.body,
tableContainer : ""
};
/**
* 3
* Generate a htm-table from
* the prepared JSON-content (internalSettings.completeTableContentSorted)
**/
let createTable = function(){
let myTable = document.createElement("table");
let tableContent = internalSettings.completeTableContentSorted;
let tableContentLength = tableContent.length; // amount rows
// Could look like following
//"1|1|divisionOne"
//"2|2|divisionDescriptionOne|a list of some movies ..."
//"3|2|movies"
//"4|3|cinema"
//"5|4|titles"
//"6|5|oblivion|tom cruise,and a girl"
//"7|5|blade runner|harrison ford,and a girl"
//"8|5|ghost in the shell|the girl"
//"9|5|metropolis|the girl"
let rememberValueForSameLineNextCol = "unset";
for (let row=1; row<=tableContentLength; row++){
let myTableRow = document.createElement("tr");
myTable.appendChild(myTableRow); // attach a row for every entry in array "tableContent"
let theWantedRow = parseInt(tableContent[row-1].split("|")[0]);
let theWantedColumn = parseInt(tableContent[row-1].split("|")[1]);
let theWantedPropertyName = tableContent[row-1].split("|")[2];
let rowContentLength = tableContent[row-1].split("|").length;
for (let column=1; column<=internalSettings.columnsAmount; column++){
let myTableColumn = document.createElement("td");
if (theWantedRow == row && theWantedColumn == column){
myTableColumn.innerText = theWantedPropertyName;
}
// a. In case the property has a value
// which must be written in the same line but next column ...
if (rowContentLength > 3){
// b. ... we remember the value ...
rememberValueForSameLineNextCol = tableContent[row-1].split("|")[3];
if (theWantedRow == row && theWantedColumn+1 == column && rememberValueForSameLineNextCol != "unset"){
// c. ... and write it in the next td-round when we are in the next column...
myTableColumn.innerText = rememberValueForSameLineNextCol;
rememberValueForSameLineNextCol = "unset"; // ... finally we set the flag, back to "unset".
}
}
myTableRow.appendChild(myTableColumn);
}
}
DOM.tableContainer.appendChild(myTable);
};
// Source code found here:
// https://stackoverflow.com/questions/39941691/how-to-get-the-json-path-from-element
// Adaptation:
// I would have preferred to comment that answer on stackoverflow, but I had not enough reputation.
// In my case there was a small issue with my JSON-content.
// Some values were the boolean "false",
// and some values were the number 0 (not as string),
// and that always led to a script error.
// I was able to avoid the error by adapting the "if"-query,
// by converting the first o[k] to a string.
// Like this: "if (k === key && o[k].toString() && o[k].type === value) {"
let getPath = function (object, search) {
function iter(o, p) {
return Object.keys(o).some(function (k) {
if (k === key && o[k].toString() && o[k].type === value) {
path = p.concat(k).join('.');
return true;
}
if (o[k] !== null && typeof o[k] === 'object') {
return iter(o[k],
k === 'properties' && !o.title ?
p :
p.concat(k === 'properties' && o.title ? o.title : k)
);
}
});
}
let parts = search.split(':'),
key = parts[0],
value = parts[1],
path;
iter(object, []);
// IMPORTANT NOTE @Dev:
// the "path" would be the path to the object-property
// separated by a dot e.g. // myProp1.myProp11.myProp111
// return path;
let myColumn = path.split(".").length;
return myColumn;
};
// Source code found here:
// https://stackoverflow.com/questions/13523951/how-to-check-the-depth-of-an-object
let findOutHowManyColumnsTheTableNeeds = function(object) {
let level = 1;
for(let key in object) {
if (!object.hasOwnProperty(key)) continue;
if(typeof object[key] == 'object'){
let depth = findOutHowManyColumnsTheTableNeeds(object[key]) + 1;
level = Math.max(depth, level);
}
}
return level;
};
/**
* 2
* Get the right table row, column and value of the properties.
**/
function walkThrough(myBIGJSON) {
let propNames = Object.getOwnPropertyNames(myBIGJSON);
let props = Object.keys(myBIGJSON);
for (let i=0; i<propNames.length; i++){
let prop = myBIGJSON[propNames[i]];
let flagArrBool = Array.isArray(prop);
if (typeof prop == 'object' && prop !== null && flagArrBool != true) {
// Here we have the situation, that we have a property which has a deeper Object in it as value
internalSettings.tableRowContent = internalSettings.rowNumber + "|" + getPath(internalSettings.myBIGJSONPrototype, props[i]) + "|" + props[i];
internalSettings.completeTableContentSorted.push(internalSettings.tableRowContent);
internalSettings.rowNumber++;
walkThrough(prop); // RECURSIVE !
} else {
// Here we have the situation, that the property has a value which needs to be placed in the same line
if (typeof props[i] != "undefined" && props[i] != null && props[i] != 0){
internalSettings.columnNumber = getPath(internalSettings.myBIGJSONPrototype, props[i]);
internalSettings.tableRowContent = internalSettings.rowNumber + "|" + getPath(internalSettings.myBIGJSONPrototype, props[i]) + "|" + props[i];
// Increase column-counter for the value of the property in the same line
internalSettings.columnNumber = parseInt(internalSettings.columnNumber) + 1;
internalSettings.tableRowContent = internalSettings.tableRowContent + "|" + prop;
internalSettings.completeTableContentSorted.push(internalSettings.tableRowContent);
internalSettings.rowNumber++;
}
}
}
};
/**
* 1
* We need to find out how many columns the table will need,
* then we walkThrough the JSON to get all the wanted content,
* means the property-names, their values
* and find out where they have to be positioned in the table.
*
* Then we prepare a list (completeTableContentSorted) where
* we remember the collected informations.
*
* An entry could look like: "10|5|title|ghost in the shell"
* To be read like: row 10, column 5, property-name "title" and value "ghost in the shell"
**/
let getTablePositions = function(myBIGJSON){
internalSettings.columnsAmount = findOutHowManyColumnsTheTableNeeds(myBIGJSON);
walkThrough(myBIGJSON);
createTable(); // htm-table
};
/**
* PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC
* PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC PUBLIC
*/
/**
* 0 entrypoint
**/
this.init = function(myBIGJSON, DOMTargetContainer){
// We want to remeber the original JSON-object, we could need it later on.
internalSettings.myBIGJSONPrototype = myBIGJSON;
DOM.tableContainer = DOMTargetContainer;
getTablePositions(myBIGJSON);
};
};
/********************************************************************************
* INSTANTIATE (with "new") the Variable "JSON2Table" *
* with the class "convertJSON2Table" to make the class available to be invoked *
********************************************************************************/
let JSON2Table = new convertJSON2Table();