mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
alert when creating new block with unsaved changes (#594)
working warnings on tab switches and create new block
This commit is contained in:
@@ -64,6 +64,8 @@ AppController = function() {
|
||||
this.tabMap[AppController.EXPORTER] =
|
||||
goog.dom.getElement('blocklibraryExporter_tab');
|
||||
|
||||
// Last selected tab.
|
||||
this.lastSelectedTab = null;
|
||||
// Selected tab.
|
||||
this.selectedTab = AppController.BLOCK_FACTORY;
|
||||
};
|
||||
@@ -268,6 +270,7 @@ AppController.prototype.addTabHandlers = function(tabMap) {
|
||||
* AppController.WORKSPACE_FACTORY, or AppController.EXPORTER
|
||||
*/
|
||||
AppController.prototype.setSelected_ = function(tabName) {
|
||||
this.lastSelectedTab = this.selectedTab;
|
||||
this.selectedTab = tabName;
|
||||
};
|
||||
|
||||
@@ -297,14 +300,28 @@ AppController.prototype.onTab = function() {
|
||||
var exporterTab = this.tabMap[AppController.EXPORTER];
|
||||
var workspaceFactoryTab = this.tabMap[AppController.WORKSPACE_FACTORY];
|
||||
|
||||
// Turn selected tab on and other tabs off.
|
||||
this.styleTabs_();
|
||||
// Warn user if they have unsaved changes when leaving Block Factory.
|
||||
if (this.lastSelectedTab == AppController.BLOCK_FACTORY &&
|
||||
this.selectedTab != AppController.BLOCK_FACTORY) {
|
||||
if (!BlockFactory.isStarterBlock() && !this.savedBlockChanges()) {
|
||||
if (!confirm('You have unsaved changes in Block Factory.')) {
|
||||
// If the user doesn't want to switch tabs with unsaved changes,
|
||||
// stay on Block Factory Tab.
|
||||
this.setSelected_(AppController.BLOCK_FACTORY);
|
||||
this.lastSelectedTab == AppController.BLOCK_FACTORY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only enable key events in workspace factory if workspace factory tab is
|
||||
// selected.
|
||||
this.workspaceFactoryController.keyEventsEnabled =
|
||||
this.selectedTab == AppController.WORKSPACE_FACTORY;
|
||||
|
||||
// Turn selected tab on and other tabs off.
|
||||
this.styleTabs_();
|
||||
|
||||
if (this.selectedTab == AppController.EXPORTER) {
|
||||
// Hide other tabs.
|
||||
FactoryUtils.hide('workspaceFactoryContent');
|
||||
@@ -462,6 +479,24 @@ AppController.prototype.ifCheckedDisplay = function(checkbox, elementArray) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not a block's changes has been saved to the Block Library.
|
||||
*
|
||||
* @return {boolean} True if all changes made to the block have been saved to
|
||||
* the Block Library.
|
||||
*/
|
||||
AppController.prototype.savedBlockChanges = function() {
|
||||
var blockType = this.blockLibraryController.getCurrentBlockType();
|
||||
var currentXml = Blockly.Xml.workspaceToDom(BlockFactory.mainWorkspace);
|
||||
|
||||
if (this.blockLibraryController.has(blockType)) {
|
||||
// Block is saved in block library.
|
||||
var savedXml = this.blockLibraryController.getBlockXml(blockType);
|
||||
return FactoryUtils.sameBlockXml(savedXml, currentXml);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign button click handlers for the block library.
|
||||
*/
|
||||
@@ -524,9 +559,18 @@ AppController.prototype.assignBlockFactoryClickHandlers = function() {
|
||||
|
||||
document.getElementById('createNewBlockButton')
|
||||
.addEventListener('click', function() {
|
||||
BlockFactory.showStarterBlock();
|
||||
BlockLibraryView.selectDefaultOption('blockLibraryDropdown');
|
||||
});
|
||||
// If there are unsaved changes to the block in open in Block Factory,
|
||||
// warn user that proceeding to create a new block will cause them to lose
|
||||
// their changes if they don't save.
|
||||
if (!self.savedBlockChanges()) {
|
||||
if(!confirm('You have unsaved changes. By proceeding without saving ' +
|
||||
' your block first, you will lose these changes.')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
BlockFactory.showStarterBlock();
|
||||
BlockLibraryView.selectDefaultOption('blockLibraryDropdown');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,7 +59,7 @@ BlockLibraryController = function(blockLibraryName, opt_blockLibraryStorage) {
|
||||
*
|
||||
* @return {string} The current block's type.
|
||||
*/
|
||||
BlockLibraryController.prototype.getCurrentBlockType_ = function() {
|
||||
BlockLibraryController.prototype.getCurrentBlockType = function() {
|
||||
var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace);
|
||||
var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase();
|
||||
// Replace white space with underscores
|
||||
@@ -72,7 +72,7 @@ BlockLibraryController.prototype.getCurrentBlockType_ = function() {
|
||||
* @param {string} blockType - Type of block.
|
||||
*/
|
||||
BlockLibraryController.prototype.removeFromBlockLibrary = function() {
|
||||
var blockType = this.getCurrentBlockType_();
|
||||
var blockType = this.getCurrentBlockType();
|
||||
this.storage.removeBlock(blockType);
|
||||
this.storage.saveToLocalStorage();
|
||||
this.populateBlockLibrary();
|
||||
@@ -131,14 +131,13 @@ BlockLibraryController.prototype.clearBlockLibrary = function() {
|
||||
* Saves current block to local storage and updates dropdown.
|
||||
*/
|
||||
BlockLibraryController.prototype.saveToBlockLibrary = function() {
|
||||
var blockType = this.getCurrentBlockType_();
|
||||
|
||||
var blockType = this.getCurrentBlockType();
|
||||
// If block under that name already exists, confirm that user wants to replace
|
||||
// saved block.
|
||||
if (this.isInBlockLibrary(blockType)) {
|
||||
if (this.has(blockType)) {
|
||||
var replace = confirm('You already have a block called "' + blockType +
|
||||
'" in your library. Replace this block?');
|
||||
if ( !replace) {
|
||||
if (!replace) {
|
||||
// Do not save if user doesn't want to replace the saved block.
|
||||
return;
|
||||
}
|
||||
@@ -171,7 +170,7 @@ BlockLibraryController.prototype.saveToBlockLibrary = function() {
|
||||
* @param {string} blockType - Type of block.
|
||||
* @return {boolean} Boolean indicating whether or not block is in the library.
|
||||
*/
|
||||
BlockLibraryController.prototype.isInBlockLibrary = function(blockType) {
|
||||
BlockLibraryController.prototype.has = function(blockType) {
|
||||
var blockLibrary = this.storage.blocks;
|
||||
return (blockType in blockLibrary && blockLibrary[blockType] != null);
|
||||
};
|
||||
@@ -204,6 +203,16 @@ BlockLibraryController.prototype.getBlockLibrary = function() {
|
||||
return this.storage.getBlockXmlTextMap();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return stored xml of a given block type.
|
||||
*
|
||||
* @param {!string} blockType - The type of block.
|
||||
* @return {!Element} Xml element of a given block type or null.
|
||||
*/
|
||||
BlockLibraryController.prototype.getBlockXml = function(blockType) {
|
||||
return this.storage.getBlockXml(blockType);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the block library storage object from which exporter exports.
|
||||
*
|
||||
|
||||
@@ -60,19 +60,12 @@ BlockFactory.UNNAMED = 'unnamed';
|
||||
*/
|
||||
BlockFactory.oldDir = null;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
/*
|
||||
* The starting xml for the Block Factory main workspace. Contains the
|
||||
* unmovable, undeletable factory_base block.
|
||||
*/
|
||||
FactoryUtils.injectCode = function(code, id) {
|
||||
var pre = document.getElementById(id);
|
||||
pre.textContent = code;
|
||||
code = pre.innerHTML;
|
||||
code = prettyPrintOne(code, 'js');
|
||||
pre.innerHTML = code;
|
||||
};
|
||||
BlockFactory.STARTER_BLOCK_XML_TEXT = '<xml><block type="factory_base" ' +
|
||||
'deletable="false" movable="false"></block></xml>';
|
||||
|
||||
/**
|
||||
* Change the language code format.
|
||||
@@ -243,9 +236,19 @@ BlockFactory.disableEnableLink = function() {
|
||||
* Render starter block (factory_base).
|
||||
*/
|
||||
BlockFactory.showStarterBlock = function() {
|
||||
BlockFactory.mainWorkspace.clear();
|
||||
var xml = '<xml><block type="factory_base" deletable="false" ' +
|
||||
'movable="false"></block></xml>';
|
||||
Blockly.Xml.domToWorkspace(
|
||||
Blockly.Xml.textToDom(xml), BlockFactory.mainWorkspace);
|
||||
BlockFactory.mainWorkspace.clear();
|
||||
var xml = Blockly.Xml.textToDom(BlockFactory.STARTER_BLOCK_XML_TEXT);
|
||||
Blockly.Xml.domToWorkspace(xml, BlockFactory.mainWorkspace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not the current block open is the starter block.
|
||||
*/
|
||||
BlockFactory.isStarterBlock = function() {
|
||||
var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace);
|
||||
// The starter block does not have blocks nested into the factory_base block.
|
||||
return !(rootBlock.getChildren().length > 0 ||
|
||||
rootBlock.getFieldValue('NAME').trim().toLowerCase() != 'block_type' ||
|
||||
rootBlock.getFieldValue('CONNECTIONS') != 'NONE' ||
|
||||
rootBlock.getFieldValue('INLINE') != 'AUTO');
|
||||
};
|
||||
|
||||
@@ -886,3 +886,30 @@ FactoryUtils.injectCode = function(code, id) {
|
||||
code = prettyPrintOne(code, 'js');
|
||||
pre.innerHTML = code;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not two blocks are the same based on their xml. Expects
|
||||
* xml with a single child node that is a factory_base block. The xml found on
|
||||
* Block Factory's main workspace.
|
||||
*
|
||||
* @param {!Element} blockXml1 - An xml element with a single child node that
|
||||
* is a factory_base block.
|
||||
* @param {!Element} blockXml2 - An xml element with a single child node that
|
||||
* is a factory_base block.
|
||||
* @return {boolean} Whether or not two blocks are the same based on their xml.
|
||||
*/
|
||||
FactoryUtils.sameBlockXml = function(blockXml1, blockXml2) {
|
||||
// Each block xml has only one child.
|
||||
var blockXmlText1 = Blockly.Xml.domToText(
|
||||
blockXml1.getElementsByTagName('block')[0]);
|
||||
var blockXmlText2 = Blockly.Xml.domToText(
|
||||
blockXml2.getElementsByTagName('block')[0]);
|
||||
|
||||
// Strip white space.
|
||||
blockXmlText1 = blockXmlText1.replace(/\s+/g, '');
|
||||
blockXmlText2 = blockXmlText2.replace(/\s+/g, '');
|
||||
|
||||
// Return whether or not changes have been saved.
|
||||
return blockXmlText1 == blockXmlText2;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user