본문으로 건너뛰기

SourceEditor

이 컨트롤은 무엇인가요?

SourceEditor는 마이크로소프트의 Monaco Editor(VS Code에서 사용하는 것과 같은 코드 편집 엔진)를 감싼 syn.uicontrols 컨트롤입니다. <syn_sourceeditor> 태그를 화면에 배치하면, 컨트롤이 초기화되면서 다음과 같은 동작이 일어납니다.

  1. 원래 배치했던 엘리먼트는 id="<원래id>_hidden"으로 이름이 바뀌고 화면에서 숨겨집니다(display: none). 이 엘리먼트는 옵션 값을 보관하는 용도로만 남습니다.
  2. 같은 부모 아래에 id="<원래id>"를 그대로 물려받은 새 <div>가 만들어지고, 그 안에 실제 Monaco 에디터(monaco.editor.create(...))가 렌더링됩니다.
  3. Monaco 엔진 자체(/lib/monaco-editor/min/vs/loader.js)는 최초 1회만 비동기로 로드되며, 로드가 끝나기 전에 여러 개의 <syn_sourceeditor>가 있으면 대기열(editorPendings)에 쌓였다가 로드 완료 후 순서대로 초기화됩니다.

HtmlEditor(WYSIWYG)와의 차이

구분HtmlEditor ($htmleditor)SourceEditor ($sourceeditor)
기반 엔진TinyMCEMonaco Editor (VS Code 편집 엔진)
편집 대상서식 있는 문서(HTML 리치 텍스트) — 굵게, 표, 이미지 삽입 등소스 코드/구조화된 텍스트 — JavaScript, JSON, SQL, HTML 등
결과물HTML 마크업 문자열언어 문법에 맞는 순수 텍스트(소스 코드) 문자열
대표 기능툴바(굵게/이미지/표), 이미지 업로드(fileManagerServer)문법 강조(syntax highlight), 줄 번호, 미니맵, 코드 접기
용도 예게시판 본문, 이메일 템플릿, 공지사항스크립트/쿼리 편집, 설정 JSON 편집, 로그/코드 뷰어

즉, "사람이 읽는 문서를 예쁘게 꾸미는 것"이 목적이면 HtmlEditor를, "코드나 JSON처럼 문법이 있는 텍스트를 정확하게 편집하는 것"이 목적이면 SourceEditor를 사용합니다.

언제 사용하나요?

  • JavaScript, JSON, SQL, HTML, XML 등 특정 언어 문법의 소스 코드를 화면에서 직접 편집해야 할 때
  • 줄 번호, 문법 강조, 미니맵 같은 코드 편집기 UI가 필요할 때
  • 설정 값(JSON)이나 쿼리문처럼 형식이 엄격한 텍스트를 사용자가 직접 입력/수정하게 할 때
  • 단순한 여러 줄 텍스트(메모 등)만 필요하다면 TextArea(CodeMirror 기반, 더 가벼움)를, 서식 있는 문서 편집이 필요하다면 HtmlEditor(TinyMCE 기반)를 대신 검토하세요.

빠른 시작

  1. 페이지에 <syn_sourceeditor> 태그를 배치하고 id, syn-datafield, syn-options 속성을 지정합니다.
<syn_sourceeditor id="txtEditor1"
syn-datafield="SourceCode"
syn-options="{language: 'javascript', theme: 'vs-dark', minimap: {enabled: true}}"></syn_sourceeditor>
  1. 페이지 하단에 syn.loader.js 스크립트 한 줄만 추가하면, 로더가 필요한 CSS/JS(SourceEditor.js, SourceEditor.css, Monaco 엔진 로더)를 자동으로 주입하고 컨트롤을 초기화합니다.
<script src="/js/syn.loader.js"></script>
  1. 값을 읽거나 설정할 때는 페이지 스크립트에서 syn.uicontrols.$sourceeditor를 사용합니다.
// 현재 값 조회
var code = syn.uicontrols.$sourceeditor.getValue('txtEditor1');

// 값 설정
syn.uicontrols.$sourceeditor.setValue('txtEditor1', 'function hello() {\n\talert("Hello world!");\n}');

// 값 초기화
syn.uicontrols.$sourceeditor.clear('txtEditor1');

Monaco 에디터는 비동기로 로드됩니다. 컨트롤이 아직 초기화되기 전(스크립트 로드 중)에는 getValue/setValue가 대상을 찾지 못할 수 있으므로, 페이지 로드 직후 곧바로 호출하기보다는 버튼 클릭 등 사용자 이벤트 시점에 호출하는 것이 안전합니다.

예제 실행하기

이 폴더의 example 디렉토리에 초보자용 실행 예제가 있습니다. 웹 서버를 통해 /uicontrols/SourceEditor/example/*.html 경로로 접속해서 바로 확인할 수 있습니다.

  • basic.html: JavaScript 모드 기본 에디터를 배치하고 getValue/setValue/clear 버튼으로 값을 다루는 가장 단순한 예제
  • language-mode.html: language 옵션을 JSON/HTML 등으로 바꿔가며 같은 컨트롤이 언어별로 어떻게 강조되는지 비교하는 예제
  • events.html: Monaco 자체 이벤트 API(getControl().editor.onDidChangeModelContent)로 변경 이벤트를 감지하고, getValue/setValue/clear도 함께 보여주는 예제

각 예제는 <script src="/js/syn.loader.js"></script> 한 줄만으로 동작하도록 만들어졌습니다.

더 알아보기

  • 전체 옵션(Options), 메서드, 이벤트(및 알려진 제약사항) 목록은 같은 폴더의 아래 API 참조 섹션 문서를 참고하세요.
  • 실제 소스 코드는 SourceEditor.js, SourceEditor.css 파일에서 확인할 수 있습니다.
  • Monaco 에디터 자체의 옵션/API는 Monaco Editor 공식 문서를 참고하세요. syn-options에 지정한 값은 monaco.editor.create(container, setting)에 그대로 전달되므로, 이 문서에 표로 정리한 옵션 외에도 Monaco가 지원하는 모든 생성 옵션(IStandaloneEditorConstructionOptions)을 사용할 수 있습니다.

실전 예제 페이지

/uicontrols/SourceEditor/example/ 경로의 예제를 아래 iframe에서 바로 확인할 수 있습니다.

basic.html

events.html

language-mode.html

소스와 로드 파일

항목내용
컨트롤SourceEditor
전역 별칭syn.uicontrols.$sourceeditor
버전v2026.2.25
소스uicontrols/SourceEditor/SourceEditor.js
스타일uicontrols/SourceEditor/SourceEditor.css

API 참조

syn.uicontrols.$sourceeditor

마크업

<syn_sourceeditor id="txtEditor1"
syn-datafield="SourceCode"
syn-options="{language: 'javascript', theme: 'vs-dark', minimap: {enabled: true}}"></syn_sourceeditor>
  • 태그 이름 syn_sourceeditorsyn.loader.jsSYN_ 접두사를 인식해 sourceeditor 타입 컨트롤로 매핑하는 규칙을 따릅니다(case 'sourceeditor'SourceEditor.js/SourceEditor.css 로드).
  • syn-options : JSON 형식의 문자열로 옵션(defaultSetting)을 덮어씁니다. 이 값은 그대로 monaco.editor.create(container, setting)에 전달됩니다.
  • 컨트롤이 초기화되면 원래 태그는 id="<원래id>_hidden"으로 숨겨지고, 같은 id를 가진 새 <div>가 만들어져 그 안에 Monaco 에디터가 렌더링됩니다. 이후 getValue/setValue 등 API는 원래 지정했던 id를 그대로 사용합니다.

Options (defaultSetting)

SourceEditor.jsdefaultSetting에 정의된 값입니다. syn-options 속성으로 필요한 값만 덮어써서 사용합니다. 여기 표에 없는 값이라도 Monaco의 IStandaloneEditorConstructionOptions에 해당하는 옵션이면 함께 전달할 수 있습니다.

옵션기본값설명
width'100%'에디터 컨테이너 너비.
height'360px'에디터 컨테이너 높이.
language'javascript'문법 강조에 사용할 언어 모드. Monaco가 지원하는 언어 id(json, typescript, html, css, sql, xml, markdown, python 등)를 사용할 수 있습니다.
minimap객체 설정코드 축소판(미니맵) 표시 여부.
roundedSelectionfalse선택 영역 모서리를 둥글게 표시할지 여부.
scrollBeyondLastLinefalse마지막 줄 이후로도 스크롤이 가능하게 할지 여부.
readOnlyfalsetrue이면 읽기 전용 에디터가 됩니다.
lineNumbers'on'줄 번호 표시 방식('on', 'off', 'relative', 'interval').
theme'vs-dark'에디터 테마. Monaco 내장 테마 'vs'(밝은 테마), 'vs-dark'(어두운 테마), 'hc-black'(고대비) 등을 사용할 수 있습니다.
dataType'string'값의 데이터 타입 표기.
basePath'/lib/monaco-editor/min/vs'Monaco 엔진 로더 경로. syn.Config.DomainBaseUrl이 현재 origin과 다르면 자동으로 해당 도메인 기준 경로로 치환됩니다.
belongIDnull소속 그룹/컨테이너 식별자.
controlTextnull컨트롤에 표시할 보조 텍스트.
validatorsnull유효성 검증 설정.
transactConfignull데이터 송수신(트랜잭션) 관련 설정.
triggerConfignull트리거 동작 관련 설정.

메서드

syn.uicontrols.$sourceeditor.<메서드명>(...) 형태로 호출합니다.

메서드매개변수반환값설명
getValueelID, metastring에디터의 현재 텍스트 값을 반환합니다.
setValueelID, value, meta없음에디터의 텍스트 값을 설정합니다.
clearelID, isControlLoad없음에디터 값을 빈 문자열로 초기화합니다.
layoutResizeelID없음에디터 레이아웃을 다시 계산합니다(editor.layout()). 컨테이너 크기가 코드로 바뀐 직후 등에 사용합니다. 참고로 브라우저 창 크기 변경(resize)은 모든 SourceEditor 인스턴스에 대해 자동으로 처리됩니다.
getActionselID`array \null`
getControlelID`object \null`
controlLoadelID, setting없음컨트롤 초기화 진입점입니다. syn 프레임워크가 페이지 로드 시 자동으로 호출하며, 직접 호출할 필요는 없습니다(Monaco 엔진이 아직 로드되지 않았으면 내부 대기열에 넣었다가 로드 완료 후 초기화합니다).
setLocaleelID, translations, control, options없음다국어 텍스트 적용 훅입니다. 현재 구현은 빈 함수(별도 동작 없음)입니다.

⚠️ 참고용 메서드 — 현재 구현에 알려진 제약(버그)이 있음

아래 메서드들은 SourceEditor.js(v2026.2.25) 소스에 정의는 되어 있지만, 함수 선언에 elID 매개변수가 없는 상태로 내부에서 elID 변수를 참조하고 있습니다. 즉, 호출 스코프에 전역 변수 elID가 존재하지 않는 한 실제로 호출하면 ReferenceError: elID is not defined가 발생합니다.

메서드매개변수(선언부)의도된 기능
applyEditstext, position지정 위치(또는 현재 커서 위치)에 텍스트를 삽입/치환
getValueInRangeposition지정 범위의 텍스트 조회
getContentLinetext특정 문자열이 포함된 줄 번호 조회
setSelectionrange지정 범위를 선택 영역으로 지정
revealLineline지정한 줄로 스크롤 이동
findSelectiontext찾기 위젯을 열어 텍스트 검색

대안: 이 기능들이 필요하면 getControl(elID).editor로 Monaco 인스턴스를 직접 얻어, 위 메서드들이 내부적으로 호출하던 Monaco 공식 API를 그대로 사용하세요.

var control = syn.uicontrols.$sourceeditor.getControl('txtEditor1');
if (control && control.editor) {
var editor = control.editor;

// revealLine(line) 대신
editor.revealLine(3);

// setSelection(range) 대신
editor.setSelection(range);

// getValueInRange(position) 대신
var text = editor.getModel().getValueInRange(range);
}

이벤트 (syn-events)

SourceEditor는 다른 syn.uicontrols 컨트롤과 달리 syn-events 속성을 통한 이벤트 자동 연결을 지원하지 않습니다. SourceEditor.js 내부에는 syn-events를 읽어 event.<id>_<이벤트명> 핸들러에 연결하는 로직이 없으며, 자체적으로는 브라우저 resize 이벤트에 대한 내부 처리(editor.layout() 재호출)와 Ctrl+Space 키 입력 기본 동작 방지만 등록되어 있습니다.

변경 감지, 포커스/블러 감지 등이 필요하면 getControl(elID).editor로 얻은 Monaco 인스턴스에 Monaco의 공식 이벤트 API를 직접 등록하세요.

Monaco 이벤트 API설명
editor.onDidChangeModelContent(handler)에디터 내용이 변경될 때 발생합니다. (change에 해당)
editor.onDidBlurEditorText(handler)에디터가 포커스를 잃을 때 발생합니다. (blur에 해당)
editor.onDidFocusEditorText(handler)에디터가 포커스를 얻을 때 발생합니다. (focus에 해당)
editor.onDidChangeCursorPosition(handler)커서 위치가 바뀔 때 발생합니다.
var control = syn.uicontrols.$sourceeditor.getControl('txtEditor1');
if (control && control.editor) {
control.editor.onDidChangeModelContent(function (evt) {
syn.$l.eventLog('txtEditor1_change', control.editor.getValue());
});
}

컨트롤이 비동기(Monaco 엔진 로드 후)로 초기화되므로, 위 이벤트 등록 코드는 pageLoad 직후가 아니라 버튼 클릭 등 사용자가 페이지를 조작한 이후(에디터 초기화가 끝난 시점) 또는 getControlnull이 아님을 확인한 뒤에 실행하는 것이 안전합니다.

참고

  • 실제 구현 파일: SourceEditor.js, SourceEditor.css
  • 내부적으로 Monaco Editor를 사용하며, 엔진 스크립트는 basePath(/lib/monaco-editor/min/vs)에서 최초 1회만 비동기로 로드됩니다.
  • Monaco 엔진이 아직 로드되지 않은 상태에서 여러 <syn_sourceeditor>가 배치돼 있으면, 로드가 끝날 때까지 내부 대기열(editorPendings)에 쌓였다가 순서대로 초기화됩니다.
  • applyEdits, getValueInRange, getContentLine, setSelection, revealLine, findSelection 메서드는 현재 소스 기준 elID 매개변수 누락 버그가 있어 직접 호출 시 오류가 발생합니다. 위 "참고용 메서드" 절의 대안(getControl(elID).editor로 Monaco API 직접 호출)을 사용하세요.