mirror of
https://github.com/google/blockly.git
synced 2026-01-24 09:10:09 +01:00
Blockly Factory: Workspace Factory UI (#577)
* Some UI changes made * CSS changes * Done with UI tweaks * Changing arrow key event listeners, also changing category header in category list * Fixed bug with error on updating toolbox with read only * Changes to factory.css and workspacefactory view * Bug fixes and UI changes and refactoring to have enableKeyEvents in wfactory controller * Uncommented catch * Changes to app_controller.js to use constants, other nit changes * Nit line breaks
This commit is contained in:
committed by
picklesrus
parent
6953afb0b5
commit
ab850b9863
@@ -56,16 +56,23 @@ AppController = function() {
|
||||
new BlockExporterController(this.blockLibraryController.storage);
|
||||
|
||||
// Map of tab type to the div element for the tab.
|
||||
this.tabMap = {
|
||||
'BLOCK_FACTORY' : goog.dom.getElement('blockFactory_tab'),
|
||||
'WORKSPACE_FACTORY': goog.dom.getElement('workspaceFactory_tab'),
|
||||
'EXPORTER' : goog.dom.getElement('blocklibraryExporter_tab')
|
||||
};
|
||||
this.tabMap = Object.create(null);
|
||||
this.tabMap[AppController.BLOCK_FACTORY] =
|
||||
goog.dom.getElement('blockFactory_tab');
|
||||
this.tabMap[AppController.WORKSPACE_FACTORY] =
|
||||
goog.dom.getElement('workspaceFactory_tab');
|
||||
this.tabMap[AppController.EXPORTER] =
|
||||
goog.dom.getElement('blocklibraryExporter_tab');
|
||||
|
||||
// Selected tab.
|
||||
this.selectedTab = 'BLOCK_FACTORY';
|
||||
this.selectedTab = AppController.BLOCK_FACTORY;
|
||||
};
|
||||
|
||||
// Constant values representing the three tabs in the controller.
|
||||
AppController.BLOCK_FACTORY = 'BLOCK_FACTORY';
|
||||
AppController.WORKSPACE_FACTORY = 'WORKSPACE_FACTORY';
|
||||
AppController.EXPORTER = 'EXPORTER';
|
||||
|
||||
/**
|
||||
* Tied to the 'Import Block Library' button. Imports block library from file to
|
||||
* Block Factory. Expects user to upload a single file of JSON mapping each
|
||||
@@ -256,7 +263,8 @@ AppController.prototype.addTabHandlers = function(tabMap) {
|
||||
* Set the selected tab.
|
||||
* @private
|
||||
*
|
||||
* @param {string} tabName 'BLOCK_FACTORY', 'WORKSPACE_FACTORY', or 'EXPORTER'
|
||||
* @param {string} tabName AppController.BLOCK_FACTORY,
|
||||
* AppController.WORKSPACE_FACTORY, or AppController.EXPORTER
|
||||
*/
|
||||
AppController.prototype.setSelected_ = function(tabName) {
|
||||
this.selectedTab = tabName;
|
||||
@@ -266,7 +274,8 @@ AppController.prototype.setSelected_ = function(tabName) {
|
||||
* Creates the tab click handler specific to the tab specified.
|
||||
* @private
|
||||
*
|
||||
* @param {string} tabName 'BLOCK_FACTORY', 'WORKSPACE_FACTORY', or 'EXPORTER'
|
||||
* @param {string} tabName AppController.BLOCK_FACTORY,
|
||||
* AppController.WORKSPACE_FACTORY, or AppController.EXPORTER
|
||||
* @return {Function} The tab click handler.
|
||||
*/
|
||||
AppController.prototype.makeTabClickHandler_ = function(tabName) {
|
||||
@@ -283,14 +292,19 @@ AppController.prototype.makeTabClickHandler_ = function(tabName) {
|
||||
*/
|
||||
AppController.prototype.onTab = function() {
|
||||
// Get tab div elements.
|
||||
var blockFactoryTab = this.tabMap['BLOCK_FACTORY'];
|
||||
var exporterTab = this.tabMap['EXPORTER'];
|
||||
var workspaceFactoryTab = this.tabMap['WORKSPACE_FACTORY'];
|
||||
var blockFactoryTab = this.tabMap[AppController.BLOCK_FACTORY];
|
||||
var exporterTab = this.tabMap[AppController.EXPORTER];
|
||||
var workspaceFactoryTab = this.tabMap[AppController.WORKSPACE_FACTORY];
|
||||
|
||||
// Turn selected tab on and other tabs off.
|
||||
this.styleTabs_();
|
||||
|
||||
if (this.selectedTab == 'EXPORTER') {
|
||||
// Only enable key events in workspace factory if workspace factory tab is
|
||||
// selected.
|
||||
this.workspaceFactoryController.keyEventsEnabled =
|
||||
this.selectedTab == AppController.WORKSPACE_FACTORY;
|
||||
|
||||
if (this.selectedTab == AppController.EXPORTER) {
|
||||
// Update toolbox to reflect current block library.
|
||||
this.exporter.updateToolbox();
|
||||
|
||||
@@ -309,12 +323,12 @@ AppController.prototype.onTab = function() {
|
||||
FactoryUtils.show('blockLibraryExporter');
|
||||
FactoryUtils.hide('workspaceFactoryContent');
|
||||
|
||||
} else if (this.selectedTab == 'BLOCK_FACTORY') {
|
||||
} else if (this.selectedTab == AppController.BLOCK_FACTORY) {
|
||||
// Hide container of exporter.
|
||||
FactoryUtils.hide('blockLibraryExporter');
|
||||
FactoryUtils.hide('workspaceFactoryContent');
|
||||
|
||||
} else if (this.selectedTab == 'WORKSPACE_FACTORY') {
|
||||
} else if (this.selectedTab == AppController.WORKSPACE_FACTORY) {
|
||||
// Update block library category.
|
||||
var categoryXml = this.exporter.getBlockLibCategory();
|
||||
this.workspaceFactoryController.setBlockLibCategory(categoryXml);
|
||||
|
||||
@@ -299,8 +299,8 @@ aside {
|
||||
}
|
||||
|
||||
td.tabon {
|
||||
border-bottom-color: #ddd !important;
|
||||
background-color: #ddd;
|
||||
background-color: #ccc;
|
||||
border-bottom-color: #ccc;
|
||||
padding: 5px 19px;
|
||||
}
|
||||
|
||||
@@ -331,9 +331,15 @@ td {
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
#workspaceTabs {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #ccc;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#toolbox_section {
|
||||
height: 480px;
|
||||
width: 80%;
|
||||
height: 405px;
|
||||
width: 60%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -343,20 +349,34 @@ td {
|
||||
}
|
||||
|
||||
#preview_blocks {
|
||||
height: 300px;
|
||||
height: 395px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#createDiv {
|
||||
width: 70%;
|
||||
padding: 0.5%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#previewDiv {
|
||||
width: 30%;
|
||||
border: 10px solid #eee;
|
||||
margin-right: 0.5%;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
#previewBorder {
|
||||
border: 5px solid #ddd;
|
||||
padding: 2%;
|
||||
}
|
||||
|
||||
#toolbox_div, #preload_div {
|
||||
width: 20%;
|
||||
margin-right: 5%;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
#workspace_options {
|
||||
max-height: 250px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#disable_div {
|
||||
|
||||
@@ -164,13 +164,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="button_print">Print Toolbox</button>
|
||||
<button id="button_clear">Clear Toolbox</button>
|
||||
<button id="button_clear">Clear</button>
|
||||
|
||||
</p>
|
||||
|
||||
<section id="createDiv">
|
||||
<h3>Workspace Editor:</h3>
|
||||
<p id="editHelpText">Drag blocks into your toolbox:</p>
|
||||
<h3>Edit</h3>
|
||||
<p id="editHelpText">Drag blocks into the workspace to configure the toolbox in your custom workspace.</p>
|
||||
<table id='workspaceTabs' style="width:auto">
|
||||
<td id="tab_toolbox" class="tabon">Toolbox</td>
|
||||
<td id="tab_preload" class="taboff">Workspace</td>
|
||||
@@ -180,8 +180,8 @@
|
||||
<div id='disable_div'></div>
|
||||
</section>
|
||||
<aside id="toolbox_div">
|
||||
<p id="categoryHeader">Your categories will appear here</p>
|
||||
<table id="categoryTable" style="width:auto">
|
||||
<td id="tab_help">Your categories will appear here</td>
|
||||
</table>
|
||||
<p> </p>
|
||||
|
||||
@@ -199,7 +199,7 @@
|
||||
<button id="button_up" class="large">↑</button>
|
||||
<button id="button_down" class="large">↓</button>
|
||||
|
||||
<p> </p>
|
||||
<br>
|
||||
<div class='dropdown'>
|
||||
<button id="button_editCategory">Edit Category</button>
|
||||
<div id="dropdownDiv_editCategory" class="dropdown-content">
|
||||
@@ -222,7 +222,7 @@
|
||||
|
||||
<aside id='preload_div' style='display:none'>
|
||||
<p>Configure the <a href="https://developers.google.com/blockly/guides/get-started/web">options</a> for your Blockly inject call.</p>
|
||||
<button class="small" id="button_standardOptions">Standard Options</button>
|
||||
<button class="small" id="button_standardOptions">Reset Options</button>
|
||||
<form id="workspace_options">
|
||||
<input type="checkbox" id="option_collapse_checkbox" class="optionsInput">Collapsible Blocks<br>
|
||||
<input type="checkbox" id="option_comments_checkbox" class="optionsInput">Comments for Blocks<br>
|
||||
@@ -258,8 +258,11 @@
|
||||
</section>
|
||||
|
||||
<aside id="previewDiv">
|
||||
<h3>Preview Workspace:</h3>
|
||||
<div id="preview_blocks" class="content"></div>
|
||||
<div id="previewBorder">
|
||||
<h3>Preview</h3>
|
||||
<p>This is what your custom workspace will look like.</p>
|
||||
<div id="preview_blocks" class="content"></div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ WorkspaceFactoryController = function(toolboxName, toolboxDiv, previewDiv) {
|
||||
this.generator = new WorkspaceFactoryGenerator(this.model);
|
||||
// Tracks which editing mode the user is in. Toolbox mode on start.
|
||||
this.selectedMode = WorkspaceFactoryController.MODE_TOOLBOX;
|
||||
// True if key events are enabled, false otherwise.
|
||||
this.keyEventsEnabled = true;
|
||||
};
|
||||
|
||||
// Toolbox editing mode. Changes the user makes to the workspace updates the
|
||||
@@ -399,24 +401,30 @@ WorkspaceFactoryController.prototype.updatePreview = function() {
|
||||
|
||||
if (this.selectedMode == WorkspaceFactoryController.MODE_TOOLBOX) {
|
||||
// If currently editing the toolbox.
|
||||
// Get toolbox XML.
|
||||
var tree = Blockly.Options.parseToolboxTree
|
||||
(this.generator.generateToolboxXml());
|
||||
// No categories, creates a simple flyout.
|
||||
if (tree.getElementsByTagName('category').length == 0) {
|
||||
|
||||
// Only update the toolbox if not in read only mode.
|
||||
if (!this.model.options['readOnly']) {
|
||||
// Get toolbox XML.
|
||||
var tree = Blockly.Options.parseToolboxTree
|
||||
(this.generator.generateToolboxXml());
|
||||
|
||||
// No categories, creates a simple flyout.
|
||||
if (this.previewWorkspace.toolbox_) {
|
||||
this.reinjectPreview(tree); // Switch to simple flyout, more expensive.
|
||||
if (tree.getElementsByTagName('category').length == 0) {
|
||||
// No categories, creates a simple flyout.
|
||||
if (this.previewWorkspace.toolbox_) {
|
||||
this.reinjectPreview(tree); // Switch to simple flyout, expensive.
|
||||
} else {
|
||||
this.previewWorkspace.updateToolbox(tree);
|
||||
}
|
||||
} else {
|
||||
this.previewWorkspace.flyout_.show(tree.childNodes);
|
||||
}
|
||||
} else {
|
||||
// Uses categories, creates a toolbox.
|
||||
if (!this.previewWorkspace.toolbox_) {
|
||||
this.reinjectPreview(tree); // Create a toolbox, more expensive.
|
||||
} else {
|
||||
this.previewWorkspace.toolbox_.populate_(tree);
|
||||
// Uses categories, creates a toolbox.
|
||||
if (!this.previewWorkspace.toolbox_) {
|
||||
this.reinjectPreview(tree); // Create a toolbox, expensive.
|
||||
} else {
|
||||
this.previewWorkspace.updateToolbox(tree);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update pre-loaded blocks in the preview workspace to make sure that
|
||||
@@ -425,6 +433,7 @@ WorkspaceFactoryController.prototype.updatePreview = function() {
|
||||
this.previewWorkspace.clear();
|
||||
Blockly.Xml.domToWorkspace(this.generator.generateWorkspaceXml(),
|
||||
this.previewWorkspace);
|
||||
|
||||
} else if (this.selectedMode == WorkspaceFactoryController.MODE_PRELOAD){
|
||||
// If currently editing the pre-loaded workspace.
|
||||
this.previewWorkspace.clear();
|
||||
@@ -676,6 +685,7 @@ WorkspaceFactoryController.prototype.importFile = function(file, importMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
Blockly.Events.disable();
|
||||
var controller = this;
|
||||
var reader = new FileReader();
|
||||
|
||||
@@ -697,9 +707,11 @@ WorkspaceFactoryController.prototype.importFile = function(file, importMode) {
|
||||
// Throw error if invalid mode.
|
||||
throw new Error("Unknown import mode: " + importMode);
|
||||
}
|
||||
} catch(e) {
|
||||
alert('Cannot load XML from file.');
|
||||
console.log(e);
|
||||
} catch(e) {
|
||||
alert('Cannot load XML from file.');
|
||||
console.log(e);
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,8 +785,6 @@ WorkspaceFactoryController.prototype.importToolboxFromTree_ = function(tree) {
|
||||
this.view.updateState(this.model.getIndexByElementId
|
||||
(this.model.getSelectedId()), this.model.getSelected());
|
||||
|
||||
this.saveStateFromWorkspace();
|
||||
|
||||
this.saveStateFromWorkspace();
|
||||
// Allow the user to set default configuration options for a single flyout
|
||||
// or multiple categories.
|
||||
@@ -828,15 +838,15 @@ WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the toolbox editing area completely, deleting all categories and all
|
||||
* blocks in the model and view. Sets the mode to toolbox mode. Tied to "Clear
|
||||
* Toolbox" button.
|
||||
* Clears the editing area completely, deleting all categories and all
|
||||
* blocks in the model and view and all pre-loaded blocks. Tied to the
|
||||
* "Clear" button.
|
||||
*/
|
||||
WorkspaceFactoryController.prototype.clearToolbox = function() {
|
||||
this.setMode(WorkspaceFactoryController.MODE_TOOLBOX);
|
||||
WorkspaceFactoryController.prototype.clearAll = function() {
|
||||
var hasCategories = this.model.hasElements();
|
||||
this.model.clearToolboxList();
|
||||
this.view.clearToolboxTabs();
|
||||
this.model.savePreloadXml(Blockly.Xml.textToDom('<xml></xml>'));
|
||||
this.view.addEmptyCategoryMessage();
|
||||
this.view.updateState(-1, null);
|
||||
this.toolboxWorkspace.clear();
|
||||
@@ -998,8 +1008,6 @@ WorkspaceFactoryController.prototype.setMode = function(mode) {
|
||||
|
||||
if (mode == WorkspaceFactoryController.MODE_TOOLBOX) {
|
||||
// Open the toolbox editing space.
|
||||
document.getElementById('editHelpText').textContent =
|
||||
'Drag blocks into your toolbox:';
|
||||
this.model.savePreloadXml
|
||||
(Blockly.Xml.workspaceToDom(this.toolboxWorkspace));
|
||||
this.clearAndLoadXml_(this.model.getSelectedXml());
|
||||
@@ -1007,8 +1015,6 @@ WorkspaceFactoryController.prototype.setMode = function(mode) {
|
||||
(this.model.getSelected()));
|
||||
} else {
|
||||
// Open the pre-loaded workspace editing space.
|
||||
document.getElementById('editHelpText').textContent =
|
||||
'Drag blocks into your pre-loaded workspace:';
|
||||
if (this.model.getSelected()) {
|
||||
this.model.getSelected().saveFromWorkspace(this.toolboxWorkspace);
|
||||
}
|
||||
|
||||
@@ -235,12 +235,6 @@ WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ =
|
||||
document.getElementById('dropdownDiv_load').classList.remove("show");
|
||||
document.getElementById('dropdownDiv_importBlocks').classList.
|
||||
remove("show");
|
||||
})
|
||||
|
||||
document.getElementById('button_print').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.printConfig();
|
||||
});
|
||||
|
||||
document.getElementById('button_up').addEventListener
|
||||
@@ -351,11 +345,11 @@ document.getElementById('button_importBlocks').addEventListener
|
||||
document.getElementById('button_clear').addEventListener
|
||||
('click',
|
||||
function() {
|
||||
controller.clearToolbox();
|
||||
document.getElementById('dropdownDiv_importBlocks').classList.
|
||||
remove("show");
|
||||
document.getElementById('dropdownDiv_export').classList.remove("show");
|
||||
document.getElementById('dropdownDiv_load').classList.remove("show");
|
||||
controller.clearAll();
|
||||
});
|
||||
|
||||
document.getElementById('dropdown_addShadow').addEventListener
|
||||
@@ -394,13 +388,18 @@ document.getElementById('button_importBlocks').addEventListener
|
||||
*/
|
||||
WorkspaceFactoryInit.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) {
|
||||
// Don't let arrow keys have any effect if not in Workspace Factory
|
||||
// editing the toolbox.
|
||||
if (!(controller.keyEventsEnabled && controller.selectedMode
|
||||
== WorkspaceFactoryController.MODE_TOOLBOX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode == 38) {
|
||||
// Arrow up.
|
||||
controller.moveElement(-1);
|
||||
} else if (this.selectedTab != 'WORKSPACE_FACTORY' && e.keyCode == 40) {
|
||||
} else if (e.keyCode == 40) {
|
||||
// Arrow down.
|
||||
controller.moveElement(1);
|
||||
}
|
||||
@@ -414,7 +413,7 @@ WorkspaceFactoryInit.addWorkspaceFactoryEventListeners_ = function(controller) {
|
||||
!block.getSurroundParent()) ||
|
||||
(!controller.isUserGenShadowBlock(block.id) && block.getSurroundParent()
|
||||
&& controller.isUserGenShadowBlock(block.getSurroundParent().id)));
|
||||
}
|
||||
};
|
||||
|
||||
// Add change listeners for toolbox workspace in workspace factory.
|
||||
controller.toolboxWorkspace.addChangeListener(function(e) {
|
||||
|
||||
@@ -52,7 +52,7 @@ WorkspaceFactoryView.prototype.addCategoryRow =
|
||||
var table = document.getElementById('categoryTable');
|
||||
// Delete help label and enable category buttons if it's the first category.
|
||||
if (firstCategory) {
|
||||
table.deleteRow(0);
|
||||
document.getElementById('categoryHeader').textContent = 'Your Categories:';
|
||||
}
|
||||
// Create tab.
|
||||
var count = table.rows.length;
|
||||
@@ -94,8 +94,8 @@ WorkspaceFactoryView.prototype.deleteElementRow = function(id, index) {
|
||||
WorkspaceFactoryView.prototype.addEmptyCategoryMessage = function() {
|
||||
var table = document.getElementById('categoryTable');
|
||||
if (table.rows.length == 0) {
|
||||
var row = table.insertRow(0);
|
||||
row.textContent = 'Your categories will appear here';
|
||||
document.getElementById('categoryHeader').textContent =
|
||||
'Your categories will appear here';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,11 +216,14 @@ WorkspaceFactoryView.prototype.moveTabToIndex =
|
||||
oldIndex >= table.rows.length) {
|
||||
throw new Error('Index out of bounds when moving tab in the view.');
|
||||
}
|
||||
if (newIndex < oldIndex) { // Inserting before.
|
||||
|
||||
if (newIndex < oldIndex) {
|
||||
// Inserting before.
|
||||
var row = table.insertRow(newIndex);
|
||||
row.appendChild(this.tabMap[id]);
|
||||
table.deleteRow(oldIndex + 1);
|
||||
} else { // Inserting after.
|
||||
} else {
|
||||
// Inserting after.
|
||||
var row = table.insertRow(newIndex + 1);
|
||||
row.appendChild(this.tabMap[id]);
|
||||
table.deleteRow(oldIndex);
|
||||
@@ -296,6 +299,7 @@ WorkspaceFactoryView.prototype.clearToolboxTabs = function() {
|
||||
var oldCategoryTable = document.getElementById('categoryTable');
|
||||
var newCategoryTable = document.createElement('table');
|
||||
newCategoryTable.id = 'categoryTable';
|
||||
newCategoryTable.style.width = 'auto';
|
||||
oldCategoryTable.parentElement.replaceChild(newCategoryTable,
|
||||
oldCategoryTable);
|
||||
};
|
||||
@@ -370,8 +374,13 @@ WorkspaceFactoryView.prototype.setModeSelection = function(mode) {
|
||||
* WorkspaceFactoryController.MODE_PRELOAD).
|
||||
*/
|
||||
WorkspaceFactoryView.prototype.updateHelpText = function(mode) {
|
||||
var helpText = 'Drag your blocks into your ' + (mode ==
|
||||
WorkspaceFactoryController.MODE_TOOLBOX ? 'toolbox: ' : 'pre-loaded workspace: ');
|
||||
if (mode == WorkspaceFactoryController.MODE_TOOLBOX) {
|
||||
var helpText = 'Drag blocks into the workspace to configure the toolbox '
|
||||
+ 'in your custom workspace.';
|
||||
} else {
|
||||
var helpText = 'Drag blocks into the workspace to pre-load them in your '
|
||||
+ 'custom workspace.'
|
||||
}
|
||||
document.getElementById('editHelpText').textContent = helpText;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user