mirror of
https://github.com/google/blockly.git
synced 2026-01-09 01:50:11 +01:00
Support extending themes with a base theme property. (#3731)
* Support extending themes with a base theme property.
This commit is contained in:
@@ -282,8 +282,7 @@ Blockly.Options.parseThemeOptions_ = function(options) {
|
||||
if (theme instanceof Blockly.Theme) {
|
||||
return /** @type {!Blockly.Theme} */ (theme);
|
||||
}
|
||||
return new Blockly.Theme('builtin',
|
||||
theme['blockStyles'], theme['categoryStyles'], theme['componentStyles']);
|
||||
return Blockly.Theme.defineTheme('builtin', theme);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,27 +13,27 @@ goog.provide('Blockly.Theme');
|
||||
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.colour');
|
||||
goog.require('Blockly.utils.object');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a theme.
|
||||
* @param {string} name Theme name.
|
||||
* @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
|
||||
* @param {!Object.<string, Blockly.Theme.BlockStyle>=} opt_blockStyles A map
|
||||
* from style names (strings) to objects with style attributes for blocks.
|
||||
* @param {!Object.<string, Blockly.Theme.CategoryStyle>=} opt_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(name, blockStyles, categoryStyles,
|
||||
Blockly.Theme = function(name, opt_blockStyles, opt_categoryStyles,
|
||||
opt_componentStyles) {
|
||||
|
||||
/**
|
||||
* The theme name. This can be used to reference a specific theme in CSS.
|
||||
* @type {string}
|
||||
* @package
|
||||
*/
|
||||
this.name = name;
|
||||
|
||||
@@ -42,36 +42,36 @@ Blockly.Theme = function(name, blockStyles, categoryStyles,
|
||||
* @type {!Object.<string, !Blockly.Theme.BlockStyle>}
|
||||
* @package
|
||||
*/
|
||||
this.blockStyles = blockStyles;
|
||||
this.blockStyles = opt_blockStyles || Object.create(null);
|
||||
|
||||
/**
|
||||
* The category styles map.
|
||||
* @type {!Object.<string, Blockly.Theme.CategoryStyle>}
|
||||
* @package
|
||||
*/
|
||||
this.categoryStyles = categoryStyles;
|
||||
this.categoryStyles = opt_categoryStyles || Object.create(null);
|
||||
|
||||
/**
|
||||
* The UI components styles map.
|
||||
* @type {!Object.<string, *>}
|
||||
* @private
|
||||
* @package
|
||||
*/
|
||||
this.componentStyles_ = opt_componentStyles || Object.create(null);
|
||||
this.componentStyles = opt_componentStyles || Object.create(null);
|
||||
|
||||
/**
|
||||
* The font style.
|
||||
* @type {?Blockly.Theme.FontStyle}
|
||||
* @type {Blockly.Theme.FontStyle}
|
||||
* @package
|
||||
*/
|
||||
this.fontStyle = null;
|
||||
this.fontStyle = /** @type {Blockly.Theme.FontStyle} */ (Object.create(null));
|
||||
|
||||
/**
|
||||
* Whether or not to add a 'hat' on top of all blocks with no previous or
|
||||
* output connections.
|
||||
* @type {?boolean}
|
||||
* @type {boolean}
|
||||
* @package
|
||||
*/
|
||||
this.startHats = null;
|
||||
this.startHats = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -122,6 +122,31 @@ Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName,
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure a theme's font style.
|
||||
* @param {Blockly.Theme.FontStyle} fontStyle The font style.
|
||||
@@ -140,26 +165,28 @@ Blockly.Theme.prototype.setStartHats = function(startHats) {
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Define a new Blockly theme.
|
||||
* @param {string} name The name of the theme.
|
||||
* @param {!Object} themeObj An object containing theme properties.
|
||||
* @return {!Blockly.Theme} A new Blockly theme.
|
||||
*/
|
||||
Blockly.Theme.prototype.setComponentStyle = function(componentName,
|
||||
styleValue) {
|
||||
this.componentStyles_[componentName] = styleValue;
|
||||
Blockly.Theme.defineTheme = function(name, themeObj) {
|
||||
var theme = new Blockly.Theme(name);
|
||||
var base = themeObj['base'];
|
||||
if (base && base instanceof Blockly.Theme) {
|
||||
Blockly.utils.object.deepMerge(theme, base);
|
||||
}
|
||||
|
||||
Blockly.utils.object.deepMerge(theme.blockStyles,
|
||||
themeObj['blockStyles']);
|
||||
Blockly.utils.object.deepMerge(theme.categoryStyles,
|
||||
themeObj['categoryStyles']);
|
||||
Blockly.utils.object.deepMerge(theme.componentStyles,
|
||||
themeObj['componentStyles']);
|
||||
Blockly.utils.object.deepMerge(theme.fontStyle,
|
||||
themeObj['fontStyle']);
|
||||
if (themeObj['startHats'] != null) {
|
||||
theme.startHats = themeObj['startHats'];
|
||||
}
|
||||
return theme;
|
||||
};
|
||||
|
||||
@@ -12,143 +12,18 @@
|
||||
|
||||
goog.provide('Blockly.Themes.Dark');
|
||||
|
||||
goog.require('Blockly.Css');
|
||||
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 = Blockly.Theme.defineTheme('dark', {
|
||||
'base': Blockly.Themes.Classic,
|
||||
'componentStyles': {
|
||||
'workspaceBackgroundColour': '#1e1e1e',
|
||||
'toolboxBackgroundColour': '#333',
|
||||
'toolboxForegroundColour': '#fff',
|
||||
'flyoutBackgroundColour': '#252526',
|
||||
'flyoutForegroundColour': '#ccc',
|
||||
'flyoutOpacity': 1,
|
||||
'scrollbarColour': '#797979',
|
||||
'scrollbarOpacity': 0.4
|
||||
}
|
||||
};
|
||||
|
||||
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('dark', Blockly.Themes.Dark.defaultBlockStyles,
|
||||
Blockly.Themes.Dark.categoryStyles);
|
||||
|
||||
Blockly.Themes.Dark.setComponentStyle('workspaceBackgroundColour', '#1e1e1e');
|
||||
Blockly.Themes.Dark.setComponentStyle('toolboxBackgroundColour', '#333');
|
||||
Blockly.Themes.Dark.setComponentStyle('toolboxForegroundColour', '#fff');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyoutBackgroundColour', '#252526');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyoutForegroundColour', '#ccc');
|
||||
Blockly.Themes.Dark.setComponentStyle('flyoutOpacity', 1);
|
||||
Blockly.Themes.Dark.setComponentStyle('scrollbarColour', '#797979');
|
||||
Blockly.Themes.Dark.setComponentStyle('scrollbarOpacity', 0.4);
|
||||
|
||||
/**
|
||||
* CSS for the dark theme.
|
||||
* This registers CSS that is specific to this theme. It does so by prepending a
|
||||
* ``.dark-theme`` selector before every CSS rule that we wish to override by
|
||||
* this theme.
|
||||
*/
|
||||
(function() {
|
||||
var selector = '.dark-theme';
|
||||
Blockly.Css.register([
|
||||
/* eslint-disable indent */
|
||||
// Toolbox hover
|
||||
selector + ' .blocklyTreeRow:not(.blocklyTreeSelected):hover {',
|
||||
'background-color: #2a2d2e;',
|
||||
'}',
|
||||
// Dropdown and Widget div.
|
||||
selector + '.blocklyWidgetDiv .goog-menu, ',
|
||||
selector + '.blocklyDropDownDiv {',
|
||||
'background-color: #3c3c3c;',
|
||||
'}',
|
||||
selector + '.blocklyDropDownDiv {',
|
||||
'border-color: #565656;',
|
||||
'}',
|
||||
selector + '.blocklyWidgetDiv .goog-menuitem-content, ',
|
||||
selector + '.blocklyDropDownDiv .goog-menuitem-content {',
|
||||
'color: #f0f0f0;',
|
||||
'}',
|
||||
selector + '.blocklyWidgetDiv .goog-menuitem-disabled',
|
||||
' .goog-menuitem-content,',
|
||||
selector + '.blocklyDropDownDiv .goog-menuitem-disabled',
|
||||
' .goog-menuitem-content {',
|
||||
'color: #8a8a8a !important;',
|
||||
'}',
|
||||
/* eslint-enable indent */
|
||||
]);
|
||||
})();
|
||||
});
|
||||
|
||||
@@ -780,7 +780,7 @@ Blockly.Css.register([
|
||||
'}',
|
||||
|
||||
'.blocklyTreeRow:not(.blocklyTreeSelected):hover {',
|
||||
'background-color: #e4e4e4;',
|
||||
'background-color: rgba(255, 255, 255, 0.2);',
|
||||
'}',
|
||||
|
||||
'.blocklyTreeSeparator {',
|
||||
|
||||
@@ -37,6 +37,24 @@ Blockly.utils.object.mixin = function(target, source) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Complete a deep merge of all members of a source object with a target object.
|
||||
* @param {!Object} target Target.
|
||||
* @param {!Object} source Source.
|
||||
* @return {!Object} The resulting object.
|
||||
*/
|
||||
Blockly.utils.object.deepMerge = function(target, source) {
|
||||
for (var x in source) {
|
||||
if (typeof source[x] === 'object') {
|
||||
target[x] = Blockly.utils.object.deepMerge(
|
||||
target[x] || Object.create(null), source[x]);
|
||||
} else {
|
||||
target[x] = source[x];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of a given object's own enumerable property values.
|
||||
* @param {!Object} obj Object containing values.
|
||||
|
||||
@@ -11,15 +11,17 @@ goog.provide('Blockly.TestThemes');
|
||||
/**
|
||||
* A theme with classic colours but enables start hats.
|
||||
*/
|
||||
Blockly.Themes.TestHats = new Blockly.Theme('testhats',
|
||||
Blockly.Themes.Classic.blockStyles, Blockly.Themes.Classic.categoryStyles);
|
||||
Blockly.Themes.TestHats = Blockly.Theme.defineTheme('testhats', {
|
||||
'base': Blockly.Themes.Classic
|
||||
});
|
||||
Blockly.Themes.TestHats.setStartHats(true);
|
||||
|
||||
/**
|
||||
* A theme with classic colours but a different font.
|
||||
*/
|
||||
Blockly.Themes.TestFont = new Blockly.Theme('testfont',
|
||||
Blockly.Themes.Classic.blockStyles, Blockly.Themes.Classic.categoryStyles);
|
||||
Blockly.Themes.TestFont = Blockly.Theme.defineTheme('testfont', {
|
||||
'base': Blockly.Themes.Classic
|
||||
});
|
||||
Blockly.Themes.TestFont.setFontStyle({
|
||||
'family': '"Times New Roman", Times, serif',
|
||||
'weight': null, // Use default font-weight
|
||||
|
||||
Reference in New Issue
Block a user