249 lines
8.0 KiB
JavaScript
249 lines
8.0 KiB
JavaScript
|
||
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);
|
||
}
|
||
}
|