Skip to content

Commit 67accf2

Browse files
committed
Add JSON highlighting demo.
1 parent ee0a558 commit 67accf2

File tree

3 files changed

+238
-0
lines changed

3 files changed

+238
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ with.
1010

1111
## My JavaScript Demos - I Love JavaScript!
1212

13+
* [Highlighting Dynamic Parts Of A Pretty-Printed JSON Value](https://bennadel.github.io/JavaScript-Demos/demos/highlighting-json)
1314
* [Exploring Randomness In JavaScript](https://bennadel.github.io/JavaScript-Demos/demos/web-crypto-rand)
1415
* [Color Palette Utility In Alpine.js](https://bennadel.github.io/JavaScript-Demos/demos/color-palette)
1516
* [Using Both Tab And Arrow Keys For Keyboard Navigation](https://bennadel.github.io/JavaScript-Demos/demos/tab-group)

demos/highlighting-json/index.htm

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>
7+
Highlighting Dynamic Parts Of A Pretty-Printed JSON Value
8+
</title>
9+
<link rel="stylesheet" type="text/css" href="./main.css" />
10+
</head>
11+
<body>
12+
13+
<h1>
14+
Highlighting Dynamic Parts Of A Pretty-Printed JSON Value
15+
</h1>
16+
17+
<div x-data="Demo">
18+
<form>
19+
<input
20+
type="text"
21+
x-model="form.firstName"
22+
@input="updatePolicy()"
23+
placeholder="First name..."
24+
/>
25+
<input
26+
type="text"
27+
x-model="form.lastName"
28+
@input="updatePolicy()"
29+
placeholder="Last name..."
30+
/>
31+
<button type="button" @click="copyPolicy()">
32+
Copy
33+
</button>
34+
</form>
35+
36+
<!--
37+
The JSON for the policy will be accessible in two ways. First, the user can
38+
use the COPY button above; and second, the user will need to be able to copy-
39+
paste the text right out of the page. As such, white-space is relevant.
40+
--
41+
Note: Since PRE tags make strict use of white-space, I'm mangling my HTML tags
42+
such that the line-breaks are part of the tag element and not part of the
43+
interstitial tag space. This provides better readability without introducing
44+
additional line-breaks in the output.
45+
-->
46+
<pre
47+
><code
48+
><template x-for="segment in policyParts"
49+
><span
50+
x-text="segment.value"
51+
:class="{
52+
highlight: segment.highlight
53+
}"
54+
></span
55+
></template
56+
></code
57+
></pre>
58+
</div>
59+
60+
<script type="text/javascript" src="../../vendor/alpine/3.13.5/alpine.3.13.5.min.js" defer></script>
61+
<script type="text/javascript">
62+
63+
function Demo() {
64+
65+
return {
66+
form: {
67+
firstName: "",
68+
lastName: ""
69+
},
70+
policyParts: [],
71+
policyJson: "",
72+
73+
// Public methods.
74+
init: $init,
75+
copyPolicy: copyPolicy,
76+
updatePolicy: updatePolicy,
77+
78+
// Private methods.
79+
_buildPolicy: buildPolicy
80+
}
81+
82+
// ---
83+
// PUBLIC METHODS.
84+
// ---
85+
86+
/**
87+
* I initialize the component.
88+
*/
89+
function $init() {
90+
91+
this.updatePolicy();
92+
93+
}
94+
95+
/**
96+
* I copy the current policy to the user's clipboard (not really).
97+
*/
98+
function copyPolicy() {
99+
100+
console.group( "Mock copy to Clipboard" );
101+
console.log( this.policyJson );
102+
console.groupEnd();
103+
104+
}
105+
106+
/**
107+
* I update the policy using the current form view-model.
108+
*/
109+
function updatePolicy() {
110+
111+
// First, we're going build a data-structure that contains placeholder
112+
// values with a known pattern.
113+
var policy = this._buildPolicy( ":::firstName:::", ":::lastName:::" );
114+
var fallbacks = {
115+
firstName: "YOUR_FIRST_NAME",
116+
lastName: "YOUR_LAST_NAME",
117+
};
118+
119+
// Second, we're going to STRINGIFY the data structure and SPLIT the JSON
120+
// payload on the known pattern. And, by including part of the pattern in
121+
// a capturing group, the .split() method will return each "delimiter" as
122+
// an element interleaved with the rest of the natural segments. These
123+
// segments will then be mapped onto an array of parts to be rendered in
124+
// the PRE/CODE UI.
125+
this.policyParts = JSON
126+
.stringify( policy, null, 4 )
127+
.split( /:::(\w+):::/g )
128+
.map(
129+
( segment, i ) => {
130+
131+
// Since we're capturing part of the delimiter, we know that
132+
// the placeholder token is always in the ODD index. These
133+
// segments will be highlighted in the output.
134+
if ( i % 2 ) {
135+
136+
return {
137+
value: ( this.form[ segment ] || fallbacks[ segment ] ),
138+
highlight: true
139+
};
140+
141+
}
142+
143+
return {
144+
value: segment
145+
};
146+
147+
}
148+
)
149+
;
150+
151+
// Once we have all our JSON parts, we can create the full JSON structure
152+
// but combining all the values.
153+
// --
154+
// Note: I could have just called JSON.stringify(buildPolicy()) again. But
155+
// this approach makes sure that all of the white-space is the same and
156+
// none of the logic is duplicated.
157+
this.policyJson = this.policyParts
158+
.map( part => part.value )
159+
.join( "" )
160+
;
161+
162+
}
163+
164+
// ---
165+
// PRIVATE METHODS.
166+
// ---
167+
168+
/**
169+
* I build the policy data structure using the given values.
170+
*/
171+
function buildPolicy( firstName, lastName ) {
172+
173+
return {
174+
plan: "WOOT.7.17",
175+
version: 3,
176+
holder: {
177+
firstName: firstName,
178+
lastName: lastName
179+
},
180+
expires: "2025-01-01"
181+
};
182+
183+
}
184+
185+
}
186+
187+
</script>
188+
189+
</body>
190+
</html>

demos/highlighting-json/main.css

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
html {
3+
box-sizing: border-box ;
4+
}
5+
html *,
6+
html *:before,
7+
html *:after {
8+
box-sizing: inherit ;
9+
}
10+
11+
body {
12+
font-family: monospace ;
13+
font-size: 18px ;
14+
line-height: 1.4 ;
15+
}
16+
17+
form {
18+
display: flex ;
19+
gap: 7px ;
20+
margin: 0 0 10px 0 ;
21+
}
22+
form input,
23+
form button {
24+
font-family: inherit ;
25+
font-size: inherit ;
26+
}
27+
form input {
28+
padding: 8px ;
29+
}
30+
form button {
31+
padding: 8px 12px ;
32+
}
33+
34+
pre {
35+
background-color: #f0f0f0 ;
36+
border: 1px solid #cccccc ;
37+
border-radius: 4px ;
38+
margin: 0 ;
39+
padding: 20px ;
40+
}
41+
42+
.highlight {
43+
background-color: yellow ;
44+
display: inline-block ;
45+
font-weight: bold ;
46+
padding-inline: 7px ;
47+
}

0 commit comments

Comments
 (0)