added preview of code to export in exporter tab, it dynamically updates with each block selection (#573)

moved inject code out to factory utils, refactored updatePreview and similar functions in exporter controller

refactor
This commit is contained in:
Tina Quach
2016-08-23 10:33:48 -07:00
committed by picklesrus
parent 7516866804
commit 6953afb0b5
7 changed files with 210 additions and 60 deletions

View File

@@ -302,6 +302,9 @@ AppController.prototype.onTab = function() {
var usedBlockTypes = this.workspaceFactoryController.getAllUsedBlockTypes();
this.exporter.setUsedBlockTypes(usedBlockTypes);
// Update the preview to reflect any changes made to the blocks.
this.exporter.updatePreview();
// Show container of exporter.
FactoryUtils.show('blockLibraryExporter');
FactoryUtils.hide('workspaceFactoryContent');
@@ -344,7 +347,6 @@ AppController.prototype.styleTabs_ = function() {
*/
AppController.prototype.assignExporterClickHandlers = function() {
var self = this;
document.getElementById('button_setBlocks').addEventListener('click',
function() {
document.getElementById('dropdownDiv_setBlocks').classList.toggle("show");
@@ -375,6 +377,68 @@ AppController.prototype.assignExporterClickHandlers = function() {
});
};
/**
* Assign change listeners for the exporter. These allow for the dynamic update
* of the exporter preview.
*/
AppController.prototype.assignExporterChangeListeners = function() {
var self = this;
var blockDefCheck = document.getElementById('blockDefCheck');
var genStubCheck = document.getElementById('genStubCheck');
var blockDefs = document.getElementById('blockDefs');
var blockDefSettings = document.getElementById('blockDefSettings');
var blockDefElements = [blockDefs, blockDefSettings];
var genStubs = document.getElementById('genStubs');
var genStubSettings = document.getElementById('genStubSettings');
var genStubElements = [genStubs, genStubSettings];
// Select the block definitions and generator stubs on default.
blockDefCheck.checked = true;
genStubCheck.checked = true;
// Checking the block definitions checkbox displays preview of code to export.
document.getElementById('blockDefCheck').addEventListener('change',
function(e) {
self.ifCheckedDisplay(blockDefCheck, blockDefElements);
});
// Preview updates when user selects different block definition format.
document.getElementById('exportFormat').addEventListener('change',
function(e) {
self.exporter.updatePreview();
});
// Checking the generator stub checkbox displays preview of code to export.
document.getElementById('genStubCheck').addEventListener('change',
function(e) {
self.ifCheckedDisplay(genStubCheck, genStubElements);
});
// Preview updates when user selects different generator stub language.
document.getElementById('exportLanguage').addEventListener('change',
function(e) {
self.exporter.updatePreview();
});
self.exporter.addChangeListenersToSelectorWorkspace();
};
/**
* If given checkbox is checked, display given elements. Otherwise, hide.
*
* @param {!Element} checkbox - Input element of type checkbox.
* @param {!Array.<!Element>} elementArray - Array of elements to show when
* block is checked.
*/
AppController.prototype.ifCheckedDisplay = function(checkbox, elementArray) {
for (var i = 0, element; element = elementArray[i]; i++) {
element.style.display = checkbox.checked ? 'block' : 'none';
}
};
/**
* Assign button click handlers for the block library.
*/
@@ -522,7 +586,8 @@ AppController.prototype.init = function() {
// Add tab handlers for switching between Block Factory and Block Exporter.
this.addTabHandlers(this.tabMap);
this.exporter.addChangeListenersToSelectorWorkspace();
// Assign exporter change listeners.
this.assignExporterChangeListeners();
// Create the root block on Block Factory main workspace.
if ('BlocklyStorage' in window && window.location.hash.length > 1) {

View File

@@ -103,13 +103,6 @@ BlockExporterController.prototype.export = function() {
var blockTypes = this.getSelectedBlockTypes_();
var blockXmlMap = this.blockLibStorage.getBlockXmlMap(blockTypes);
// Pull workspace-related settings from the Export Settings form.
var wantToolbox = document.getElementById('toolboxCheck').checked;
var wantPreloadedWorkspace =
document.getElementById('preloadedWorkspaceCheck').checked;
var wantWorkspaceOptions =
document.getElementById('workspaceOptsCheck').checked;
// Pull block definition(s) settings from the Export Settings form.
var wantBlockDef = document.getElementById('blockDefCheck').checked;
var definitionFormat = document.getElementById('exportFormat').value;
@@ -121,21 +114,6 @@ BlockExporterController.prototype.export = function() {
var generatorStub_filename = document.getElementById(
'generatorStub_filename').value;
if (wantToolbox) {
// TODO(quachtina96): create and download file once wfactory has been
// integrated.
}
if (wantPreloadedWorkspace) {
// TODO(quachtina96): create and download file once wfactory has been
// integrated.
}
if (wantWorkspaceOptions) {
// TODO(quachtina96): create and download file once wfactory has been
// integrated.
}
if (wantBlockDef) {
// User wants to export selected blocks' definitions.
if (!blockDef_filename) {
@@ -143,7 +121,7 @@ BlockExporterController.prototype.export = function() {
alert('Please enter a filename for your block definition(s) download.');
} else {
// Get block definition code in the selected format for the blocks.
var blockDefs = this.tools.getBlockDefs(blockXmlMap,
var blockDefs = this.tools.getBlockDefinitions(blockXmlMap,
definitionFormat);
// Download the file, using .js file ending for JSON or Javascript.
FactoryUtils.createAndDownloadFile(
@@ -267,6 +245,7 @@ BlockExporterController.prototype.onSelectBlockForExport_ = function(event) {
this.setBlockEnabled(blockType, false);
// Show currently selected blocks in helper text.
this.view.listSelectedBlocks(this.getSelectedBlockTypes_());
this.updatePreview();
}
};
@@ -291,6 +270,7 @@ BlockExporterController.prototype.onDeselectBlockForExport_ = function(event) {
}
// Show currently selected blocks in helper text.
this.view.listSelectedBlocks(this.getSelectedBlockTypes_());
this.updatePreview();
}
};
@@ -391,3 +371,58 @@ BlockExporterController.prototype.setUsedBlockTypes =
function(usedBlockTypes) {
this.usedBlockTypes = usedBlockTypes;
};
/**
* Updates preview code (block definitions and generator stubs) in the exporter
* preview to reflect selected blocks.
*/
BlockExporterController.prototype.updatePreview = function() {
// Generate preview code for selected blocks.
var blockDefs = this.getBlockDefinitionsOfSelected();
var genStubs = this.getGeneratorStubsOfSelected();
// Update the text areas containing the code.
FactoryUtils.injectCode(blockDefs, 'blockDefs_textArea');
FactoryUtils.injectCode(genStubs, 'genStubs_textArea');
};
/**
* Returns a map of each selected block's type to its corresponding xml.
*
* @return {!Object} a map of each selected block's type (a string) to its
* corresponding xml element.
*/
BlockExporterController.prototype.getSelectedBlockXmlMap = function() {
var blockTypes = this.getSelectedBlockTypes_();
return this.blockLibStorage.getBlockXmlMap(blockTypes);
};
/**
* Get block definition code in the selected format for selected blocks.
*
* @return {!string} The concatenation of each selected block's language code
* in the format specified in export settings.
*/
BlockExporterController.prototype.getBlockDefinitionsOfSelected = function() {
// Get selected blocks' information.
var blockXmlMap = this.getSelectedBlockXmlMap();
// Get block definition code in the selected format for the blocks.
var definitionFormat = document.getElementById('exportFormat').value;
return this.tools.getBlockDefinitions(blockXmlMap, definitionFormat);
};
/**
* Get generator stubs in the selected language for selected blocks.
*
* @return {!string} The concatenation of each selected block's generator stub
* in the language specified in export settings.
*/
BlockExporterController.prototype.getGeneratorStubsOfSelected = function() {
// Get selected blocks' information.
var blockXmlMap = this.getSelectedBlockXmlMap();
// Get generator stub code in the selected language for the blocks.
var language = document.getElementById('exportLanguage').value;
return this.tools.getGeneratorCode(blockXmlMap, language);
};

View File

@@ -83,7 +83,7 @@ BlockExporterTools.prototype.getRootBlockFromXml_ = function(xml) {
* @return {string} The concatenation of each block's language code in the
* desired format.
*/
BlockExporterTools.prototype.getBlockDefs =
BlockExporterTools.prototype.getBlockDefinitions =
function(blockXmlMap, definitionFormat) {
var blockCode = [];
for (var blockType in blockXmlMap) {
@@ -160,7 +160,7 @@ BlockExporterTools.prototype.getGeneratorCode =
* @param {!Object} blockXmlMap - Map of block type to xml.
*/
BlockExporterTools.prototype.addBlockDefinitions = function(blockXmlMap) {
var blockDefs = this.getBlockDefs(blockXmlMap, 'JavaScript');
var blockDefs = this.getBlockDefinitions(blockXmlMap, 'JavaScript');
eval(blockDefs);
};

View File

@@ -20,6 +20,7 @@
html, body {
height: 100%;
min-height: 375px;
}
body {
@@ -209,24 +210,49 @@ button, .buttonStyle {
}
::-webkit-scrollbar {
-webkit-appearance: none;
width: 7px;
-webkit-appearance: none;
width: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: #ccc;
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5);
border-radius: 4px;
background-color: #ccc;
-webkit-box-shadow: 0 0 1px rgba(255,255,255,.5);
}
.subsettings {
margin: 0px 25px;
}
#exporterHiddenWorkspace {
display: none;
}
#exporterPreview {
#exportPreview {
float: right;
padding: 16px;
height: 90%;
overflow: hidden;
background-color: blue;
width: 45%;
}
.exportPreviewTextArea {
display: block;
float: right;
height: 40%;
width: 100%;
}
#genStubs_textArea, #blockDefs_textArea {
display: block;
height: 80%;
margin-right: 20px;
max-height: 300px;
overflow: scroll;
position: static;
}
#blockDefs_label, #genStubs_label {
display: block;
}
/* Tabs */

View File

@@ -87,7 +87,7 @@ BlockFactory.oldDir = null;
* @param {string} code Lines of code.
* @param {string} id ID of <pre> element to inject into.
*/
BlockFactory.injectCode = function(code, id) {
FactoryUtils.injectCode = function(code, id) {
var pre = document.getElementById(id);
pre.textContent = code;
code = pre.innerHTML;
@@ -135,7 +135,7 @@ BlockFactory.updateLanguage = function() {
var format = document.getElementById('format').value;
var code = FactoryUtils.getBlockDefinition(blockType, rootBlock, format,
BlockFactory.mainWorkspace);
BlockFactory.injectCode(code, 'languagePre');
FactoryUtils.injectCode(code, 'languagePre');
BlockFactory.updatePreview();
};
@@ -146,7 +146,7 @@ BlockFactory.updateLanguage = function() {
BlockFactory.updateGenerator = function(block) {
var language = document.getElementById('language').value;
var generatorStub = FactoryUtils.getGeneratorStub(block, language);
BlockFactory.injectCode(generatorStub, 'generatorPre');
FactoryUtils.injectCode(generatorStub, 'generatorPre');
};
/**

View File

@@ -873,3 +873,16 @@ FactoryUtils.defineAndGetBlockTypes = function(blockDefsString, format) {
return blockTypes;
};
/**
* Inject code into a pre tag, with syntax highlighting.
* Safe from HTML/script injection.
* @param {string} code Lines of code.
* @param {string} id ID of <pre> element to inject into.
*/
FactoryUtils.injectCode = function(code, id) {
var pre = document.getElementById(id);
pre.textContent = code;
code = pre.innerHTML;
code = prettyPrintOne(code, 'js');
pre.innerHTML = code;
};

View File

@@ -79,43 +79,54 @@
<div id="exportSettings">
<br>
<h3> Export Settings </h3>
<br>
<form id="exportSettingsForm">
<div id="selectedBlocksTextContainer">
<p>Currently Selected:</p>
<p id="selectedBlocksText"></p>
</div>
Block Definition(s):
<input type="checkbox" id="blockDefCheck"><br>
Language code:
<select id="exportFormat">
<option value="JSON">JSON</option>
<option value="JavaScript">JavaScript</option>
</select><br>
Block Definition(s) File Name:<br>
<input type="checkbox" id="blockDefCheck">Block Definition(s)<br>
<div id="blockDefSettings" class="subsettings">
Format:
<select id="exportFormat">
<option value="JSON">JSON</option>
<option value="JavaScript">JavaScript</option>
</select>
<br>
File Name:
<br>
<input type="text" id="blockDef_filename">
</div>
<br>
<input type="checkbox" id="genStubCheck">Generator Stub(s)<br>
<div id="genStubSettings" class="subsettings">
Language:
<select id="exportLanguage">
<option value="JavaScript">JavaScript</option>
<option value="Python">Python</option>
<option value="PHP">PHP</option>
<option value="Lua">Lua</option>
<option value="Dart">Dart</option>
</select>
<br>
File Name:
<br>
Generator Stub(s):
<input type="checkbox" id="genStubCheck"><br>
<select id="exportLanguage">
<option value="JavaScript">JavaScript</option>
<option value="Python">Python</option>
<option value="PHP">PHP</option>
<option value="Lua">Lua</option>
<option value="Dart">Dart</option>
</select><br>
Block Generator Stub(s) File Name: <br>
<input type="text" id="generatorStub_filename"><br>
</div>
<br>
</form>
<button id="exporterSubmitButton"> Export </button>
</div>
<div id="exportPreview">
<br>
<h3>Preview Workspace: </h3>
<div id="exportpreview_blocks">
</div>
<h3>Export Preview </h3>
<div id="blockDefs" class="exportPreviewTextArea">
<p id="blockDefs_label">Block Definitions:</p>
<pre id="blockDefs_textArea"></pre>
</div>
<div id="genStubs" class="exportPreviewTextArea">
<p id="genStubs_label">Generator Stubs:</p>
<pre id="genStubs_textArea"></pre>
</div>
</div>
</div>