mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-08-28 22:10:31 -04:00
Add Workspace Factory to Blockly Factory Tab (#538)
* Starting to integrate workspacefactory * Committing before switching branches * Tab for workspace factory working * Committing before switching branches * Refactored to have FactoryInit namespace and move logic out of AppController * Nit typo fix. * Fixed bugs from rebasing * Nit fix in factory.css * Added this. to previewWorkspace
This commit is contained in:
parent
1c06bcdacc
commit
8ec5745611
6 changed files with 997 additions and 33 deletions
|
@ -33,6 +33,8 @@ goog.require('BlockLibraryController');
|
|||
goog.require('BlockExporterController');
|
||||
goog.require('goog.dom.classlist');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.ui.PopupColorPicker');
|
||||
goog.require('goog.ui.ColorPicker');
|
||||
|
||||
/**
|
||||
* Controller for the Blockly Factory
|
||||
|
@ -45,6 +47,10 @@ AppController = function() {
|
|||
new BlockLibraryController(this.blockLibraryName);
|
||||
this.blockLibraryController.populateBlockLibrary();
|
||||
|
||||
// Construct Workspace Factory Controller.
|
||||
this.workspaceFactoryController = new FactoryController
|
||||
('workspacefactory_toolbox', 'toolbox_blocks', 'preview_blocks');
|
||||
|
||||
// Initialize Block Exporter
|
||||
this.exporter =
|
||||
new BlockExporterController(this.blockLibraryController.storage);
|
||||
|
@ -361,18 +367,20 @@ AppController.prototype.assignLibraryClickHandlers = function() {
|
|||
/**
|
||||
* Assign button click handlers for the block factory.
|
||||
*/
|
||||
AppController.prototype.assignFactoryClickHandlers = function() {
|
||||
AppController.prototype.assignBlockFactoryClickHandlers = function() {
|
||||
var self = this;
|
||||
// Assign button event handlers for Block Factory.
|
||||
document.getElementById('localSaveButton')
|
||||
.addEventListener('click', function() {
|
||||
self.exportBlockLibraryToFile();
|
||||
});
|
||||
|
||||
document.getElementById('helpButton').addEventListener('click',
|
||||
function() {
|
||||
open('https://developers.google.com/blockly/custom-blocks/block-factory',
|
||||
'BlockFactoryHelp');
|
||||
});
|
||||
|
||||
document.getElementById('files').addEventListener('change',
|
||||
function() {
|
||||
// Warn user.
|
||||
|
@ -386,6 +394,7 @@ AppController.prototype.assignFactoryClickHandlers = function() {
|
|||
this.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('createNewBlockButton')
|
||||
.addEventListener('click', function() {
|
||||
BlockFactory.showStarterBlock();
|
||||
|
@ -396,7 +405,7 @@ AppController.prototype.assignFactoryClickHandlers = function() {
|
|||
/**
|
||||
* Add event listeners for the block factory.
|
||||
*/
|
||||
AppController.prototype.addFactoryEventListeners = function() {
|
||||
AppController.prototype.addBlockFactoryEventListeners = function() {
|
||||
BlockFactory.mainWorkspace.addChangeListener(BlockFactory.updateLanguage);
|
||||
document.getElementById('direction')
|
||||
.addEventListener('change', BlockFactory.updatePreview);
|
||||
|
@ -429,6 +438,7 @@ AppController.prototype.initializeBlocklyStorage = function() {
|
|||
BlocklyStorage.link(BlockFactory.mainWorkspace);});
|
||||
BlockFactory.disableEnableLink();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize Blockly and layout. Called on page load.
|
||||
*/
|
||||
|
@ -441,7 +451,7 @@ AppController.prototype.init = function() {
|
|||
// Assign click handlers.
|
||||
this.assignExporterClickHandlers();
|
||||
this.assignLibraryClickHandlers();
|
||||
this.assignFactoryClickHandlers();
|
||||
this.assignBlockFactoryClickHandlers();
|
||||
|
||||
// Handle resizing of Block Factory elements.
|
||||
var expandList = [
|
||||
|
@ -463,7 +473,7 @@ AppController.prototype.init = function() {
|
|||
window.addEventListener('resize', onresize);
|
||||
|
||||
// Inject Block Factory Main Workspace.
|
||||
var toolbox = document.getElementById('toolbox');
|
||||
var toolbox = document.getElementById('blockfactory_toolbox');
|
||||
BlockFactory.mainWorkspace = Blockly.inject('blockly',
|
||||
{collapse: false,
|
||||
toolbox: toolbox,
|
||||
|
@ -484,5 +494,10 @@ AppController.prototype.init = function() {
|
|||
BlockFactory.mainWorkspace.clearUndo();
|
||||
|
||||
// Add Block Factory event listeners.
|
||||
this.addFactoryEventListeners();
|
||||
this.addBlockFactoryEventListeners();
|
||||
|
||||
// Workspace Factory init.
|
||||
FactoryInit.initWorkspaceFactory(this.workspaceFactoryController);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -38,17 +38,17 @@ goog.require('goog.dom');
|
|||
*
|
||||
* @param {Element} toolbox - Xml for the toolbox of the selector workspace.
|
||||
*/
|
||||
BlockExporterView = function(toolbox) {
|
||||
BlockExporterView = function(selectorToolbox) {
|
||||
// Xml representation of the toolbox
|
||||
if (toolbox.hasChildNodes) {
|
||||
this.toolbox = toolbox;
|
||||
if (selectorToolbox.hasChildNodes) {
|
||||
this.toolbox = selectorToolbox;
|
||||
} else {
|
||||
// Toolbox is empty. Append dummy category to toolbox because toolbox
|
||||
// cannot switch between category and flyout-only mode after injection.
|
||||
var categoryElement = goog.dom.createDom('category');
|
||||
categoryElement.setAttribute('name', 'Next Saved Block');
|
||||
toolbox.appendChild(categoryElement);
|
||||
this.toolbox = toolbox;
|
||||
selectorToolbox.appendChild(categoryElement);
|
||||
this.toolbox = selectorToolbox;
|
||||
}
|
||||
// Workspace users use to select blocks for export
|
||||
this.selectorWorkspace =
|
||||
|
@ -142,4 +142,3 @@ BlockExporterView.prototype.getSelectedBlocks = function() {
|
|||
return this.selectorWorkspace.getAllBlocks();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,11 @@ h3 {
|
|||
}
|
||||
|
||||
table {
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -58,7 +62,6 @@ p {
|
|||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
|
||||
#blockly {
|
||||
position: fixed;
|
||||
}
|
||||
|
@ -130,6 +133,12 @@ button, .buttonStyle {
|
|||
|
||||
#blockFactoryContent {
|
||||
height: 87%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#blockFactoryPreview {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#blockLibraryContainer {
|
||||
|
@ -230,3 +239,180 @@ button, .buttonStyle {
|
|||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Workspace Factory */
|
||||
|
||||
section {
|
||||
float: left;
|
||||
}
|
||||
|
||||
aside {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#categoryTable>table {
|
||||
border: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
td.tabon {
|
||||
border-bottom-color: #ddd !important;
|
||||
background-color: #ddd;
|
||||
padding: 5px 19px;
|
||||
}
|
||||
|
||||
td.taboff {
|
||||
cursor: pointer;
|
||||
padding: 5px 19px;
|
||||
}
|
||||
|
||||
td.taboff:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.inputfile {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
#toolbox_section {
|
||||
height: 480px;
|
||||
width: 80%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#toolbox_blocks {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#preview_blocks {
|
||||
height: 300px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#createDiv {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#previewDiv {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
#category_section {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#disable_div {
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: .5;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: -1; /* Start behind workspace */
|
||||
}
|
||||
|
||||
/* Rules for Closure popup color picker */
|
||||
.goog-palette {
|
||||
outline: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.goog-palette-cell {
|
||||
height: 13px;
|
||||
width: 15px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid #000000;
|
||||
font-size: 1px;
|
||||
}
|
||||
|
||||
.goog-palette-colorswatch {
|
||||
border: 1px solid #000000;
|
||||
height: 13px;
|
||||
position: relative;
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
.goog-palette-cell-hover .goog-palette-colorswatch {
|
||||
border: 1px solid #FFF;
|
||||
}
|
||||
|
||||
.goog-palette-cell-selected .goog-palette-colorswatch {
|
||||
border: 1px solid #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.goog-palette-table {
|
||||
border: 1px solid #000;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.goog-popupcolorpicker {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* The container <div> - needed to position the dropdown content */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Dropdown Content (Hidden by Default) */
|
||||
.dropdown-content {
|
||||
background-color: #f9f9f9;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,.2);
|
||||
display: none;
|
||||
min-width: 170px;
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Links inside the dropdown */
|
||||
.dropdown-content a {
|
||||
color: black;
|
||||
display: block;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Change color of dropdown links on hover */
|
||||
.dropdown-content a:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
/* Show the dropdown menu */
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.shadowBlock>.blocklyPath {
|
||||
fill-opacity: .5;
|
||||
stroke-opacity: .5;
|
||||
}
|
||||
|
||||
.shadowBlock>.blocklyPathLight,
|
||||
.shadowBlock>.blocklyPathDark {
|
||||
display: none;
|
||||
}
|
||||
|
||||
>>>>>>> Starting to integrate workspacefactory
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="target-densitydpi=device-dpi, height=660, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Blockly Demo: Blockly Factory</title>
|
||||
<script src="../../blockly_compressed.js"></script>
|
||||
<script src="../../javascript_compressed.js"></script>
|
||||
<script src="../../msg/messages.js"></script>
|
||||
<script src="../../blocks_compressed.js"></script>
|
||||
<script src="workspacefactory/wfactory_model.js"></script>
|
||||
<script src="workspacefactory/wfactory_controller.js"></script>
|
||||
<script src="workspacefactory/wfactory_view.js"></script>
|
||||
<script src="workspacefactory/wfactory_generator.js"></script>
|
||||
<script src="workspacefactory/wfactory_init.js"></script>
|
||||
<script src="workspacefactory/standard_categories.js"></script>
|
||||
<script src="/storage.js"></script>
|
||||
<script src="../../blockly_uncompressed.js"></script>
|
||||
<script src="../../generators/javascript.js"></script>
|
||||
<script src="../../../closure-library/closure/goog/base.js"></script>
|
||||
<script src="factory_utils.js"></script>
|
||||
<script src="factory.js"></script>
|
||||
|
@ -106,11 +114,77 @@
|
|||
</form>
|
||||
<button id="exporterSubmitButton"> Export </button>
|
||||
</div>
|
||||
<div id="exportPreview">
|
||||
<h3>Preview Workspace: </h3>
|
||||
<div id="exportpreview_blocks">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Workspace Factory tab -->
|
||||
|
||||
<div id="workspaceFactoryContent">
|
||||
<p>
|
||||
<input type="file" id="input_import" class="inputfile" class="large"></input>
|
||||
<label for="input_import" class="buttonStyle large">Import</label>
|
||||
<button id="button_export" class="large">Export</button>
|
||||
<button id="button_print" class="large">Print</button>
|
||||
<button id="button_clear" class="large">Clear</button>
|
||||
</p>
|
||||
|
||||
<section id="createDiv">
|
||||
<h3>Workspace Editor:</h3>
|
||||
<p>Drag blocks into your toolbox.</p>
|
||||
<section id="toolbox_section">
|
||||
<div id="toolbox_blocks" class="content"></div>
|
||||
<div id='disable_div'></div>
|
||||
</section>
|
||||
<aside id="category_section">
|
||||
<table id="categoryTable" style="width:auto">
|
||||
<td id="tab_help">Your categories will appear here</td>
|
||||
</table>
|
||||
<p> </p>
|
||||
|
||||
<div class='dropdown'>
|
||||
<button id="button_add" class="large">+</button>
|
||||
<div id="dropdownDiv_add" class="dropdown-content">
|
||||
<a id='dropdown_newCategory'>New Category</a>
|
||||
<a id='dropdown_loadCategory'>Standard Category</a>
|
||||
<a id='dropdown_separator'>Separator</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="button_remove" class="large">-</button>
|
||||
|
||||
<button id="button_up" class="large">↑</button>
|
||||
<button id="button_down" class="large">↓</button>
|
||||
|
||||
<p> </p>
|
||||
<div class='dropdown'>
|
||||
<button id="button_editCategory" class="large">Edit Category</button>
|
||||
<div id="dropdownDiv_editCategory" class="dropdown-content">
|
||||
<a id='dropdown_name'>Name</a>
|
||||
<a id='dropdown_color'>Color</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='dropdown'>
|
||||
<button id="button_editShadow" class="large">Edit Block</button>
|
||||
<div id="dropdownDiv_editShadowAdd" class="dropdown-content">
|
||||
<a id='dropdown_addShadow'>Add Shadow</a>
|
||||
</div>
|
||||
<div id="dropdownDiv_editShadowRemove" class="dropdown-content">
|
||||
<a id='dropdown_removeShadow'>Remove Shadow</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<aside id="previewDiv">
|
||||
<h3>Preview Workspace:</h3>
|
||||
<div id="preview_blocks" class="content"></div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<!-- Blockly Factory Tab -->
|
||||
|
@ -141,7 +215,7 @@
|
|||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<table id="blockFactoryPreview">
|
||||
<tr>
|
||||
<td id="previewContainer">
|
||||
<h3>Preview:
|
||||
|
@ -225,7 +299,7 @@
|
|||
</td>
|
||||
</table>
|
||||
|
||||
<xml id="toolbox">
|
||||
<xml id="blockfactory_toolbox">
|
||||
<category name="Input">
|
||||
<block type="input_value">
|
||||
<value name="TYPE">
|
||||
|
@ -276,5 +350,310 @@
|
|||
<block type="colour_hue"><mutation colour="330"></mutation><field name="HUE">330</field></block>
|
||||
</category>
|
||||
</xml>
|
||||
|
||||
<xml id="workspacefactory_toolbox" style="display: none">
|
||||
<category name="Logic" colour="210">
|
||||
<block type="controls_if"></block>
|
||||
<block type="logic_compare"></block>
|
||||
<block type="logic_operation"></block>
|
||||
<block type="logic_negate"></block>
|
||||
<block type="logic_boolean"></block>
|
||||
<block type="logic_null"></block>
|
||||
<block type="logic_ternary"></block>
|
||||
</category>
|
||||
<category name="Loops" colour="120">
|
||||
<block type="controls_repeat_ext">
|
||||
<value name="TIMES">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="controls_whileUntil"></block>
|
||||
<block type="controls_for">
|
||||
<value name="FROM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="TO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="BY">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="controls_forEach"></block>
|
||||
<block type="controls_flow_statements"></block>
|
||||
</category>
|
||||
<category name="Math" colour="230">
|
||||
<block type="math_number"></block>
|
||||
<block type="math_arithmetic">
|
||||
<value name="A">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="B">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_single">
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">9</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_trig">
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">45</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_constant"></block>
|
||||
<block type="math_number_property">
|
||||
<value name="NUMBER_TO_CHECK">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_change">
|
||||
<value name="DELTA">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_round">
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">3.1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_on_list"></block>
|
||||
<block type="math_modulo">
|
||||
<value name="DIVIDEND">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">64</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="DIVISOR">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_constrain">
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">50</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="LOW">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="HIGH">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_random_int">
|
||||
<value name="FROM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="TO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_random_float"></block>
|
||||
</category>
|
||||
<category name="Text" colour="160">
|
||||
<block type="text"></block>
|
||||
<block type="text_join"></block>
|
||||
<block type="text_append">
|
||||
<value name="TEXT">
|
||||
<shadow type="text"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_length">
|
||||
<value name="VALUE">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_isEmpty">
|
||||
<value name="VALUE">
|
||||
<shadow type="text">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_indexOf">
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">text</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="FIND">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_charAt">
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">text</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_getSubstring">
|
||||
<value name="STRING">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">text</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_changeCase">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_trim">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_print">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_prompt_ext">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Lists" colour="260">
|
||||
<block type="lists_create_with">
|
||||
<mutation items="0"></mutation>
|
||||
</block>
|
||||
<block type="lists_create_with"></block>
|
||||
<block type="lists_repeat">
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_length"></block>
|
||||
<block type="lists_isEmpty"></block>
|
||||
<block type="lists_indexOf">
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_getIndex">
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_setIndex">
|
||||
<value name="LIST">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_getSublist">
|
||||
<value name="LIST">
|
||||
<block type="variables_get">
|
||||
<field name="VAR">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_split">
|
||||
<value name="DELIM">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">,</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_sort"></block>
|
||||
</category>
|
||||
<category name="Colour" colour="20">
|
||||
<block type="colour_picker"></block>
|
||||
<block type="colour_random"></block>
|
||||
<block type="colour_rgb">
|
||||
<value name="RED">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="GREEN">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">50</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="BLUE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="colour_blend">
|
||||
<value name="COLOUR1">
|
||||
<shadow type="colour_picker">
|
||||
<field name="COLOUR">#ff0000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="COLOUR2">
|
||||
<shadow type="colour_picker">
|
||||
<field name="COLOUR">#3333ff</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="RATIO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</category>
|
||||
<sep></sep>
|
||||
<category name="Variables" colour="330" custom="VARIABLE"></category>
|
||||
<category name="Functions" colour="290" custom="PROCEDURE"></category>
|
||||
</xml>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -35,18 +35,41 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Class for a FactoryController
|
||||
* Class for a FactoryController.
|
||||
* @constructor
|
||||
* @param {!Blockly.workspace} toolboxWorkspace workspace where blocks are
|
||||
* dragged into corresponding categories
|
||||
* @param {!Blockly.workspace} previewWorkspace workspace that shows preview
|
||||
* of what workspace would look like using generated XML
|
||||
*
|
||||
* @param {!string} toolboxName Name of workspace toolbox XML.
|
||||
* @param {!string} toolboxDiv Name of div to inject toolbox workspace in.
|
||||
* @param {!string} previewDiv Name of div to inject preview workspace in.
|
||||
*/
|
||||
FactoryController = function(toolboxWorkspace, previewWorkspace) {
|
||||
FactoryController = function(toolboxName, toolboxDiv, previewDiv) {
|
||||
var toolbox = document.getElementById(toolboxName);
|
||||
|
||||
// Workspace for user to drag blocks in for a certain category.
|
||||
this.toolboxWorkspace = toolboxWorkspace;
|
||||
this.toolboxWorkspace = Blockly.inject(toolboxDiv,
|
||||
{grid:
|
||||
{spacing: 25,
|
||||
length: 3,
|
||||
colour: '#ccc',
|
||||
snap: true},
|
||||
media: '../../media/',
|
||||
toolbox: toolbox,
|
||||
});
|
||||
|
||||
// Workspace for user to preview their changes.
|
||||
this.previewWorkspace = previewWorkspace;
|
||||
this.previewWorkspace = Blockly.inject(previewDiv,
|
||||
{grid:
|
||||
{spacing: 25,
|
||||
length: 3,
|
||||
colour: '#ccc',
|
||||
snap: true},
|
||||
media: '../../media/',
|
||||
toolbox: '<xml></xml>',
|
||||
zoom:
|
||||
{controls: true,
|
||||
wheel: true}
|
||||
});
|
||||
|
||||
// Model to keep track of categories and blocks.
|
||||
this.model = new FactoryModel();
|
||||
// Updates the category tabs.
|
||||
|
@ -275,11 +298,13 @@ FactoryController.prototype.clearAndLoadElement = function(id) {
|
|||
|
||||
// Selects the next tab.
|
||||
this.view.setCategoryTabSelection(id, true);
|
||||
|
||||
// Order blocks as if shown in the flyout.
|
||||
this.toolboxWorkspace.cleanUp_();
|
||||
}
|
||||
|
||||
// Mark all shadow blocks laoded and order blocks as if shown in a flyout.
|
||||
this.view.markShadowBlocks(this.model.getShadowBlocksInWorkspace
|
||||
(this.toolboxWorkspace.getAllBlocks()));
|
||||
this.toolboxWorkspace.cleanUp_();
|
||||
|
||||
// Update category editing buttons.
|
||||
this.view.updateState(this.model.getIndexByElementId
|
||||
(this.model.getSelectedId()), this.model.getSelected());
|
||||
|
@ -380,11 +405,9 @@ FactoryController.prototype.updatePreview = function() {
|
|||
} else {
|
||||
this.previewWorkspace.flyout_.show(tree.childNodes);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Uses categories, creates a toolbox.
|
||||
|
||||
if (!previewWorkspace.toolbox_) {
|
||||
if (!this.previewWorkspace.toolbox_) {
|
||||
this.reinjectPreview(tree); // Create a toolbox, more expensive.
|
||||
} else {
|
||||
this.previewWorkspace.toolbox_.populate_(tree);
|
||||
|
@ -397,7 +420,7 @@ FactoryController.prototype.updatePreview = function() {
|
|||
this.previewWorkspace.clear();
|
||||
Blockly.Xml.domToWorkspace(this.generator.generateWorkspaceXml(),
|
||||
this.previewWorkspace);
|
||||
} else if (this.selectedMode == FactoryController.MODE_PRELOAD){
|
||||
} else if (this.selectedMode == FactoryController.MODE_PRELOAD) {
|
||||
// If currently editing the pre-loaded workspace.
|
||||
this.previewWorkspace.clear();
|
||||
Blockly.Xml.domToWorkspace(this.generator.generateWorkspaceXml(),
|
||||
|
@ -720,8 +743,6 @@ FactoryController.prototype.importToolboxFromTree_ = function(tree) {
|
|||
}
|
||||
|
||||
// Evenly space the blocks.
|
||||
// TODO(evd2014): Change to cleanUp once cleanUp_ is made public in
|
||||
// master.
|
||||
this.toolboxWorkspace.cleanUp_();
|
||||
|
||||
// Convert actual shadow blocks to user-generated shadow blocks.
|
||||
|
|
364
demos/blocklyfactory/workspacefactory/wfactory_init.js
Normal file
364
demos/blocklyfactory/workspacefactory/wfactory_init.js
Normal file
|
@ -0,0 +1,364 @@
|
|||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2016 Google Inc.
|
||||
* https://developers.google.com/blockly/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Contains the init functions for the workspace factory tab.
|
||||
* Adds click handlers to buttons and dropdowns, adds event listeners for
|
||||
* keydown events and Blockly events, and configures the initial setup of
|
||||
* the page.
|
||||
*
|
||||
* @author Emma Dauterman (evd2014)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Namespace for workspace factory initialization methods.
|
||||
* @namespace
|
||||
*/
|
||||
FactoryInit = {};
|
||||
|
||||
/**
|
||||
* Initialization for workspace factory tab.
|
||||
*
|
||||
* @param {!FactoryController} controller The controller for the workspace
|
||||
* factory tab.
|
||||
*/
|
||||
FactoryInit.initWorkspaceFactory = function(controller) {
|
||||
// Disable category editing buttons until categories are created.
|
||||
document.getElementById('button_remove').disabled = true;
|
||||
document.getElementById('button_up').disabled = true;
|
||||
document.getElementById('button_down').disabled = true;
|
||||
document.getElementById('button_editCategory').disabled = true;
|
||||
document.getElementById('button_editShadow').disabled = true;
|
||||
|
||||
this.initColorPicker_(controller);
|
||||
this.addWorkspaceFactoryEventListeners_(controller);
|
||||
this.assignWorkspaceFactoryClickHandlers_(controller);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the color picker in workspace factory.
|
||||
* @private
|
||||
*
|
||||
* @param {!FactoryController} controller The controller for the workspace
|
||||
* factory tab.
|
||||
*/
|
||||
FactoryInit.initColorPicker_ = function(controller) {
|
||||
// Array of Blockly category colors, variety of hues with saturation 45%
|
||||
// and value 65% as specified in Blockly Developer documentation:
|
||||
// https://developers.google.com/blockly/guides/create-custom-blocks/define-blocks
|
||||
var colors = ['#A65C5C',
|
||||
'#A6635C',
|
||||
'#A66A5C',
|
||||
'#A6725C',
|
||||
'#A6795C',
|
||||
'#A6815C',
|
||||
'#A6885C',
|
||||
'#A6905C',
|
||||
'#A6975C',
|
||||
'#A69F5C',
|
||||
'#A6A65C',
|
||||
'#9FA65C',
|
||||
'#97A65C',
|
||||
'#90A65C',
|
||||
'#88A65C',
|
||||
'#81A65C',
|
||||
'#79A65C',
|
||||
'#6FA65C',
|
||||
'#66A65C',
|
||||
'#5EA65C',
|
||||
'#5CA661',
|
||||
'#5CA668',
|
||||
'#5CA66F',
|
||||
'#5CA677',
|
||||
'#5CA67E',
|
||||
'#5CA686',
|
||||
'#5CA68D',
|
||||
'#5CA695',
|
||||
'#5CA69C',
|
||||
'#5CA6A4',
|
||||
'#5CA1A6',
|
||||
'#5C9AA6',
|
||||
'#5C92A6',
|
||||
'#5C8BA6',
|
||||
'#5C83A6',
|
||||
'#5C7CA6',
|
||||
'#5C74A6',
|
||||
'#5C6AA6',
|
||||
'#5C61A6',
|
||||
'#5E5CA6',
|
||||
'#665CA6',
|
||||
'#6D5CA6',
|
||||
'#745CA6',
|
||||
'#7C5CA6',
|
||||
'#835CA6',
|
||||
'#8B5CA6',
|
||||
'#925CA6',
|
||||
'#9A5CA6',
|
||||
'#A15CA6',
|
||||
'#A65CA4',
|
||||
'#A65C9C',
|
||||
'#A65C95',
|
||||
'#A65C8D',
|
||||
'#A65C86',
|
||||
'#A65C7E',
|
||||
'#A65C77',
|
||||
'#A65C6F',
|
||||
'#A65C66',
|
||||
'#A65C61',
|
||||
'#A65C5E'];
|
||||
|
||||
// Create color picker with specific set of Blockly colors.
|
||||
var colorPicker = new goog.ui.ColorPicker();
|
||||
colorPicker.setColors(colors);
|
||||
|
||||
// Create and render the popup color picker and attach to button.
|
||||
var popupPicker = new goog.ui.PopupColorPicker(null, colorPicker);
|
||||
popupPicker.render();
|
||||
popupPicker.attach(document.getElementById('dropdown_color'));
|
||||
popupPicker.setFocusable(true);
|
||||
goog.events.listen(popupPicker, 'change', function(e) {
|
||||
controller.changeSelectedCategoryColor(popupPicker.getSelectedColor());
|
||||
document.getElementById('dropdownDiv_editCategory').classList.remove
|
||||
("show");
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign click handlers for workspace factory.
|
||||
* @private
|
||||
*
|
||||
* @param {!FactoryController} controller The controller for the workspace
|
||||
* factory tab.
|
||||
*/
|
||||
FactoryInit.assignWorkspaceFactoryClickHandlers_ = function(controller) {
|
||||
document.getElementById('button_add').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
document.getElementById('dropdownDiv_add').classList.toggle("show");
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_newCategory').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.addCategory();
|
||||
document.getElementById('dropdownDiv_add').classList.remove("show");
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_loadCategory').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.loadCategory();
|
||||
document.getElementById('dropdownDiv_add').classList.remove("show");
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_separator').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.addSeparator();
|
||||
document.getElementById('dropdownDiv_add').classList.remove("show");
|
||||
});
|
||||
|
||||
document.getElementById('button_remove').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.removeElement();
|
||||
});
|
||||
|
||||
document.getElementById('button_export').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.exportConfig();
|
||||
});
|
||||
|
||||
document.getElementById('button_print').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.printConfig();
|
||||
});
|
||||
|
||||
document.getElementById('button_up').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.moveElement(-1);
|
||||
});
|
||||
|
||||
document.getElementById('button_down').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.moveElement(1);
|
||||
});
|
||||
|
||||
document.getElementById('button_editCategory').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
document.getElementById('dropdownDiv_editCategory').classList.
|
||||
toggle("show");
|
||||
});
|
||||
|
||||
document.getElementById('button_editShadow').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
if (Blockly.selected) {
|
||||
// Can only edit blocks when a block is selected.
|
||||
|
||||
if (!controller.isUserGenShadowBlock(Blockly.selected.id) &&
|
||||
Blockly.selected.getSurroundParent() != null) {
|
||||
// If a block is selected that could be a valid shadow block (not a
|
||||
// shadow block, has a surrounding parent), let the user make it a
|
||||
// shadow block. Use toggle instead of add so that the user can
|
||||
// click the button again to make the dropdown disappear without
|
||||
// clicking one of the options.
|
||||
document.getElementById('dropdownDiv_editShadowRemove').classList.
|
||||
remove("show");
|
||||
document.getElementById('dropdownDiv_editShadowAdd').classList.
|
||||
toggle("show");
|
||||
} else {
|
||||
// If the block is a shadow block, let the user make it a normal
|
||||
// block.
|
||||
document.getElementById('dropdownDiv_editShadowAdd').classList.
|
||||
remove("show");
|
||||
document.getElementById('dropdownDiv_editShadowRemove').classList.
|
||||
toggle("show");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_name').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.changeCategoryName();
|
||||
document.getElementById('dropdownDiv_editCategory').classList.
|
||||
remove("show");
|
||||
});
|
||||
|
||||
document.getElementById('input_import').addEventListener
|
||||
('change',
|
||||
function(event) {
|
||||
controller.importFile(event.target.files[0]);
|
||||
});
|
||||
|
||||
document.getElementById('button_clear').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.clear();
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_addShadow').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.addShadow();
|
||||
document.getElementById('dropdownDiv_editShadowAdd').classList.
|
||||
remove("show");
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_removeShadow').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.removeShadow();
|
||||
document.getElementById('dropdownDiv_editShadowRemove').classList.
|
||||
remove("show");
|
||||
// If turning invalid shadow block back to normal block, remove
|
||||
// warning and disable block editing privileges.
|
||||
Blockly.selected.setWarningText(null);
|
||||
if (!Blockly.selected.getSurroundParent()) {
|
||||
document.getElementById('button_editShadow').disabled = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add event listeners for workspace factory.
|
||||
* @private
|
||||
*
|
||||
* @param {!FactoryController} controller The controller for the workspace
|
||||
* factory tab.
|
||||
*/
|
||||
FactoryInit.addWorkspaceFactoryEventListeners_ = function(controller) {
|
||||
// Use up and down arrow keys to move categories.
|
||||
// TODO(evd2014): When merge with next CL for editing preloaded blocks, make
|
||||
// sure mode is toolbox.
|
||||
window.addEventListener('keydown', function(e) {
|
||||
if (this.selectedTab != 'WORKSPACE_FACTORY' && e.keyCode == 38) {
|
||||
// Arrow up.
|
||||
controller.moveElement(-1);
|
||||
} else if (this.selectedTab != 'WORKSPACE_FACTORY' && e.keyCode == 40) {
|
||||
// Arrow down.
|
||||
controller.moveElement(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Add change listeners for toolbox workspace in workspace factory.
|
||||
controller.toolboxWorkspace.addChangeListener(
|
||||
function(e) {
|
||||
// Listen for Blockly move and delete events to update preview.
|
||||
// Not listening for Blockly create events because causes the user to drop
|
||||
// blocks when dragging them into workspace. Could cause problems if ever
|
||||
// load blocks into workspace directly without calling updatePreview.
|
||||
if (e.type == Blockly.Events.MOVE || e.type == Blockly.Events.DELETE) {
|
||||
controller.updatePreview();
|
||||
}
|
||||
|
||||
// Listen for Blockly UI events to correctly enable the "Edit Block"
|
||||
// button. Only enable "Edit Block" when a block is selected and it has a
|
||||
// surrounding parent, meaning it is nested in another block (blocks that
|
||||
// are not nested in parents cannot be shadow blocks).
|
||||
if (e.type == Blockly.Events.MOVE || (e.type == Blockly.Events.UI &&
|
||||
e.element == 'selected')) {
|
||||
var selected = Blockly.selected;
|
||||
|
||||
if (selected != null && selected.getSurroundParent() != null) {
|
||||
|
||||
// A valid shadow block is selected. Enable block editing and remove
|
||||
// warnings.
|
||||
document.getElementById('button_editShadow').disabled = false;
|
||||
Blockly.selected.setWarningText(null);
|
||||
} else {
|
||||
if (selected != null &&
|
||||
controller.isUserGenShadowBlock(selected.id)) {
|
||||
|
||||
// Provide warning if shadow block is moved and is no longer a valid
|
||||
// shadow block.
|
||||
Blockly.selected.setWarningText('Shadow blocks must be nested' +
|
||||
' inside other blocks to be displayed.');
|
||||
|
||||
// Give editing options so that the user can make an invalid shadow
|
||||
// block a normal block.
|
||||
document.getElementById('button_editShadow').disabled = false;
|
||||
} else {
|
||||
|
||||
// No block selected that is a shadow block or could be a valid
|
||||
// shadow block.
|
||||
// Disable block editing.
|
||||
document.getElementById('button_editShadow').disabled = true;
|
||||
document.getElementById('dropdownDiv_editShadowRemove').classList.
|
||||
remove("show");
|
||||
document.getElementById('dropdownDiv_editShadowAdd').classList.
|
||||
remove("show");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert actual shadow blocks added from the toolbox to user-generated
|
||||
// shadow blocks.
|
||||
if (e.type == Blockly.Events.CREATE) {
|
||||
controller.convertShadowBlocks();
|
||||
}
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue