diff --git a/source/entryjs/api/2024-02-29-popup.md b/source/entryjs/api/2024-02-29-popup.md index ed747ad8..12948b44 100644 --- a/source/entryjs/api/2024-02-29-popup.md +++ b/source/entryjs/api/2024-02-29-popup.md @@ -10,9 +10,7 @@ description: thumbnail: author: Entrylabs date: 2024-03-19 - -updated: 2024-03-19 - +updated: 2024-04-08 --- 이 문서에서는 [entry-tool](https://github.com/entrylabs/entry-tool)의 팝업과 기타 툴들을 사용하는 방법을 소개합니다. @@ -53,7 +51,6 @@ updated: 2024-03-19 - [projects](#projects) - [table](#table) - [이벤트](#이벤트) - - [팝업 데이터 타입 정의](#팝업-데이터-타입-정의)
@@ -355,7 +352,9 @@ navigations 프로퍼티에서 어떤 단독기능 type을 사용중인지 확 페이지 구현 type들은 자신이 사용하는 단독type에서 사용하는 이벤트를 핸들링하여 setData로 적절히 데이터 처리를 해야 합니다. -페이지 구현 type들은 tool.data.data.data의 데이터들이 조금씩 다릅니다. 각 타입별 데이터는 [팝업 데이터 타입 정의](#팝업-데이터-타입-정의)에서 다룹니다. +페이지 구현 type들은 tool.data.data.data의 데이터들이 조금씩 다릅니다. + +**submit 이벤트로 제출시 entryjs를 사용해서 어떻게 WS화면에 추가하는지를 기술합니다.** 좀 더 구체적인 사용 예시는 entry-offline의 [entryModalHelper.ts](https://github.com/entrylabs/entry-offline/blob/master/src/renderer/helper/entry/entryModalHelper.ts)파일에서도 확인이 가능합니다. @@ -435,7 +434,7 @@ popup.show(); // 사용자 로컬 디렉토리에서 선택한 파일을 1차로 임시저장 // 업로드한 파일이 sound, image, table 이면 formData에 object 데이터이면 'objectData'를 통해 넘어옵니다. popup.on('dummyUploads', async ({ formData, objectData }) => { - const validFormData = handleFormData(formData); + const validFormData = handleFormData(formData); const validObjectData = handleObjectData(objectData); // 가공된 파일데이터를 setData로 전달해서 팝업화면에 반영 @@ -454,13 +453,13 @@ popup.on('dummyUploads', async ({ formData, objectData }) => { }) // 사용자가 '추가히기' 버튼을 클릭하여 임시보관중인 업로드 파일들을 서비스에 반영 popup.on('uploads', (data) => { - data.uploads.map((item) => { + data.uploads.map((item) => { // 데이터 종류에 맞게 엔트리WS에 반영 }) }) // 업로드 실패시 에러 핸들링 popup.on('uploadFail', (data) => { - console.alert(`${data.messageParent}${data.message}`); + console.alert(`${data.messageParent}${data.message}`); }) ``` @@ -534,6 +533,68 @@ popup.on('write', (data) => { 내부적으로 select, upload, draw, write 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (spriteItems) => { + // ex) data가 엔트리 오브젝트(sprite)인 경우 + spriteItems.map((spriteItem) => { + spriteItem.name = spriteItem.label['국가'] + const object = { + id: Entry.generateHash(), + objectType: 'sprite', + sprite: spriteItem, + } + Entry.container.addObject(object, 0); + } +} +``` + +#### 샘플 데이터 + +```json +// spriteItem +{ + "id": "58197081c9ec3d9257523608", + "name": "점프 엔트리봇", + // 국가별로 name값을 변경하고 싶다면, spriteItem.name = spriteItem.label['국가']로 변경 + // 이하 picture, sound 등 모두 동일합니다. + "label": { + "ko": "점프 엔트리봇", + "en": "Jumping Entrybot", + "ja": null, + "vn": "Jumping Entrybot" + }, + "category": { + "main": "entrybot_friends", + "sub": null + }, + // 오브젝트가 포함한 이미지들 : Array, + "pictures": [ + { + "id": null, + "name": "점프 엔트리봇_1", + "label": { + "ko": "점프 엔트리봇_1", + "en": "Jumping Entrybot_1", + "ja": null, + "vn": "Jumping Entrybot_1" + }, + "filename": "f8d5a3da311c906490416996a02904d7", + "imageType": null, + "dimension": { + "width": 289, + "height": 302 + }, + "trimmed": null + } + ], + // 오브젝트가 포함한 사운드들 : Array + "sounds": [] +} +``` +
### picture @@ -544,6 +605,47 @@ popup.on('write', (data) => { 내부적으로 select, upload, draw 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (pictureItems) => { + // ex) data가 엔트리 이미지(picture)인 경우 + pictureItems.map((pictureItem) => { + // id가 없거나 WS에서 새로 발급해야 하는 경우 + pictureItem.id = Entry.generateHash(); + pictureItem.imageType = pictureItem.imageType || 'png'; + Entry.playground.addPicture(pictureItem, true); + } +} +``` + +#### 샘플 데이터 + +```js +// pictureItem +{ + "id": "58196ed2edbbbf16684da2fb", + "name": "달리기하는 엔트리봇_1", + // 국가별 언어분리시 사용 + "label": { + "ko": "달리기하는 엔트리봇_1", + "en": "Running Entrybot_1", + "ja": null, + "vn": "Running Entrybot_1" + }, + "filename": "41e5cafe6afb9bd7a9bcb3fbfdf55bd3", + "imageType": "png", + "dimension": { + "width": 332, + "height": 351 + }, + "trimmed": null +} +``` + + +
### paint @@ -552,8 +654,28 @@ popup.on('write', (data) => { '모양 가져오기'에서 사용하는 팝업입니다. +'모양 추가하기'와 달리 현재 이미지 위에 다른 이미지를 덧입히는 기능입니다. + 내부적으로 select, upload 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (pictureItems) => { + // ex) data가 엔트리 이미지(picture)인 경우 + pictureItems.map((pictureItem) => { + pictureItem.id = Entry.generateHash(); + pictureItem.imageType = pictureItem.imageType || 'png'; + Entry.dispatchEvent('pictureImport', pictureItem); + } +} +``` + +#### 샘플 데이터 + +- 'picture'와 동일하게 pictureItem을 사용합니다. +
### sound @@ -564,6 +686,42 @@ popup.on('write', (data) => { 내부적으로 select, upload 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (soundItems) => { + // ex) data가 엔트리 사운드(sound)인 경우 + soundItems.map((soundItem) => { + soundItem.id = Entry.generateHash(); + Entry.playground.addSound(soundItem, true); + } + // 'play' 이벤트로 재생되던 소리를 중지 + Entry.Utils.forceStopSounds(); +} +``` + +#### 샘플 데이터 + +```js +// soundItem +{ + "id": "63646e925d35950030903022", + "name": "기타 루프1", + // 국가별 언어분리시 사용 + "label": { + "ko": "기타 루프1", + "en": "기타 루프1.mp3", + "ja": null, + "vn": "기타 루프1.mp3" + }, + "filename": "9pcv13o6la1u2rhr000q75262d1nupd0", + "duration": 8 +} +``` + + +
### expansion @@ -572,7 +730,117 @@ popup.on('write', (data) => { '확장 블록 불러오기'에서 사용하는 팝업입니다. -내부적으로 select 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +내부적으로 select 팝업 기능을 사용합니다. + +#### WS에 등록 + +```js +const expansionBlocks = []; +// submit 이벤트 핸들링 +popup.on('submit', (expansionItems) => { + // ex) data가 엔트리 확장블럭(expansion)인 경우 + + // 확장블럭 추가 이벤트 dispatch + Entry.dispatchEvent('popupAddBlocks', { category: 'expansion', expansionItems }); + // 추가할 블럭 필터링 + const addBlocks = expansionItems.filter(({ name }) => !Entry.expansionBlocks.includes(name)); + // 필요시 제거할 확장블럭 필터링 + const removeBlocks = this.expansionBlocks + .filter((item) => item.active) + .filter((item) => !expansionItems.includes(item)); + // WS 블록메뉴에 확장블럭 추가 + Entry.playground.addExpansionBlocks(addBlocks, true, true); + // 필요할 경우 WS 블록메뉴에 확장블럭 제거 + Entry.playground.removeExpansionBlocks(removeBlocks, true, true); +} +``` + +#### 샘플 데이터 + +```js +// expansionItem +{ + "name": "festival", + "imageName": "festival.png", + "title": { + "ko": "행사", + "en": "festival", + "jp": "イベント" + }, + "titleKey": "template.festival_title_text", + "description": "국내 지역별 다양한 행사 및 축제와 관련된 불록 모음 입니다. [한국관광공사 제공]", + "descriptionKey": "Msgs.expansion_festival_description", + "isInitialized": false, + "api": "/api/expansionBlock/ko/festival", + "locationMap": { + "Seoul": { + "code": 1, + "sub": [ + "강남구", + "강동구", + "강북구", + ] + }, + "Incheon": { + "code": 2, + "sub": [ + "강화군", + "계양구", + "남구", + ] + }, + "Daejeon": { + "code": 3, + "sub": [ + "대덕구", + "동구", + ] + }, + "Daegu": { + "code": 4, + "sub": [ + "남구", + "달서구", + ] + }, + "Gwangju": { + "code": 5, + "sub": [ + "광산구", + "남구", + ] + }, + }, + "infoTypeMap": { + "title": "title", + "address": "addr1", + "start_date": "eventstartdate", + "end_date": "eventenddate", + "coordinatex": "mapx", + "coordinatey": "mapy", + "area": "sigungucode", + "homepage": "homepage", + "overview": "overview" + }, + "monthMap": { + "January": 1, + "Febuary ": 2, + "March": 3, + "April": 4, + "May": 5, + "June": 6, + "July": 7, + "August": 8, + "September": 9, + "October": 10, + "November": 11, + "December": 12 + }, + "active": false +} +``` + +
@@ -582,7 +850,64 @@ popup.on('write', (data) => { '인공지능 블록 불러오기'에서 사용하는 팝업입니다. -내부적으로 select 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +내부적으로 select 팝업 기능을 사용합니다. + +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +const aiUtilizeBlocks = []; + +// 확장블럭 추가 이벤트 dispatch +popup.on('submit', (aiUtilizeItems) => { + // ex) data가 엔트리 인공지능 블럭(aiUtilizeBlock)인 경우 + Entry.dispatchEvent('popupAddBlocks', { category: 'ai_utilize', aiUtilizeItems }); + // 추가할 블럭 필터링 + const addBlocks = aiUtilizeItems.filter(({ name }) => !Entry.aiUtilizeBlocks.includes(name)); + // 필요시 제거할 블록 필터링 + const removeBlocks = this.aiUtilizeBlocks + .filter((item) => item.active) + .filter((item) => !aiUtilizeItems.includes(item)); + // 인공지능 블럭 WS 블록메뉴에 추가 + Entry.playground.addAIUtilizeBlocks(addBlocks, true, true); + // 인공지능 블럭 WS 블록메뉴에 제거 + Entry.playground.removeAIUtilizeBlocks(removeBlocks, true, true); +} +``` + +#### 샘플 데이터 + +```js +// aiUtilizeItems +{ + "name": "translate", + "imageName": "papago.svg", + "category": "general", + "sponsorText": "Powered by {image}", + "sponsorImage": "naver.png", + "sponsorOnImage": "naverOn.png", + "title": { + "ko": "번역", + "en": "translate", + "jp": "翻訳" + }, + "titleKey": "template.translate_title_text", + "description": "파파고를 이용하여 다른 언어로 번역할 수 있는 블록 모음입니다.", + "descriptionKey": "Msgs.expansion_translate_description", + "isInitialized": false, + "api": "/api/expansionBlock/papago/", + "sponsor": "papagoNaver", + "sponsorLink": "https://www.ncloud.com/product/aiService/papagoNmt", + "typeMap": { + "dictionary": "nsmt", + "artificial_intelligence": "n2mt" + }, + "apiType": "n2mt", + "active": false +} +``` + +
@@ -592,7 +917,66 @@ popup.on('write', (data) => { 하드웨어 '브라우저로 연결하기'에서 사용하는 팝업입니다. -내부적으로 select 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +내부적으로 select 팝업 기능을 사용합니다. + +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (hardwareLiteItems) => { + // ex) data가 엔트리 하드웨어 웹연결(hardwareLite)인 경우 + // 일반적으로 하드웨어 연결은 한번에 1개씩만 + const selectedModule = hardwareLiteItems.selected[0]; + + // 선택된 하드웨어 모듈을 WS에 추가 + Entry.playground.addHardwareLiteModule(selectedModule); + const selectedFirmware = HARDWARE_LITE_FIRMWARE_REQUIRED[selectedModule.id]; + + // 모듈에 문제가 있는 경우엔 failMenu 노출 + Entry.hwLite.getConnectFailedMenu(); + // 모듈에 문제가 없는 경우 연결 시도 + Entry.hwLite.connect(); +} +``` + +#### 샘플 데이터 + +```js +// hardwareLiteItems +{ + "retryLimitCnt": 8, + "portData": { + "baudRate": 115200, + "dataBits": 8, + "parity": "none", + "stopBits": 1, + "bufferSize": 512, + "connectionType": "ascii" + }, + "duration": 64, + "id": "220301", + "url": "http://microbit.org/ko/", + "imageName": "microbit2lite.png", + "title": { + "ko": "마이크로비트" + }, + "name": "Microbit2lite", + "blockMenuBlocks": [ + "microbit2lite_common_title", + "microbit2lite_get_analog", + "microbit2lite_set_analog", + ], + "version": "2", + "description": "Micro:bit Educational Foundation", + "linkBox": { + "desc": "고객센터", + "url": "http://microbit.org/ko/" + }, + "active": false +} +``` + +
@@ -631,6 +1015,58 @@ popup.setData({ }); ``` +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (projectItems) => { + // 프로젝트 저장정보의 경우 entryjs에서 제공하는 project저장 데이터와 완전히 독립적입니다. + // 따라서, 현재 엔트리 웹 서비스에서 사용하는 project데이터의 예시 샘플 데이터만 공유드립니다. +} +``` + +#### 샘플 데이터 + +```js +// projectItem +[ + { + "id": "", + "name": "작품명", + "user": { + "id": "사용자id", + "username": "사용자명", + "nickname": "사용자 닉네임", + "profileImage": null, + "_id": "", + "avatarImage": false + }, + "thumb": "썸네일 경로/파일명.png", + "isopen": false, + "isPracticalCourse": false, + "category": "기타", + "categoryCode": "etc", + "created": "2024-02-28T05:41:16.878Z", + "updated": "2024-02-28T05:41:16.878Z", + "special": null, + "isForLecture": false, + "isForStudy": false, + "isForSubmit": false, + "hashId": null, + "complexity": 0, + "staffPicked": null, + "ranked": null, + "visit": 0, + "likeCnt": 0, + "comment": 0, + "showComment": true, + "project": null + } +] +``` + + +
### table @@ -643,6 +1079,98 @@ popup.setData({ 내부적으로 select, dragUpload, draw 팝업 기능을 사용하며 상단 naviation에서 확인 가능합니다. +#### WS에 등록 + +```js +// submit 이벤트 핸들링 +popup.on('submit', (datas) => { + // ex) data가 엔트리 테이블(table)인 경우 + const tableItems = datas.selected; + + tableItems.map((tableItem) => { + Entry.playground.dataTable.addSources(tableItem); + Entry.creationChangedEvent.notify(); + }) +} +``` + +#### 샘플 데이터 + +```js +// tableItems +{ + "_id": "63eb28429b18bc31f53a2180", + "name": "vibe 장르별 재생 수", + "lang": "ko", + "url": "", + "rows": 12, + "fields": [ + "월", + " 발라드", + " 댄스", + " 힙합", + " 팝", + " 락", + " 캐롤", + " 합계" + ], + "fieldInfos": [], + "provider": "vibe", + "summary": "summary", + "description": "summary", + "exampleurl": null, + "linkText": "", + "isOpen": true, + "projectTable": { + "_id": "63eb28b4045eb131fdb0d156", + "chart": [], + "fields": [ + "월", + " 발라드", + " 댄스", + " 힙합", + " 팝", + " 락", + " 캐롤", + " 합계" + ], + "type": "user", + "data": [ + [ + "2019-01", + " 4580340", + " 3506013", + " 2530997", + " 1781670", + " 433264", + " 0", + " 12832284" + ], + [ + "2019-02", + " 5983086", + " 5039213", + " 3306147", + " 2441981", + " 563172", + " 0", + " 17333599" + ], + ], + "name": "월발라드댄스힙합팝락캐롤합계.csv", + "user": "5f9ab512df5079a03d4611f2", + "created": "2023-02-14T06:22:44.770Z", + "updated": "2023-02-14T06:22:44.770Z", + "__v": 0 + }, + "updated": "2023-02-14T06:22:45.960Z", + "hasOtherTypes": false, + "otherTypes": [] +} +``` + + +
@@ -823,344 +1351,6 @@ item 선택 해제시 발생하는 이벤트입니다.
-### 팝업 데이터 타입 정의 - -팝업에서 사용하는 파라미터들의 타입을 임시로 정의한 문서입니다. - -아래 타입들은 현재 엔트리웹&엔트리 오프라인에서 사용중인 데이터 구조로 일부 필수값을 제외하면 임의로 변경이 가능합니다. - -이 문서는 추후 세분화하여 별도의 페이지로 옮겨질 예정입니다. - -#### popup.data - -```js -popup.setData( - { - // project type에서 검색 기능을 위해 사용 - projectNavOptions: { - categoryOptions: ['all', 'game', 'living','etc'], - sortOptions: ['updated', 'visit', 'likeCnt', 'comment'], - periodOptions: ['all', 'today', 'week', 'month', 'quarter'], - }, - // select type에서 사용 - sidebar: { - "people": { - "id": "", - "name": "사람", - "value": "people", - "sub": { - "all": { - "id": "", - "name": "전체", - "value": "all" - } - } - }, - "animal": { ... }, - }, - data : { - // select type에서 사용 - imageBaseUrl: '/assets/images/', - data: [ - { - name: 'item1', - description: '아이템 설명', - label: { - ko: '타이틀', - en: 'title', - }, - imageName: 'file1.png' - } - ], - } - } - ) -``` - -
- - -#### ObjectItems - -```json -// sprite 팝업의 data type -[{ - "id": "id", - "name": "(1)엔트리봇", - "label": { - "ko": "(1)엔트리봇", - "en": "(1)Entrybot", - "ja": null, - "vn": null, - }, - "category": { - "main": "entrybot_friends", - "sub": null - }, - "pictures": pictureItems, - "sounds": SoundItems, -}] -``` - -
- -#### pictureItems - -```json -// picture 팝업의 data type -{ - "id": "", - "name": "(1)엔트리봇_걷기1", - "label": { - "ko": "(1)엔트리봇_걷기1", - "en": "(1)Entrybot_walk1", - "ja": null, - "vn": null - }, - "filename": "filename", - "imageType": "png", - "dimension": { - "width": 284, - "height": 350 - }, - "trimmed": null -} -``` - -
- -#### SoundItems - -```json -// sound 팝업의 data type -[ - { - "id": "", - "name": "기타 루프1", - "label": { - "ko": "기타 루프1", - "en": "기타 루프1.mp3", - "ja": null, - "vn": "기타 루프1.mp3" - }, - "filename": "9pd0", - "duration": 8 - } -] -``` - -#### tableItems - -```json -// table 팝업의 data type -[ - { - "id": "id", - "name": "vibe 장르별 재생 수", - "lang": "ko", - "url": "", - "rows": 12, - "fields": [ - "월", - " 발라드", - " 댄스", - " 힙합", - " 팝", - " 락", - " 캐롤", - " 합계" - ], - "fieldInfos": [], - "provider": "vibe", - "summary": "summary", - "description": "summary", - "exampleurl": null, - "linkText": "", - "isOpen": true, - "projectTable": { - "_id": "id", - "chart": [], - "fields": [ - "월", - " 발라드", - " 댄스", - " 힙합", - " 팝", - " 락", - " 캐롤", - " 합계" - ], - "type": "user", - "data": [ - [ - "2019-01", - " 4580340", - " 3506013", - " 2530997", - " 1781670", - " 433264", - " 0", - " 12832284" - ], - ], - "name": "월발라드댄스힙합팝락캐롤합계.csv", - "user": "", - "created": "2023-02-14T06:22:44.770Z", - "updated": "2023-02-14T06:22:44.770Z", - "__v": 0 - }, - "updated": "2023-02-14T06:22:45.960Z", - "hasOtherTypes": false, - "otherTypes": [] - } -] -``` - -
- -#### aiUtilizeItems - -```json -// aiUtilizeItems 팝업의 data type -[ - { - "name": "translate", - "imageName": "papago.svg", - "category": "general", - "sponsorText": "Powered by {image}", - "sponsorImage": "naver.png", - "sponsorOnImage": "naverOn.png", - "title": { - "ko": "번역", - "en": "translate", - "jp": "翻訳" - }, - "titleKey": "template.translate_title_text", - "description": "파파고를 이용하여 다른 언어로 번역할 수 있는 블록 모음입니다.", - "descriptionKey": "Msgs.expansion_translate_description", - "isInitialized": false, - "api": "/api/expansionBlock/papago/", - "sponsor": "papagoNaver", - "typeMap": { - "dictionary": "nsmt", - "artificial_intelligence": "n2mt" - }, - "apiType": "n2mt", - "active": false - } -] -``` - -
- -#### expansionItems - -```json -// expansionItems 팝업의 data type -[ - { - "name": "behaviorConductLifeSafety", - "imageName": "firstaid.png", - "title": { - "ko": "생활안전", - "en": "LifeSafety", - "jp": "生活安全" - }, - "titleKey": "template.behaviorConductLifeSafety_title_text", - "description": "생활 속 안전을 위해 국민이 지켜야 하는 행동요령에 대한 블록 모음입니다. [국민안전처 제공]", - "descriptionKey": "설명", - "isInitialized": false, - "api": "/api/expansionBlock/behaviorConduct", - "apiType": "03", - "active": false - } -] -``` - -
- -#### projectItems - -```json -// projectItems 팝업의 data type -[ - { - "id": "", - "name": "작품명", - "user": { - "id": "사용자id", - "username": "사용자명", - "nickname": "사용자 닉네임", - "profileImage": null, - "_id": "", - "avatarImage": false - }, - "thumb": "썸네일 경로/파일명.png", - "isopen": false, - "isPracticalCourse": false, - "category": "기타", - "categoryCode": "etc", - "created": "2024-02-28T05:41:16.878Z", - "updated": "2024-02-28T05:41:16.878Z", - "special": null, - "isForLecture": false, - "isForStudy": false, - "isForSubmit": false, - "hashId": null, - "complexity": 0, - "staffPicked": null, - "ranked": null, - "visit": 0, - "likeCnt": 0, - "comment": 0, - "showComment": true, - "project": null - } -] -``` - -
- -#### hardwareLiteItems - -```json -// hardwareLiteItems 팝업의 data type -[ - { - "id": "하드웨어 id", - "name": "선택한 하드웨어명", - "url": "제조사 사이트 url", - "imageName": "이미지명.png", - "title": { - "ko": "네오스파이더" - }, - "duration": 32, - "blockMenuBlocks": [ - // 블럭정보 - "neospiderlite_get_analog_value", - "neospiderlite_get_analog_value_map", - ], - "portData": { - "baudRate": 115200, - "duration": 32, - "dataBits": 8, - "parity": "none", - "stopBits": 1, - "bufferSize": 512, - "constantServing": true - }, - "description": "하드웨어 설명", - "linkBox": { - "desc": "썸네일 하단 링크", - "url": "링크 클릭시 이동할 url" - }, - "active": false - } -] -``` - -
- ## Widget **이 문서는 작성중인 문서입니다.** @@ -1285,4 +1475,3 @@ return() ### Component.MusicScale ### Component.ContextMenu -