How to change the position of the backpack workspace?

197 views
Skip to first unread message

fu6...@gmail.com

unread,
Aug 28, 2021, 10:07:06 PM8/28/21
to Blockly
Hi,
I added the backpack plugin to my code. I want to change  the position of the backpack workspace to the left side . Would this be possible?
1.png

Maribeth Bottorff

unread,
Aug 30, 2021, 9:39:22 PM8/30/21
to Blockly
Hello, 

At the moment I don't think this can be easily configured to do so. The current behavior is to go the opposite corner of the main toolbox position.

You could subclass the Backpack and change the position method to reverse the logic for which corner it's placed in, but you might need to do additional math to make sure it doesn't cover up the toolbox flyout (unless you want it to)

Message has been deleted
Message has been deleted
Message has been deleted

fu6...@gmail.com

unread,
Sep 9, 2021, 10:03:22 AM9/9/21
to Blockly
I have modified my sample code and it works well.




Blockly.myBackpack={};
Blockly.myBackpack.NAME_TYPE=Blockly.MYBACKPACK_CATEGORY_NAME;
Blockly.myBackpack.Blocks=[];

Blockly.myBackpack.flyoutCategory=function(a){
var c=[];
var b = Blockly.myBackpack.Blocks;
for (var i=0;i<b.length;i++)
c.push(Blockly.Xml.textToDom(b[i]))
return c
};

function registerCopyToMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('copy_to_MyBackpack')) {
    return;
  }
  const copyToMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_ADD;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "");
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
if (n[i]==b)
return 'hidden';
}
}
return 'enabled';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "");
Blockly.myBackpack.Blocks.push(b);
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'copy_to_MyBackpack',
    weight: 201,
  };
  Blockly.ContextMenuRegistry.registry.register(copyToMyBackpack);
}
  
registerCopyToMyBackpack();

function registerRemoveFromMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('remove_from_MyBackpack')) {
    return;
  }
  const removeFromMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_REMOVE;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "");
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
if (n[i]==b)
return 'enabled';
}
}
return 'hidden';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "");
if (Blockly.myBackpack.Blocks) {
var i = Blockly.myBackpack.Blocks.indexOf(b);
if (i!= -1) {
  Blockly.myBackpack.Blocks.splice(i,1);
}
}
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'remove_from_MyBackpack',
    weight: 202,
  };
  Blockly.ContextMenuRegistry.registry.register(removeFromMyBackpack);
}
  
registerRemoveFromMyBackpack();






//toolbox.xml

<category id="catMyBackPack" name="catMyBackPack" colour="290"  custom="MYBACKPACK"></category>

//blockly_compressed.js

Blockly.MYBACKPACK_CATEGORY_NAME="MYBACKPACK";
Blockly.myBackpack&&Blockly.myBackpack.flyoutCategory&&(this.registerToolboxCategoryCallback(Blockly.MYBACKPACK_CATEGORY_NAME,Blockly.myBackpack.flyoutCategory));

//en.js

Blockly.Msg.MYBACKPACK_ADD = "Copy to my backpack";
Blockly.Msg.MYBACKPACK_REMOVE = "Remove from my backpack";
錄製_2021_09_09_11_19_04_914.mp4
Message has been deleted

fu6...@gmail.com

unread,
Sep 9, 2021, 8:46:33 PM9/9/21
to Blockly
I wrote the backpack function for my project and I found a issue. The inline value are not the same, so I need to use the code as below to check the blocks that exist in my backpack.
.replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"")


Blockly.Xml.blockToDom(a.block, true)
<block type="lists_create_with" inline="false"><mutation items="3"></mutation></block>

Blockly.Xml.domToText
<block xmlns="https://developers.google.com/blockly/xml" type="lists_create_with" inline=" false"><mutation items="3"></mutation></block>

Blockly.Xml.textToDom
<block xmlns="https://developers.google.com/blockly/xml" type="lists_create_with" inline="0"> <mutation items="3"></mutation></block>

fu6...@gmail.com 在 2021年9月9日 星期四下午11:12:07 [UTC+8] 的信中寫道:
Update my sample code.



Blockly.myBackpack={};
Blockly.myBackpack.NAME_TYPE=Blockly.MYBACKPACK_CATEGORY_NAME;
Blockly.myBackpack.Blocks=[];

Blockly.myBackpack.flyoutCategory=function(a){
var c=[];
var b = Blockly.myBackpack.Blocks;
for (var i=0;i<b.length;i++) {
c.push(Blockly.Xml.textToDom(b[i]));
}
return c
};

function registerCopyToMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('copy_to_MyBackpack')) {
    return;
  }
  const copyToMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_ADD;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
console.log(d);
console.log(b);
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
console.log(n[i]);
if (n[i]==b)
return 'hidden';
}
}
return 'enabled';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");;
Blockly.myBackpack.Blocks.push(b);
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'copy_to_MyBackpack',
    weight: 201,
  };
  Blockly.ContextMenuRegistry.registry.register(copyToMyBackpack);
}
  
registerCopyToMyBackpack();

function registerRemoveFromMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('remove_from_MyBackpack')) {
    return;
  }
  const removeFromMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_REMOVE;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");;
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
if (n[i]==b)
return 'enabled';
}
}
return 'hidden';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");;
if (Blockly.myBackpack.Blocks) {
var i = Blockly.myBackpack.Blocks.indexOf(b);
if (i!= -1) {
  Blockly.myBackpack.Blocks.splice(i,1);
}
}
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'remove_from_MyBackpack',
    weight: 202,
  };
  Blockly.ContextMenuRegistry.registry.register(removeFromMyBackpack);
}
  
registerRemoveFromMyBackpack();

function registerRemoveAllMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('remove_all_MyBackpack')) {
    return;
  }
  const removeAllMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_REMOVE_ALL;
},
    preconditionFn: function(a) {
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
return 'enabled';
}
}
return 'hidden';
    },
    callback: function(a) {
var result = confirm(Blockly.Msg.MYBACKPACK_REMOVE_ALL_TITLE);
if (result) {
Blockly.myBackpack.Blocks=[];
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'remove_all_MyBackpack',
    weight: 203,
  };
  Blockly.ContextMenuRegistry.registry.register(removeAllMyBackpack);
}
  
registerRemoveAllMyBackpack();






//toolbox.xml

<category id="catMyBackPack" name="catMyBackPack" colour="290"  custom="MYBACKPACK"></category>

//blockly_compressed.js

Blockly.MYBACKPACK_CATEGORY_NAME="MYBACKPACK";
Blockly.myBackpack&&Blockly.myBackpack.flyoutCategory&&(this.registerToolboxCategoryCallback(Blockly.MYBACKPACK_CATEGORY_NAME,Blockly.myBackpack.flyoutCategory));

//en.js

Blockly.Msg.MYBACKPACK_ADD = "Copy to my backpack";
Blockly.Msg.MYBACKPACK_REMOVE = "Remove from my backpack";
Blockly.Msg.MYBACKPACK_REMOVE_ALL = "Remove all my backpack";
Blockly.Msg.MYBACKPACK_REMOVE_ALL_TITLE = "Are you sure to remove all my backpack?";

fu6...@gmail.com 在 2021年9月9日 星期四下午10:03:22 [UTC+8] 的信中寫道:
Message has been deleted

fu6...@gmail.com

unread,
Sep 13, 2021, 4:51:45 AM9/13/21
to Blockly
This is my first time to build plugin. I am new to Javascript.
https://github.com/fustyles/webduino/tree/master/LinkIt7697/MyBackpack

fu6...@gmail.com 在 2021年9月11日 星期六下午11:07:28 [UTC+8] 的信中寫道:
I am pleased to share my code about the backpack function. The function is helpful to teachers to teach coding in the class. 
https://drive.google.com/drive/folders/1H9JqdsWU0cqRwcO7T_bpJz-pjL8JXZUP?usp=sharing


/*
Last Update Time : 9/11/2021 23:00 (Taiwan Standard Time)
Author: ChungYi Fu, Taiwan
*/

Blockly.myBackpack={};
Blockly.myBackpack.NAME_TYPE=Blockly.MYBACKPACK_CATEGORY_NAME;
Blockly.myBackpack.Blocks=[];

Blockly.myBackpack.flyoutCategory=function(a){
var c=[];
var b = Blockly.myBackpack.Blocks;
for (var i=0;i<b.length;i++) {
c.push(Blockly.Xml.textToDom(b[i]));
}
return c
};

function registerCopyToMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('copy_to_MyBackpack')) {
    return;
  }
  const copyToMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_ADD;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
if (n[i]==b)
return 'hidden';
}
}
return 'enabled';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
Blockly.myBackpack.Blocks.push(b);
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
var c=Blockly.myBackpack.flyoutCategory();
t.getFlyout().show(c);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'copy_to_MyBackpack',
    weight: 201,
  };
  Blockly.ContextMenuRegistry.registry.register(copyToMyBackpack);
}
  
registerCopyToMyBackpack();

function registerRemoveFromMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('remove_from_MyBackpack')) {
    return;
  }
  const removeFromMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_REMOVE;
},
    preconditionFn: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
if (Blockly.myBackpack.Blocks) {
var n = Blockly.myBackpack.Blocks;
for (var i=0;i<n.length;i++) {
if (n[i]==b)
return 'enabled';
}
}
return 'hidden';
    },
    callback: function(a) {
var d = Blockly.Xml.blockToDom(a.block,true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
function registerFileImportMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('file_import_MyBackpack')) {
    return;
  }
  const fileImportMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_IMPORT_FILE;
},
    preconditionFn: function(a) {
return 'enabled';
    },
    callback: function(a) {
var e = document.getElementById("fileImportBlocksToMyBackpack");
if (e) {
e.click();
return;
}
var input=document.createElement('input');
input.type="file";
input.id="fileImportBlocksToMyBackpack";
input.style.display = "none";
input.accept=".xmlbp";
input.onchange = function(element) {
try {
var file = this.files[0];
if (file) {
var fr = new FileReader();           
fr.onload = function (event) {
Blockly.myBackpack.Blocks = [];
var blocks = Blockly.Xml.textToDom(event.target.result);
var child = blocks.childNodes;
for (var i=0;i<child.length;i++){
if (child[i].nodeName!="#text") {
var b = Blockly.Xml.domToText(child[i]).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
var n = Blockly.myBackpack.Blocks;
var exist = false;
for (var j=0;j<n.length;j++) {
if (n[j]==b) { 
exist = true;
}
}
if (exist==false) Blockly.myBackpack.Blocks.push(b);
}
}
};
fr.readAsText(file);
}
} catch (e) {
alert(e);
}   
}

document.body.appendChild(input);
setTimeout(function(){
input.click();
},500);
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
    id: 'file_import_MyBackpack',
    weight: 204,
  };
  Blockly.ContextMenuRegistry.registry.register(fileImportMyBackpack);
}
  
registerFileImportMyBackpack();

function registerWorkspaceImportMyBackpack() {
  if (Blockly.ContextMenuRegistry.registry.getItem('workspace_import_MyBackpack')) {
    return;
  }
  const workspaceImportMyBackpack = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_IMPORT_WORKSPACE;
},
    preconditionFn: function(a) {
return 'enabled';
    },
    callback: function(a) {
var result = confirm(Blockly.Msg.MYBACKPACK_IMPORT_WORKSPACE_TITLE);
if (result) {
Blockly.myBackpack.Blocks = [];
var t = Blockly.getMainWorkspace().getTopBlocks();
for (var i=0;i<t.length;i++){
var d = Blockly.Xml.blockToDom(t[i],true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
var n = Blockly.myBackpack.Blocks;
var exist = false;
for (var j=0;j<n.length;j++) {
if (n[j]==b) { 
exist = true;
}
}
if (exist==false) Blockly.myBackpack.Blocks.push(b);
}
}
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
    id: 'workspace_import_MyBackpack',
    weight: 205,
  };
  Blockly.ContextMenuRegistry.registry.register(workspaceImportMyBackpack);
}
  
registerWorkspaceImportMyBackpack();

function registerWorkspaceExportFile() {
  if (Blockly.ContextMenuRegistry.registry.getItem('workspace_export_file')) {
    return;
  }
  const workspaceExportFile = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_WORKSPACE_EXPORT_FILE;
},
    preconditionFn: function(a) {
return 'enabled';
    },
    callback: function(a) {
var xml = '<xml xmlns="https://developers.google.com/blockly/xml">';
var t = Blockly.getMainWorkspace().getTopBlocks();
for (var i=0;i<t.length;i++){
var d = Blockly.Xml.blockToDom(t[i],true);
var b = Blockly.Xml.domToText(d).replace(/(?:\r\n|\r|\n|\t)/g, "").replace(/\"false\"/g, "\"0\"").replace(/\"true\"/g, "\"1\"");
xml += b;
}
xml += '</xml>';
var link = document.createElement('a');
link.download="backpack.xmlbp";
link.href="data:application/octet-stream;utf-8," + encodeURIComponent(xml);
document.body.appendChild(link);
link.click();
link.remove();
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
    id: 'workspace_export_file',
    weight: 206,
  };
  Blockly.ContextMenuRegistry.registry.register(workspaceExportFile);
}
  
registerWorkspaceExportFile();


function registerMyBackpackExportFile() {
  if (Blockly.ContextMenuRegistry.registry.getItem('mybackpack_export_file')) {
    return;
  }
  const myBackpackExportFile = {
    displayText: function(){
return Blockly.Msg.MYBACKPACK_MYBACKPACK_EXPORT_FILE;
},
    preconditionFn: function(a) {
var t = Blockly.getMainWorkspace();
if (t.toolbox_.getSelectedItem()) {
if (t.toolbox_.getSelectedItem().flyoutItems_=="MYBACKPACK") {
return 'enabled';
}
}
return 'hidden';
    },
    callback: function(a) {
var xml = '<xml xmlns="https://developers.google.com/blockly/xml">';
var b = Blockly.myBackpack.Blocks;
for (var i=0;i<b.length;i++){
xml += b[i];
}
xml += '</xml>';
var link = document.createElement('a');
link.download="backpack.xmlbp";
link.href="data:application/octet-stream;utf-8," + encodeURIComponent(xml);
document.body.appendChild(link);
link.click();
link.remove();
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'mybackpack_export_file',
    weight: 207,
  };
  Blockly.ContextMenuRegistry.registry.register(myBackpackExportFile);
}
  
registerMyBackpackExportFile();





//toolbox.xml

<category id="catMyBackPack" name="catMyBackPack" colour="290"  custom="MYBACKPACK"></category>

//blockly_compressed.js

Blockly.MYBACKPACK_CATEGORY_NAME="MYBACKPACK";
Blockly.myBackpack&&Blockly.myBackpack.flyoutCategory&&(this.registerToolboxCategoryCallback(Blockly.MYBACKPACK_CATEGORY_NAME,Blockly.myBackpack.flyoutCategory));

//en.js

Blockly.Msg.MYBACKPACK_ADD = "Copy to my backpack";
Blockly.Msg.MYBACKPACK_REMOVE = "Remove from my backpack";
Blockly.Msg.MYBACKPACK_REMOVE_ALL = "Remove all my backpack";
Blockly.Msg.MYBACKPACK_REMOVE_ALL_TITLE = "Are you sure that remove all my backpack?";
Blockly.Msg.MYBACKPACK_IMPORT_FILE = "Import blocks to my backpack from backpack file";
Blockly.Msg.MYBACKPACK_IMPORT_WORKSPACE = "Import blocks to my backpack from workspace";
Blockly.Msg.MYBACKPACK_IMPORT_WORKSPACE_TITLE = "Are you sure that import blocks to my backpack from workspace?";
Blockly.Msg.MYBACKPACK_WORKSPACE_EXPORT_FILE = "Export blocks to backpack file from workspace";
Blockly.Msg.MYBACKPACK_MYBACKPACK_EXPORT_FILE = "Export all blocks to backpack file from my backpack";
Reply all
Reply to author
Forward
0 new messages