mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-13 07:42:54 +01:00
Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
45
packages/noodl-editor/src/shared/utils/EventDispatcher.ts
Normal file
45
packages/noodl-editor/src/shared/utils/EventDispatcher.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export class EventDispatcher {
|
||||
listeners: any[];
|
||||
|
||||
constructor() {
|
||||
this.listeners = [];
|
||||
}
|
||||
|
||||
on(event: string | string[], listener, group: unknown) {
|
||||
this.listeners.push({ event: event, listener: listener, group: group });
|
||||
}
|
||||
|
||||
notifyListeners(event: string, args?) {
|
||||
const testForComps = event.split('.');
|
||||
|
||||
function notify(event, listener, eventName) {
|
||||
const comps = event.split('.');
|
||||
if (comps[0] === testForComps[0] && (comps[1] === '*' || comps[1] === testForComps[1])) listener(args, eventName);
|
||||
}
|
||||
|
||||
for (const i in this.listeners) {
|
||||
if (this.listeners[i].event instanceof Array) {
|
||||
for (const j in this.listeners[i].event) notify(this.listeners[i].event[j], this.listeners[i].listener, event);
|
||||
} else {
|
||||
notify(this.listeners[i].event, this.listeners[i].listener, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit(event: string, args?) {
|
||||
this.notifyListeners(event, args);
|
||||
}
|
||||
|
||||
off(group: unknown) {
|
||||
if (group === undefined) return;
|
||||
|
||||
for (let i = 0; i < this.listeners.length; i++) {
|
||||
if (this.listeners[i].group === group) {
|
||||
this.listeners.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static instance = new EventDispatcher();
|
||||
}
|
||||
68
packages/noodl-editor/src/shared/utils/jsonstorage.js
Normal file
68
packages/noodl-editor/src/shared/utils/jsonstorage.js
Normal file
@@ -0,0 +1,68 @@
|
||||
const path = require('path');
|
||||
const mkdir = require('mkdirp-sync');
|
||||
const fs = require('fs');
|
||||
const rimraf = require('rimraf');
|
||||
const electron = require('electron');
|
||||
const app = electron.app || require('@electron/remote').app;
|
||||
|
||||
function fileNameForKey(key) {
|
||||
const keyFileName = path.basename(key, '.json') + '.json';
|
||||
|
||||
// Prevent ENOENT and other similar errors when using
|
||||
// reserved characters in Windows filenames.
|
||||
// See: https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords
|
||||
const escapedFileName = encodeURIComponent(keyFileName);
|
||||
|
||||
const userDataPath = app.getPath('userData');
|
||||
return path.join(userDataPath, escapedFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depracted This implementation is not cross-platform use this instead:
|
||||
* ```ts
|
||||
* import { JSONStorage } from '@noodl/platform';
|
||||
* ```
|
||||
*
|
||||
* Can't remove this file because it's called from main thread,
|
||||
* where the platform code is not setup.
|
||||
*/
|
||||
module.exports = {
|
||||
get: function (key, callback) {
|
||||
var filename = fileNameForKey(key);
|
||||
fs.readFile(filename, { encoding: 'utf8' }, function (error, object) {
|
||||
if (!error) {
|
||||
var objectJSON = {};
|
||||
try {
|
||||
objectJSON = JSON.parse(object);
|
||||
} catch (error) {
|
||||
return callback(); //new Error('Invalid data'));
|
||||
}
|
||||
return callback(objectJSON);
|
||||
}
|
||||
|
||||
if (error.code === 'ENOENT') {
|
||||
return callback(JSON.stringify({}));
|
||||
}
|
||||
|
||||
return callback();
|
||||
});
|
||||
|
||||
/*storage.get(path, function(error, data) {
|
||||
if (error) { callback(); return }
|
||||
callback(data);
|
||||
});*/
|
||||
},
|
||||
set: function (key, data) {
|
||||
var filename = fileNameForKey(key);
|
||||
const json = JSON.stringify(data);
|
||||
|
||||
mkdir(path.dirname(filename));
|
||||
fs.writeFileSync(filename, json);
|
||||
},
|
||||
remove: function (key, callback) {
|
||||
var filename = fileNameForKey(key);
|
||||
rimraf(filename, callback);
|
||||
|
||||
// storage.remove(path,callback);
|
||||
}
|
||||
};
|
||||
161
packages/noodl-editor/src/shared/utils/projectmodules.js
Normal file
161
packages/noodl-editor/src/shared/utils/projectmodules.js
Normal file
@@ -0,0 +1,161 @@
|
||||
const fs = require('fs');
|
||||
|
||||
class ProjectModules {
|
||||
constructor() {}
|
||||
scanProjectModules(projectDirectory, callback) {
|
||||
if (projectDirectory === undefined) {
|
||||
callback(); // No project directory, no modules
|
||||
return;
|
||||
}
|
||||
|
||||
var modulesPath = projectDirectory + '/noodl_modules';
|
||||
fs.readdir(modulesPath, function (err, files) {
|
||||
if (err) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//we only care about directories
|
||||
const directories = files.filter((f) => {
|
||||
var stats = fs.lstatSync(modulesPath + '/' + f);
|
||||
return stats.isDirectory() || stats.isSymbolicLink();
|
||||
});
|
||||
|
||||
if (directories.length === 0) {
|
||||
callback();
|
||||
} else {
|
||||
// For each subfolder in noodl_modules
|
||||
var modules = [];
|
||||
var modulesLeft = 0;
|
||||
|
||||
function completeModule(path, manifest) {
|
||||
if (path && manifest) {
|
||||
// Module manifest is fetched, resolve local paths
|
||||
var m = {
|
||||
dependencies: [],
|
||||
browser: manifest.browser,
|
||||
runtimes: manifest.runtimes || ['browser'] //default to browser
|
||||
};
|
||||
|
||||
if (manifest.main) {
|
||||
m.index = path + '/' + manifest.main;
|
||||
}
|
||||
|
||||
if (manifest.dependencies) {
|
||||
for (var j = 0; j < manifest.dependencies.length; j++) {
|
||||
var d = manifest.dependencies[j];
|
||||
if (!d.startsWith['http']) d = path + '/' + d;
|
||||
|
||||
m.dependencies.push(d);
|
||||
}
|
||||
}
|
||||
|
||||
modules.push(m);
|
||||
}
|
||||
|
||||
modulesLeft--;
|
||||
if (modulesLeft === 0) {
|
||||
//sort modules so the order is deterministics
|
||||
//helps the editor understand when node libraries change, or are the same
|
||||
const modulesWithIndexFile = modules.filter((m) => m.index);
|
||||
const modulesWithoutIndexFile = modules.filter((m) => !m.index);
|
||||
|
||||
modulesWithIndexFile.sort((a, b) => a.index.localeCompare(b.index));
|
||||
|
||||
callback(modulesWithIndexFile.concat(modulesWithoutIndexFile));
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < directories.length; i++) {
|
||||
const dir = directories[i];
|
||||
modulesLeft++;
|
||||
// Read manifest
|
||||
fs.readFile(
|
||||
modulesPath + '/' + dir + '/manifest.json',
|
||||
'utf8',
|
||||
(function () {
|
||||
const _dir = dir;
|
||||
return function (err, data) {
|
||||
if (err) {
|
||||
completeModule(); // Module load failed
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
completeModule('noodl_modules/' + _dir, JSON.parse(data));
|
||||
} catch (e) {
|
||||
// JSON not valid
|
||||
completeModule(); // Module load failed
|
||||
}
|
||||
};
|
||||
})()
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
injectIntoHtml(projectDirectory, template, pathPrefix, callback) {
|
||||
this.scanProjectModules(projectDirectory, function (modules) {
|
||||
var dependencies = '';
|
||||
var modulesMain = '';
|
||||
if (modules) {
|
||||
const browserModules = modules.filter((m) => m.runtimes.indexOf('browser') !== -1);
|
||||
for (var i = 0; i < browserModules.length; i++) {
|
||||
var m = browserModules[i];
|
||||
if (m.index) {
|
||||
modulesMain += '<script type="text/javascript" src="' + pathPrefix + m.index + '"></script>\n';
|
||||
}
|
||||
|
||||
// Module javascript dependencies
|
||||
if (m.dependencies) {
|
||||
for (var j = 0; j < m.dependencies.length; j++) {
|
||||
var d = m.dependencies[j];
|
||||
var dTag = '<script type="text/javascript" src="' + pathPrefix + d + '"></script>\n';
|
||||
if (dependencies.indexOf(dTag) === -1) dependencies += dTag;
|
||||
}
|
||||
}
|
||||
|
||||
// Browser modules
|
||||
if (m.browser) {
|
||||
if (m.browser.head) {
|
||||
var head = m.browser.head;
|
||||
for (var j = 0; j < head.length; j++) {
|
||||
dependencies += head[j] + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
if (m.browser.styles) {
|
||||
var styles = m.browser.styles;
|
||||
for (var j = 0; j < styles.length; j++) {
|
||||
dependencies += '<style>' + styles[j] + '</style>' + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
if (m.browser.stylesheets) {
|
||||
var sheets = m.browser.stylesheets;
|
||||
for (var j = 0; j < sheets.length; j++) {
|
||||
if (typeof sheets[j] === 'string') {
|
||||
let path = sheets[j];
|
||||
if (!path.startsWith('http')) {
|
||||
path = pathPrefix + path;
|
||||
}
|
||||
|
||||
dependencies += '<link href="' + path + '" rel="stylesheet">';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var injected = template.replace('<%modules_dependencies%>', dependencies);
|
||||
injected = injected.replace('<%modules_main%>', modulesMain);
|
||||
|
||||
callback(injected);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ProjectModules.instance = new ProjectModules();
|
||||
|
||||
module.exports = ProjectModules;
|
||||
Reference in New Issue
Block a user