mirror of
https://github.com/google/blockly.git
synced 2026-01-04 23:50:12 +01:00
* chore: move arrayRemove to a new utils.array namespace * chore: move getBlockTypeCounts out of utils.js * chore: remove last functions from utils.js * chore: reorder imports * chore: add re-export for runAfterPageLoad
208 lines
5.8 KiB
JavaScript
208 lines
5.8 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Object in charge of storing and updating a workspace theme
|
|
* and UI components.
|
|
*/
|
|
'use strict';
|
|
|
|
/**
|
|
* Object in charge of storing and updating a workspace theme
|
|
* and UI components.
|
|
* @class
|
|
*/
|
|
goog.module('Blockly.ThemeManager');
|
|
|
|
const arrayUtils = goog.require('Blockly.utils.array');
|
|
const dom = goog.require('Blockly.utils.dom');
|
|
/* eslint-disable-next-line no-unused-vars */
|
|
const {Theme} = goog.requireType('Blockly.Theme');
|
|
/* eslint-disable-next-line no-unused-vars */
|
|
const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
|
|
/* eslint-disable-next-line no-unused-vars */
|
|
const {Workspace} = goog.requireType('Blockly.Workspace');
|
|
|
|
|
|
/**
|
|
* Class for storing and updating a workspace's theme and UI components.
|
|
* @param {!WorkspaceSvg} workspace The main workspace.
|
|
* @param {!Theme} theme The workspace theme.
|
|
* @constructor
|
|
* @package
|
|
* @alias Blockly.ThemeManager
|
|
*/
|
|
const ThemeManager = function(workspace, theme) {
|
|
/**
|
|
* The main workspace.
|
|
* @type {!WorkspaceSvg}
|
|
* @private
|
|
*/
|
|
this.workspace_ = workspace;
|
|
|
|
/**
|
|
* The Blockly theme to use.
|
|
* @type {!Theme}
|
|
* @private
|
|
*/
|
|
this.theme_ = theme;
|
|
|
|
/**
|
|
* A list of workspaces that are subscribed to this theme.
|
|
* @type {!Array<Workspace>}
|
|
* @private
|
|
*/
|
|
this.subscribedWorkspaces_ = [];
|
|
|
|
/**
|
|
* A map of subscribed UI components, keyed by component name.
|
|
* @type {!Object<string, !Array<!ThemeManager.Component>>}
|
|
* @private
|
|
*/
|
|
this.componentDB_ = Object.create(null);
|
|
};
|
|
|
|
/**
|
|
* A Blockly UI component type.
|
|
* @typedef {{
|
|
* element:!Element,
|
|
* propertyName:string
|
|
* }}
|
|
*/
|
|
ThemeManager.Component;
|
|
|
|
/**
|
|
* Get the workspace theme.
|
|
* @return {!Theme} The workspace theme.
|
|
* @package
|
|
*/
|
|
ThemeManager.prototype.getTheme = function() {
|
|
return this.theme_;
|
|
};
|
|
|
|
/**
|
|
* Set the workspace theme, and refresh the workspace and all components.
|
|
* @param {!Theme} theme The workspace theme.
|
|
* @package
|
|
*/
|
|
ThemeManager.prototype.setTheme = function(theme) {
|
|
const prevTheme = this.theme_;
|
|
this.theme_ = theme;
|
|
|
|
// Set the theme name onto the injection div.
|
|
const injectionDiv = this.workspace_.getInjectionDiv();
|
|
if (injectionDiv) {
|
|
if (prevTheme) {
|
|
dom.removeClass(injectionDiv, prevTheme.getClassName());
|
|
}
|
|
dom.addClass(injectionDiv, this.theme_.getClassName());
|
|
}
|
|
|
|
// Refresh all subscribed workspaces.
|
|
for (let i = 0, workspace; (workspace = this.subscribedWorkspaces_[i]); i++) {
|
|
workspace.refreshTheme();
|
|
}
|
|
|
|
// Refresh all registered Blockly UI components.
|
|
for (let i = 0, keys = Object.keys(this.componentDB_), key; (key = keys[i]);
|
|
i++) {
|
|
for (let j = 0, component; (component = this.componentDB_[key][j]); j++) {
|
|
const element = component.element;
|
|
const propertyName = component.propertyName;
|
|
const style = this.theme_ && this.theme_.getComponentStyle(key);
|
|
element.style[propertyName] = style || '';
|
|
}
|
|
}
|
|
|
|
for (const workspace of this.subscribedWorkspaces_) {
|
|
workspace.hideChaff();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Subscribe a workspace to changes to the selected theme. If a new theme is
|
|
* set, the workspace is called to refresh its blocks.
|
|
* @param {!Workspace} workspace The workspace to subscribe.
|
|
* @package
|
|
*/
|
|
ThemeManager.prototype.subscribeWorkspace = function(workspace) {
|
|
this.subscribedWorkspaces_.push(workspace);
|
|
};
|
|
|
|
/**
|
|
* Unsubscribe a workspace to changes to the selected theme.
|
|
* @param {!Workspace} workspace The workspace to unsubscribe.
|
|
* @package
|
|
*/
|
|
ThemeManager.prototype.unsubscribeWorkspace = function(workspace) {
|
|
if (!arrayUtils.removeElem(this.subscribedWorkspaces_, workspace)) {
|
|
throw Error('Cannot unsubscribe a workspace that hasn\'t been subscribed.');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
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.
|
|
const 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
|
|
*/
|
|
ThemeManager.prototype.unsubscribe = function(element) {
|
|
if (!element) {
|
|
return;
|
|
}
|
|
// Go through all component, and remove any references to this element.
|
|
const componentNames = Object.keys(this.componentDB_);
|
|
for (let c = 0, componentName; (componentName = componentNames[c]); c++) {
|
|
const elements = this.componentDB_[componentName];
|
|
for (let 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}
|
|
*/
|
|
ThemeManager.prototype.dispose = function() {
|
|
this.owner_ = null;
|
|
this.theme_ = null;
|
|
this.subscribedWorkspaces_ = null;
|
|
this.componentDB_ = null;
|
|
};
|
|
|
|
exports.ThemeManager = ThemeManager;
|