graviton-plugin-sdk
Version:
Gravtion plugin Dev Kit
931 lines (891 loc) • 24.2 kB
JavaScript
/*
########################################
MIT License
Copyright (c) 2019 Marc Espin Sanz
License > https://github.com/Graviton-Code-Editor/Graviton-App/blob/master/LICENSE.md
#########################################
*/
;
const GravitonInfo = {
date: "191101",
version: "1.2.0",
state: "Beta"
};
const fs = require("fs-extra"),
remote = require("electron").remote,
BrowserWindow = require("electron").BrowserWindow,
app = remote.remote,
getAppDataPath = require("appdata-path"),
{ webFrame } = require("electron"),
g_window = remote.getCurrentWindow(),
{ systemPreferences } = remote,
CodeMirror = require("codemirror"),
semver = require("semver"),
tinycolor = require("tinycolor2"),
EventEmitter = require("events");
require(path.join(
__dirname,
"src",
"javascript",
"api",
"codemirror-langs.js"
)).langs(); //Load CodeMirror files
const { elasticContainerComponent, elasticContainer } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"elastic_container.js"
));
window.customElements.define("elastic-container", elasticContainerComponent);
graviton.loadEditor = require(path.join(
__dirname,
"src",
"javascript",
"api",
"editors.js"
)).loadEditor;
const { loadLanguage, getTranslation } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"languages.js"
)),
{ getFormat, getLanguageName, updateCodeMode } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"format.js"
)),
screens = require(path.join(
__dirname,
"src",
"javascript",
"api",
"screens.js"
)),
updater = require(path.join(
__dirname,
"src",
"javascript",
"api",
"updater.js"
));
graviton.setTheme = require(path.join(
__dirname,
"src",
"javascript",
"api",
"theming.js"
)).setTheme;
const Settings = require(path.join(
__dirname,
"src",
"javascript",
"windows",
"settings.js"
)).Settings,
Welcome = require(path.join(
__dirname,
"src",
"javascript",
"windows",
"welcome.js"
)).Welcome,
Setup = require(path.join(
__dirname,
"src",
"javascript",
"windows",
"setup.js"
)).Setup,
Market = require(path.join(
__dirname,
"src",
"javascript",
"windows",
"market.js"
)).Market,
NewProject = require(path.join(
__dirname,
"src",
"javascript",
"windows",
"new_project.js"
)).NewProject,
Plugins = require(path.join(
__dirname,
"src",
"javascript",
"api",
"plugins.js"
)).Plugins,
Menus = require(path.join(__dirname, "src", "javascript", "api", "menus.js"))
.Menus,
Explorer = require(path.join(
__dirname,
"src",
"javascript",
"api",
"explorer.js"
)).Explorer,
Control = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"control.js"
)).Control,
{ Dialog, closeDialog } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"dialogs.js"
)),
{ Window, closeWindow } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"windows.js"
)),
{ Notification, closeNotification } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"notifications.js"
)),
{ Tab, closeTab, loadTab } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"tabs.js"
)),
dropMenu = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"dropmenus.js"
)).Dropmenu;
let { icons } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"icons.js"
));
const { commander, commanders } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"commanders.js"
));
const { Panel } = require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"panels.js"
));
window.customElements.define(
"gv-switch",
require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"switch.js"
))
);
window.customElements.define(
"gv-navpanel",
require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"gv_navbar.js"
))
);
require(path.join(__dirname, "src", "javascript", "npm", "npm_panel.js"));
window.customElements.define(
"gv-process",
require(path.join(
__dirname,
"src",
"javascript",
"api",
"components",
"process_bar.js"
))
);
let current_screen,
dir_path,
i,
b,
DataFolderDir = path.join(path.join(__dirname, ".."), ".graviton"),
tabs = [],
FirstFolder = null,
editingTab,
plang = "",
_notifications = [],
filepath = null,
editors = [],
editor,
editorID,
editor_mode = "normal",
g_highlighting = "activated",
log = [],
themes = [],
pagesEvents = [],
themeObject = {
colors: {
accentColor: getComputedStyle(document.documentElement).getPropertyValue(
"--accentColor"
),
accentLightColor: getComputedStyle(
document.documentElement
).getPropertyValue("--accentLightColor"),
accentDarkColor: getComputedStyle(
document.documentElement
).getPropertyValue("--accentDarkColor"),
"editor-background-color": getComputedStyle(
document.documentElement
).getPropertyValue("--editor-background-color")
}
},
new_update = false,
mouseClicked = false,
touchingResizerValue = false,
editor_screens = [],
languages = [],
dictionary = autocomplete,
Mousetrap = require("mousetrap"),
terminal = null,
workspaces = [],
plugins_market = [],
current_plugins = 0,
templates = {},
plugins_list = [],
plugins_dbs = [],
anyDropON = null,
full_plugins = [],
projectServices = [];
const default_plugins = [
"Graviton-Code-Editor/Dark",
"Graviton-Code-Editor/Arctic"
]; //Plugins which are installed in the setup process
if (graviton.isProduction()) {
DataFolderDir = path.join(getAppDataPath(), ".graviton");
}
if (!fs.existsSync(DataFolderDir)) fs.mkdirSync(DataFolderDir); // Create .graviton if it doesn't exist
/* Set path for graviton's files and dirs */
let logDir = path.join(DataFolderDir, "log.json"),
configDir = path.join(DataFolderDir, "config.json"),
plugins_folder = path.join(DataFolderDir, "plugins"),
plugins_db = path.join(DataFolderDir, "plugins_db"),
market_file = path.join(DataFolderDir, "market.json");
document.addEventListener(
"mousedown",
function(event) {
if (event.which) mouseClicked = true;
},
true
);
document.addEventListener(
"mouseup",
function(event) {
if (event.which) mouseClicked = false;
},
true
);
document.addEventListener("graviton_loaded", () => {
/**
* @desc The resizer between the explorer panel and the editors
*/
const element = document.getElementById("editor_resizer");
element.addEventListener("mousedown", initialiseResize, false);
function initialiseResize(e) {
window.addEventListener("mousemove", startResizing, false);
window.addEventListener("mouseup", stopResizing, false);
}
function startResizing(e) {
const explorer = document.getElementById("explorer_app");
const content_app = document.getElementById("content_app");
if (current_config.explorerPosition === "left") {
explorer.style = `width: ${e.clientX - 3}px`;
} else {
explorer.style = `width: ${content_app.clientWidth - e.clientX}px`;
}
for (i = 0; i < editors.length; i++) {
editors[i].object.blur();
}
graviton.resizeTerminals();
}
function stopResizing(e) {
window.removeEventListener("mousemove", startResizing, false);
window.removeEventListener("mouseup", stopResizing, false);
}
});
preload([
"src/icons/folder_opened.svg",
"src/icons/custom_icons/git.svg",
"src/icons/custom_icons/node_modules.svg"
]);
preloadFont(["editor", "terminal"]);
window.onload = function() {
fs.readdir(path.join(__dirname, "src", "templates"), (err, paths) => {
/* Load UI templates */
let temporal_count = 0;
paths.forEach((dir, index) => {
fs.readFile(
path.join(__dirname, "src", "templates", dir),
"utf8",
function(err, data) {
templates[path.basename(dir, ".js")] = data;
temporal_count++;
document.getElementById("boot_loader").children[0].style.width =
temporal_count + 20 + "%";
if (temporal_count == paths.length) {
fs.readdir(path.join(__dirname, "languages"), (err, paths) => {
/* Load languages */
let path_count = 0;
paths.forEach((dir, index) => {
languages.push(require(path.join(__dirname, "languages", dir)));
path_count++;
if (paths.length === path_count) {
graviton.loadControlButtons();
loadConfig();
graviton.consoleInfo("All templates have been loaded.");
if (document.getElementById("boot_loader") !== null)
document.getElementById("boot_loader").children[0].style =
"width: 100%; border-radius:100px;";
}
});
});
}
}
);
});
});
};
graviton.setTitle(`v${GravitonInfo.version}`); //Initial title
const appendBinds = () => {
Mousetrap.bind("mod+s", function() {
saveFile();
});
Mousetrap.bind("mod+n", function() {
screens.add();
});
Mousetrap.bind("mod+l", function() {
screens.remove(current_screen.id);
});
Mousetrap.bind("mod+e", function() {
graviton.toggleZenMode();
});
Mousetrap.bind("mod+t", function() {
if (terminal != null) {
commanders.show(terminal.id);
return;
}
commanders.terminal();
});
Mousetrap.bind("mod+u", function() {
commanders.closeTerminal();
});
Mousetrap.bind("mod+h", function() {
if (terminal != null) {
commanders.hide(terminal.id);
}
});
Mousetrap.bind("f11", function() {
graviton.toggleFullScreen();
});
Mousetrap.bind("mod+tab", function() {
graviton.toggleMenus();
});
};
function saveFileAs() {
const { dialog } = remote;
dialog
.showSaveDialog(g_window)
.then(result => {
if (result.canceled) return;
fs.writeFile(result.filePath, editor.getValue())
.then(() => {
filepath = result.filePath;
new Notification({
title: "Graviton",
content: `The file has been succesfully saved in ${result.filePath}`
});
})
.catch(err => {
if (err) {
alert(`An error ocurred creating the file ${err.message}`);
return;
}
});
})
.catch(err => {
console.log(err);
});
}
function openFile() {
const { dialog } = remote;
dialog
.showOpenDialog(g_window, {
properties: ["openFile", "multiSelections"]
})
.then(result => {
if (result.canceled) return;
result.filePaths.forEach(file => {
new Tab({
id: Math.random() + file.replace(/\\/g, "") + "B",
path: file,
name: file,
type: "file"
});
});
})
.catch(err => {
console.log(err);
});
}
function openFolder() {
const { dialog } = remote;
dialog
.showOpenDialog(g_window, {
properties: ["openDirectory"]
})
.then(result => {
if (result.canceled) return;
console.log("dsf");
Explorer.load(result.filePaths[0], "g_directories", true);
})
.catch(err => {
console.log(err);
});
}
function saveFile() {
const { dialog } = remote;
if (graviton.getCurrentEditor() === null) return;
if (graviton.getCurrentEditor().editor === undefined) return;
fs.writeFile(filepath, editor.getValue())
.then(() => {
document.getElementById(editingTab).setAttribute("file_status", "saved");
document
.getElementById(editingTab)
.children[1].setAttribute(
"onclick",
document
.getElementById(editingTab)
.children[1].getAttribute("onclose")
);
document.getElementById(editingTab).children[1].innerHTML =
icons["close"];
const file_saved_event = new CustomEvent("file_saved", {
data: {
object: graviton.getCurrentEditor().object
}
});
document.dispatchEvent(file_saved_event);
})
.catch(err => {
console.err(err);
});
}
const create = {
folder(id, value) {
const element = document.getElementById(id);
const dir = path.join(element.getAttribute("dir"), value);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
Explorer.load(
element.getAttribute("dir"),
element.id,
element.getAttribute("global")
);
} else {
new Notification({
title: "Graviton",
content: getTranslation("ExplorerError2")
});
}
},
file(id, value) {
const element = document.getElementById(id);
const dir = path.join(element.getAttribute("dir"), value);
if (!fs.existsSync(dir)) {
fs.writeFile(dir, "", function() {
Explorer.load(
element.getAttribute("dir"),
element.id,
element.getAttribute("global")
);
});
} else {
new Notification({
title: "Graviton",
content: getTranslation("ExplorerError1")
});
}
}
};
const directories = {
newFolder(object) {
new Dialog({
id: "new_folder",
title: getTranslation("Dialog.RenameTo"),
content: `<input id='rename_dialog' class='section-1 input2' placeholder="New Folder" > </input>`,
buttons: {
[getTranslation("Cancel")]: {},
[getTranslation("Accept")]: {
click: () => {
create.folder(
object,
document.getElementById("rename_dialog").value === ""
? "New folder"
: document.getElementById("rename_dialog").value
);
},
important: true
}
}
});
document
.getElementById("rename_dialog")
.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
create.folder(object, this.value === "" ? "New folder" : this.value);
closeDialog("new_folder");
}
});
document.getElementById("rename_dialog").focus();
},
newFile(object) {
new Dialog({
id: "new_file",
title: getTranslation("Dialog.RenameTo"),
content: `<input id='rename_dialog' class='section-1 input2' placeholder="NewFile.txt" > </input>`,
buttons: {
[getTranslation("Cancel")]: {},
[getTranslation("Accept")]: {
click: () => {
create.file(
object,
document.getElementById("rename_dialog").value === ""
? "NewFile.txt"
: document.getElementById("rename_dialog").value
);
},
important: true
}
}
});
document
.getElementById("rename_dialog")
.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
create.file(object, this.value === "" ? "NewFile.txt" : this.value);
closeDialog("new_file");
}
});
document.getElementById("rename_dialog").focus();
},
removeFileDialog(object) {
new Dialog({
id: "remove_file",
title: getTranslation("Dialog.AreYouSure"),
content: "",
buttons: {
[getTranslation("Cancel")]: {},
[getTranslation("Accept")]: {
click: () => {
directories.removeFile(object.id);
}
}
}
});
},
removeFolderDialog(object) {
new Dialog({
id: "remove_folder",
title: getTranslation("Dialog.AreYouSure"),
content: "",
buttons: {
[getTranslation("Cancel")]: {},
[getTranslation("Accept")]: {
click: () => {
directories.removeFolder(object.id);
}
}
}
});
},
removeFile(id) {
const object = document.getElementById(id);
fs.unlink(object.getAttribute("dir"), function(err) {
if (err) graviton.throwError(err);
object.remove();
});
},
removeFolder(id) {
const rimraf = require("rimraf");
const object = document.getElementById(id);
rimraf.sync(object.getAttribute("dir"));
object.remove();
},
getCustomIcon(dir, state) {
if (
themeObject.icons == undefined ||
dir == "node_modules" ||
dir == ".git" ||
(themeObject.icons["folder_closed"] == undefined && state == "close") ||
(themeObject.icons["folder_opened"] == undefined && state == "open")
) {
switch (dir) {
case "node_modules":
return "src/icons/custom_icons/node_modules.svg";
break;
case ".git":
return "src/icons/custom_icons/git.svg";
break;
default:
if (state == "close") {
return "src/icons/folder_closed.svg";
} else {
return "src/icons/folder_opened.svg";
}
}
} else {
switch (dir) {
case "node_modules":
return path.join(themeObject.name, themeObject.icons["node_modules"]);
break;
case ".git":
return path.join(themeObject.name, themeObject.icons["git"]);
break;
default:
if (state == "close") {
return path.join(
themeObject.name,
themeObject.icons["folder_closed"]
);
} else {
return path.join(
themeObject.name,
themeObject.icons["folder_opened"]
);
}
}
}
}
};
const registerNewProject = function(dir) {
// Add a new directory to the history if it is the first time it has been opened in the editor
for (i = 0; i < log.length + 1; i++) {
if (i != log.length) {
if (log[i].Path == dir) {
return;
}
} else if (i == log.length) {
log.unshift({
Name: path.basename(dir),
Path: dir
});
const recent_project_event = new CustomEvent("new_recent_project", {
detail: {
name: path.basename(dir),
path: dir
}
});
document.dispatchEvent(recent_project_event);
fs.writeFile(logDir, JSON.stringify(log));
return;
}
}
};
const createNewProject = function(template) {
dialog.showOpenDialog(
{
properties: ["openDirectory"]
},
selectedFiles => {
if (selectedFiles.length != 0) {
switch (template) {
case "html":
const g_project_dir = path.join(
selectedFiles[0],
".GravitonProject " + Date.now()
);
fs.mkdirSync(g_project_dir);
fs.writeFile(
path.join(g_project_dir, "index.html"),
graviton.getTemplate("html_project"),
err => {
if (err) {
return err;
}
Explorer.load(g_project_dir, "g_directories", true);
}
);
break;
}
}
}
);
};
const installCli = function() {
const npm = require("npm");
npm.load(
{
global: true
},
function(er) {
if (er) return er;
npm.commands.install(["graviton-cli"], function(er, data) {
if (er) return er;
console.log("Graviton CLI has been installed!");
});
}
);
};
window.onclick = function(event) {
if (
!(event.target.matches(".dropbtn") || event.target.matches(".icon_border"))
) {
graviton.closeDropmenus();
}
if (!event.target.matches(".option")) {
document.getElementById("context").parentElement.style = "display:none";
}
if (!event.target.matches("#context_menu")) {
if (document.getElementById("context_menu") != undefined) {
document.getElementById("context_menu").remove();
}
}
};
graviton.refreshCustomization = () => {
document.documentElement.style.setProperty(
"--editor-font-size",
`${current_config.fontSizeEditor}px`
); // Update settings from start
webFrame.setZoomFactor(current_config.appZoom / 25);
if (current_config.blurPreferences != 0) {
document.documentElement.style.setProperty(
"--blur",
`${current_config.blurPreferences}px`
);
} else {
document.documentElement.style.setProperty("--blur", `none`);
}
};
const selectionFromTo = (parent, toSelect) => {
const children = parent.children;
for (let child of children) {
child.classList.remove("active");
}
toSelect.classList.add("active");
};
/**
* @desc Language indicator and Line/Char counter Controls
*/
document.addEventListener("screen_loaded", e => {
const screen = e.detail.screen;
function refreshStats(id = current_screen.id) {
if (id != screen) return;
langController.setText(graviton.getLanguage());
langController.setHint(`Current: ${graviton.getLanguage()}`);
if (editor == undefined) {
counter.hide();
return;
}
if (graviton.getCurrentTab().getAttribute("typeeditor") === "free") {
langController.hide();
}
counter.show();
langController.show();
counter.setText(
editor.getCursor().line + 1 + "/" + Number(editor.getCursor().ch + 1)
);
counter.setHint(
`Line ${editor.getCursor().line + 1} , Char ${Number(
editor.getCursor().ch + 1
)}`
);
editor.on("cursorActivity", function(a) {
counter.setText(
editor.getCursor().line + 1 + "/" + Number(editor.getCursor().ch + 1)
);
counter.setHint(
`Line ${editor.getCursor().line + 1} , Char ${Number(
editor.getCursor().ch + 1
)}`
);
counter.show();
});
}
let langController = new Control({
text: graviton.getLanguage(),
hint: `Current: ${graviton.getLanguage()}`
});
if (editor != undefined) {
var counter = new Control({
text:
editor.getCursor().line + 1 + "/" + Number(editor.getCursor().ch + 1),
hint: `Line ${editor.getCursor().line + 1} , Char ${Number(
editor.getCursor().ch + 1
)}`
});
refreshStats();
} else {
var counter = new Control({
text: ""
});
counter.hide();
refreshStats();
}
document.addEventListener("tab_loaded", e => {
refreshStats(e.detail.screen);
});
document.addEventListener("tab_closed", e => {
refreshStats(e.detail.screen);
});
document.addEventListener("tab_created", () => {
refreshStats();
});
});
projectServices.push({
name: "HTML",
description: "Basic HTML project",
onclick: () => createNewProject("html")
});
const EXPLORER_PANEL = new Panel({
minHeight: "",
content: `
<div style="height:100%;">
<span id="openFolder" height="24px" width="24px" onclick="openFolder()"></span>
</div>
`
});