Files
mixly3/common/js/py2block_editor.js
2024-07-19 10:16:00 +08:00

249 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function Py2blockEditor(py2block_conveter, ace_editor){
this.convert = py2block_conveter;
this.editor = ace_editor;
this.silentText = false;
this.silentBlock = false;
this.lastCodeSnapshot = "";
this.fromCode = false;
}
Py2blockEditor.prototype.isFuncStartLine = function(line){
return /^ *?def *?.*?\(.*?\): *?$/.test(line);
}
Py2blockEditor.prototype.isEmptyNewLine = function(line){
return /^ +?$/.test(line) || line == "";
}
Py2blockEditor.prototype.getIndentOfLine = function(line){
for(var i = 0 ; i < line.length ; i ++){
if(line[i] != " "){
return i;
}
}
return 0;
}
// 换行和tab的处理
Py2blockEditor.prototype.formatLine = function (python_code) {
python_code = python_code.replace("\r\n", "\n")
.replace("\r", "\n")
.replace("\t", " ");
return python_code;
}
// 格式化模块方法的调用形式. 如 Pin->machine.Pin
Py2blockEditor.prototype.formatModule = function (python_code) {
var keylist = py2block_config.formatModuleKeyL;
var modulelist = py2block_config.formatModuleL;
for (var i = 0; i < keylist.length; i++) {
for (var j = 0; j < keylist[i].length; j++) {
var reg = new RegExp(modulelist[i] + "." + keylist[i][j], "g");
python_code = python_code.replace(reg, keylist[i][j]);
var reg = new RegExp("(" + "\\b"+keylist[i][j] + "\\(" + "|" +"\\b"+ keylist[i][j] + "\\." + ")", "g");
python_code = python_code.replace(reg, function(match) {
return modulelist[i] + "." + match;
});
}
}
return python_code;
}
//为函数定义前后增加空行
Py2blockEditor.prototype.addNewLines = function(python_code){
var lines = python_code.split("\n");
var isFirstLine = true;
var isNewLine = false;
var isFuncDefScope = false;
var indent = 0;
var new_python_code = "";
var newLine = "";
//遍历每行
for(var i = 0 ; i < lines.length ; i ++){
var line = lines[i];
//函数定义的开始行def XXX()
if(this.isFuncStartLine(line)){
isFuncDefScope = true;
indent = this.getIndentOfLine(line);
if(!isFirstLine && !isNewLine){
line = "\n" + line;
}
}else if(isFuncDefScope && this.getIndentOfLine(line) <= indent){//函数定义结束后的第一行
if(!this.isEmptyNewLine(line)){
line = "\n" + line;
}else {
isFuncDefScope = false;
}
}
//是否是空行
if(this.isEmptyNewLine(line)){
isNewLine = true;
}else{
isNewLine = false;
}
new_python_code += line + "\n";
isFirstLine = false;
}
return new_python_code;
}
Py2blockEditor.prototype.encodeChinese = function(code){
return code.replace(/[\u4e00-\u9fa5]+/g, function (s) {
return encodeURIComponent(s).replace(/%/g, "_");
})
}
Py2blockEditor.prototype.decodeChinese = function(code){
return code.replace(/(_[0-9A-F]{2}_[0-9A-F]{2}_[0-9A-F]{2})+/g, function (s) {
return decodeURIComponent(s.replace(/_/g, '%'));
});
}
Py2blockEditor.prototype.setBlocks = function(python_code){
var xml_code = "";
py2block_config.reset();
python_code = this.formatLine(python_code);
python_code = this.formatModule(python_code);
python_code = this.addNewLines(python_code);
if (python_code !== '' && python_code !== undefined && python_code.trim().charAt(0) !== '<') {
var result = this.convert.convertSource(python_code);
xml_code = this.decodeChinese(result.xml);
if (result.error !== null) {
console.log(result.error);
} else {
}
}
var error_code = this.convert.convertSourceToCodeBlock(python_code);
var errorXml = Blockly.utils.xml.textToDom(error_code);
if (python_code == '' || python_code == undefined || python_code.trim() == '') {
Mixly.Editor.blockEditor.clear();
} else if (xml_code !== '' && xml_code !== undefined) {
var blocklyXml = Blockly.utils.xml.textToDom(xml_code);
try {
this.setBlocksFromXml(blocklyXml);
} catch (e) {
console.error(e);
this.setBlocksFromXml(errorXml);
}
} else {
this.setBlocksFromXml(errorXml);
}
}
Py2blockEditor.prototype.setBlocksFromXml = function(xml){
Mixly.Editor.blockEditor.clear();
Blockly.Xml.domToWorkspace(xml, Mixly.Editor.blockEditor);
Mixly.Editor.blockEditor.scrollCenter();
}
Py2blockEditor.prototype.gotoEditorEnd = function(){
var row = this.editor.session.getLength() - 1;
for(var rowid = row; rowid >= 0; rowid --) {
var column = this.editor.session.getLine(rowid).length; // or simply Infinity
if(column !== 0) {
this.editor.gotoLine(rowid + 1, column);
this.editor.focus();
break;
}
}
}
Py2blockEditor.prototype.getFocus = function(){
this.editor.focus();
}
Py2blockEditor.prototype.updateText = function(){
if(!this.silentText) {
this.silentBlock = true;
this.setBlocks(this.encodeChinese(this.editor.getValue()));
var py2blockEditor = this;
setTimeout(function(){
py2blockEditor.silentBlock = false;
}, 50);
}
}
Py2blockEditor.prototype.updateBlock = function(){
if(this.fromCode) {
this.fromCode = false;
var encodeCode = this.encodeChinese(this.editor.getValue());
this.setBlocks(encodeCode);
}
}
Blockly.Xml.domToWorkspaceDestructive = function(xml, workspace, errorXml) {
if (xml instanceof Blockly.Workspace) {
var swap = xml;
xml = workspace;
workspace = swap;
console.warn('Deprecated call to Blockly.Xml.domToWorkspace, ' +
'swap the arguments.');
}
var width; // Not used in LTR.
if (workspace.RTL) {
width = workspace.getWidth();
}
Blockly.utils.dom.startTextWidthCache();
// Safari 7.1.3 is known to provide node lists with extra references to
// children beyond the lists' length. Trust the length, do not use the
// looping pattern of checking the index for an object.
var childCount = xml.childNodes.length;
var existingGroup = Blockly.Events.getGroup();
if (!existingGroup) {
Blockly.Events.setGroup(true);
}
Blockly.Events.disable();
var blockLHeight = [];
while (workspace.topBlocks_.length) {
workspace.topBlocks_[0].dispose();
//blockLHeight.push(workspace.topBlocks_[0].getHeightWidth()['height']);
}
//workspace.variableList.length = 0;
Blockly.Events.enable();
// Disable workspace resizes as an optimization.
if (workspace.setResizesEnabled) {
workspace.setResizesEnabled(false);
}
var currY = 10;
for (var i = 0; i < childCount; i++) {
var xmlChild = xml.childNodes[i];
var name = xmlChild.nodeName.toLowerCase();
if (name == 'block' ||
(name == 'shadow' && !Blockly.Events.recordUndo)) {
// Allow top-level shadow blocks if recordUndo is disabled since
// that means an undo is in progress. Such a block is expected
// to be moved to a nested destination in the next operation.
var block = Blockly.Xml.domToBlock(xmlChild, workspace);
var blockX = 0;
var blockY = currY;
currY = blockY + workspace.topBlocks_[i].getHeightWidth()['height'] + 50;
if (!isNaN(blockX) && !isNaN(blockY)) {
block.moveBy(workspace.RTL ? width - blockX : blockX, blockY);
}
} else if (name == 'shadow') {
goog.asserts.fail('Shadow block cannot be a top-level block.');
}
}
if (!existingGroup) {
Blockly.Events.setGroup(false);
}
Blockly.utils.dom.stopTextWidthCache();
//workspace.updateVariableList(false);
// Re-enable workspace resizing.
if (workspace.setResizesEnabled) {
workspace.setResizesEnabled(true);
}
}