mirror of
https://github.com/antos-rde/antosdk-apps.git
synced 2025-07-23 17:29:51 +02:00
first release of libantosdk
This commit is contained in:
@ -1,3 +1,38 @@
|
||||
<afx-app-window apptitle="Antedit" width="500" height="400" data-id="Antedit">
|
||||
<afx-hbox ></afx-hbox>
|
||||
<afx-app-window apptitle="Antos Editor" width="600" height="400" data-id="antedit">
|
||||
<afx-vbox>
|
||||
<afx-hbox data-id="wrapper">
|
||||
<afx-vbox data-width = "155" min-width="155" data-id = "sidebar">
|
||||
<div data-height="10"></div>
|
||||
<afx-file-view chdir="false" data-id = "fileview" view="tree" status = "false">
|
||||
</afx-file-view>
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width = "3" ></afx-resizer>
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<afx-vbox data-id="left-panel">
|
||||
<afx-tab-bar closable="true" data-height="26" data-id = "left-tabbar"></afx-tab-bar>
|
||||
<div data-id="left-editorarea"></div>
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width="3"></afx-resizer>
|
||||
<afx-vbox data-id="right-panel">
|
||||
<afx-tab-bar closable="true" data-height="26" data-id = "right-tabbar"></afx-tab-bar>
|
||||
<div data-id="right-editorarea"></div>
|
||||
</afx-vbox>
|
||||
</afx-hbox>
|
||||
<afx-resizer data-height = "3" dir = "ve" attachnext = "true" ></afx-resizer>
|
||||
<afx-tab-container data-id = "bottombar" data-height="150" min-height="150" tabbarheight= "22">
|
||||
<afx-hbox tabname="__(Output)" iconclass = "fa fa-file-text" class = "bottom-tab-content">
|
||||
<afx-button text = "" data-id="logger-clear" iconclass="fa fa-trash" data-width="21"></afx-button>
|
||||
<div data-id="output-tab" iconclass = "fa fa-file-text" >
|
||||
</div>
|
||||
</afx-hbox>
|
||||
</afx-tab-container>
|
||||
</afx-vbox>
|
||||
</afx-hbox>
|
||||
<div data-height="20" data-id="statctn">
|
||||
<afx-label text=" " data-id = "current-file-lbl" style="float:left;"></afx-label>
|
||||
<afx-label data-id="langstat" style="float:right; padding-right: 10px;"></afx-label>
|
||||
<afx-label data-id="editorstat" style="float:right;"></afx-label>
|
||||
</div>
|
||||
</afx-vbox>
|
||||
</afx-app-window>
|
15
Antedit/build/debug/README.md
Normal file
15
Antedit/build/debug/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Antedit
|
||||
This is an example project, generated by AntOS Development Kit
|
||||
|
||||
## Howto
|
||||
Use the CodePad command palette to access to the SDK functionalities:
|
||||
|
||||
1. Create new project
|
||||
2. Init the project from the current folder located in side bar
|
||||
3. Build and run the project
|
||||
4. Release the project in zip package
|
||||
|
||||
## Set up build target
|
||||
|
||||
Open the `project.json` file from the current project tree and add/remove
|
||||
build target entries. Save the file
|
19
Antedit/build/debug/extensions/EditorExtensionMaker/main.tpl
Normal file
19
Antedit/build/debug/extensions/EditorExtensionMaker/main.tpl
Normal file
@ -0,0 +1,19 @@
|
||||
(function() {
|
||||
// import the CodePad application module
|
||||
const App = this.OS.application.Antedit;
|
||||
|
||||
// define the extension
|
||||
App.extensions.{0} = class {0} extends App.EditorBaseExtension {
|
||||
constructor(app) {
|
||||
super("{0}",app);
|
||||
}
|
||||
|
||||
test() {
|
||||
return this.notify("Test action is invoked");
|
||||
}
|
||||
|
||||
cleanup() {}
|
||||
|
||||
};
|
||||
|
||||
}).call(this);
|
15
Antedit/build/debug/extensions/EditorExtensionMaker/meta.tpl
Normal file
15
Antedit/build/debug/extensions/EditorExtensionMaker/meta.tpl
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"javascripts": ["{0}.js"],
|
||||
"copies": [],
|
||||
"meta": {
|
||||
"name": "{0}",
|
||||
"text": "{0}",
|
||||
"version": "0.0.1-a",
|
||||
"actions" : [
|
||||
{
|
||||
"text": "__(Example action)",
|
||||
"name": "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
33
Antedit/build/debug/extensions/extensions.json
Normal file
33
Antedit/build/debug/extensions/extensions.json
Normal file
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"name": "EditorExtensionMaker",
|
||||
"text": "Antedit Extension",
|
||||
"version": "0.0.1-a",
|
||||
"actions" : [
|
||||
{
|
||||
"text": "__(New Extension)",
|
||||
"name": "create"
|
||||
},
|
||||
{
|
||||
"text": "__(Build)",
|
||||
"name": "build"
|
||||
},
|
||||
{
|
||||
"text": "__(Run)",
|
||||
"name": "run"
|
||||
},
|
||||
{
|
||||
"text": "__(Build release)",
|
||||
"name": "release"
|
||||
},
|
||||
{
|
||||
"text": "__(Install extension from file)",
|
||||
"name": "install"
|
||||
},
|
||||
{
|
||||
"text": "__(Install extension from URL)",
|
||||
"name": "installFromURL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
168
Antedit/build/debug/main.css
Normal file
168
Antedit/build/debug/main.css
Normal file
@ -0,0 +1,168 @@
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container
|
||||
{
|
||||
/*border-top: 1px solid #272822;*/
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
scrollbar-width: none;
|
||||
/*scrollbar-color: #656565 transparent;*/
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar {
|
||||
height: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-thumb {
|
||||
background-color: #656565;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul
|
||||
{
|
||||
width: intrinsic;
|
||||
width: -moz-max-content;
|
||||
width: -webkit-max-content;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li.selected,
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul > afx-list-item > li.selected{
|
||||
background-color:#272822;
|
||||
color:white;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view afx-list-view i.closable:before {
|
||||
color:afafaf;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li,
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul li{
|
||||
background-color:#333333;
|
||||
color:#afafaf;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 20px;
|
||||
border-right: 1px solid #272822;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-vbox[data-id = "sidebar"]{
|
||||
background-color:#272822;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] div.afx-window-content {
|
||||
background-color:#333333;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-resizer {
|
||||
background-color:#272822;
|
||||
border-right: 1px solid #656565;
|
||||
border-bottom: 1px solid #656565;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .bottom-tab-content {
|
||||
background-color:#272822;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-tree-view{
|
||||
color: white;
|
||||
padding: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-tree-view afx-tree-view-item ul li{
|
||||
padding-left: 10px;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper .afx_tree_item_selected ul{
|
||||
background-color: #116cd6;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-file-view afx-tree-view .afx-tree-view-item:before{
|
||||
color: white;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper div[data-id="statctn"]{
|
||||
color: white;
|
||||
background-color: #007acc;
|
||||
padding-right: 10px;
|
||||
padding-top: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper div[data-id="statctn"] afx-label {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper{
|
||||
border-radius: 0px;
|
||||
border: 0;
|
||||
/*border: 1px solid #37373d;*/
|
||||
background-color: transparent;
|
||||
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65);
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view ul afx-list-item:nth-child(even) li
|
||||
{
|
||||
background-color: transparent;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view afx-list-item li{
|
||||
background-color: transparent;
|
||||
color:#afafaf;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper div.list-container > ul li:hover{
|
||||
background-color: #37373d;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view ul afx-list-item:nth-child(even) li.selected,
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrappe dafx-list-viewafx-list-view ul li.selected
|
||||
{
|
||||
background-color: #116cd6;
|
||||
color:white;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-top{
|
||||
height: 0;
|
||||
border:0;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] input{
|
||||
border: 1px solid #007acc;
|
||||
border-radius: 0;
|
||||
font-size: 12px;
|
||||
color:#afafaf;
|
||||
background-color:#272822;
|
||||
padding-left: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-content{
|
||||
background-color:#272822;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre {
|
||||
margin: 3px;
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-warn {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-info {
|
||||
color: white;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-button[ data-id="logger-clear" ] button{
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
1
Antedit/build/debug/main.js
Normal file
1
Antedit/build/debug/main.js
Normal file
File diff suppressed because one or more lines are too long
24
Antedit/build/debug/package.json
Normal file
24
Antedit/build/debug/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"pkgname": "Antedit",
|
||||
"app":"Antedit",
|
||||
"name":"Antos Editor",
|
||||
"description":"Antos text/code editor",
|
||||
"info":{
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "mrsang@iohub.dev"
|
||||
},
|
||||
"version":"0.1.0-a",
|
||||
"category":"Development",
|
||||
"iconclass":"bi bi-journal-code",
|
||||
"mimes":[
|
||||
"text/.*",
|
||||
"[^/]*/json.*",
|
||||
"[^/]*/.*ml",
|
||||
"[^/]*/javascript",
|
||||
"dir"
|
||||
],
|
||||
"dependencies":[
|
||||
"MonacoCore@0.23.0-r"
|
||||
],
|
||||
"locale": {}
|
||||
}
|
38
Antedit/build/debug/scheme.html
Normal file
38
Antedit/build/debug/scheme.html
Normal file
@ -0,0 +1,38 @@
|
||||
<afx-app-window apptitle="Antos Editor" width="600" height="400" data-id="antedit">
|
||||
<afx-vbox>
|
||||
<afx-hbox data-id="wrapper">
|
||||
<afx-vbox data-width = "155" min-width="155" data-id = "sidebar">
|
||||
<div data-height="10"></div>
|
||||
<afx-file-view chdir="false" data-id = "fileview" view="tree" status = "false">
|
||||
</afx-file-view>
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width = "3" ></afx-resizer>
|
||||
<afx-vbox>
|
||||
<afx-hbox>
|
||||
<afx-vbox data-id="left-panel">
|
||||
<afx-tab-bar closable="true" data-height="26" data-id = "left-tabbar"></afx-tab-bar>
|
||||
<div data-id="left-editorarea"></div>
|
||||
</afx-vbox>
|
||||
<afx-resizer data-width="3"></afx-resizer>
|
||||
<afx-vbox data-id="right-panel">
|
||||
<afx-tab-bar closable="true" data-height="26" data-id = "right-tabbar"></afx-tab-bar>
|
||||
<div data-id="right-editorarea"></div>
|
||||
</afx-vbox>
|
||||
</afx-hbox>
|
||||
<afx-resizer data-height = "3" dir = "ve" attachnext = "true" ></afx-resizer>
|
||||
<afx-tab-container data-id = "bottombar" data-height="150" min-height="150" tabbarheight= "22">
|
||||
<afx-hbox tabname="__(Output)" iconclass = "fa fa-file-text" class = "bottom-tab-content">
|
||||
<afx-button text = "" data-id="logger-clear" iconclass="fa fa-trash" data-width="21"></afx-button>
|
||||
<div data-id="output-tab" iconclass = "fa fa-file-text" >
|
||||
</div>
|
||||
</afx-hbox>
|
||||
</afx-tab-container>
|
||||
</afx-vbox>
|
||||
</afx-hbox>
|
||||
<div data-height="20" data-id="statctn">
|
||||
<afx-label text=" " data-id = "current-file-lbl" style="float:left;"></afx-label>
|
||||
<afx-label data-id="langstat" style="float:right; padding-right: 10px;"></afx-label>
|
||||
<afx-label data-id="editorstat" style="float:right;"></afx-label>
|
||||
</div>
|
||||
</afx-vbox>
|
||||
</afx-app-window>
|
BIN
Antedit/build/release/Antedit.zip
Normal file
BIN
Antedit/build/release/Antedit.zip
Normal file
Binary file not shown.
@ -1,7 +0,0 @@
|
||||
class Antedit extends this.OS.application.BaseApplication
|
||||
constructor: ( args ) ->
|
||||
super "Antedit", args
|
||||
|
||||
main: () ->
|
||||
|
||||
this.OS.register "Antedit", Antedit
|
167
Antedit/css/main.css
Normal file
167
Antedit/css/main.css
Normal file
@ -0,0 +1,167 @@
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container
|
||||
{
|
||||
/*border-top: 1px solid #272822;*/
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
scrollbar-width: none;
|
||||
/*scrollbar-color: #656565 transparent;*/
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar {
|
||||
height: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-thumb {
|
||||
background-color: #656565;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul
|
||||
{
|
||||
width: intrinsic;
|
||||
width: -moz-max-content;
|
||||
width: -webkit-max-content;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li.selected,
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul > afx-list-item > li.selected{
|
||||
background-color:#272822;
|
||||
color:white;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view afx-list-view i.closable:before {
|
||||
color:afafaf;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li,
|
||||
afx-app-window[data-id = "antedit"] afx-tab-bar> afx-list-view > div.list-container > ul li{
|
||||
background-color:#333333;
|
||||
color:#afafaf;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 20px;
|
||||
border-right: 1px solid #272822;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-vbox[data-id = "sidebar"]{
|
||||
background-color:#272822;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] div.afx-window-content {
|
||||
background-color:#333333;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] afx-resizer {
|
||||
background-color:#272822;
|
||||
border-right: 1px solid #656565;
|
||||
border-bottom: 1px solid #656565;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .bottom-tab-content {
|
||||
background-color:#272822;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-tree-view{
|
||||
color: white;
|
||||
padding: 0;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper afx-tree-view afx-tree-view-item ul li{
|
||||
padding-left: 10px;
|
||||
}
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper .afx_tree_item_selected ul{
|
||||
background-color: #116cd6;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-file-view afx-tree-view .afx-tree-view-item:before{
|
||||
color: white;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper div[data-id="statctn"]{
|
||||
color: white;
|
||||
background-color: #007acc;
|
||||
padding-right: 10px;
|
||||
padding-top: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] .afx-window-wrapper div[data-id="statctn"] afx-label {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper{
|
||||
border-radius: 0px;
|
||||
border: 0;
|
||||
/*border: 1px solid #37373d;*/
|
||||
background-color: transparent;
|
||||
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65);
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view ul afx-list-item:nth-child(even) li
|
||||
{
|
||||
background-color: transparent;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view afx-list-item li{
|
||||
background-color: transparent;
|
||||
color:#afafaf;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper div.list-container > ul li:hover{
|
||||
background-color: #37373d;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrapper afx-list-view ul afx-list-item:nth-child(even) li.selected,
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-wrappe dafx-list-viewafx-list-view ul li.selected
|
||||
{
|
||||
background-color: #116cd6;
|
||||
color:white;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-top{
|
||||
height: 0;
|
||||
border:0;
|
||||
}
|
||||
afx-app-window[data-id = "cmd-win"] input{
|
||||
border: 1px solid #007acc;
|
||||
border-radius: 0;
|
||||
font-size: 12px;
|
||||
color:#afafaf;
|
||||
background-color:#272822;
|
||||
padding-left: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "cmd-win"] .afx-window-content{
|
||||
background-color:#272822;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre {
|
||||
margin: 3px;
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-warn {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] div[data-id="output-tab"] pre.code-pad-log-info {
|
||||
color: white;
|
||||
}
|
||||
|
||||
afx-app-window[data-id = "antedit"] afx-button[ data-id="logger-clear" ] button{
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
19
Antedit/extensions/EditorExtensionMaker/main.tpl
Normal file
19
Antedit/extensions/EditorExtensionMaker/main.tpl
Normal file
@ -0,0 +1,19 @@
|
||||
(function() {
|
||||
// import the CodePad application module
|
||||
const App = this.OS.application.Antedit;
|
||||
|
||||
// define the extension
|
||||
App.extensions.{0} = class {0} extends App.EditorBaseExtension {
|
||||
constructor(app) {
|
||||
super("{0}",app);
|
||||
}
|
||||
|
||||
test() {
|
||||
return this.notify("Test action is invoked");
|
||||
}
|
||||
|
||||
cleanup() {}
|
||||
|
||||
};
|
||||
|
||||
}).call(this);
|
15
Antedit/extensions/EditorExtensionMaker/meta.tpl
Normal file
15
Antedit/extensions/EditorExtensionMaker/meta.tpl
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"javascripts": ["{0}.js"],
|
||||
"copies": [],
|
||||
"meta": {
|
||||
"name": "{0}",
|
||||
"text": "{0}",
|
||||
"version": "0.0.1-a",
|
||||
"actions" : [
|
||||
{
|
||||
"text": "__(Example action)",
|
||||
"name": "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
33
Antedit/extensions/extensions.json
Normal file
33
Antedit/extensions/extensions.json
Normal file
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"name": "EditorExtensionMaker",
|
||||
"text": "Antedit Extension",
|
||||
"version": "0.0.1-a",
|
||||
"actions" : [
|
||||
{
|
||||
"text": "__(New Extension)",
|
||||
"name": "create"
|
||||
},
|
||||
{
|
||||
"text": "__(Build)",
|
||||
"name": "build"
|
||||
},
|
||||
{
|
||||
"text": "__(Run)",
|
||||
"name": "run"
|
||||
},
|
||||
{
|
||||
"text": "__(Build release)",
|
||||
"name": "release"
|
||||
},
|
||||
{
|
||||
"text": "__(Install extension from file)",
|
||||
"name": "install"
|
||||
},
|
||||
{
|
||||
"text": "__(Install extension from URL)",
|
||||
"name": "installFromURL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -1,16 +1,24 @@
|
||||
{
|
||||
"pkgname": "Antedit",
|
||||
"app":"Antedit",
|
||||
"name":"Antedit",
|
||||
"description":"Antedit",
|
||||
"name":"Antos Editor",
|
||||
"description":"Antos text/code editor",
|
||||
"info":{
|
||||
"author": "",
|
||||
"email": ""
|
||||
"author": "Xuan Sang LE",
|
||||
"email": "mrsang@iohub.dev"
|
||||
},
|
||||
"version":"0.0.1-a",
|
||||
"category":"Other",
|
||||
"iconclass":"fa fa-adn",
|
||||
"mimes":["none"],
|
||||
"dependencies":[],
|
||||
"version":"0.1.0-a",
|
||||
"category":"Development",
|
||||
"iconclass":"bi bi-journal-code",
|
||||
"mimes":[
|
||||
"text/.*",
|
||||
"[^/]*/json.*",
|
||||
"[^/]*/.*ml",
|
||||
"[^/]*/javascript",
|
||||
"dir"
|
||||
],
|
||||
"dependencies":[
|
||||
"MonacoCore@0.23.0-r"
|
||||
],
|
||||
"locale": {}
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
{
|
||||
"name": "Antedit",
|
||||
"css": [],
|
||||
"css": ["css/main.css"],
|
||||
"javascripts": [],
|
||||
"coffees": ["coffees/main.coffee"],
|
||||
"ts": [],
|
||||
"copies": ["assets/scheme.html", "package.json", "README.md"]
|
||||
"coffees": [],
|
||||
"ts": [
|
||||
"ts/monaco.d.ts",
|
||||
"ts/BaseEditorModel.ts",
|
||||
"ts/MonacoEditorModel.ts",
|
||||
"ts/main.ts",
|
||||
"ts/EditorExtensionMaker.ts"
|
||||
],
|
||||
"copies": ["extensions","assets/scheme.html", "package.json", "README.md"]
|
||||
}
|
570
Antedit/ts/BaseEditorModel.ts
Normal file
570
Antedit/ts/BaseEditorModel.ts
Normal file
@ -0,0 +1,570 @@
|
||||
namespace OS {
|
||||
export namespace application {
|
||||
|
||||
/**
|
||||
* Extends the [[RemoteFileHandle]] interface with some useful
|
||||
* properties used by [[BaseEditorModel]]
|
||||
*/
|
||||
export type EditorFileHandle = API.VFS.RemoteFileHandle & {
|
||||
/**
|
||||
* The text will be displayed on the tab bar when opened
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
text: string;
|
||||
|
||||
/**
|
||||
* Editor text model attached to the file
|
||||
* modification history of the file
|
||||
*
|
||||
* @type {any}
|
||||
*/
|
||||
textModel: any;
|
||||
|
||||
/**
|
||||
* Indicate whether the file is selected
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
selected: boolean;
|
||||
|
||||
};
|
||||
|
||||
export abstract class BaseEditorModel {
|
||||
/**
|
||||
* Reference to the current editing file handle
|
||||
*
|
||||
* @protected
|
||||
* @type {EditorFileHandle}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected currfile: EditorFileHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Referent to the parent app
|
||||
*
|
||||
* @private
|
||||
* @type {BaseApplication}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private app: BaseApplication;
|
||||
|
||||
/**
|
||||
* Reference to the editor tab bar UI
|
||||
*
|
||||
* @private
|
||||
* @type {GUI.tag.TabBarTag}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private tabbar: GUI.tag.TabBarTag;
|
||||
|
||||
|
||||
/**
|
||||
* Referent to the editor container
|
||||
*
|
||||
* @private
|
||||
* @type {HTMLElement}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private container: HTMLElement;
|
||||
|
||||
onstatuschange: (stat: GenericObject<any>) => void;
|
||||
|
||||
/**
|
||||
* Editor mutex
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private editormux: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of BaseEditorModel.
|
||||
*
|
||||
* @param {Antedit} app parent app
|
||||
* @param {GUI.tag.TabBarTag} tabbar tabbar DOM element
|
||||
* @param {HTMLElement} editorarea editor container DOM element
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
constructor(app: BaseApplication, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
||||
this.container = editorarea;
|
||||
this.currfile = "Untitled".asFileHandle() as EditorFileHandle;
|
||||
this.tabbar = tabbar;
|
||||
this.editorSetup(editorarea);
|
||||
this.app = app;
|
||||
this.editormux = false;
|
||||
this.onstatuschange = undefined;
|
||||
|
||||
this.on("focus", () => {
|
||||
if (this.onstatuschange)
|
||||
this.onstatuschange(this.getEditorStatus());
|
||||
});
|
||||
this.on("input", () => {
|
||||
if (this.editormux) {
|
||||
this.editormux = false;
|
||||
return false;
|
||||
}
|
||||
if (!this.currfile.dirty) {
|
||||
this.currfile.dirty = true;
|
||||
this.currfile.text += "*";
|
||||
return this.tabbar.update(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
this.on("changeCursor", () => {
|
||||
if (this.onstatuschange)
|
||||
this.onstatuschange(this.getEditorStatus());
|
||||
});
|
||||
|
||||
this.tabbar.ontabselect = (e) => {
|
||||
return this.selecteTab($(e.data.item).index());
|
||||
};
|
||||
this.tabbar.ontabclose = (e) => {
|
||||
const it = e.data.item;
|
||||
if (!it) {
|
||||
return false;
|
||||
}
|
||||
if (!it.data.dirty) {
|
||||
return this.closeTab(it);
|
||||
}
|
||||
this.app.openDialog("YesNoDialog", {
|
||||
title: __("Close tab"),
|
||||
text: __("Close without saving ?"),
|
||||
}).then((d) => {
|
||||
if (d) {
|
||||
return this.closeTab(it);
|
||||
}
|
||||
return this.focus();
|
||||
});
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a tab on the tabbar corresponding to a file handle
|
||||
*
|
||||
* @private
|
||||
* @param {EditorFileHandle} file then file handle to search
|
||||
* @returns {number}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private findTabByFile(file: EditorFileHandle): number {
|
||||
const lst = this.tabbar.items;
|
||||
const its = (() => {
|
||||
const result = [];
|
||||
for (let i = 0; i < lst.length; i++) {
|
||||
const d = lst[i];
|
||||
if (d.hash() === file.hash()) {
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
if (its.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
return its[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new tab when opening a file
|
||||
*
|
||||
* @private
|
||||
* @param {EditorFileHandle} file
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private newTab(file: EditorFileHandle): void {
|
||||
file.text = file.basename ? file.basename : file.path;
|
||||
if (!file.cache) {
|
||||
file.cache = "";
|
||||
}
|
||||
file.textModel = this.newTextModelFrom(file);
|
||||
this.currfile.selected = false;
|
||||
file.selected = true;
|
||||
//console.log cnt
|
||||
this.tabbar.push(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a tab when a file is closed
|
||||
*
|
||||
* @private
|
||||
* @param {GUI.tag.ListViewItemTag} it reference to the tab to close
|
||||
* @returns {boolean}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private closeTab(it: GUI.tag.ListViewItemTag): boolean {
|
||||
this.tabbar.delete(it);
|
||||
const cnt = this.tabbar.items.length;
|
||||
|
||||
if (cnt === 0) {
|
||||
this.openFile(
|
||||
"Untitled".asFileHandle() as EditorFileHandle
|
||||
);
|
||||
return false;
|
||||
}
|
||||
this.tabbar.selected = cnt - 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a tab by its index
|
||||
*
|
||||
* @private
|
||||
* @param {number} i tab index
|
||||
* @returns {void}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private selecteTab(i: number): void {
|
||||
//return if i is @tabbar.get "selidx"
|
||||
const file = this.tabbar.items[i] as EditorFileHandle;
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
//return if file is @currfile
|
||||
if (this.currfile !== file) {
|
||||
this.currfile.textModel = this.getTexModel();
|
||||
this.currfile.selected = false;
|
||||
this.currfile = file;
|
||||
}
|
||||
|
||||
this.editormux = true;
|
||||
this.setTextModel(file.textModel);
|
||||
if (this.onstatuschange)
|
||||
this.onstatuschange(this.getEditorStatus());
|
||||
this.focus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Select an opened file, this will select the corresponding tab
|
||||
*
|
||||
* @param {(EditorFileHandle | string)} file
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
selectFile(file: EditorFileHandle | string): void {
|
||||
const i = this.findTabByFile(
|
||||
file.asFileHandle() as EditorFileHandle
|
||||
);
|
||||
if (i !== -1) {
|
||||
this.tabbar.selected = i;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Open a file in new tab. If the file is already opened,
|
||||
* the just select the tab
|
||||
*
|
||||
*
|
||||
* @param {EditorFileHandle} file file to open
|
||||
* @returns {void}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
openFile(file: EditorFileHandle): void {
|
||||
//find tab
|
||||
const i = this.findTabByFile(file);
|
||||
if (i !== -1) {
|
||||
this.tabbar.selected = i;
|
||||
return;
|
||||
}
|
||||
if (file.path.toString() === "Untitled") {
|
||||
this.newTab(file);
|
||||
return;
|
||||
}
|
||||
|
||||
file.read()
|
||||
.then((d) => {
|
||||
file.cache = d || "";
|
||||
return this.newTab(file);
|
||||
})
|
||||
.catch((e) => {
|
||||
return this.app.error(
|
||||
__("Unable to open: {0}", file.path),
|
||||
e
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* write a file
|
||||
*
|
||||
* @private
|
||||
* @param {EditorFileHandle} file
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
private write(file: EditorFileHandle): void {
|
||||
this.currfile.cache = this.getValue();
|
||||
file.write("text/plain")
|
||||
.then((d) => {
|
||||
file.dirty = false;
|
||||
file.text = file.basename;
|
||||
this.tabbar.update(undefined);
|
||||
})
|
||||
.catch((e) =>
|
||||
this.app.error(__("Unable to save file: {0}", file.path), e)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the current opened file
|
||||
*
|
||||
* @return {*} {void}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
save(): void {
|
||||
this.currfile.cache = this.getValue();
|
||||
if (this.currfile.basename) {
|
||||
return this.write(this.currfile);
|
||||
}
|
||||
return this.saveAs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current file as another file
|
||||
*
|
||||
* @public
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
saveAs(): void {
|
||||
this.app.openDialog("FileDialog", {
|
||||
title: __("Save as"),
|
||||
file: this.currfile,
|
||||
}).then((f) => {
|
||||
let d = f.file.path.asFileHandle();
|
||||
if (f.file.type === "file") {
|
||||
d = d.parent();
|
||||
}
|
||||
this.currfile.setPath(`${d.path}/${f.name}`);
|
||||
this.write(this.currfile);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dirty file handles in the editor
|
||||
*
|
||||
* @return {*} {EditorFileHandle[]}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
dirties(): EditorFileHandle[] {
|
||||
const result = [];
|
||||
for (let v of Array.from(this.tabbar.items)) {
|
||||
if (v.dirty) {
|
||||
result.push(v);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context menu handle for the editor
|
||||
*
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
set contextmenuHandle(cb: (e: any, m: any) => void) {
|
||||
this.container.contextmenuHandle = cb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close all opened files
|
||||
*
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
closeAll(): void {
|
||||
this.tabbar.items = [];
|
||||
this.resetEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the editor is dirty
|
||||
*
|
||||
* @return {*} {boolean}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
isDirty(): boolean {
|
||||
return this.dirties().length > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up the editor instance
|
||||
* Should be implemented by subclass
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @param {HTMLElement} el
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract editorSetup(el: HTMLElement): void;
|
||||
|
||||
|
||||
/**
|
||||
* Listen to editor event
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} evt_str
|
||||
* @param {() => void} callback
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract on(evt_str: string, callback: () => void): void;
|
||||
|
||||
|
||||
/**
|
||||
* Resize the editor
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract resize(): void;
|
||||
|
||||
|
||||
/**
|
||||
* Make the editor focused
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract focus(): void;
|
||||
|
||||
|
||||
/**
|
||||
* Get language mode from file extension
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @param {string} path
|
||||
* @return {*} {GenericObject<any>}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract getModeForPath(path: string): GenericObject<any>;
|
||||
|
||||
|
||||
/**
|
||||
* Query the editor status
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @return {*} {GenericObject<any>}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract getEditorStatus(): GenericObject<any>;
|
||||
|
||||
|
||||
/**
|
||||
* Get the editor value
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @return {*} {string}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract getValue(): string;
|
||||
|
||||
|
||||
/**
|
||||
* Set the editor value
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} value
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract setValue(value: string): void;
|
||||
|
||||
/**
|
||||
* Set the editor language mode
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @param {GenericObject<any>} m
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract setMode(m: GenericObject<any>): void;
|
||||
|
||||
|
||||
/**
|
||||
* Get textModel from the current editor session
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @return {*} {*}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract getTexModel(): any;
|
||||
|
||||
|
||||
/**
|
||||
* Set text model to the current editor session
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @param {*} model
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract setTextModel(model: any): void;
|
||||
|
||||
|
||||
/**
|
||||
* Create new text model from the VFS file
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @param {EditorFileHandle} file
|
||||
* @return {*} {*}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract newTextModelFrom(file: EditorFileHandle): any;
|
||||
|
||||
|
||||
/**
|
||||
* Reset the editor
|
||||
*
|
||||
* @protected
|
||||
* @abstract
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
protected abstract resetEditor(): void;
|
||||
|
||||
/**
|
||||
* Set the current editor theme
|
||||
*
|
||||
* Should be implemented by subclasses
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} theme
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract setTheme(theme: string): void;
|
||||
|
||||
|
||||
/**
|
||||
* Get all language modes supported by the editor
|
||||
*
|
||||
* @abstract
|
||||
* @return {*} {GenericObject<any>[]}
|
||||
* @memberof BaseEditorModel
|
||||
*/
|
||||
abstract getModes(): GenericObject<any>[];
|
||||
|
||||
/**
|
||||
* Get the real editor model
|
||||
*/
|
||||
abstract getEditor(): any;
|
||||
}
|
||||
}
|
||||
}
|
472
Antedit/ts/EditorExtensionMaker.ts
Normal file
472
Antedit/ts/EditorExtensionMaker.ts
Normal file
@ -0,0 +1,472 @@
|
||||
|
||||
namespace OS {
|
||||
|
||||
declare var JSZip: any;
|
||||
|
||||
export namespace application {
|
||||
export type AnteditBaseExtension = typeof EditorBaseExtension;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @class EditorBaseExtension
|
||||
*/
|
||||
class EditorBaseExtension {
|
||||
static dependencies: string[];
|
||||
|
||||
protected app: OS.application.Antedit;
|
||||
protected name: string;
|
||||
constructor(name:string, app: OS.application.Antedit) {
|
||||
this.app = app;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns {Promise<any>}
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
preload(): Promise<any> {
|
||||
return API.require(OS.application.Antedit.extensions[this.name].dependencies);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @returns {string}
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
protected basedir(): string {
|
||||
return `${this.app.meta().path}/extensions/${this.name}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @param {(string | FormattedString)} m
|
||||
* @returns {void}
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
protected notify(m: string | FormattedString): void {
|
||||
return this.app.notify(m);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @param {(string | FormattedString)} m
|
||||
* @param {Error} e
|
||||
* @returns {void}
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
protected error(m: string | FormattedString, e: Error): void {
|
||||
return this.app.error(m, e);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @return {AnteditLogger} editor logger
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
protected logger(): any {
|
||||
if (!this.app.setting.showBottomBar) {
|
||||
this.app.showOutput(true);
|
||||
}
|
||||
else {
|
||||
this.app.showOutput(false);
|
||||
}
|
||||
return this.app.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @protected
|
||||
* @param {string} file
|
||||
* @returns {Promise<GenericObject<any>>}
|
||||
* @memberof EditorBaseExtension
|
||||
*/
|
||||
protected metadata(file: string): Promise<GenericObject<any>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.app.currdir) {
|
||||
return reject(
|
||||
API.throwe(__("Current folder is not found"))
|
||||
);
|
||||
}
|
||||
`${this.app.currdir.path}/${file}`
|
||||
.asFileHandle()
|
||||
.read("json")
|
||||
.then((data) => {
|
||||
if (!data.root && this.app.currdir) {
|
||||
data.root = this.app.currdir.path;
|
||||
}
|
||||
resolve(data);
|
||||
})
|
||||
.catch((e) => {
|
||||
// try to ask user to select a folder
|
||||
this.app.openDialog("FileDialog", {
|
||||
title: __("Select build directory"),
|
||||
root: this.app.currdir.path,
|
||||
mimes: ["dir"]
|
||||
})
|
||||
.then((d) => {
|
||||
`${d.file.path}/${file}`
|
||||
.asFileHandle()
|
||||
.read("json")
|
||||
.then((data) => {
|
||||
if (!data.root) {
|
||||
data.root = d.file.path;
|
||||
}
|
||||
resolve(data);
|
||||
})
|
||||
.catch((e1) => reject(e1))
|
||||
})
|
||||
.catch(
|
||||
(e1) => reject(API.throwe(__("Unable to read meta-data"))
|
||||
))
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
EditorBaseExtension.dependencies = [];
|
||||
OS.application.Antedit.extensions = {};
|
||||
OS.application.Antedit.EditorBaseExtension = EditorBaseExtension;
|
||||
|
||||
class EditorExtensionMaker extends EditorBaseExtension {
|
||||
constructor(app: OS.application.Antedit) {
|
||||
super("EditorExtensionMaker", app);
|
||||
}
|
||||
|
||||
create(): void {
|
||||
this.logger().clear();
|
||||
this.app
|
||||
.openDialog("FileDialog", {
|
||||
title: "__(New CodePad extension at)",
|
||||
file: { basename: __("ExtensionName") },
|
||||
mimes: ["dir"],
|
||||
})
|
||||
.then((d) => {
|
||||
return this.mktpl(d.file.path, d.name);
|
||||
});
|
||||
}
|
||||
|
||||
build(callback?: () => void): void {
|
||||
this.logger().clear();
|
||||
this.metadata("extension.json")
|
||||
.then(async (meta) => {
|
||||
try {
|
||||
const jsrc = await API.VFS.cat(meta.javascripts.map(v => `${meta.root}/${v}`),"");
|
||||
|
||||
await `${meta.root}/build/debug/main.js`
|
||||
.asFileHandle()
|
||||
.setCache(jsrc)
|
||||
.write("text/plain");
|
||||
|
||||
await `${meta.root}/build/debug/extension.json`
|
||||
.asFileHandle()
|
||||
.setCache(meta.meta)
|
||||
.write("object");
|
||||
|
||||
await API.VFS.copy( meta.copies.map(v => `${meta.root}/${v}`),`${meta.root}/build/debug`);
|
||||
this.logger().info(__("Files generated in {0}", `${meta.root}/build/debug`));
|
||||
if(callback)
|
||||
callback();
|
||||
} catch (e) {
|
||||
return this.logger().error(__("Unable to build extension:{0}", e.stack));
|
||||
}
|
||||
})
|
||||
.catch((e) => this.logger().error(__("Unable to read meta-data:{0}", e.stack)));
|
||||
}
|
||||
|
||||
run(): void {
|
||||
this.logger().clear();
|
||||
this.metadata("extension.json")
|
||||
.then(async (meta) => {
|
||||
if(!meta || !meta.meta || !meta.meta.name)
|
||||
return this.logger().error(__("Invalid extension meta-data"));
|
||||
try {
|
||||
const path = `${meta.root}/build/debug/main.js`;
|
||||
if (API.shared[path]) {
|
||||
delete API.shared[path];
|
||||
}
|
||||
await API.requires(path);
|
||||
if (this.app.extensions[meta.meta.name] && this.app.extensions[meta.meta.name].cleanup)
|
||||
{
|
||||
this.app.extensions[meta.meta.name].cleanup();
|
||||
}
|
||||
this.app.extensions[meta.meta.name] = new OS.application.Antedit.extensions[meta.meta.name](this.app);
|
||||
for (let v of meta.meta.actions) {
|
||||
this.app.eum.addAction(meta.meta, v, (e_name, a_name) => {
|
||||
this.app.loadAndRunExtensionAction(e_name, a_name, `${meta.root}/build`);
|
||||
});
|
||||
}
|
||||
this.app.eum.active.getEditor().trigger(meta.meta.name, 'editor.action.quickCommand');
|
||||
} catch (e) {
|
||||
return this.logger().error(__("Unable to run extension:{0}", e.stack));
|
||||
}
|
||||
})
|
||||
.catch((e) => this.logger().error(__("Unable to read meta-data:{0}", e.stack)));
|
||||
}
|
||||
|
||||
release(): void {
|
||||
this.logger().clear();
|
||||
this.metadata("extension.json")
|
||||
.then((meta) => {
|
||||
this.build(async () => {
|
||||
try {
|
||||
API.VFS.mkar(
|
||||
`${meta.root}/build/debug`,
|
||||
`${meta.root}/build/release/${meta.meta.name}.zip`
|
||||
);
|
||||
this.logger().info(__("Archive created at {0}", `${meta.root}/build/release/${meta.meta.name}.zip`));
|
||||
} catch (e) {
|
||||
return this.logger().error(
|
||||
__("Unable to create archive: {0}",
|
||||
e.stack
|
||||
));
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((e) => this.logger().error(__("Unable to read meta-data: {0}", e.stack)));
|
||||
}
|
||||
|
||||
install(): void {
|
||||
this.logger().clear();
|
||||
this.app
|
||||
.openDialog("FileDialog", {
|
||||
title: "__(Select extension archive)",
|
||||
mimes: [".*/zip"],
|
||||
})
|
||||
.then(async (d) => {
|
||||
try {
|
||||
await this.installZip(d.file.path);
|
||||
this.logger().info(__("Extension installed"));
|
||||
return this.app.loadExtensionMetaData();
|
||||
} catch (e) {
|
||||
return this.logger().error(__("Unable to install extension: {0}", e.stack));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
installFromURL(): void
|
||||
{
|
||||
this.logger().clear();
|
||||
this.app
|
||||
.openDialog("PromptDialog", {
|
||||
title: __("Enter URI"),
|
||||
label: __("Please enter extension URI:")
|
||||
})
|
||||
.then(async (v) => {
|
||||
if(!v) return;
|
||||
try {
|
||||
await this.installZip(v);
|
||||
this.logger().info(__("Extension installed"));
|
||||
return this.app.loadExtensionMetaData();
|
||||
} catch (e) {
|
||||
return this.app.error(__("Unable to install extension: {0}", v));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @param {string} path
|
||||
* @param {string} name
|
||||
* @memberof EditorExtensionMaker
|
||||
*/
|
||||
private mktpl(path: string, name: string): void {
|
||||
const rpath = `${path}/${name}`;
|
||||
const dirs = [
|
||||
rpath,
|
||||
`${rpath}/build`,
|
||||
`${rpath}/build/release`,
|
||||
`${rpath}/build/debug`,
|
||||
];
|
||||
const files = [
|
||||
["main.tpl", `${rpath}/${name}.js`],
|
||||
["meta.tpl", `${rpath}/extension.json`],
|
||||
];
|
||||
API.VFS.mkdirAll(dirs)
|
||||
.then(async () => {
|
||||
try {
|
||||
await API.VFS.mktpl(files, this.basedir(), (data)=>{
|
||||
return data.format(name, `${path}/${name}`);
|
||||
});
|
||||
this.app.currdir = rpath.asFileHandle();
|
||||
this.app.toggleSideBar();
|
||||
return this.app.eum.active.openFile(
|
||||
`${rpath}/${name}.js`.asFileHandle() as application.EditorFileHandle
|
||||
);
|
||||
} catch (e) {
|
||||
return this.logger().error(
|
||||
__("Unable to create extension template: {0}",
|
||||
e.stack)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((e) =>
|
||||
this.logger().error(__("Unable to create extension directories: {0}", e.stack))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @param {string} path
|
||||
* @returns {Promise<any>}
|
||||
* @memberof EditorExtensionMaker
|
||||
*/
|
||||
private installZip(path: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
API.requires("os://scripts/jszip.min.js")
|
||||
.then(() => {
|
||||
path.asFileHandle()
|
||||
.read("binary")
|
||||
.then((data) => {
|
||||
JSZip.loadAsync(data)
|
||||
.then((zip: any) => {
|
||||
zip.file("extension.json").async("uint8array")
|
||||
.then((d) =>{
|
||||
const meta = JSON.parse(new TextDecoder("utf-8").decode(d));
|
||||
const pth = this.ext_dir(meta.name);
|
||||
const dir = [pth];
|
||||
const files = [];
|
||||
for (let name in zip.files) {
|
||||
const file = zip.files[name];
|
||||
if (file.dir) {
|
||||
dir.push(pth + "/" + name);
|
||||
} else if(name != "extension.json") {
|
||||
files.push(name);
|
||||
}
|
||||
}
|
||||
if (dir.length > 0) {
|
||||
API.VFS.mkdirAll(dir)
|
||||
.then(() => {
|
||||
this.installFiles(files, zip, meta)
|
||||
.then(() => resolve())
|
||||
.catch((e) =>
|
||||
reject(__e(e))
|
||||
);
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
} else {
|
||||
this.installFiles(files, zip, meta)
|
||||
.then(() => resolve())
|
||||
.catch((e) => reject(__e(e)));
|
||||
}
|
||||
})
|
||||
.catch(e => reject(__e(e)));
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private ext_dir(en: string): string
|
||||
{
|
||||
return `${this.app.meta().path}/extensions/${en}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @param {string[]} files
|
||||
* @param {*} zip
|
||||
* @param {GenericObject<any>} meta
|
||||
* @returns {Promise<any>}
|
||||
* @memberof EditorExtensionMaker
|
||||
*/
|
||||
private installFiles(
|
||||
files: string[],
|
||||
zip: any,
|
||||
meta: GenericObject<any>
|
||||
): Promise<void> {
|
||||
if (files.length === 0) {
|
||||
return this.installMeta(meta);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = files.splice(0, 1)[0];
|
||||
const path = `${this.ext_dir(meta.name)}/${file}`;
|
||||
return zip
|
||||
.file(file)
|
||||
.async("uint8array")
|
||||
.then((d: Uint8Array) => {
|
||||
return path
|
||||
.asFileHandle()
|
||||
.setCache(new Blob([d], { type: "octet/stream" }))
|
||||
.write("text/plain")
|
||||
.then((r) => {
|
||||
if (r.error) {
|
||||
return reject(r.error);
|
||||
}
|
||||
return this.installFiles(files, zip, meta)
|
||||
.then(() => resolve())
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e) => reject(__e(e)));
|
||||
})
|
||||
.catch((e: Error) => reject(__e(e)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @param {GenericObject<any>} meta
|
||||
* @returns {Promise<void>}
|
||||
* @memberof EditorExtensionMaker
|
||||
*/
|
||||
private installMeta(meta: GenericObject<any>): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const file = `${this.ext_dir("")}/extensions.json`.asFileHandle();
|
||||
try {
|
||||
const data = await file.read("json");
|
||||
const names = [];
|
||||
for (let v of data) {
|
||||
names.push(v.name);
|
||||
}
|
||||
const idx = names.indexOf(meta.name);
|
||||
if (idx >= 0) {
|
||||
data.splice(idx, 1);
|
||||
}
|
||||
data.push(meta);
|
||||
try {
|
||||
await file.setCache(data).write("object");
|
||||
return resolve();
|
||||
} catch (e) {
|
||||
return reject(__e(e));
|
||||
}
|
||||
} catch (e_1) {
|
||||
// try to create new file
|
||||
try {
|
||||
await file.setCache([meta]).write("object");
|
||||
return resolve();
|
||||
} catch (e_2) {
|
||||
return reject(__e(e_2));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
OS.application.Antedit.extensions.EditorExtensionMaker = EditorExtensionMaker;
|
||||
}
|
271
Antedit/ts/MonacoEditorModel.ts
Normal file
271
Antedit/ts/MonacoEditorModel.ts
Normal file
@ -0,0 +1,271 @@
|
||||
namespace OS {
|
||||
export namespace application {
|
||||
/**
|
||||
* Wrapper model for the ACE text editor
|
||||
*
|
||||
* @export
|
||||
* @class MonacoEditorModel
|
||||
* @extends {BaseEditorModel}
|
||||
*/
|
||||
export class MonacoEditorModel extends BaseEditorModel {
|
||||
|
||||
static modes: GenericObject<monaco.languages.ILanguageExtensionPoint>;
|
||||
|
||||
/**
|
||||
* Creates an instance of MonacoEditorModel.
|
||||
* @param {MonacoEditorModel} app MonacoEditorModel instance
|
||||
* @param {GUI.tag.TabBarTag} tabbar tabbar element
|
||||
* @param {HTMLElement} editorarea main editor container element
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
constructor(app: BaseApplication, tabbar: GUI.tag.TabBarTag, editorarea: HTMLElement) {
|
||||
super(app, tabbar, editorarea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the editor
|
||||
*
|
||||
* @protected
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected resetEditor(): void {
|
||||
this.setValue("");
|
||||
// TODO create new textmodel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a text model from the current editor session
|
||||
*
|
||||
* @protected
|
||||
* @return {*}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected getTexModel() {
|
||||
return {
|
||||
model: this.editor.getModel(),
|
||||
position: this.editor.getPosition()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set text model to current editor session
|
||||
*
|
||||
* @protected
|
||||
* @param {*} model
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected setTextModel(model: any): void {
|
||||
this.editor.setModel(model.model);
|
||||
if(model.position)
|
||||
this.editor.setPosition(model.position);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create new editor model from file
|
||||
*
|
||||
* @protected
|
||||
* @param {EditorFileHandle} file
|
||||
* @return {*} {*}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected newTextModelFrom(file: EditorFileHandle): any {
|
||||
if(file.path.toString() === "Untitled") {
|
||||
return {
|
||||
model: monaco.editor.createModel(file.cache, "textplain")
|
||||
}
|
||||
}
|
||||
const uri = monaco.Uri.parse(file.path);
|
||||
const model = monaco.editor.getModel(uri);
|
||||
if(model)
|
||||
{
|
||||
return { model: model };
|
||||
}
|
||||
return {
|
||||
model: monaco.editor.createModel(file.cache, undefined, uri)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language modes
|
||||
*
|
||||
* @return {*} {GenericObject<any>[]}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
getModes(): GenericObject<any>[] {
|
||||
//const list = [];
|
||||
//return list;
|
||||
return monaco.languages.getLanguages();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the editor theme
|
||||
*
|
||||
* @param {string} theme theme name
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
setTheme(theme: string): void {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set editor language mode
|
||||
*
|
||||
* The mode object should be in the following format:
|
||||
* ```ts
|
||||
* {
|
||||
* text: string,
|
||||
* mode: string
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {GenericObject<any>} m language mode object
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
setMode(m: GenericObject<any>): void {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to the editor instance
|
||||
*
|
||||
* @private
|
||||
* @type {GenericObject<any>}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
private editor: GenericObject<any>;
|
||||
|
||||
|
||||
/**
|
||||
* Setup the editor
|
||||
*
|
||||
* @protected
|
||||
* @param {HTMLElement} el editor container DOM
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected editorSetup(el: HTMLElement): void {
|
||||
this.editor = monaco.editor.create(el, {
|
||||
value: "",
|
||||
language: 'textplain'
|
||||
});
|
||||
if(!MonacoEditorModel.modes)
|
||||
{
|
||||
MonacoEditorModel.modes = {};
|
||||
monaco.languages.getLanguages().forEach((el) =>{
|
||||
MonacoEditorModel.modes[el.id] = el;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register to editor event
|
||||
*
|
||||
* @param {string} evt_str event name
|
||||
* @param {() => void} callback callback function
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
on(evt_str: string, callback: () => void): void {
|
||||
switch (evt_str) {
|
||||
case "input":
|
||||
this.editor.onDidChangeModelContent(callback);
|
||||
break;
|
||||
case "focus":
|
||||
this.editor.onDidFocusEditorText(callback);
|
||||
break;
|
||||
case "changeCursor":
|
||||
this.editor.onDidChangeCursorPosition(callback);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resize the editor
|
||||
*
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
resize(): void {
|
||||
if(this.editor)
|
||||
this.editor.layout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Focus on the editor
|
||||
*
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
focus(): void {
|
||||
if(this.editor)
|
||||
this.editor.focus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get language mode from path
|
||||
*
|
||||
* @protected
|
||||
* @param {string} path
|
||||
* @return {*} {GenericObject<any>}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
protected getModeForPath(path: string): GenericObject<any> {
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the editor status
|
||||
*
|
||||
* @return {*} {GenericObject<any>}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
getEditorStatus(): GenericObject<any> {
|
||||
const pos = this.editor.getPosition();
|
||||
const mode = MonacoEditorModel.modes[this.editor.getModel().getModeId()];
|
||||
return {
|
||||
row: pos.lineNumber,
|
||||
column: pos.column,
|
||||
line: this.editor.getModel().getLineCount(),
|
||||
langmode: {
|
||||
text: mode.aliases[0],
|
||||
mode: mode
|
||||
},
|
||||
file: this.currfile.path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get editor value
|
||||
*
|
||||
* @return {*} {string}
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
getValue(): string {
|
||||
return this.editor.getValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set editor value
|
||||
*
|
||||
* @param {string} value
|
||||
* @memberof MonacoEditorModel
|
||||
*/
|
||||
setValue(value: string): void {
|
||||
this.editor.setValue(value);
|
||||
}
|
||||
|
||||
getEditor(): any {
|
||||
return this.editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1106
Antedit/ts/main.ts
1106
Antedit/ts/main.ts
File diff suppressed because it is too large
Load Diff
7370
Antedit/ts/monaco.d.ts
vendored
Normal file
7370
Antedit/ts/monaco.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user