@@ -43,6 +43,180 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e)
4343
4444initTheme ( ) ;
4545
46+ // Examples data
47+ const exampleCases = [
48+ {
49+ id : 'math' ,
50+ title : 'Mathematical Expression' ,
51+ description : 'Basic math operations with variables' ,
52+ expression : '(x + y) * multiplier + sqrt(16)' ,
53+ context : {
54+ x : 10 ,
55+ y : 5 ,
56+ multiplier : 3
57+ }
58+ } ,
59+ {
60+ id : 'arrays' ,
61+ title : 'Working with Arrays' ,
62+ description : 'Array functions like sum, min, max' ,
63+ expression : 'sum(numbers) + max(numbers) - min(numbers)' ,
64+ context : {
65+ numbers : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] ,
66+ values : [ 15 , 25 , 35 ]
67+ }
68+ } ,
69+ {
70+ id : 'objects' ,
71+ title : 'Object Manipulation' ,
72+ description : 'Access nested object properties' ,
73+ expression : 'user.profile.score * level.multiplier + bonus.points' ,
74+ context : {
75+ user : {
76+ name : "Alice" ,
77+ profile : {
78+ score : 85 ,
79+ rank : "Gold"
80+ }
81+ } ,
82+ level : {
83+ current : 5 ,
84+ multiplier : 1.5
85+ } ,
86+ bonus : {
87+ points : 100 ,
88+ active : true
89+ }
90+ }
91+ } ,
92+ {
93+ id : 'map-filter' ,
94+ title : 'Map and Filter Functions' ,
95+ description : 'Transform and filter data with callbacks' ,
96+ expression : 'sum(map(filter(items, item => item > 3), x => x * 2))' ,
97+ context : {
98+ items : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ,
99+ threshold : 3
100+ }
101+ } ,
102+ {
103+ id : 'complex' ,
104+ title : 'Complex Objects' ,
105+ description : 'Work with deeply nested data structures' ,
106+ expression : 'company.departments[0].employees.length * company.settings.bonusRate + sum(map(company.departments, d => d.budget))' ,
107+ context : {
108+ company : {
109+ name : "TechCorp" ,
110+ departments : [
111+ {
112+ name : "Engineering" ,
113+ budget : 500000 ,
114+ employees : [ "John" , "Jane" , "Bob" ]
115+ } ,
116+ {
117+ name : "Marketing" ,
118+ budget : 200000 ,
119+ employees : [ "Alice" , "Carol" ]
120+ }
121+ ] ,
122+ settings : {
123+ bonusRate : 0.15 ,
124+ fiscalYear : 2024
125+ }
126+ }
127+ }
128+ } ,
129+ {
130+ id : 'data-transform' ,
131+ title : 'Data Transformation' ,
132+ description : 'Flatten nested objects and transform rows' ,
133+ expression : "map(f(row) = {_id: row.rowId} + flatten(row.data, ''), $event)" ,
134+ context : {
135+ "$event" : [
136+ { "rowId" : 1 , "state" : "saved" , "data" : { "InventoryId" : 1256 , "Description" : "Bal" , "Weight" : { "Unit" : "g" , "Amount" : 120 } } } ,
137+ { "rowId" : 2 , "state" : "new" , "data" : { "InventoryId" : 2344 , "Description" : "Basket" , "Weight" : { "Unit" : "g" , "Amount" : 300 } } } ,
138+ { "rowId" : 3 , "state" : "unchanged" , "data" : { "InventoryId" : 9362 , "Description" : "Wood" , "Weight" : { "Unit" : "kg" , "Amount" : 18 } } }
139+ ]
140+ }
141+ }
142+ ] ;
143+
144+ // Render examples sidebar
145+ function renderExamplesSidebar ( ) {
146+ const examplesList = document . getElementById ( 'examplesList' ) ;
147+ if ( ! examplesList ) return ;
148+
149+ examplesList . innerHTML = exampleCases . map ( example => `
150+ <button
151+ class="example-item w-full text-left p-3 rounded-lg transition-all duration-200
152+ hover:bg-white dark:hover:bg-[#2d2d2d]
153+ hover:shadow-sm hover:border-indigo-200 dark:hover:border-[#3c3c3c]
154+ border border-transparent
155+ group"
156+ data-example-id="${ example . id } "
157+ >
158+ <div class="flex items-start gap-2">
159+ <div class="flex-shrink-0 w-6 h-6 rounded bg-indigo-100 dark:bg-[#3c3c3c] flex items-center justify-center mt-0.5">
160+ <svg class="w-3.5 h-3.5 text-indigo-600 dark:text-[#569cd6]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
161+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
162+ </svg>
163+ </div>
164+ <div class="flex-1 min-w-0">
165+ <p class="text-sm font-medium text-gray-800 dark:text-[#cccccc] truncate group-hover:text-indigo-600 dark:group-hover:text-[#569cd6]">
166+ ${ example . title }
167+ </p>
168+ <p class="text-xs text-gray-500 dark:text-[#808080] mt-0.5 line-clamp-2">
169+ ${ example . description }
170+ </p>
171+ </div>
172+ </div>
173+ </button>
174+ ` ) . join ( '' ) ;
175+
176+ // Add click handlers
177+ examplesList . querySelectorAll ( '.example-item' ) . forEach ( button => {
178+ button . addEventListener ( 'click' , ( ) => {
179+ const exampleId = button . dataset . exampleId ;
180+ const example = exampleCases . find ( e => e . id === exampleId ) ;
181+ if ( example ) {
182+ loadExample ( example ) ;
183+ }
184+ } ) ;
185+ } ) ;
186+ }
187+
188+ // Load example into editors
189+ function loadExample ( example ) {
190+ if ( typeof expressionEditor !== 'undefined' && expressionEditor ) {
191+ expressionEditor . getModel ( ) . setValue ( example . expression ) ;
192+ }
193+ if ( typeof contextEditor !== 'undefined' && contextEditor ) {
194+ contextEditor . getModel ( ) . setValue ( JSON . stringify ( example . context , null , 2 ) ) ;
195+ }
196+ }
197+
198+ // Initialize sidebar
199+ renderExamplesSidebar ( ) ;
200+
201+ // Get example ID from URL query parameter
202+ function getExampleFromUrl ( ) {
203+ const params = new URLSearchParams ( window . location . search ) ;
204+ return params . get ( 'example' ) ;
205+ }
206+
207+ // Load example from URL if present (called after Monaco initializes)
208+ function loadExampleFromUrl ( ) {
209+ const exampleId = getExampleFromUrl ( ) ;
210+ if ( exampleId ) {
211+ const example = exampleCases . find ( e => e . id === exampleId ) ;
212+ if ( example ) {
213+ loadExample ( example ) ;
214+ return true ;
215+ }
216+ }
217+ return false ;
218+ }
219+
46220// Split pane resizing
47221( function ( ) {
48222 const resizer = document . getElementById ( 'resizer' ) ;
@@ -281,24 +455,22 @@ require(['vs/editor/editor.main'], function () {
281455 } ) ;
282456
283457 // Syntax highlighting
458+ let highlightDecorations = [ ] ;
459+
284460 function applyHighlighting ( ) {
285461 const doc = makeTextDocument ( expressionModel ) ;
286462 const tokens = ls . getHighlighting ( doc ) ;
287- const rangesByClass = new Map ( ) ;
288- for ( const t of tokens ) {
463+ const decorations = tokens . map ( t => {
289464 const start = expressionModel . getPositionAt ( t . start ) ;
290465 const end = expressionModel . getPositionAt ( t . end ) ;
291- const range = new monaco . Range ( start . lineNumber , start . column , end . lineNumber , end . column ) ;
292- const cls = 'tok-' + t . type ;
293- if ( ! rangesByClass . has ( cls ) ) rangesByClass . set ( cls , [ ] ) ;
294- rangesByClass . get ( cls ) . push ( { range, options : { inlineClassName : cls } } ) ;
295- }
296-
297- window . __exprEvalDecos = window . __exprEvalDecos || { } ;
298- for ( const [ cls , decos ] of rangesByClass . entries ( ) ) {
299- const prev = window . __exprEvalDecos [ cls ] || [ ] ;
300- window . __exprEvalDecos [ cls ] = expressionEditor . deltaDecorations ( prev , decos ) ;
301- }
466+ return {
467+ range : new monaco . Range ( start . lineNumber , start . column , end . lineNumber , end . column ) ,
468+ options : { inlineClassName : 'tok-' + t . type }
469+ } ;
470+ } ) ;
471+
472+ // deltaDecorations replaces old decorations with new ones atomically
473+ highlightDecorations = expressionEditor . deltaDecorations ( highlightDecorations , decorations ) ;
302474 }
303475
304476 // Result display functions
@@ -443,6 +615,9 @@ require(['vs/editor/editor.main'], function () {
443615 applyHighlighting ( ) ;
444616 evaluate ( ) ;
445617
618+ // Load example from URL query parameter if present
619+ loadExampleFromUrl ( ) ;
620+
446621 // Event listeners for changes
447622 expressionModel . onDidChangeContent ( ( ) => {
448623 applyHighlighting ( ) ;
0 commit comments