From 9b4fdc28812e13c48ccffc3e3fd8f17fc4788fba Mon Sep 17 00:00:00 2001 From: Hunter Koppen Date: Wed, 13 Nov 2024 13:47:11 +0100 Subject: [PATCH] Added on change event and fixed lint errors --- package-lock.json | 4 +- package.json | 2 +- src/CodeEditor.editorConfig.ts | 99 ++++++------ src/CodeEditor.tsx | 265 +++++++++++++++++---------------- src/CodeEditor.xml | 16 +- src/package.xml | 2 +- typings/CodeEditorProps.d.ts | 1 + 7 files changed, 202 insertions(+), 187 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7feeb96..9f2ee3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codeeditor", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codeeditor", - "version": "1.1.0", + "version": "1.1.1", "license": "Apache-2.0", "dependencies": { "ace-builds": "^1.36.2", diff --git a/package.json b/package.json index 8de8f8b..5258672 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codeeditor", "widgetName": "CodeEditor", - "version": "1.1.1", + "version": "1.1.2", "description": "Ace code editor, as a Mendix pluggable widget.", "copyright": "© Mendix Technology BV 2022. All rights reserved.", "author": "Carter Moorse", diff --git a/src/CodeEditor.editorConfig.ts b/src/CodeEditor.editorConfig.ts index deba739..b8ed3c3 100644 --- a/src/CodeEditor.editorConfig.ts +++ b/src/CodeEditor.editorConfig.ts @@ -34,66 +34,75 @@ export type Problem = { }; type BaseProps = { - type: "Image" | "Container" | "RowLayout" | "Text" | "DropZone" | "Selectable" | "Datasource"; - grow?: number; // optionally sets a growth factor if used in a layout (default = 1) -} + type: "Image" | "Container" | "RowLayout" | "Text" | "DropZone" | "Selectable" | "Datasource"; + grow?: number; // optionally sets a growth factor if used in a layout (default = 1) +}; type ImageProps = BaseProps & { - type: "Image"; - document?: string; // svg image - data?: string; // base64 image - property?: object; // widget image property object from Values API - width?: number; // sets a fixed maximum width - height?: number; // sets a fixed maximum height -} + type: "Image"; + document?: string; // svg image + data?: string; // base64 image + property?: object; // widget image property object from Values API + width?: number; // sets a fixed maximum width + height?: number; // sets a fixed maximum height +}; type ContainerProps = BaseProps & { - type: "Container" | "RowLayout"; - children: PreviewProps[]; // any other preview element - borders?: boolean; // sets borders around the layout to visually group its children - borderRadius?: number; // integer. Can be used to create rounded borders - backgroundColor?: string; // HTML color, formatted #RRGGBB - borderWidth?: number; // sets the border width - padding?: number; // integer. adds padding around the container -} + type: "Container" | "RowLayout"; + children: PreviewProps[]; // any other preview element + borders?: boolean; // sets borders around the layout to visually group its children + borderRadius?: number; // integer. Can be used to create rounded borders + backgroundColor?: string; // HTML color, formatted #RRGGBB + borderWidth?: number; // sets the border width + padding?: number; // integer. adds padding around the container +}; type RowLayoutProps = ContainerProps & { - type: "RowLayout"; - columnSize?: "fixed" | "grow" // default is fixed -} + type: "RowLayout"; + columnSize?: "fixed" | "grow"; // default is fixed +}; type TextProps = BaseProps & { - type: "Text"; - content: string; // text that should be shown - fontSize?: number; // sets the font size - fontColor?: string; // HTML color, formatted #RRGGBB - bold?: boolean; - italic?: boolean; -} + type: "Text"; + content: string; // text that should be shown + fontSize?: number; // sets the font size + fontColor?: string; // HTML color, formatted #RRGGBB + bold?: boolean; + italic?: boolean; +}; type DropZoneProps = BaseProps & { - type: "DropZone"; - property: object; // widgets property object from Values API - placeholder: string; // text to be shown inside the dropzone when empty - showDataSourceHeader?: boolean; // true by default. Toggles whether to show a header containing information about the datasource -} - + type: "DropZone"; + property: object; // widgets property object from Values API + placeholder: string; // text to be shown inside the dropzone when empty + showDataSourceHeader?: boolean; // true by default. Toggles whether to show a header containing information about the datasource +}; type SelectableProps = BaseProps & { - type: "Selectable"; - object: object; // object property instance from the Value API - child: PreviewProps; // any type of preview property to visualize the object instance -} + type: "Selectable"; + object: object; // object property instance from the Value API + child: PreviewProps; // any type of preview property to visualize the object instance +}; type DatasourceProps = BaseProps & { - type: "Datasource"; - property: object | null; // datasource property object from Values API - child?: PreviewProps; // any type of preview property component (optional) -} - -export type PreviewProps = ImageProps | ContainerProps | RowLayoutProps | TextProps | DropZoneProps | SelectableProps | DatasourceProps; + type: "Datasource"; + property: object | null; // datasource property object from Values API + child?: PreviewProps; // any type of preview property component (optional) +}; -export function getProperties(_values: CodeEditorPreviewProps, defaultProperties: Properties/*, target: Platform*/): Properties { +export type PreviewProps = + | ImageProps + | ContainerProps + | RowLayoutProps + | TextProps + | DropZoneProps + | SelectableProps + | DatasourceProps; + +export function getProperties( + _values: CodeEditorPreviewProps, + defaultProperties: Properties /* target: Platform */ +): Properties { // Do the values manipulation here to control the visibility of properties in Studio and Studio Pro conditionally. /* Example if (values.myProperty === "custom") { diff --git a/src/CodeEditor.tsx b/src/CodeEditor.tsx index 7752f9c..4b6138d 100644 --- a/src/CodeEditor.tsx +++ b/src/CodeEditor.tsx @@ -6,147 +6,150 @@ import "emmet"; import { CodeEditorContainerProps } from "../typings/CodeEditorProps"; export default class CodeEditor extends Component { - editorRef: RefObject = createRef(); - - static basePath = "widgets/carterm/codeeditor/src-min-noconflict"; + static basePath = "widgets/carterm/codeeditor/src-min-noconflict"; - loadAce(filename: string): Promise { - return new Promise((resolve) => { - const location = CodeEditor.basePath + "/" + filename; - const head = document.getElementsByTagName("head")[0]; - let script: HTMLScriptElement | null = document.querySelector("script[src=\"" + location + "\"]"); - if (script == null) { - script = document.createElement("script"); - script.src = location; - head.appendChild(script); - script.onload = () => { - script?.setAttribute("has-loaded", "true"); - resolve(script); - } - } - else if (script.getAttribute("has-loaded") == "true") { - resolve(script); - } - }) - } + editorRef: RefObject = createRef(); - loadModules() { - const editor = this.editorRef.current?.editor; - if (!editor) return; - - if (this.props.enableBasicAutocompletion || - this.props.enableLiveAutocompletion || - this.props.enableSnippets) { - this.loadAce("ext-language_tools.js").then(() => editor.setOptions({ - "enableBasicAutocompletion": this.props.enableBasicAutocompletion, - "enableLiveAutocompletion": this.props.enableLiveAutocompletion, - "enableSnippets": this.props.enableSnippets - })); - } - if (this.props.enableEmmet) { - this.loadAce("ext-emmet.js")//.then(() => editor.setOption("enableEmmet", this.props.enableEmmet)); + loadAce(filename: string): Promise { + return new Promise(resolve => { + const location = CodeEditor.basePath + "/" + filename; + const head = document.getElementsByTagName("head")[0]; + let script: HTMLScriptElement | null = document.querySelector('script[src="' + location + '"]'); + if (script == null) { + script = document.createElement("script"); + script.src = location; + head.appendChild(script); + script.onload = () => { + script?.setAttribute("has-loaded", "true"); + resolve(script); + }; + } else if (script.getAttribute("has-loaded") === "true") { + resolve(script); + } + }); } - if (this.props.useElasticTabstops) { - this.loadAce("ext-elastic_tabstops_lite.js")//.then(() => editor.setOption("useElasticTabstops", this.props.useElasticTabstops)); + + loadModules() { + const editor = this.editorRef.current?.editor; + if (!editor) { + return; + } + + if (this.props.enableBasicAutocompletion || this.props.enableLiveAutocompletion || this.props.enableSnippets) { + this.loadAce("ext-language_tools.js").then(() => + editor.setOptions({ + enableBasicAutocompletion: this.props.enableBasicAutocompletion, + enableLiveAutocompletion: this.props.enableLiveAutocompletion, + enableSnippets: this.props.enableSnippets + }) + ); + } + if (this.props.enableEmmet) { + this.loadAce("ext-emmet.js"); // .then(() => editor.setOption("enableEmmet", this.props.enableEmmet)); + } + if (this.props.useElasticTabstops) { + this.loadAce("ext-elastic_tabstops_lite.js"); // .then(() => editor.setOption("useElasticTabstops", this.props.useElasticTabstops)); + } } - } - componentDidMount(): void { - this.loadModules(); - } + componentDidMount(): void { + this.loadModules(); + } - componentDidUpdate(): void { - this.loadModules(); - } + componentDidUpdate(): void { + this.loadModules(); + } - render(): ReactNode { - return this.props.value.setValue(value)} - editorProps={{ $blockScrolling: true }} - setOptions={{ - /* - * editor options - */ - selectionStyle: this.props.selectionStyle, - highlightActiveLine: this.props.highlightActiveLine, - highlightSelectedWord: this.props.highlightSelectedWord, - readOnly: this.props.value.readOnly, - cursorStyle: this.props.cursorStyle, - mergeUndoDeltas: this.props.mergeUndoDeltas, - behavioursEnabled: this.props.behavioursEnabled, - wrapBehavioursEnabled: this.props.wrapBehavioursEnabled, - autoScrollEditorIntoView: this.props.autoScrollEditorIntoView, - copyWithEmptySelection: this.props.copyWithEmptySelection, - useSoftTabs: this.props.useSoftTabs, - navigateWithinSoftTabs: this.props.navigateWithinSoftTabs, - enableMultiselect: this.props.enableMultiselect, - enableAutoIndent: this.props.enableAutoIndent, - enableKeyboardAccessibility: this.props.enableKeyboardAccessibility, - /* - * renderer options - */ - hScrollBarAlwaysVisible: this.props.hScrollBarAlwaysVisible, - vScrollBarAlwaysVisible: this.props.vScrollBarAlwaysVisible, - highlightGutterLine: this.props.highlightGutterLine, - animatedScroll: this.props.animatedScroll, - showInvisibles: this.props.showInvisibles, - showPrintMargin: this.props.showPrintMargin, - printMarginColumn: this.props.printMarginColumn, - printMargin: this.props.printMargin, - fadeFoldWidgets: this.props.fadeFoldWidgets, - showFoldWidgets: this.props.showFoldWidgets, - showLineNumbers: this.props.showLineNumbers, - showGutter: this.props.showGutter, - displayIndentGuides: this.props.displayIndentGuides, - highlightIndentGuides: this.props.highlightIndentGuides, - fontSize: this.props.fontSize, - fontFamily: this.props.fontFamily || undefined, - maxLines: this.props.maxLines, - minLines: this.props.minLines, - scrollPastEnd: this.props.scrollPastEnd, - fixedWidthGutter: this.props.fixedWidthGutter, - customScrollbar: this.props.customScrollbar, - hasCssTransforms: this.props.hasCssTransforms, - maxPixelHeight: this.props.maxPixelHeight, - useSvgGutterIcons: this.props.useSvgGutterIcons, - /* - * mouseHandler options - */ - scrollSpeed: this.props.scrollSpeed || undefined, - dragDelay: this.props.dragDelay || undefined, - dragEnabled: this.props.dragEnabled, - // focusTimout: this.props.focusTimout, - tooltipFollowsMouse: this.props.tooltipFollowsMouse, - /* - * session options - */ - firstLineNumber: this.props.firstLineNumber, - // overwrite: this.props.overwrite, - newLineMode: this.props.newLineMode, - useWorker: this.props.useWorker, - indentedSoftWrap: this.props.indentedSoftWrap, - tabSize: this.props.tabSize, - wrap: this.props.wrap, - // wrapMethod: this.props.wrapMethod, - foldStyle: this.props.foldStyle - }} - />; - } + render(): ReactNode { + return ( + this.props.value.setValue(value)} + editorProps={{ $blockScrolling: true }} + setOptions={{ + /* + * editor options + */ + selectionStyle: this.props.selectionStyle, + highlightActiveLine: this.props.highlightActiveLine, + highlightSelectedWord: this.props.highlightSelectedWord, + readOnly: this.props.value.readOnly, + cursorStyle: this.props.cursorStyle, + mergeUndoDeltas: this.props.mergeUndoDeltas, + behavioursEnabled: this.props.behavioursEnabled, + wrapBehavioursEnabled: this.props.wrapBehavioursEnabled, + autoScrollEditorIntoView: this.props.autoScrollEditorIntoView, + copyWithEmptySelection: this.props.copyWithEmptySelection, + useSoftTabs: this.props.useSoftTabs, + navigateWithinSoftTabs: this.props.navigateWithinSoftTabs, + enableMultiselect: this.props.enableMultiselect, + enableAutoIndent: this.props.enableAutoIndent, + enableKeyboardAccessibility: this.props.enableKeyboardAccessibility, + /* + * renderer options + */ + hScrollBarAlwaysVisible: this.props.hScrollBarAlwaysVisible, + vScrollBarAlwaysVisible: this.props.vScrollBarAlwaysVisible, + highlightGutterLine: this.props.highlightGutterLine, + animatedScroll: this.props.animatedScroll, + showInvisibles: this.props.showInvisibles, + showPrintMargin: this.props.showPrintMargin, + printMarginColumn: this.props.printMarginColumn, + printMargin: this.props.printMargin, + fadeFoldWidgets: this.props.fadeFoldWidgets, + showFoldWidgets: this.props.showFoldWidgets, + showLineNumbers: this.props.showLineNumbers, + showGutter: this.props.showGutter, + displayIndentGuides: this.props.displayIndentGuides, + highlightIndentGuides: this.props.highlightIndentGuides, + fontSize: this.props.fontSize, + fontFamily: this.props.fontFamily || undefined, + maxLines: this.props.maxLines, + minLines: this.props.minLines, + scrollPastEnd: this.props.scrollPastEnd, + fixedWidthGutter: this.props.fixedWidthGutter, + customScrollbar: this.props.customScrollbar, + hasCssTransforms: this.props.hasCssTransforms, + maxPixelHeight: this.props.maxPixelHeight, + useSvgGutterIcons: this.props.useSvgGutterIcons, + /* + * mouseHandler options + */ + scrollSpeed: this.props.scrollSpeed || undefined, + dragDelay: this.props.dragDelay || undefined, + dragEnabled: this.props.dragEnabled, + // focusTimout: this.props.focusTimout, + tooltipFollowsMouse: this.props.tooltipFollowsMouse, + /* + * session options + */ + firstLineNumber: this.props.firstLineNumber, + // overwrite: this.props.overwrite, + newLineMode: this.props.newLineMode, + useWorker: this.props.useWorker, + indentedSoftWrap: this.props.indentedSoftWrap, + tabSize: this.props.tabSize, + wrap: this.props.wrap, + // wrapMethod: this.props.wrapMethod, + foldStyle: this.props.foldStyle + }} + /> + ); + } } config.set("packaged", true); config.set("basePath", CodeEditor.basePath); config.set("workerPath", CodeEditor.basePath); config.set("modePath", CodeEditor.basePath); -config.set("themePath", CodeEditor.basePath); \ No newline at end of file +config.set("themePath", CodeEditor.basePath); diff --git a/src/CodeEditor.xml b/src/CodeEditor.xml index 3bfd929..a917a5e 100644 --- a/src/CodeEditor.xml +++ b/src/CodeEditor.xml @@ -1,9 +1,7 @@ - + Code Editor Ace code editor, as a Mendix pluggable widget. @@ -268,13 +266,17 @@ - + Attribute + + On change + + @@ -299,7 +301,7 @@ Highlight active line - + Highlight selected word diff --git a/src/package.xml b/src/package.xml index 429068f..ffe1120 100644 --- a/src/package.xml +++ b/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/typings/CodeEditorProps.d.ts b/typings/CodeEditorProps.d.ts index e5c01dc..644e9d1 100644 --- a/typings/CodeEditorProps.d.ts +++ b/typings/CodeEditorProps.d.ts @@ -101,6 +101,7 @@ export interface CodeEditorPreviewProps { theme: ThemeEnum; mode: ModeEnum; value: string; + onChangeAction: {} | null; debounceChangePeriod: number | null; selectionStyle: SelectionStyleEnum; highlightActiveLine: boolean;