Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 37 additions & 39 deletions src/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export class Editor {
private currentModule: commonStorage.Module | null = null;
private modulePath: string = '';
private robotPath: string = '';
private moduleContent: string = '';
private robotContent: string = '';
private moduleContentText: string = '';
private robotContent: commonStorage.ModuleContent | null = null;
private bindedOnChange: any = null;
private toolbox: Blockly.utils.toolbox.ToolboxDefinition = EMPTY_TOOLBOX;

Expand Down Expand Up @@ -117,31 +117,31 @@ export class Editor {
this.modulePath = '';
this.robotPath = '';
}
this.moduleContent = '';
this.robotContent = '';
this.moduleContentText = '';
this.robotContent = null;
this.clearBlocklyWorkspace();

if (currentModule) {
// Fetch the content for the current module and the robot.
// TODO: Also fetch the content for the mechanisms?
const promises: { [key: string]: Promise<string> } = {}; // key is module path, value is promise of module content.
promises[this.modulePath] = this.storage.fetchModuleContent(this.modulePath);
promises[this.modulePath] = this.storage.fetchModuleContentText(this.modulePath);
if (this.robotPath !== this.modulePath) {
// Also fetch the robot module content. It contains components, etc, that can be used in OpModes.
promises[this.robotPath] = this.storage.fetchModuleContent(this.robotPath)
promises[this.robotPath] = this.storage.fetchModuleContentText(this.robotPath)
}

const moduleContents: { [key: string]: string } = {}; // key is module path, value is module content
const modulePathToContentText: { [key: string]: string } = {}; // key is module path, value is module content
await Promise.all(
Object.entries(promises).map(async ([modulePath, promise]) => {
moduleContents[modulePath] = await promise;
modulePathToContentText[modulePath] = await promise;
})
);
this.moduleContent = moduleContents[this.modulePath];
this.moduleContentText = modulePathToContentText[this.modulePath];
if (this.robotPath === this.modulePath) {
this.robotContent = this.moduleContent;
this.robotContent = commonStorage.parseModuleContentText(this.moduleContentText);
} else {
this.robotContent = moduleContents[this.robotPath];
this.robotContent = commonStorage.parseModuleContentText(modulePathToContentText[this.robotPath]);
}
this.loadBlocksIntoBlocklyWorkspace();
}
Expand Down Expand Up @@ -169,10 +169,8 @@ export class Editor {
// Add the while-loading listener.
this.bindedOnChange = this.onChangeWhileLoading.bind(this);
this.blocklyWorkspace.addChangeListener(this.bindedOnChange);
const blocksContent = commonStorage.extractBlocksContent(this.moduleContent);
if (blocksContent) {
Blockly.serialization.workspaces.load(JSON.parse(blocksContent), this.blocklyWorkspace);
}
const moduleContent = commonStorage.parseModuleContentText(this.moduleContentText);
Blockly.serialization.workspaces.load(moduleContent.getBlocks(), this.blocklyWorkspace);
}

public updateToolbox(shownPythonToolboxCategories: Set<string>): void {
Expand All @@ -194,33 +192,33 @@ export class Editor {
/*
// This code is helpful for debugging issues where the editor says
// 'Blocks have been modified!'.
if (this.getModuleContent() !== this.moduleContent) {
if (this.getModuleContentText() !== this.moduleContentText) {
console.log('isModified will return true');
console.log('this.getModuleContent() is ' + this.getModuleContent());
console.log('this.moduleContent is ' + this.moduleContent);
console.log('this.getModuleContentText() is ' + this.getModuleContentText());
console.log('this.moduleContentText is ' + this.moduleContentText);
}
*/
return this.getModuleContent() !== this.moduleContent;
return this.getModuleContentText() !== this.moduleContentText;
}

private getModuleContent(): string {
private getModuleContentText(): string {
if (!this.currentModule) {
throw new Error('getModuleContent: this.currentModule is null.');
throw new Error('getModuleContentText: this.currentModule is null.');
}
const pythonCode = extendedPythonGenerator.mrcWorkspaceToCode(
this.blocklyWorkspace, this.generatorContext);
const blocksContent = JSON.stringify(
Blockly.serialization.workspaces.save(this.blocklyWorkspace));
const methodsContent = (

// Generate python because some parts of components, events, and methods are affected.
extendedPythonGenerator.mrcWorkspaceToCode(this.blocklyWorkspace, this.generatorContext);

const blocks = Blockly.serialization.workspaces.save(this.blocklyWorkspace);
const components: commonStorage.Component[] = this.getComponentsFromWorkspace();
const events: commonStorage.Event[] = this.getEventsFromWorkspace();
const methods: commonStorage.Method[] = (
this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT ||
this.currentModule?.moduleType === commonStorage.MODULE_TYPE_MECHANISM)
? JSON.stringify(this.getMethodsForOutsideFromWorkspace())
: '[]';
const componentsContent = JSON.stringify(this.getComponentsFromWorkspace());
const eventsContent = JSON.stringify(this.getEventsFromWorkspace());
return commonStorage.makeModuleContent(
this.currentModule, pythonCode, blocksContent,
methodsContent, componentsContent, eventsContent);
? this.getMethodsForOutsideFromWorkspace()
: [];
return commonStorage.makeModuleContentText(
this.currentModule, blocks, components, events, methods);
}

public getComponentsFromWorkspace(): commonStorage.Component[] {
Expand Down Expand Up @@ -261,10 +259,10 @@ export class Editor {
}

public async saveBlocks() {
const moduleContent = this.getModuleContent();
const moduleContentText = this.getModuleContentText();
try {
await this.storage.saveModule(this.modulePath, moduleContent);
this.moduleContent = moduleContent;
await this.storage.saveModule(this.modulePath, moduleContentText);
this.moduleContentText = moduleContentText;
} catch (e) {
throw e;
}
Expand All @@ -280,7 +278,7 @@ export class Editor {
if (!this.robotContent) {
throw new Error('getComponentsFromRobot: this.robotContent is null.');
}
return commonStorage.extractComponents(this.robotContent);
return this.robotContent.getComponents();
}

/**
Expand All @@ -293,7 +291,7 @@ export class Editor {
if (!this.robotContent) {
throw new Error('getEventsFromRobot: this.robotContent is null.');
}
return commonStorage.extractEvents(this.robotContent);
return this.robotContent.getEvents();
}

/**
Expand All @@ -306,7 +304,7 @@ export class Editor {
if (!this.robotContent) {
throw new Error('getMethodsFromRobot: this.robotContent is null.');
}
return commonStorage.extractMethods(this.robotContent);
return this.robotContent.getMethods();
}

public static getEditorForBlocklyWorkspace(workspace: Blockly.Workspace): Editor | null {
Expand Down
42 changes: 21 additions & 21 deletions src/storage/client_side_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class ClientSideStorage implements commonStorage.Storage {
};
});
}

async listProjects(): Promise<commonStorage.Project[]> {
return new Promise((resolve, reject) => {
const projects: {[key: string]: commonStorage.Project} = {}; // key is project name, value is Project
Expand Down Expand Up @@ -220,7 +220,7 @@ class ClientSideStorage implements commonStorage.Storage {
});
}

async fetchModuleContent(modulePath: string): Promise<string> {
async fetchModuleContentText(modulePath: string): Promise<string> {
return new Promise((resolve, reject) => {
const getRequest = this.db.transaction(['modules'], 'readonly')
.objectStore('modules').get(modulePath);
Expand All @@ -243,20 +243,20 @@ class ClientSideStorage implements commonStorage.Storage {
async createProject(projectName: string, robotContent: string, opmodeContent : string): Promise<void> {
const modulePath = commonStorage.makeRobotPath(projectName);
const opmodePath = commonStorage.makeModulePath(projectName, 'Teleop');

await this._saveModule(commonStorage.MODULE_TYPE_ROBOT, modulePath, robotContent);
await this._saveModule(commonStorage.MODULE_TYPE_OPMODE, opmodePath, opmodeContent);
}

async createModule(moduleType: string, modulePath: string, moduleContent: string): Promise<void> {
return this._saveModule(moduleType, modulePath, moduleContent);
async createModule(moduleType: string, modulePath: string, moduleContentText: string): Promise<void> {
return this._saveModule(moduleType, modulePath, moduleContentText);
}

async saveModule(modulePath: string, moduleContent: string): Promise<void> {
return this._saveModule('', modulePath, moduleContent);
async saveModule(modulePath: string, moduleContentText: string): Promise<void> {
return this._saveModule('', modulePath, moduleContentText);
}

private async _saveModule(moduleType: string, modulePath: string, moduleContent: string)
private async _saveModule(moduleType: string, modulePath: string, moduleContentText: string)
: Promise<void> {
// When creating a new module, moduleType must be truthy.
// When saving an existing module, the moduleType must be falsy.
Expand Down Expand Up @@ -301,7 +301,7 @@ class ClientSideStorage implements commonStorage.Storage {
}
value = getRequest.result;
}
value.content = moduleContent;
value.content = moduleContentText;
value.dateModifiedMillis = Date.now();
const putRequest = modulesObjectStore.put(value);
putRequest.onerror = () => {
Expand Down Expand Up @@ -545,7 +545,7 @@ class ClientSideStorage implements commonStorage.Storage {
async downloadProject(projectName: string): Promise<string> {
return new Promise((resolve, reject) => {
// Collect all the modules in the project.
const moduleContents: {[key: string]: string} = {}; // key is module name, value is module content
const moduleNameToContentText: {[key: string]: string} = {}; // key is module name, value is module content
const openCursorRequest = this.db.transaction(['modules'], 'readonly')
.objectStore('modules')
.openCursor();
Expand All @@ -560,13 +560,13 @@ class ClientSideStorage implements commonStorage.Storage {
const value = cursor.value;
if (commonStorage.getProjectName(value.path) === projectName) {
const moduleName = commonStorage.getModuleName(value.path);
moduleContents[moduleName] = value.content;
moduleNameToContentText[moduleName] = value.content;
}
cursor.continue();
} else {
// The cursor is done. We have finished collecting all the modules in the project.
// Now create the blob for download.
const blobUrl = await commonStorage.produceDownloadProjectBlob(projectName, moduleContents);
const blobUrl = await commonStorage.produceDownloadProjectBlob(moduleNameToContentText);
resolve(blobUrl);
}
};
Expand All @@ -576,17 +576,17 @@ class ClientSideStorage implements commonStorage.Storage {
async uploadProject(projectName: string, blobUrl: string): Promise<void> {
return new Promise(async (resolve, reject) => {
// Process the uploaded blob to get the module types and contents.
let moduleTypes: {[key: string]: string}; // key is module name, value is module content
let moduleContents: {[key: string]: string}; // key is module name, value is module content
let moduleNameToType: {[key: string]: string}; // key is module name, value is module content
let moduleNameToContentText: {[key: string]: string}; // key is module name, value is module content
try {
[moduleTypes, moduleContents] = await commonStorage.processUploadedBlob(
[moduleNameToType, moduleNameToContentText] = await commonStorage.processUploadedBlob(
projectName, blobUrl);
} catch (e) {
console.log('commonStorage.processUploadedBlob failed.');
reject(new Error('commonStorage.processUploadedBlob failed.'));
return;
}

// Save each module.
const transaction = this.db.transaction(['modules'], 'readwrite');
transaction.oncomplete = () => {
Expand All @@ -597,10 +597,10 @@ class ClientSideStorage implements commonStorage.Storage {
reject(new Error('IndexedDB transaction aborted.'));
};
const modulesObjectStore = transaction.objectStore('modules');
for (const moduleName in moduleTypes) {
const moduleType = moduleTypes[moduleName];
const moduleContent = moduleContents[moduleName];

for (const moduleName in moduleNameToType) {
const moduleType = moduleNameToType[moduleName];
const moduleContentText = moduleNameToContentText[moduleName];
const modulePath = commonStorage.makeModulePath(projectName, moduleName);
const getRequest = modulesObjectStore.get(modulePath);
getRequest.onerror = () => {
Expand All @@ -617,7 +617,7 @@ class ClientSideStorage implements commonStorage.Storage {
const value = Object.create(null);
value.path = modulePath;
value.type = moduleType;
value.content = moduleContent;
value.content = moduleContentText;
value.dateModifiedMillis = Date.now();
const putRequest = modulesObjectStore.put(value);
putRequest.onerror = () => {
Expand Down
Loading