mirror of
https://github.com/google/blockly.git
synced 2026-01-04 23:50:12 +01:00
704 lines
18 KiB
JavaScript
704 lines
18 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2012 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Colour input field.
|
|
*/
|
|
'use strict';
|
|
|
|
/**
|
|
* Colour input field.
|
|
* @class
|
|
*/
|
|
goog.module('Blockly.FieldColour');
|
|
|
|
const Css = goog.require('Blockly.Css');
|
|
const aria = goog.require('Blockly.utils.aria');
|
|
const browserEvents = goog.require('Blockly.browserEvents');
|
|
const colour = goog.require('Blockly.utils.colour');
|
|
const dom = goog.require('Blockly.utils.dom');
|
|
const fieldRegistry = goog.require('Blockly.fieldRegistry');
|
|
const idGenerator = goog.require('Blockly.utils.idGenerator');
|
|
const object = goog.require('Blockly.utils.object');
|
|
const {DropDownDiv} = goog.require('Blockly.DropDownDiv');
|
|
const {Field} = goog.require('Blockly.Field');
|
|
const {KeyCodes} = goog.require('Blockly.utils.KeyCodes');
|
|
const {Size} = goog.require('Blockly.utils.Size');
|
|
/** @suppress {extraRequire} */
|
|
goog.require('Blockly.Events.BlockChange');
|
|
|
|
|
|
/**
|
|
* Class for a colour input field.
|
|
* @param {string=} opt_value The initial value of the field. Should be in
|
|
* '#rrggbb' format. Defaults to the first value in the default colour array.
|
|
* @param {Function=} opt_validator A function that is called to validate
|
|
* changes to the field's value. Takes in a colour string & returns a
|
|
* validated colour string ('#rrggbb' format), or null to abort the
|
|
* change.Blockly.
|
|
* @param {Object=} opt_config A map of options used to configure the field.
|
|
* See the [field creation documentation]{@link
|
|
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour}
|
|
* for a list of properties this parameter supports.
|
|
* @extends {Field}
|
|
* @constructor
|
|
* @alias Blockly.FieldColour
|
|
*/
|
|
const FieldColour = function(opt_value, opt_validator, opt_config) {
|
|
FieldColour.superClass_.constructor.call(
|
|
this, opt_value, opt_validator, opt_config);
|
|
|
|
/**
|
|
* The field's colour picker element.
|
|
* @type {?Element}
|
|
* @private
|
|
*/
|
|
this.picker_ = null;
|
|
|
|
/**
|
|
* Index of the currently highlighted element.
|
|
* @type {?number}
|
|
* @private
|
|
*/
|
|
this.highlightedIndex_ = null;
|
|
|
|
/**
|
|
* Mouse click event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onClickWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse move event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseMoveWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse enter event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseEnterWrapper_ = null;
|
|
|
|
/**
|
|
* Mouse leave event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onMouseLeaveWrapper_ = null;
|
|
|
|
/**
|
|
* Key down event data.
|
|
* @type {?browserEvents.Data}
|
|
* @private
|
|
*/
|
|
this.onKeyDownWrapper_ = null;
|
|
};
|
|
object.inherits(FieldColour, Field);
|
|
|
|
/**
|
|
* Construct a FieldColour from a JSON arg object.
|
|
* @param {!Object} options A JSON object with options (colour).
|
|
* @return {!FieldColour} The new field instance.
|
|
* @package
|
|
* @nocollapse
|
|
*/
|
|
FieldColour.fromJson = function(options) {
|
|
// `this` might be a subclass of FieldColour if that class doesn't override
|
|
// the static fromJson method.
|
|
return new this(options['colour'], undefined, options);
|
|
};
|
|
|
|
/**
|
|
* Serializable fields are saved by the XML renderer, non-serializable fields
|
|
* are not. Editable fields should also be serializable.
|
|
* @type {boolean}
|
|
*/
|
|
FieldColour.prototype.SERIALIZABLE = true;
|
|
|
|
/**
|
|
* Mouse cursor style when over the hotspot that initiates the editor.
|
|
*/
|
|
FieldColour.prototype.CURSOR = 'default';
|
|
|
|
/**
|
|
* Used to tell if the field needs to be rendered the next time the block is
|
|
* rendered. Colour fields are statically sized, and only need to be
|
|
* rendered at initialization.
|
|
* @type {boolean}
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.isDirty_ = false;
|
|
|
|
/**
|
|
* Array of colours used by this field. If null, use the global list.
|
|
* @type {Array<string>}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.colours_ = null;
|
|
|
|
/**
|
|
* Array of colour tooltips used by this field. If null, use the global list.
|
|
* @type {Array<string>}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.titles_ = null;
|
|
|
|
/**
|
|
* Number of colour columns used by this field. If 0, use the global setting.
|
|
* By default use the global constants for columns.
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.columns_ = 0;
|
|
|
|
/**
|
|
* Configure the field based on the given map of options.
|
|
* @param {!Object} config A map of options to configure the field based on.
|
|
* @protected
|
|
* @override
|
|
*/
|
|
FieldColour.prototype.configure_ = function(config) {
|
|
FieldColour.superClass_.configure_.call(this, config);
|
|
if (config['colourOptions']) {
|
|
this.colours_ = config['colourOptions'];
|
|
this.titles_ = config['colourTitles'];
|
|
}
|
|
if (config['columns']) {
|
|
this.columns_ = config['columns'];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create the block UI for this colour field.
|
|
* @package
|
|
*/
|
|
FieldColour.prototype.initView = function() {
|
|
this.size_ = new Size(
|
|
this.getConstants().FIELD_COLOUR_DEFAULT_WIDTH,
|
|
this.getConstants().FIELD_COLOUR_DEFAULT_HEIGHT);
|
|
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
|
this.createBorderRect_();
|
|
this.borderRect_.style['fillOpacity'] = '1';
|
|
} else {
|
|
this.clickTarget_ = this.sourceBlock_.getSvgRoot();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
FieldColour.prototype.applyColour = function() {
|
|
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
|
|
if (this.borderRect_) {
|
|
this.borderRect_.style.fill = /** @type {string} */ (this.getValue());
|
|
}
|
|
} else {
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', this.getValue());
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Ensure that the input value is a valid colour.
|
|
* @param {*=} opt_newValue The input value.
|
|
* @return {?string} A valid colour, or null if invalid.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
|
|
if (typeof opt_newValue !== 'string') {
|
|
return null;
|
|
}
|
|
return colour.parse(opt_newValue);
|
|
};
|
|
|
|
/**
|
|
* Update the value of this colour field, and update the displayed colour.
|
|
* @param {*} newValue The value to be saved. The default validator guarantees
|
|
* that this is a colour in '#rrggbb' format.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
|
this.value_ = newValue;
|
|
if (this.borderRect_) {
|
|
this.borderRect_.style.fill = /** @type {string} */ (newValue);
|
|
} else if (this.sourceBlock_ && this.sourceBlock_.rendered) {
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', newValue);
|
|
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get the text for this field. Used when the block is collapsed.
|
|
* @return {string} Text representing the value of this field.
|
|
*/
|
|
FieldColour.prototype.getText = function() {
|
|
let colour = /** @type {string} */ (this.value_);
|
|
// Try to use #rgb format if possible, rather than #rrggbb.
|
|
if (/^#(.)\1(.)\2(.)\3$/.test(colour)) {
|
|
colour = '#' + colour[1] + colour[3] + colour[5];
|
|
}
|
|
return colour;
|
|
};
|
|
|
|
/**
|
|
* An array of colour strings for the palette.
|
|
* Copied from goog.ui.ColorPicker.SIMPLE_GRID_COLORS
|
|
* All colour pickers use this unless overridden with setColours.
|
|
* @type {!Array<string>}
|
|
*/
|
|
FieldColour.COLOURS = [
|
|
// grays
|
|
'#ffffff',
|
|
'#cccccc',
|
|
'#c0c0c0',
|
|
'#999999',
|
|
'#666666',
|
|
'#333333',
|
|
'#000000',
|
|
// reds
|
|
'#ffcccc',
|
|
'#ff6666',
|
|
'#ff0000',
|
|
'#cc0000',
|
|
'#990000',
|
|
'#660000',
|
|
'#330000',
|
|
// oranges
|
|
'#ffcc99',
|
|
'#ff9966',
|
|
'#ff9900',
|
|
'#ff6600',
|
|
'#cc6600',
|
|
'#993300',
|
|
'#663300',
|
|
// yellows
|
|
'#ffff99',
|
|
'#ffff66',
|
|
'#ffcc66',
|
|
'#ffcc33',
|
|
'#cc9933',
|
|
'#996633',
|
|
'#663333',
|
|
// olives
|
|
'#ffffcc',
|
|
'#ffff33',
|
|
'#ffff00',
|
|
'#ffcc00',
|
|
'#999900',
|
|
'#666600',
|
|
'#333300',
|
|
// greens
|
|
'#99ff99',
|
|
'#66ff99',
|
|
'#33ff33',
|
|
'#33cc00',
|
|
'#009900',
|
|
'#006600',
|
|
'#003300',
|
|
// turquoises
|
|
'#99ffff',
|
|
'#33ffff',
|
|
'#66cccc',
|
|
'#00cccc',
|
|
'#339999',
|
|
'#336666',
|
|
'#003333',
|
|
// blues
|
|
'#ccffff',
|
|
'#66ffff',
|
|
'#33ccff',
|
|
'#3366ff',
|
|
'#3333ff',
|
|
'#000099',
|
|
'#000066',
|
|
// purples
|
|
'#ccccff',
|
|
'#9999ff',
|
|
'#6666cc',
|
|
'#6633ff',
|
|
'#6600cc',
|
|
'#333399',
|
|
'#330099',
|
|
// violets
|
|
'#ffccff',
|
|
'#ff99ff',
|
|
'#cc66cc',
|
|
'#cc33cc',
|
|
'#993399',
|
|
'#663366',
|
|
'#330033',
|
|
];
|
|
|
|
/**
|
|
* The default value for this field.
|
|
* @type {*}
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.DEFAULT_VALUE = FieldColour.COLOURS[0];
|
|
|
|
/**
|
|
* An array of tooltip strings for the palette. If not the same length as
|
|
* COLOURS, the colour's hex code will be used for any missing titles.
|
|
* All colour pickers use this unless overridden with setColours.
|
|
* @type {!Array<string>}
|
|
*/
|
|
FieldColour.TITLES = [];
|
|
|
|
/**
|
|
* Number of columns in the palette.
|
|
* All colour pickers use this unless overridden with setColumns.
|
|
*/
|
|
FieldColour.COLUMNS = 7;
|
|
|
|
/**
|
|
* Set a custom colour grid for this field.
|
|
* @param {Array<string>} colours Array of colours for this block,
|
|
* or null to use default (FieldColour.COLOURS).
|
|
* @param {Array<string>=} opt_titles Optional array of colour tooltips,
|
|
* or null to use default (FieldColour.TITLES).
|
|
* @return {!FieldColour} Returns itself (for method chaining).
|
|
*/
|
|
FieldColour.prototype.setColours = function(colours, opt_titles) {
|
|
this.colours_ = colours;
|
|
if (opt_titles) {
|
|
this.titles_ = opt_titles;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Set a custom grid size for this field.
|
|
* @param {number} columns Number of columns for this block,
|
|
* or 0 to use default (FieldColour.COLUMNS).
|
|
* @return {!FieldColour} Returns itself (for method chaining).
|
|
*/
|
|
FieldColour.prototype.setColumns = function(columns) {
|
|
this.columns_ = columns;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create and show the colour field's editor.
|
|
* @protected
|
|
*/
|
|
FieldColour.prototype.showEditor_ = function() {
|
|
this.dropdownCreate_();
|
|
DropDownDiv.getContentDiv().appendChild(this.picker_);
|
|
|
|
DropDownDiv.showPositionedByField(this, this.dropdownDispose_.bind(this));
|
|
|
|
// Focus so we can start receiving keyboard events.
|
|
this.picker_.focus({preventScroll: true});
|
|
};
|
|
|
|
/**
|
|
* Handle a click on a colour cell.
|
|
* @param {!MouseEvent} e Mouse event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onClick_ = function(e) {
|
|
const cell = /** @type {!Element} */ (e.target);
|
|
const colour = cell && cell.label;
|
|
if (colour !== null) {
|
|
this.setValue(colour);
|
|
DropDownDiv.hideIfOwner(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle a key down event. Navigate around the grid with the
|
|
* arrow keys. Enter selects the highlighted colour.
|
|
* @param {!KeyboardEvent} e Keyboard event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onKeyDown_ = function(e) {
|
|
let handled = false;
|
|
if (e.keyCode === KeyCodes.UP) {
|
|
this.moveHighlightBy_(0, -1);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.DOWN) {
|
|
this.moveHighlightBy_(0, 1);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.LEFT) {
|
|
this.moveHighlightBy_(-1, 0);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.RIGHT) {
|
|
this.moveHighlightBy_(1, 0);
|
|
handled = true;
|
|
} else if (e.keyCode === KeyCodes.ENTER) {
|
|
// Select the highlighted colour.
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
const colour = highlighted && highlighted.label;
|
|
if (colour !== null) {
|
|
this.setValue(colour);
|
|
}
|
|
}
|
|
DropDownDiv.hideWithoutAnimation();
|
|
handled = true;
|
|
}
|
|
if (handled) {
|
|
e.stopPropagation();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Move the currently highlighted position by dx and dy.
|
|
* @param {number} dx Change of x
|
|
* @param {number} dy Change of y
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.moveHighlightBy_ = function(dx, dy) {
|
|
const colours = this.colours_ || FieldColour.COLOURS;
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
|
|
// Get the current x and y coordinates
|
|
let x = this.highlightedIndex_ % columns;
|
|
let y = Math.floor(this.highlightedIndex_ / columns);
|
|
|
|
// Add the offset
|
|
x += dx;
|
|
y += dy;
|
|
|
|
if (dx < 0) {
|
|
// Move left one grid cell, even in RTL.
|
|
// Loop back to the end of the previous row if we have room.
|
|
if (x < 0 && y > 0) {
|
|
x = columns - 1;
|
|
y--;
|
|
} else if (x < 0) {
|
|
x = 0;
|
|
}
|
|
} else if (dx > 0) {
|
|
// Move right one grid cell, even in RTL.
|
|
// Loop to the start of the next row, if there's room.
|
|
if (x > columns - 1 && y < Math.floor(colours.length / columns) - 1) {
|
|
x = 0;
|
|
y++;
|
|
} else if (x > columns - 1) {
|
|
x--;
|
|
}
|
|
} else if (dy < 0) {
|
|
// Move up one grid cell, stop at the top.
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
} else if (dy > 0) {
|
|
// Move down one grid cell, stop at the bottom.
|
|
if (y > Math.floor(colours.length / columns) - 1) {
|
|
y = Math.floor(colours.length / columns) - 1;
|
|
}
|
|
}
|
|
|
|
// Move the highlight to the new coordinates.
|
|
const cell =
|
|
/** @type {!Element} */ (this.picker_.childNodes[y].childNodes[x]);
|
|
const index = (y * columns) + x;
|
|
this.setHighlightedCell_(cell, index);
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse move event. Highlight the hovered colour.
|
|
* @param {!MouseEvent} e Mouse event.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseMove_ = function(e) {
|
|
const cell = /** @type {!Element} */ (e.target);
|
|
const index = cell && Number(cell.getAttribute('data-index'));
|
|
if (index !== null && index !== this.highlightedIndex_) {
|
|
this.setHighlightedCell_(cell, index);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse enter event. Focus the picker.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseEnter_ = function() {
|
|
this.picker_.focus({preventScroll: true});
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse leave event. Blur the picker and unhighlight
|
|
* the currently highlighted colour.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.onMouseLeave_ = function() {
|
|
this.picker_.blur();
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Returns the currently highlighted item (if any).
|
|
* @return {?HTMLElement} Highlighted item (null if none).
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.getHighlighted_ = function() {
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
const x = this.highlightedIndex_ % columns;
|
|
const y = Math.floor(this.highlightedIndex_ / columns);
|
|
const row = this.picker_.childNodes[y];
|
|
if (!row) {
|
|
return null;
|
|
}
|
|
const col = /** @type {HTMLElement} */ (row.childNodes[x]);
|
|
return col;
|
|
};
|
|
|
|
/**
|
|
* Update the currently highlighted cell.
|
|
* @param {!Element} cell the new cell to highlight
|
|
* @param {number} index the index of the new cell
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
|
|
// Unhighlight the current item.
|
|
const highlighted = this.getHighlighted_();
|
|
if (highlighted) {
|
|
dom.removeClass(highlighted, 'blocklyColourHighlighted');
|
|
}
|
|
// Highlight new item.
|
|
dom.addClass(cell, 'blocklyColourHighlighted');
|
|
// Set new highlighted index.
|
|
this.highlightedIndex_ = index;
|
|
|
|
// Update accessibility roles.
|
|
aria.setState(
|
|
/** @type {!Element} */ (this.picker_), aria.State.ACTIVEDESCENDANT,
|
|
cell.getAttribute('id'));
|
|
};
|
|
|
|
/**
|
|
* Create a colour picker dropdown editor.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.dropdownCreate_ = function() {
|
|
const columns = this.columns_ || FieldColour.COLUMNS;
|
|
const colours = this.colours_ || FieldColour.COLOURS;
|
|
const titles = this.titles_ || FieldColour.TITLES;
|
|
const selectedColour = this.getValue();
|
|
// Create the palette.
|
|
const table = document.createElement('table');
|
|
table.className = 'blocklyColourTable';
|
|
table.tabIndex = 0;
|
|
table.dir = 'ltr';
|
|
aria.setRole(table, aria.Role.GRID);
|
|
aria.setState(table, aria.State.EXPANDED, true);
|
|
aria.setState(
|
|
table, aria.State.ROWCOUNT, Math.floor(colours.length / columns));
|
|
aria.setState(table, aria.State.COLCOUNT, columns);
|
|
let row;
|
|
for (let i = 0; i < colours.length; i++) {
|
|
if (i % columns === 0) {
|
|
row = document.createElement('tr');
|
|
aria.setRole(row, aria.Role.ROW);
|
|
table.appendChild(row);
|
|
}
|
|
const cell = document.createElement('td');
|
|
row.appendChild(cell);
|
|
cell.label = colours[i]; // This becomes the value, if clicked.
|
|
cell.title = titles[i] || colours[i];
|
|
cell.id = idGenerator.getNextUniqueId();
|
|
cell.setAttribute('data-index', i);
|
|
aria.setRole(cell, aria.Role.GRIDCELL);
|
|
aria.setState(cell, aria.State.LABEL, colours[i]);
|
|
aria.setState(cell, aria.State.SELECTED, colours[i] === selectedColour);
|
|
cell.style.backgroundColor = colours[i];
|
|
if (colours[i] === selectedColour) {
|
|
cell.className = 'blocklyColourSelected';
|
|
this.highlightedIndex_ = i;
|
|
}
|
|
}
|
|
|
|
// Configure event handler on the table to listen for any event in a cell.
|
|
this.onClickWrapper_ =
|
|
browserEvents.conditionalBind(table, 'click', this, this.onClick_, true);
|
|
this.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mousemove', this, this.onMouseMove_, true);
|
|
this.onMouseEnterWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mouseenter', this, this.onMouseEnter_, true);
|
|
this.onMouseLeaveWrapper_ = browserEvents.conditionalBind(
|
|
table, 'mouseleave', this, this.onMouseLeave_, true);
|
|
this.onKeyDownWrapper_ =
|
|
browserEvents.conditionalBind(table, 'keydown', this, this.onKeyDown_);
|
|
|
|
this.picker_ = table;
|
|
};
|
|
|
|
/**
|
|
* Disposes of events and DOM-references belonging to the colour editor.
|
|
* @private
|
|
*/
|
|
FieldColour.prototype.dropdownDispose_ = function() {
|
|
if (this.onClickWrapper_) {
|
|
browserEvents.unbind(this.onClickWrapper_);
|
|
this.onClickWrapper_ = null;
|
|
}
|
|
if (this.onMouseMoveWrapper_) {
|
|
browserEvents.unbind(this.onMouseMoveWrapper_);
|
|
this.onMouseMoveWrapper_ = null;
|
|
}
|
|
if (this.onMouseEnterWrapper_) {
|
|
browserEvents.unbind(this.onMouseEnterWrapper_);
|
|
this.onMouseEnterWrapper_ = null;
|
|
}
|
|
if (this.onMouseLeaveWrapper_) {
|
|
browserEvents.unbind(this.onMouseLeaveWrapper_);
|
|
this.onMouseLeaveWrapper_ = null;
|
|
}
|
|
if (this.onKeyDownWrapper_) {
|
|
browserEvents.unbind(this.onKeyDownWrapper_);
|
|
this.onKeyDownWrapper_ = null;
|
|
}
|
|
this.picker_ = null;
|
|
this.highlightedIndex_ = null;
|
|
};
|
|
|
|
/**
|
|
* CSS for colour picker. See css.js for use.
|
|
*/
|
|
Css.register(`
|
|
.blocklyColourTable {
|
|
border-collapse: collapse;
|
|
display: block;
|
|
outline: none;
|
|
padding: 1px;
|
|
}
|
|
|
|
.blocklyColourTable>tr>td {
|
|
border: .5px solid #888;
|
|
box-sizing: border-box;
|
|
cursor: pointer;
|
|
display: inline-block;
|
|
height: 20px;
|
|
padding: 0;
|
|
width: 20px;
|
|
}
|
|
|
|
.blocklyColourTable>tr>td.blocklyColourHighlighted {
|
|
border-color: #eee;
|
|
box-shadow: 2px 2px 7px 2px rgba(0,0,0,.3);
|
|
position: relative;
|
|
}
|
|
|
|
.blocklyColourSelected, .blocklyColourSelected:hover {
|
|
border-color: #eee !important;
|
|
outline: 1px solid #333;
|
|
position: relative;
|
|
}
|
|
`);
|
|
|
|
fieldRegistry.register('field_colour', FieldColour);
|
|
|
|
exports.FieldColour = FieldColour;
|