@@ -2,12 +2,11 @@ import { BasePattern } from "@patternslib/patternslib/src/core/basepattern";
22import Parser from "@patternslib/patternslib/src/core/parser" ;
33import events from "@patternslib/patternslib/src/core/events" ;
44import registry from "@patternslib/patternslib/src/core/registry" ;
5- import utils from "@patternslib/patternslib/src/core/utils" ;
65
76export const parser = new Parser ( "code-editor" ) ;
87parser . addArgument ( "language" , null ) ; // programming language to use.
98parser . addArgument ( "linenumbers" , false ) ;
10- parser . addArgument ( "theme" , null ) ; // theme to use .
9+ parser . addArgument ( "theme" , "dark" ) ; // dark or light or any other theme variant .
1110
1211// CodeJar options
1312parser . addArgument ( "tab" , " " ) ; // The tab-string. "\t" for real tabs.
@@ -18,58 +17,97 @@ parser.addArgument("preserve-ident", true);
1817parser . addArgument ( "add-closing" , true ) ;
1918parser . addArgument ( "history" , true ) ;
2019
20+ const language_mapping = {
21+ atom : "xml" ,
22+ html : "xml" ,
23+ plist : "xml" ,
24+ rss : "xml" ,
25+ svg : "xml" ,
26+ wsf : "xml" ,
27+ xhtml : "xml" ,
28+ xjb : "xml" ,
29+ xsd : "xml" ,
30+ xsl : "xml" ,
31+ } ;
32+
2133class Pattern extends BasePattern {
2234 static name = "code-editor" ;
2335 static trigger = ".pat-code-editor" ;
2436 static parser = parser ;
2537
2638 async init ( ) {
2739 const CodeJar = ( await import ( "codejar" ) ) . CodeJar ;
28- const Prism = ( await import ( "prismjs" ) ) . default ;
40+ const hljs = ( await import ( "highlight.js/lib/core" ) ) . default ;
41+ let el = this . el ;
42+
43+ // Set and load the theme.
44+ let theme ;
45+ if ( this . options . theme === "light" ) {
46+ theme = "stackoverflow-light" ;
47+ } else if ( this . options . theme === "dark" ) {
48+ theme = "stackoverflow-dark" ;
49+ } else {
50+ theme = this . options . theme ;
51+ }
52+ import ( `highlight.js/styles/${ theme } .css` ) ;
53+ if ( window . __patternslib_import_styles ) {
54+ import ( "./_code-editor.scss" ) ;
55+ }
56+
57+ // Custom hightlighting function, as of:
58+ // https://github.com/antonmedv/codejar/blob/master/index.html
59+ const highlight = ( editor ) => {
60+ // highlight.js does not trim old tags,
61+ // let's do it by this hack.
62+ editor . textContent = editor . textContent ;
63+ hljs . highlightElement ( editor ) ;
64+ } ;
65+ let highlight_wrapper = highlight ;
2966
30- let prism_wrapper = Prism . highlightElement ;
67+ // Optional line numbers.
3168 if ( this . options . linenumbers ) {
3269 const linenumbers = ( await import ( "codejar/linenumbers" ) ) . withLineNumbers ;
33- prism_wrapper = linenumbers ( Prism . highlightElement ) ;
70+ highlight_wrapper = linenumbers ( highlight , {
71+ class : `codejar-linenumbers ${ theme } ` ,
72+ } ) ;
3473 }
3574
36- let el = this . el ;
75+ // Import and register the language.
76+ let language = [ ...el . classList ] . filter ( ( it ) => it . startsWith ( "language-" ) ) [ 0 ] ;
77+ language = language ? language . replace ( "language-" , "" ) : this . options . language ;
78+ language = language || "plaintext" ;
79+ const hljs_language = (
80+ await import (
81+ `highlight.js/lib/languages/${ language_mapping [ language ] || language } `
82+ )
83+ ) . default ;
84+ hljs . registerLanguage ( language , hljs_language ) ;
85+
86+ // Create a editor element in case of an input element.
3787 if ( [ "textarea" , "input" ] . includes ( this . el . nodeName . toLowerCase ( ) ) ) {
38- const unescaped_html = utils . unescape_html ( this . el . value ) ;
39- const language_class = this . options . language
40- ? `language-${ this . options . language } `
41- : "" ;
4288 const pre_el = document . createElement ( "pre" ) ;
43- el = document . createElement ( "code" ) ;
44- el . setAttribute ( "class" , language_class ) ;
45- el . setAttribute ( "contenteditable" , "" ) ;
46- el . style . display = "block" ;
47- el . textContent = unescaped_html ;
48- pre_el . append ( el ) ;
89+ pre_el . innerHTML = `<code contenteditable></code>` ;
90+ el = pre_el . querySelector ( "code" ) ;
91+ el . textContent = this . el . value ; // value is already unescaped.
4992 this . el . parentNode . insertBefore ( pre_el , this . el ) ;
5093 this . el . setAttribute ( "hidden" , "" ) ;
5194 }
5295
53- if ( this . options . language ) {
54- el . classList . add ( `language-${ this . options . language } ` ) ;
55- }
56-
57- el . classList . add ( `theme-${ this . options . theme || "default" } ` ) ;
58-
59- import (
60- `prismjs/themes/prism${
61- this . options . theme ? "-" + this . options . theme : ""
62- } .css`
96+ // Add some classes to the editor element.
97+ el . classList . add (
98+ "code-editor" ,
99+ `theme-${ this . options . theme } ` ,
100+ `language-${ language } `
63101 ) ;
64- //import("./code-editor.scss");
65102
66- // Allow spaces withing quotes to be added as tab argument.
103+ // Allow spaces within quotes to be added as tab argument.
67104 // Replace escaped tab character with real tab.
68105 const tab = this . options . tab
69106 . replace ( / ' / g, "" ) // Allow spaces within quotes
70107 . replace ( / " / g, "" )
71108 . replace ( / \\ t / g, "\t" ) ; // Replace double escaped tab character
72109
110+ // Create the editor.
73111 const config = {
74112 tab : tab ,
75113 indentOn : new RegExp ( this . options . indentOn ) ,
@@ -79,14 +117,14 @@ class Pattern extends BasePattern {
79117 addClosing : this . options . addClosing ,
80118 history : this . options . history ,
81119 } ;
120+ this . codeeditor = CodeJar ( el , highlight_wrapper , config ) ;
82121
83- this . codeeditor = CodeJar ( el , prism_wrapper , config ) ;
84-
122+ // Update the input element.
85123 if ( el !== this . el ) {
86124 // Update <textarea> or <input>, if one of these were the
87125 // initializing elements.
88126 this . codeeditor . onUpdate ( ( code ) => {
89- this . el . value = code ;
127+ this . el . value = code . trim ( ) ;
90128 this . el . dispatchEvent ( events . input_event ( ) ) ;
91129 } ) ;
92130 }
0 commit comments