1- import * as jsondiffpatch from 'jsondiffpatch/with-text-diffs' ;
1+ import { parse as json5Parse } from 'json5' ;
2+
23import * as annotatedFormatter from 'jsondiffpatch/formatters/annotated' ;
34import * as htmlFormatter from 'jsondiffpatch/formatters/html' ;
5+ import * as jsondiffpatch from 'jsondiffpatch/with-text-diffs' ;
46
5- import 'jsondiffpatch/formatters/styles/html.css' ;
67import 'jsondiffpatch/formatters/styles/annotated.css' ;
8+ import 'jsondiffpatch/formatters/styles/html.css' ;
79
810declare namespace CodeMirror {
911 function fromTextArea (
@@ -15,12 +17,15 @@ declare namespace CodeMirror {
1517 mode ?: string ;
1618 json ?: boolean ;
1719 readOnly ?: boolean ;
20+ theme ?: string ;
1821 }
1922
2023 interface Editor {
2124 getValue ( ) : string ;
2225 setValue ( content : string ) : void ;
2326 on ( eventName : 'change' , handler : ( ) => void ) : void ;
27+ refresh ( ) : void ;
28+ setOption ( option : 'theme' , value : string ) : void ;
2429 }
2530}
2631
@@ -43,6 +48,61 @@ interface Country {
4348 population ?: number ;
4449}
4550
51+ const colorSchemeIsDark = ( ) => {
52+ const colorSchemaMeta =
53+ (
54+ ( document . querySelector (
55+ 'meta[name="color-scheme"]' ,
56+ ) as HTMLMetaElement ) || null
57+ ) . content || 'default' ;
58+ return (
59+ colorSchemaMeta === 'only dark' ||
60+ ( colorSchemaMeta !== 'only light' &&
61+ window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches )
62+ ) ;
63+ } ;
64+
65+ const onColorSchemeChange = ( handler : ( dark ?: boolean ) => void ) => {
66+ window
67+ . matchMedia ( '(prefers-color-scheme: dark)' )
68+ . addEventListener ( 'change' , ( e ) => {
69+ handler ( colorSchemeIsDark ( ) ) ;
70+ } ) ;
71+ // also detect changes to the meta tag content
72+ const colorSchemaMeta = document . querySelector (
73+ 'meta[name="color-scheme"]' ,
74+ ) as HTMLMetaElement ;
75+ if ( colorSchemaMeta ) {
76+ const observer = new MutationObserver ( ( mutationsList ) => {
77+ for ( const mutation of mutationsList ) {
78+ if (
79+ mutation . type === 'attributes' &&
80+ mutation . attributeName === 'content'
81+ ) {
82+ handler ( colorSchemeIsDark ( ) ) ;
83+ }
84+ }
85+ } ) ;
86+ observer . observe ( colorSchemaMeta , { attributes : true } ) ;
87+ }
88+ } ;
89+
90+ document . body . setAttribute (
91+ 'data-color-scheme' ,
92+ colorSchemeIsDark ( ) ? 'dark' : 'light' ,
93+ ) ;
94+ onColorSchemeChange ( ( dark ) => {
95+ document . body . setAttribute ( 'data-color-scheme' , dark ? 'dark' : 'light' ) ;
96+ } ) ;
97+
98+ const parseJson = ( text : string ) => {
99+ try {
100+ return JSON . parse ( text , jsondiffpatch . dateReviver ) ;
101+ } catch {
102+ return json5Parse ( text , jsondiffpatch . dateReviver ) ;
103+ }
104+ } ;
105+
46106const getExampleJson = function ( ) {
47107 const data : Continent = {
48108 name : 'South America' ,
@@ -256,13 +316,19 @@ const dom = {
256316 url : string ,
257317 callback : ( error : Error | string | null , data ?: unknown ) => void ,
258318 ) {
319+ if ( ! url . startsWith ( 'https://api.github.com/gists' ) ) {
320+ return callback (
321+ null ,
322+ 'invalid url, for security reasons only gists are allowed' ,
323+ ) ;
324+ }
259325 let request : XMLHttpRequest | null = new XMLHttpRequest ( ) ;
260326 request . open ( 'GET' , url , true ) ;
261327 request . onreadystatechange = function ( ) {
262328 if ( this . readyState === 4 ) {
263329 let data ;
264330 try {
265- data = JSON . parse ( this . responseText , jsondiffpatch . dateReviver ) ;
331+ data = parseJson ( this . responseText ) ;
266332 } catch ( parseError ) {
267333 return callback ( 'parse error: ' + parseError ) ;
268334 }
@@ -337,7 +403,7 @@ class JsonArea {
337403 / ^ [ " ] .* [ " ] $ / . test ( txt ) ||
338404 / ^ [ { [ ] ( .| \n ) * [ } \] ] $ / . test ( txt )
339405 ) {
340- return JSON . parse ( txt , jsondiffpatch . dateReviver ) ;
406+ return parseJson ( txt ) ;
341407 }
342408 return this . getValue ( ) ;
343409 } catch ( err ) {
@@ -366,11 +432,22 @@ class JsonArea {
366432 if ( typeof CodeMirror === 'undefined' ) {
367433 return ;
368434 }
369- this . editor = CodeMirror . fromTextArea ( this . element , {
435+
436+ // Function to get current theme based on browser's interpreted scheme
437+ const getTheme = ( ) => ( colorSchemeIsDark ( ) ? 'monokai' : 'default' ) ;
438+
439+ const editor = CodeMirror . fromTextArea ( this . element , {
370440 mode : 'javascript' ,
371441 json : true ,
372442 readOnly,
443+ theme : getTheme ( ) ,
444+ } ) ;
445+ this . editor = editor ;
446+
447+ onColorSchemeChange ( ( ) => {
448+ editor . setOption ( 'theme' , getTheme ( ) ) ;
373449 } ) ;
450+
374451 if ( ! readOnly ) {
375452 this . editor . on ( 'change' , compare ) ;
376453 }
@@ -465,6 +542,7 @@ const compare = function () {
465542
466543areas . left . makeEditor ( ) ;
467544areas . right . makeEditor ( ) ;
545+ areas . delta . makeEditor ( true ) ;
468546
469547areas . left . element . addEventListener ( 'change' , compare ) ;
470548areas . right . element . addEventListener ( 'change' , compare ) ;
@@ -501,6 +579,9 @@ const showSelectedDeltaType = function () {
501579 document . getElementById ( 'delta-panel-json' ) ! . style . display =
502580 type === 'json' ? '' : 'none' ;
503581 compare ( ) ;
582+ if ( type === 'json' ) {
583+ areas . delta . editor ! . refresh ( ) ;
584+ }
504585} ;
505586
506587document
@@ -821,18 +902,6 @@ if (urlQuery) {
821902 } ) ,
822903 ) ;
823904 break ;
824- case 'urls' :
825- document . location =
826- '?desc=http%20raw%20file%20urls&left=' +
827- encodeURIComponent (
828- 'https://rawgithub.com/benjamine/JsonDiffPatch/' +
829- 'c83e942971c627f61ef874df3cfdd50a95f1c5a2/package.json' ,
830- ) +
831- '&right=' +
832- encodeURIComponent (
833- 'https://rawgithub.com/benjamine/JsonDiffPatch/master/package.json' ,
834- ) ;
835- break ;
836905 default :
837906 document . location = '?' ;
838907 break ;
0 commit comments