1+ import { component } from "../model/components.ts" ;
2+ import { Node } from "../model/mod.ts" ;
3+
4+
5+ export interface CodeExecutor {
6+ // executes the source and returns an output string.
7+ // exceptions in execution should be caught and returned as a string.
8+ execute ( source : string , options : ExecuteOptions ) : string ;
9+ }
10+
11+ export interface ExecuteOptions {
12+ language : string ;
13+ }
14+
15+ // defaultExecutor can be replaced with an external service, etc
16+ export let defaultExecutor : CodeExecutor = {
17+ execute : ( source : string , options : ExecuteOptions ) : string => {
18+ if ( options . language !== "javascript" ) {
19+ return `Unsupported language: ${ options . language } ` ;
20+ }
21+ return JSON . stringify ( window . eval ( source ) ) ;
22+ }
23+ }
24+
25+
26+
27+ @component
28+ export class CodeBlock {
29+ code : string ;
30+
31+ constructor ( ) {
32+ this . code = "" ;
33+ }
34+
35+ childrenView ( ) {
36+ return CodeEditor ;
37+ }
38+
39+ handleIcon ( collapsed : boolean = false ) : any {
40+ return (
41+ < svg xmlns = "http://www.w3.org/2000/svg" width = "15" height = "15" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" class = "node-bullet" >
42+ < polyline points = "16 18 22 12 16 6" > </ polyline >
43+ < polyline points = "8 6 2 12 8 18" > </ polyline >
44+ </ svg >
45+ ) ;
46+ }
47+
48+ static initialize ( workbench : Workbench ) {
49+ workbench . commands . registerCommand ( {
50+ id : "make-code-snippet" ,
51+ title : "Make Code Snippet" ,
52+ when : ( ctx : Context ) => {
53+ if ( ! ctx . node ) return false ;
54+ if ( ctx . node . raw . Rel === "Fields" ) return false ;
55+ if ( ctx . node . parent && ctx . node . parent . hasComponent ( Document ) ) return false ;
56+ return true ;
57+ } ,
58+ action : ( ctx : Context ) => {
59+ const com = new CodeBlock ( ) ;
60+ ctx . node . addComponent ( com ) ;
61+ ctx . node . changed ( ) ;
62+ workbench . workspace . setExpanded ( ctx . path . head , ctx . path . node , true ) ;
63+ }
64+ } ) ;
65+ }
66+
67+ }
68+
69+
70+ const CodeEditor = {
71+ oncreate ( { dom, attrs : { path} } ) {
72+ const snippet = path . node . getComponent ( CodeBlock ) ;
73+ dom . jarEditor = new window . CodeJar ( dom , ( editor ) => {
74+ // highlight.js does not trim old tags,
75+ // let's do it by this hack.
76+ editor . textContent = editor . textContent ;
77+ window . hljs . highlightBlock ( editor ) ;
78+ } ) ;
79+ dom . jarEditor . updateCode ( snippet . code ) ;
80+ dom . jarEditor . onUpdate ( code => {
81+ snippet . code = code ;
82+ path . node . changed ( ) ;
83+ } ) ;
84+ } ,
85+
86+ view ( { attrs : { workbench, path} } ) {
87+ // this cancels the keydown on the outline node
88+ // so you can use arrow keys normally
89+ const onkeydown = ( e ) => e . stopPropagation ( ) ;
90+
91+ return (
92+ < div class = "code-editor" onkeydown = { onkeydown } > </ div >
93+ )
94+ }
95+ }
0 commit comments