mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
Workspace theme (#3093)
* Move the theme object so it's on the workspace. * Add support for subscribing UI elements to theme component styles and changes.
This commit is contained in:
@@ -120,8 +120,10 @@ goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', '
|
||||
goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']);
|
||||
goog.addDependency("../../core/theme.js", ['Blockly.Theme'], []);
|
||||
goog.addDependency("../../core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']);
|
||||
goog.addDependency("../../core/theme/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Theme']);
|
||||
goog.addDependency("../../core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']);
|
||||
goog.addDependency("../../core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']);
|
||||
goog.addDependency("../../core/theme_manager.js", ['Blockly.ThemeManager'], ['Blockly.Theme']);
|
||||
goog.addDependency("../../core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.navigation', 'Blockly.Touch', 'Blockly.tree.TreeControl', 'Blockly.tree.TreeNode', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']);
|
||||
goog.addDependency("../../core/tooltip.js", ['Blockly.Tooltip'], ['Blockly.utils.string']);
|
||||
goog.addDependency("../../core/touch.js", ['Blockly.Touch'], ['Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.string']);
|
||||
@@ -153,7 +155,7 @@ goog.addDependency("../../core/variables.js", ['Blockly.Variables'], ['Blockly.B
|
||||
goog.addDependency("../../core/variables_dynamic.js", ['Blockly.VariablesDynamic'], ['Blockly.Variables', 'Blockly.Blocks', 'Blockly.Msg', 'Blockly.utils.xml', 'Blockly.VariableModel', 'Blockly.Xml']);
|
||||
goog.addDependency("../../core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object']);
|
||||
goog.addDependency("../../core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'Blockly.utils.style']);
|
||||
goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.MarkerCursor', 'Blockly.Events', 'Blockly.Themes.Classic', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']);
|
||||
goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.MarkerCursor', 'Blockly.Events', 'Blockly.ThemeManager', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']);
|
||||
goog.addDependency("../../core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent']);
|
||||
goog.addDependency("../../core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.xml']);
|
||||
goog.addDependency("../../core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.WorkspaceCommentSvg']);
|
||||
@@ -247,7 +249,9 @@ goog.require('Blockly.RenderedConnection');
|
||||
goog.require('Blockly.Scrollbar');
|
||||
goog.require('Blockly.ScrollbarPair');
|
||||
goog.require('Blockly.Theme');
|
||||
goog.require('Blockly.ThemeManager');
|
||||
goog.require('Blockly.Themes.Classic');
|
||||
goog.require('Blockly.Themes.Dark');
|
||||
goog.require('Blockly.Themes.HighContrast');
|
||||
goog.require('Blockly.Themes.Modern');
|
||||
goog.require('Blockly.Toolbox');
|
||||
|
||||
@@ -1006,11 +1006,7 @@ Blockly.Block.prototype.setColour = function(colour) {
|
||||
* @throws {Error} if the block style does not exist.
|
||||
*/
|
||||
Blockly.Block.prototype.setStyle = function(blockStyleName) {
|
||||
var theme = Blockly.getTheme();
|
||||
if (!theme) {
|
||||
throw Error('Trying to set block style to ' + blockStyleName +
|
||||
' before theme was defined via Blockly.setTheme().');
|
||||
}
|
||||
var theme = this.workspace.getTheme();
|
||||
var blockStyle = theme.getBlockStyle(blockStyleName);
|
||||
this.styleName_ = blockStyleName;
|
||||
|
||||
|
||||
@@ -117,13 +117,6 @@ Blockly.clipboardTypeCounts_ = null;
|
||||
*/
|
||||
Blockly.cache3dSupported_ = null;
|
||||
|
||||
/**
|
||||
* Holds all Blockly style attributes.
|
||||
* @type {Blockly.Theme}
|
||||
* @private
|
||||
*/
|
||||
Blockly.theme_ = null;
|
||||
|
||||
/**
|
||||
* Returns the dimensions of the specified SVG image.
|
||||
* @param {!Element} svg SVG image.
|
||||
@@ -684,72 +677,3 @@ Blockly.checkBlockColourConstant_ = function(
|
||||
console.warn(warning);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the theme for Blockly and refreshes all blocks in the toolbox and
|
||||
* workspace.
|
||||
* @param {!Blockly.Theme} theme Theme for Blockly.
|
||||
*/
|
||||
Blockly.setTheme = function(theme) {
|
||||
Blockly.theme_ = theme;
|
||||
var ws = Blockly.getMainWorkspace();
|
||||
|
||||
if (ws) {
|
||||
Blockly.refreshTheme_(ws);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh the theme for all items on the workspace.
|
||||
* @param {!Blockly.Workspace} ws Blockly workspace to refresh theme on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.refreshTheme_ = function(ws) {
|
||||
// Update all blocks in workspace that have a style name.
|
||||
Blockly.updateBlockStyles_(ws.getAllBlocks().filter(
|
||||
function(block) {
|
||||
return block.getStyleName() !== undefined;
|
||||
}
|
||||
));
|
||||
|
||||
// Update blocks in the flyout.
|
||||
if (!ws.toolbox_ && ws.flyout_ && ws.flyout_.workspace_) {
|
||||
Blockly.updateBlockStyles_(ws.flyout_.workspace_.getAllBlocks());
|
||||
} else {
|
||||
ws.refreshToolboxSelection();
|
||||
}
|
||||
|
||||
// Update colours on the categories.
|
||||
if (ws.toolbox_) {
|
||||
ws.toolbox_.updateColourFromTheme();
|
||||
}
|
||||
|
||||
var event = new Blockly.Events.Ui(null, 'theme');
|
||||
event.workspaceId = ws.id;
|
||||
Blockly.Events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates all the blocks with new style.
|
||||
* @param {!Array.<!Blockly.Block>} blocks List of blocks to update the style
|
||||
* on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.updateBlockStyles_ = function(blocks) {
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
var blockStyleName = block.getStyleName();
|
||||
block.setStyle(blockStyleName);
|
||||
if (block.mutator) {
|
||||
block.mutator.updateBlockStyle(blockStyleName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the theme.
|
||||
* @return {Blockly.Theme} Theme for Blockly.
|
||||
*/
|
||||
Blockly.getTheme = function() {
|
||||
return Blockly.theme_;
|
||||
};
|
||||
|
||||
@@ -230,6 +230,8 @@ Blockly.Flyout.prototype.createDom = function(tagName) {
|
||||
this.svgBackground_ = Blockly.utils.dom.createSvgElement('path',
|
||||
{'class': 'blocklyFlyoutBackground'}, this.svgGroup_);
|
||||
this.svgGroup_.appendChild(this.workspace_.createDom());
|
||||
this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyout', 'fill');
|
||||
this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyoutOpacity', 'fill-opacity');
|
||||
return this.svgGroup_;
|
||||
};
|
||||
|
||||
@@ -286,6 +288,7 @@ Blockly.Flyout.prototype.dispose = function() {
|
||||
this.scrollbar_ = null;
|
||||
}
|
||||
if (this.workspace_) {
|
||||
this.workspace_.getThemeManager().unsubscribe(this.svgBackground_);
|
||||
this.workspace_.targetWorkspace = null;
|
||||
this.workspace_.dispose();
|
||||
this.workspace_ = null;
|
||||
|
||||
@@ -156,6 +156,10 @@ Blockly.FlyoutButton.prototype.createDom = function() {
|
||||
},
|
||||
this.svgGroup_);
|
||||
svgText.textContent = Blockly.utils.replaceMessageReferences(this.text_);
|
||||
if (this.isLabel_) {
|
||||
this.svgText_ = svgText;
|
||||
this.workspace_.getThemeManager().subscribe(this.svgText_, 'flyoutText', 'fill');
|
||||
}
|
||||
|
||||
this.width = Blockly.utils.dom.getTextWidth(svgText);
|
||||
this.height = 20; // Can't compute it :(
|
||||
@@ -235,6 +239,9 @@ Blockly.FlyoutButton.prototype.dispose = function() {
|
||||
Blockly.utils.dom.removeNode(this.svgGroup_);
|
||||
this.svgGroup_ = null;
|
||||
}
|
||||
if (this.svgText_) {
|
||||
this.workspace_.getThemeManager().unsubscribe(this.svgText_);
|
||||
}
|
||||
this.workspace_ = null;
|
||||
this.targetWorkspace_ = null;
|
||||
};
|
||||
|
||||
@@ -72,7 +72,6 @@ Blockly.inject = function(container, opt_options) {
|
||||
|
||||
var workspace = Blockly.createMainWorkspace_(svg, options, blockDragSurface,
|
||||
workspaceDragSurface);
|
||||
Blockly.setTheme(options.theme);
|
||||
Blockly.user.keyMap.setKeyMap(options.keyMap);
|
||||
|
||||
Blockly.init_(workspace);
|
||||
@@ -231,6 +230,8 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface,
|
||||
if (options.zoomOptions && options.zoomOptions.controls) {
|
||||
mainWorkspace.addZoomControls();
|
||||
}
|
||||
// Register the workspace svg as a UI component.
|
||||
mainWorkspace.getThemeManager().subscribe(svg, 'workspace', 'background-color');
|
||||
|
||||
// A null translation will also apply the correct initial scale.
|
||||
mainWorkspace.translate(0, 0);
|
||||
|
||||
@@ -157,7 +157,8 @@ Blockly.Mutator.prototype.createEditor_ = function() {
|
||||
Blockly.TOOLBOX_AT_LEFT,
|
||||
horizontalLayout: false,
|
||||
getMetrics: this.getFlyoutMetrics_.bind(this),
|
||||
setMetrics: null
|
||||
setMetrics: null,
|
||||
renderer: this.block_.workspace.options.renderer
|
||||
};
|
||||
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
|
||||
this.workspace_.isMutator = true;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
goog.provide('Blockly.Options');
|
||||
|
||||
goog.require('Blockly.Themes.Classic');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.Xml');
|
||||
|
||||
@@ -118,7 +117,7 @@ Blockly.Options = function(options) {
|
||||
} else {
|
||||
var oneBasedIndex = !!options['oneBasedIndex'];
|
||||
}
|
||||
var theme = options['theme'] || Blockly.Themes.Classic;
|
||||
var theme = options['theme'];
|
||||
var keyMap = options['keyMap'] || Blockly.user.keyMap.createDefaultKeyMap();
|
||||
|
||||
var renderer = options['renderer'] || 'geras';
|
||||
|
||||
@@ -351,7 +351,10 @@ Blockly.Scrollbar.prototype.dispose = function() {
|
||||
this.outerSvg_ = null;
|
||||
this.svgGroup_ = null;
|
||||
this.svgBackground_ = null;
|
||||
this.svgHandle_ = null;
|
||||
if (this.svgHandle_) {
|
||||
this.workspace_.getThemeManager().unsubscribe(this.svgHandle_);
|
||||
this.svgHandle_ = null;
|
||||
}
|
||||
this.workspace_ = null;
|
||||
};
|
||||
|
||||
@@ -625,6 +628,8 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) {
|
||||
'ry': radius
|
||||
},
|
||||
this.svgGroup_);
|
||||
this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbar', 'fill');
|
||||
this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbarOpacity', 'fill-opacity');
|
||||
Blockly.utils.dom.insertAfter(this.outerSvg_, this.workspace_.getParentSvg());
|
||||
};
|
||||
|
||||
|
||||
@@ -28,16 +28,33 @@ goog.provide('Blockly.Theme');
|
||||
|
||||
/**
|
||||
* Class for a theme.
|
||||
* @param {!Object.<string, Blockly.Theme.BlockStyle>} blockStyles A map from style
|
||||
* names (strings) to objects with style attributes relating to blocks.
|
||||
* @param {!Object.<string, Blockly.Theme.CategoryStyle>} categoryStyles A map from
|
||||
* style names (strings) to objects with style attributes relating to
|
||||
* @param {!Object.<string, Blockly.Theme.BlockStyle>} blockStyles A map from
|
||||
* style names (strings) to objects with style attributes for blocks.
|
||||
* @param {!Object.<string, Blockly.Theme.CategoryStyle>} categoryStyles A map
|
||||
* from style names (strings) to objects with style attributes for
|
||||
* categories.
|
||||
* @param {!Object.<string, *>=} opt_componentStyles A map of Blockly component
|
||||
* names to style value.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Theme = function(blockStyles, categoryStyles) {
|
||||
Blockly.Theme = function(blockStyles, categoryStyles, opt_componentStyles) {
|
||||
/**
|
||||
* The block styles map.
|
||||
* @type {!Object.<string, Blockly.Theme.BlockStyle>}
|
||||
*/
|
||||
this.blockStyles_ = blockStyles;
|
||||
|
||||
/**
|
||||
* The category styles map.
|
||||
* @type {!Object.<string, Blockly.Theme.CategoryStyle>}
|
||||
*/
|
||||
this.categoryStyles_ = categoryStyles;
|
||||
|
||||
/**
|
||||
* The UI components styles map.
|
||||
* @type {!Object.<string, *>}
|
||||
*/
|
||||
this.componentStyles_ = opt_componentStyles || Object.create(null);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -114,3 +131,28 @@ Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName,
|
||||
categoryStyle) {
|
||||
this.categoryStyles_[categoryStyleName] = categoryStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the style for a given Blockly UI component. If the style value is a
|
||||
* string, we attempt to find the value of any named references.
|
||||
* @param {string} componentName The name of the component.
|
||||
* @return {?string} The style value.
|
||||
*/
|
||||
Blockly.Theme.prototype.getComponentStyle = function(componentName) {
|
||||
var style = this.componentStyles_[componentName];
|
||||
if (style && typeof propertyValue == 'string' &&
|
||||
this.getComponentStyle(/** @type {string} */ (style))) {
|
||||
return this.getComponentStyle(/** @type {string} */ (style));
|
||||
}
|
||||
return style ? String(style) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure a specific Blockly UI component with a style value.
|
||||
* @param {string} componentName The name of the component.
|
||||
* @param {*} styleValue The style value.
|
||||
*/
|
||||
Blockly.Theme.prototype.setComponentStyle = function(componentName,
|
||||
styleValue) {
|
||||
this.componentStyles_[componentName] = styleValue;
|
||||
};
|
||||
|
||||
131
core/theme/dark.js
Normal file
131
core/theme/dark.js
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2019 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 Dark theme.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Themes.Dark');
|
||||
|
||||
goog.require('Blockly.Theme');
|
||||
|
||||
|
||||
// Temporary holding object.
|
||||
Blockly.Themes.Dark = {};
|
||||
|
||||
Blockly.Themes.Dark.defaultBlockStyles = {
|
||||
"colour_blocks": {
|
||||
"colourPrimary": "#a5745b",
|
||||
"colourSecondary": "#dbc7bd",
|
||||
"colourTertiary": "#845d49"
|
||||
},
|
||||
"list_blocks": {
|
||||
"colourPrimary": "#745ba5",
|
||||
"colourSecondary": "#c7bddb",
|
||||
"colourTertiary": "#5d4984"
|
||||
},
|
||||
"logic_blocks": {
|
||||
"colourPrimary": "#5b80a5",
|
||||
"colourSecondary": "#bdccdb",
|
||||
"colourTertiary": "#496684"
|
||||
},
|
||||
"loop_blocks": {
|
||||
"colourPrimary": "#5ba55b",
|
||||
"colourSecondary": "#bddbbd",
|
||||
"colourTertiary": "#498449"
|
||||
},
|
||||
"math_blocks": {
|
||||
"colourPrimary": "#5b67a5",
|
||||
"colourSecondary": "#bdc2db",
|
||||
"colourTertiary": "#495284"
|
||||
},
|
||||
"procedure_blocks": {
|
||||
"colourPrimary": "#995ba5",
|
||||
"colourSecondary": "#d6bddb",
|
||||
"colourTertiary": "#7a4984"
|
||||
},
|
||||
"text_blocks": {
|
||||
"colourPrimary": "#5ba58c",
|
||||
"colourSecondary": "#bddbd1",
|
||||
"colourTertiary": "#498470"
|
||||
},
|
||||
"variable_blocks": {
|
||||
"colourPrimary": "#a55b99",
|
||||
"colourSecondary": "#dbbdd6",
|
||||
"colourTertiary": "#84497a"
|
||||
},
|
||||
"variable_dynamic_blocks": {
|
||||
"colourPrimary": "#a55b99",
|
||||
"colourSecondary": "#dbbdd6",
|
||||
"colourTertiary": "#84497a"
|
||||
},
|
||||
"hat_blocks": {
|
||||
"colourPrimary": "#a55b99",
|
||||
"colourSecondary": "#dbbdd6",
|
||||
"colourTertiary": "#84497a",
|
||||
"hat": "cap"
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Themes.Dark.categoryStyles = {
|
||||
"colour_category": {
|
||||
"colour": "#a5745b"
|
||||
},
|
||||
"list_category": {
|
||||
"colour": "#745ba5"
|
||||
},
|
||||
"logic_category": {
|
||||
"colour": "#5b80a5"
|
||||
},
|
||||
"loop_category": {
|
||||
"colour": "#5ba55b"
|
||||
},
|
||||
"math_category": {
|
||||
"colour": "#5b67a5"
|
||||
},
|
||||
"procedure_category": {
|
||||
"colour": "#995ba5"
|
||||
},
|
||||
"text_category": {
|
||||
"colour": "#5ba58c"
|
||||
},
|
||||
"variable_category": {
|
||||
"colour": "#a55b99"
|
||||
},
|
||||
"variable_dynamic_category": {
|
||||
"colour": "#a55b99"
|
||||
}
|
||||
};
|
||||
|
||||
// This style is still being fleshed out and may change.
|
||||
Blockly.Themes.Dark =
|
||||
new Blockly.Theme(Blockly.Themes.Dark.defaultBlockStyles,
|
||||
Blockly.Themes.Dark.categoryStyles);
|
||||
|
||||
Blockly.Themes.Dark.setComponentStyle('workspace', '#1e1e1e');
|
||||
Blockly.Themes.Dark.setComponentStyle('toolbox', '#333');
|
||||
Blockly.Themes.Dark.setComponentStyle('toolboxText', '#fff');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyout', '#252526');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyoutText', '#ccc');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyoutOpacity', 1);
|
||||
Blockly.Themes.Dark.setComponentStyle('scrollbar', '#797979');
|
||||
Blockly.Themes.Dark.setComponentStyle('scrollbarOpacity', 0.4);
|
||||
196
core/theme_manager.js
Normal file
196
core/theme_manager.js
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2019 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 Object in charge of storing and updating a workspace theme
|
||||
* and UI components.
|
||||
* @author aschmiedt@google.com (Abby Schmiedt)
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.ThemeManager');
|
||||
|
||||
goog.require('Blockly.Theme');
|
||||
|
||||
|
||||
/**
|
||||
* Class for storing and updating a workspace's theme and UI components.
|
||||
* @param {!Blockly.Theme} theme The workspace theme.
|
||||
* @constructor
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager = function(theme) {
|
||||
|
||||
/**
|
||||
* The Blockly theme to use.
|
||||
* @type {!Blockly.Theme}
|
||||
* @private
|
||||
*/
|
||||
this.theme_ = theme;
|
||||
|
||||
/**
|
||||
* A list of workspaces that are subscribed to this theme.
|
||||
* @type {!Array.<Blockly.Workspace>}
|
||||
* @private
|
||||
*/
|
||||
this.subscribedWorkspaces_ = [];
|
||||
|
||||
/**
|
||||
* A map of subscribed UI components, keyed by component name.
|
||||
* @type {!Object.<string, !Array.<!Blockly.ThemeManager.Component>>}
|
||||
* @private
|
||||
*/
|
||||
this.componentDB_ = Object.create(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* A Blockly UI component type.
|
||||
* @typedef {{
|
||||
* element:!Element,
|
||||
* propertyName:string
|
||||
* }}
|
||||
*/
|
||||
Blockly.ThemeManager.Component;
|
||||
|
||||
/**
|
||||
* Get the workspace theme.
|
||||
* @return {!Blockly.Theme} The workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.getTheme = function() {
|
||||
return this.theme_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the workspace theme, and refresh the workspace and all components.
|
||||
* @param {!Blockly.Theme} theme The workspace theme.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.setTheme = function(theme) {
|
||||
if (this.theme_ === theme) {
|
||||
// No change.
|
||||
return;
|
||||
}
|
||||
|
||||
this.theme_ = theme;
|
||||
|
||||
// Refresh all subscribed workspaces.
|
||||
for (var i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) {
|
||||
workspace.refreshTheme();
|
||||
}
|
||||
|
||||
// Refresh all registered Blockly UI components.
|
||||
for (var i = 0, keys = Object.keys(this.componentDB_),
|
||||
key; key = keys[i]; i++) {
|
||||
for (var j = 0, component; (component = this.componentDB_[key][j]); j++) {
|
||||
var element = component.element;
|
||||
var propertyName = component.propertyName;
|
||||
var style = this.theme_ && this.theme_.getComponentStyle(key);
|
||||
element.style[propertyName] = style || '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe a workspace to changes to the selected theme. If a new theme is
|
||||
* set, the workspace is called to refresh its blocks.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to subscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.subscribeWorkspace = function(workspace) {
|
||||
this.subscribedWorkspaces_.push(workspace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unsubscribe a workspace to changes to the selected theme.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to unsubscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.unsubscribeWorkspace = function(workspace) {
|
||||
var index = this.subscribedWorkspaces_.indexOf(workspace);
|
||||
if (index < 0) {
|
||||
throw Error('Cannot unsubscribe a workspace that hasn\'t been subscribed.');
|
||||
}
|
||||
this.subscribedWorkspaces_.splice(index, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe an element to changes to the selected theme. If a new theme is
|
||||
* selected, the element's style is refreshed with the new theme's style.
|
||||
* @param {!Element} element The element to subscribe.
|
||||
* @param {string} componentName The name used to identify the component. This
|
||||
* must be the same name used to configure the style in the Theme object.
|
||||
* @param {string} propertyName The inline style property name to update.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.subscribe = function(element, componentName,
|
||||
propertyName) {
|
||||
if (!this.componentDB_[componentName]) {
|
||||
this.componentDB_[componentName] = [];
|
||||
}
|
||||
|
||||
// Add the element to our component map.
|
||||
this.componentDB_[componentName].push({
|
||||
element: element,
|
||||
propertyName: propertyName
|
||||
});
|
||||
|
||||
// Initialize the element with its corresponding theme style.
|
||||
var style = this.theme_ && this.theme_.getComponentStyle(componentName);
|
||||
element.style[propertyName] = style || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Unsubscribe an element to changes to the selected theme.
|
||||
* @param {Element} element The element to unsubscribe.
|
||||
* @package
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.unsubscribe = function(element) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
// Go through all component, and remove any references to this element.
|
||||
var componentNames = Object.keys(this.componentDB_);
|
||||
for (var c = 0, componentName; (componentName = componentNames[c]); c++) {
|
||||
var elements = this.componentDB_[componentName];
|
||||
for (var i = elements.length - 1; i >= 0; i--) {
|
||||
if (elements[i].element === element) {
|
||||
elements.splice(i, 1);
|
||||
}
|
||||
}
|
||||
// Clean up the component map entry if the list is empty.
|
||||
if (!this.componentDB_[componentName].length) {
|
||||
delete this.componentDB_[componentName];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this theme manager.
|
||||
* @package
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.ThemeManager.prototype.dispose = function() {
|
||||
this.owner_ = null;
|
||||
this.theme_ = null;
|
||||
this.subscribedWorkspaces_ = null;
|
||||
this.componentDB_ = null;
|
||||
};
|
||||
@@ -156,6 +156,9 @@ Blockly.Toolbox.prototype.init = function() {
|
||||
this.HtmlDiv.className = 'blocklyToolboxDiv blocklyNonSelectable';
|
||||
this.HtmlDiv.setAttribute('dir', workspace.RTL ? 'RTL' : 'LTR');
|
||||
svg.parentNode.insertBefore(this.HtmlDiv, svg);
|
||||
var themeManager = workspace.getThemeManager();
|
||||
themeManager.subscribe(this.HtmlDiv, 'toolbox', 'background-color');
|
||||
themeManager.subscribe(this.HtmlDiv, 'toolboxText', 'color');
|
||||
|
||||
// Clicking on toolbox closes popups.
|
||||
Blockly.bindEventWithChecks_(this.HtmlDiv, 'mousedown', this,
|
||||
@@ -350,6 +353,7 @@ Blockly.Toolbox.prototype.onBlocklyAction = function(action) {
|
||||
Blockly.Toolbox.prototype.dispose = function() {
|
||||
this.flyout_.dispose();
|
||||
this.tree_.dispose();
|
||||
this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv);
|
||||
Blockly.utils.dom.removeNode(this.HtmlDiv);
|
||||
this.workspace_ = null;
|
||||
this.lastCategory_ = null;
|
||||
@@ -533,8 +537,9 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut,
|
||||
Blockly.Toolbox.prototype.setColourFromStyle_ = function(
|
||||
styleName, childOut, categoryName) {
|
||||
childOut.styleName = styleName;
|
||||
if (styleName && Blockly.getTheme()) {
|
||||
var style = Blockly.getTheme().getCategoryStyle(styleName);
|
||||
var theme = this.workspace_.getTheme();
|
||||
if (styleName && theme) {
|
||||
var style = theme.getCategoryStyle(styleName);
|
||||
if (style && style.colour) {
|
||||
this.setColour_(style.colour, childOut, categoryName);
|
||||
} else {
|
||||
@@ -566,6 +571,7 @@ Blockly.Toolbox.prototype.updateColourFromTheme_ = function(opt_tree) {
|
||||
|
||||
/**
|
||||
* Updates the category colours and background colour of selected categories.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Toolbox.prototype.updateColourFromTheme = function() {
|
||||
var tree = this.tree_;
|
||||
|
||||
@@ -29,6 +29,7 @@ goog.provide('Blockly.Workspace');
|
||||
goog.require('Blockly.Cursor');
|
||||
goog.require('Blockly.MarkerCursor');
|
||||
goog.require('Blockly.Events');
|
||||
goog.require('Blockly.ThemeManager');
|
||||
goog.require('Blockly.Themes.Classic');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.math');
|
||||
@@ -131,11 +132,16 @@ Blockly.Workspace = function(opt_options) {
|
||||
*/
|
||||
this.marker_ = new Blockly.MarkerCursor();
|
||||
|
||||
// Set the default theme. This is for headless workspaces. This will get
|
||||
// overwritten by the theme passed into the inject call for rendered workspaces.
|
||||
if (!Blockly.getTheme()) {
|
||||
Blockly.setTheme(Blockly.Themes.Classic);
|
||||
}
|
||||
/**
|
||||
* Object in charge of storing and updating the workspace theme.
|
||||
* @type {!Blockly.ThemeManager}
|
||||
* @protected
|
||||
*/
|
||||
this.themeManager_ = this.options.parentWorkspace ?
|
||||
this.options.parentWorkspace.getThemeManager() :
|
||||
new Blockly.ThemeManager(this.options.theme || Blockly.Themes.Classic);
|
||||
|
||||
this.themeManager_.subscribeWorkspace(this);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -198,16 +204,78 @@ Blockly.Workspace.prototype.getMarker = function() {
|
||||
return this.marker_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the workspace theme object.
|
||||
* @return {!Blockly.Theme} The workspace theme object.
|
||||
*/
|
||||
Blockly.Workspace.prototype.getTheme = function() {
|
||||
return this.themeManager_.getTheme();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the workspace theme object.
|
||||
* If no theme is passed, default to the `Blockly.Themes.Classic` theme.
|
||||
* @param {Blockly.Theme} theme The workspace theme object.
|
||||
*/
|
||||
Blockly.Workspace.prototype.setTheme = function(theme) {
|
||||
if (!theme) {
|
||||
theme = /** @type {!Blockly.Theme} */ (Blockly.Themes.Classic);
|
||||
}
|
||||
this.themeManager_.setTheme(theme);
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh all blocks on the workspace after a theme update.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Workspace.prototype.refreshTheme = function() {
|
||||
// Update all blocks in workspace that have a style name.
|
||||
this.updateBlockStyles_(this.getAllBlocks().filter(
|
||||
function(block) {
|
||||
return block.getStyleName() !== undefined;
|
||||
}
|
||||
));
|
||||
|
||||
var event = new Blockly.Events.Ui(null, 'theme', null, null);
|
||||
event.workspaceId = this.id;
|
||||
Blockly.Events.fire(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates all the blocks with new style.
|
||||
* @param {!Array.<!Blockly.Block>} blocks List of blocks to update the style
|
||||
* on.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Workspace.prototype.updateBlockStyles_ = function(blocks) {
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
var blockStyleName = block.getStyleName();
|
||||
block.setStyle(blockStyleName);
|
||||
if (block.mutator) {
|
||||
block.mutator.updateBlockStyle(blockStyleName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this workspace.
|
||||
* Unlink from all DOM elements to prevent memory leaks.
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
Blockly.Workspace.prototype.dispose = function() {
|
||||
this.listeners_.length = 0;
|
||||
this.clear();
|
||||
// Remove from workspace database.
|
||||
delete Blockly.Workspace.WorkspaceDB_[this.id];
|
||||
|
||||
if (this.themeManager_) {
|
||||
this.themeManager_.unsubscribeWorkspace(this);
|
||||
this.themeManager_.unsubscribe(this.svgBackground_);
|
||||
if (!this.options.parentWorkspace) {
|
||||
this.themeManager_.dispose();
|
||||
this.themeManager_ = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -810,3 +878,12 @@ Blockly.Workspace.getAll = function() {
|
||||
}
|
||||
return workspaces;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the theme manager for this workspace.
|
||||
* @return {!Blockly.ThemeManager} The theme manager for this workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Workspace.prototype.getThemeManager = function() {
|
||||
return this.themeManager_;
|
||||
};
|
||||
|
||||
@@ -97,7 +97,7 @@ Blockly.WorkspaceSvg = function(options,
|
||||
|
||||
/**
|
||||
* Object in charge of loading, storing, and playing audio for a workspace.
|
||||
* @type {Blockly.WorkspaceAudio}
|
||||
* @type {!Blockly.WorkspaceAudio}
|
||||
* @private
|
||||
*/
|
||||
this.audioManager_ = new Blockly.WorkspaceAudio(options.parentWorkspace);
|
||||
@@ -636,6 +636,8 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
|
||||
if (opt_backgroundClass == 'blocklyMainBackground' && this.grid_) {
|
||||
this.svgBackground_.style.fill =
|
||||
'url(#' + this.grid_.getPatternId() + ')';
|
||||
} else {
|
||||
this.themeManager_.subscribe(this.svgBackground_, 'workspace', 'fill');
|
||||
}
|
||||
}
|
||||
/** @type {SVGElement} */
|
||||
@@ -686,7 +688,6 @@ Blockly.WorkspaceSvg.prototype.dispose = function() {
|
||||
if (this.currentGesture_) {
|
||||
this.currentGesture_.cancel();
|
||||
}
|
||||
Blockly.WorkspaceSvg.superClass_.dispose.call(this);
|
||||
if (this.svgGroup_) {
|
||||
Blockly.utils.dom.removeNode(this.svgGroup_);
|
||||
this.svgGroup_ = null;
|
||||
@@ -732,6 +733,11 @@ Blockly.WorkspaceSvg.prototype.dispose = function() {
|
||||
this.grid_ = null;
|
||||
}
|
||||
|
||||
if (this.themeManager_) {
|
||||
this.themeManager_.unsubscribe(this.svgBackground_);
|
||||
}
|
||||
Blockly.WorkspaceSvg.superClass_.dispose.call(this);
|
||||
|
||||
this.connectionDBList = null;
|
||||
|
||||
this.toolboxCategoryCallbacks_ = null;
|
||||
@@ -2508,7 +2514,7 @@ Blockly.WorkspaceSvg.prototype.cancelCurrentGesture = function() {
|
||||
|
||||
/**
|
||||
* Get the audio manager for this workspace.
|
||||
* @return {Blockly.WorkspaceAudio} The audio manager for this workspace.
|
||||
* @return {!Blockly.WorkspaceAudio} The audio manager for this workspace.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.getAudioManager = function() {
|
||||
return this.audioManager_;
|
||||
@@ -2522,3 +2528,18 @@ Blockly.WorkspaceSvg.prototype.getAudioManager = function() {
|
||||
Blockly.WorkspaceSvg.prototype.getGrid = function() {
|
||||
return this.grid_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh all blocks on the workspace, toolbox and flyout after a theme update.
|
||||
* @package
|
||||
* @override
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.refreshTheme = function() {
|
||||
Blockly.WorkspaceSvg.superClass_.refreshTheme.call(this);
|
||||
|
||||
// Update current toolbox selection.
|
||||
this.refreshToolboxSelection();
|
||||
if (this.toolbox_) {
|
||||
this.toolbox_.updateColourFromTheme();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
function setRandomStyle() {
|
||||
var blocks = workspace.getAllBlocks();
|
||||
var styles = Object.keys(Blockly.getTheme().getAllBlockStyles());
|
||||
var styles = Object.keys(workspace.getTheme().getAllBlockStyles());
|
||||
styles.splice(styles.indexOf(blocks[0].getStyleName()), 1);
|
||||
var style = styles[Math.floor(Math.random() * styles.length)];
|
||||
for(var i = 0, block; block = blocks[i]; i++) {
|
||||
|
||||
@@ -267,7 +267,7 @@ function test_set_style() {
|
||||
};
|
||||
}
|
||||
};
|
||||
mockControl_ = setUpMockMethod(Blockly, 'getTheme', null, [styleStub]);
|
||||
mockControl_ = setUpMockMethod(workspace, 'getTheme', null, [styleStub]);
|
||||
var blockA = workspace.newBlock('row_block');
|
||||
blockA.setStyle('styleOne');
|
||||
|
||||
@@ -285,7 +285,7 @@ function test_set_style_throw_exception() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
mockControl_ = setUpMockMethod(Blockly, 'getTheme', null, [styleStub]);
|
||||
mockControl_ = setUpMockMethod(workspace, 'getTheme', null, [styleStub]);
|
||||
var blockA = workspace.newBlock('row_block');
|
||||
try {
|
||||
blockA.setStyle('styleOne');
|
||||
|
||||
@@ -131,10 +131,10 @@ function test_setTheme() {
|
||||
|
||||
var mockControl_ = setUpMockMethod(Blockly, 'getMainWorkspace', null, [workspace]);
|
||||
|
||||
Blockly.setTheme(blockStyles);
|
||||
workspace.setTheme(blockStyles);
|
||||
|
||||
//Checks that the theme was set correctly on Blockly namespace
|
||||
stringifyAndCompare(Blockly.getTheme(), blockStyles);
|
||||
stringifyAndCompare(workspace.getTheme(), blockStyles);
|
||||
|
||||
//Checks that the setTheme function was called on the block
|
||||
assertEquals(blockA.getStyleName(), 'styleTwo');
|
||||
|
||||
@@ -23,12 +23,12 @@ goog.require('Blockly.Msg');
|
||||
|
||||
suite('Procedures', function() {
|
||||
setup(function() {
|
||||
Blockly.setTheme(new Blockly.Theme({
|
||||
this.workspace = new Blockly.Workspace();
|
||||
this.workspace.setTheme(new Blockly.Theme({
|
||||
"procedure_blocks": {
|
||||
"colourPrimary": "290"
|
||||
}
|
||||
}));
|
||||
this.workspace = new Blockly.Workspace();
|
||||
|
||||
this.callForAllTypes = function(func, startName) {
|
||||
var typesArray = [
|
||||
@@ -252,7 +252,9 @@ suite('Procedures', function() {
|
||||
});
|
||||
test('Multiple Workspaces', function() {
|
||||
this.callForAllTypes(function() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var workspace = new Blockly.Workspace({
|
||||
theme: this.workspace.getTheme()
|
||||
});
|
||||
var def2 = new Blockly.Block(workspace, this.defType);
|
||||
def2.setFieldValue('name', 'NAME');
|
||||
var caller2 = new Blockly.Block(workspace, this.callType);
|
||||
@@ -294,7 +296,9 @@ suite('Procedures', function() {
|
||||
});
|
||||
test('Multiple Workspaces', function() {
|
||||
this.callForAllTypes(function() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var workspace = new Blockly.Workspace({
|
||||
theme: this.workspace.getTheme()
|
||||
});
|
||||
var def2 = new Blockly.Block(workspace, this.defType);
|
||||
def2.setFieldValue('name', 'NAME');
|
||||
var caller2 = new Blockly.Block(workspace, this.callType);
|
||||
@@ -321,8 +325,10 @@ suite('Procedures', function() {
|
||||
});
|
||||
suite('Composition', function() {
|
||||
suite('Statements', function() {
|
||||
function setStatementValue(defBlock, value) {
|
||||
var mutatorWorkspace = new Blockly.Workspace();
|
||||
function setStatementValue(mainWorkspace, defBlock, value) {
|
||||
var mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: mainWorkspace
|
||||
});
|
||||
defBlock.decompose(mutatorWorkspace);
|
||||
var containerBlock = mutatorWorkspace.getTopBlocks()[0];
|
||||
var statementField = containerBlock.getField('STATEMENTS');
|
||||
@@ -331,12 +337,12 @@ suite('Procedures', function() {
|
||||
}
|
||||
test('Has Statements', function() {
|
||||
var defBlock = new Blockly.Block(this.workspace, 'procedures_defreturn');
|
||||
setStatementValue(defBlock, true);
|
||||
setStatementValue(this.workspace, defBlock, true);
|
||||
chai.assert.isTrue(defBlock.hasStatements_);
|
||||
});
|
||||
test('Has No Statements', function() {
|
||||
var defBlock = new Blockly.Block(this.workspace, 'procedures_defreturn');
|
||||
setStatementValue(defBlock, false);
|
||||
setStatementValue(this.workspace, defBlock, false);
|
||||
chai.assert.isFalse(defBlock.hasStatements_);
|
||||
});
|
||||
test('Saving Statements', function() {
|
||||
@@ -348,9 +354,9 @@ suite('Procedures', function() {
|
||||
'</block>'
|
||||
);
|
||||
var defBlock = Blockly.Xml.domToBlock(blockXml, this.workspace);
|
||||
setStatementValue(defBlock, false);
|
||||
setStatementValue(this.workspace, defBlock, false);
|
||||
chai.assert.isNull(defBlock.getInput('STACK'));
|
||||
setStatementValue(defBlock, true);
|
||||
setStatementValue(this.workspace, defBlock, true);
|
||||
chai.assert.isNotNull(defBlock.getInput('STACK'));
|
||||
var statementBlocks = defBlock.getChildren();
|
||||
chai.assert.equal(statementBlocks.length, 1);
|
||||
@@ -361,7 +367,9 @@ suite('Procedures', function() {
|
||||
});
|
||||
suite('Untyped Arguments', function() {
|
||||
function createMutator(argArray) {
|
||||
this.mutatorWorkspace = new Blockly.Workspace();
|
||||
this.mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: this.workspace
|
||||
});
|
||||
this.containerBlock = this.defBlock.decompose(this.mutatorWorkspace);
|
||||
this.connection = this.containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < argArray.length; i++) {
|
||||
@@ -496,7 +504,9 @@ suite('Procedures', function() {
|
||||
suite('Statements', function() {
|
||||
test('Has Statement Input', function() {
|
||||
this.callForAllTypes(function() {
|
||||
var mutatorWorkspace = new Blockly.Workspace();
|
||||
var mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: this.workspace
|
||||
});
|
||||
this.defBlock.decompose(mutatorWorkspace);
|
||||
var statementInput = mutatorWorkspace.getTopBlocks()[0]
|
||||
.getInput('STATEMENT_INPUT');
|
||||
@@ -510,7 +520,9 @@ suite('Procedures', function() {
|
||||
test('Has Statements', function() {
|
||||
var defBlock = new Blockly.Block(this.workspace, 'procedures_defreturn');
|
||||
defBlock.hasStatements_ = true;
|
||||
var mutatorWorkspace = new Blockly.Workspace();
|
||||
var mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: this.workspace
|
||||
});
|
||||
defBlock.decompose(mutatorWorkspace);
|
||||
var statementValue = mutatorWorkspace.getTopBlocks()[0]
|
||||
.getField('STATEMENTS').getValueBoolean();
|
||||
@@ -519,7 +531,9 @@ suite('Procedures', function() {
|
||||
test('No Has Statements', function() {
|
||||
var defBlock = new Blockly.Block(this.workspace, 'procedures_defreturn');
|
||||
defBlock.hasStatements_ = false;
|
||||
var mutatorWorkspace = new Blockly.Workspace();
|
||||
var mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: this.workspace
|
||||
});
|
||||
defBlock.decompose(mutatorWorkspace);
|
||||
var statementValue = mutatorWorkspace.getTopBlocks()[0]
|
||||
.getField('STATEMENTS').getValueBoolean();
|
||||
@@ -529,7 +543,9 @@ suite('Procedures', function() {
|
||||
suite('Untyped Arguments', function() {
|
||||
function assertArguments(argumentsArray) {
|
||||
this.defBlock.arguments_ = argumentsArray;
|
||||
var mutatorWorkspace = new Blockly.Workspace();
|
||||
var mutatorWorkspace = new Blockly.Workspace({
|
||||
parentWorkspace: this.workspace
|
||||
});
|
||||
this.defBlock.decompose(mutatorWorkspace);
|
||||
var argBlocks = mutatorWorkspace.getBlocksByType('procedures_mutatorarg');
|
||||
chai.assert.equal(argBlocks.length, argumentsArray.length);
|
||||
|
||||
@@ -137,10 +137,10 @@ suite('Theme', function() {
|
||||
|
||||
var stub = sinon.stub(Blockly, "getMainWorkspace").returns(workspace);
|
||||
|
||||
Blockly.setTheme(blockStyles);
|
||||
workspace.setTheme(blockStyles);
|
||||
|
||||
// Checks that the theme was set correctly on Blockly namespace
|
||||
stringifyAndCompare(Blockly.getTheme(), blockStyles);
|
||||
stringifyAndCompare(workspace.getTheme(), blockStyles);
|
||||
|
||||
// Checks that the setTheme function was called on the block
|
||||
assertEquals(blockA.getStyleName(), 'styleTwo');
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
suite("Trashcan", function() {
|
||||
var themeManager = new Blockly.ThemeManager(Blockly.Themes.Classic);
|
||||
var workspace = {
|
||||
addChangeListener: function(func) {
|
||||
this.listener = func;
|
||||
@@ -26,6 +27,9 @@ suite("Trashcan", function() {
|
||||
triggerListener: function(event) {
|
||||
this.listener(event);
|
||||
},
|
||||
getThemeManager: function() {
|
||||
return themeManager;
|
||||
},
|
||||
options: {
|
||||
maxTrashcanContents: Infinity
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ goog.require('Blockly.Msg');
|
||||
suite('Procedures XML', function() {
|
||||
suite('Deserialization', function() {
|
||||
setup(function() {
|
||||
Blockly.setTheme(new Blockly.Theme({
|
||||
this.workspace = new Blockly.Workspace();
|
||||
this.workspace.setTheme(new Blockly.Theme({
|
||||
"procedure_blocks": {
|
||||
"colourPrimary": "290"
|
||||
}
|
||||
}));
|
||||
this.workspace = new Blockly.Workspace();
|
||||
|
||||
this.callForAllTypes = function(func) {
|
||||
var typesArray = [
|
||||
|
||||
@@ -185,7 +185,7 @@ function addToolboxButtonCallbacks() {
|
||||
};
|
||||
var setRandomStyle = function(button) {
|
||||
var blocks = button.workspace_.getAllBlocks();
|
||||
var styles = Object.keys(Blockly.getTheme().getAllBlockStyles());
|
||||
var styles = Object.keys(workspace.getTheme().getAllBlockStyles());
|
||||
styles.splice(styles.indexOf(blocks[0].getStyleName()), 1);
|
||||
var style = styles[Math.floor(Math.random() * styles.length)];
|
||||
for(var i = 0, block; block = blocks[i]; i++) {
|
||||
@@ -314,11 +314,13 @@ function addRenderDebugOptionsCheckboxes() {
|
||||
function changeTheme() {
|
||||
var theme = document.getElementById('themeChanger');
|
||||
if (theme.value === "modern") {
|
||||
Blockly.setTheme(Blockly.Themes.Modern);
|
||||
Blockly.getMainWorkspace().setTheme(Blockly.Themes.Modern);
|
||||
} else if (theme.value === "dark") {
|
||||
Blockly.getMainWorkspace().setTheme(Blockly.Themes.Dark);
|
||||
} else if (theme.value === "high_contrast") {
|
||||
Blockly.setTheme(Blockly.Themes.HighContrast);
|
||||
Blockly.getMainWorkspace().setTheme(Blockly.Themes.HighContrast);
|
||||
} else {
|
||||
Blockly.setTheme(Blockly.Themes.Classic);
|
||||
Blockly.getMainWorkspace().setTheme(Blockly.Themes.Classic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,6 +566,7 @@ var spaghettiXml = [
|
||||
<select id="themeChanger" name="theme" onchange="changeTheme()">
|
||||
<option value="classic">Classic</option>
|
||||
<option value="modern">Modern</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="high_contrast">High Contrast</option>
|
||||
</select>
|
||||
<p>
|
||||
|
||||
Reference in New Issue
Block a user