mirror of
https://github.com/google/blockly.git
synced 2026-01-11 10:57:07 +01:00
[zelos] Cross browser pixel perfect text input (#3466)
* Align text and widget div text input pixel perfect on all browsers
This commit is contained in:
@@ -393,6 +393,7 @@ Blockly.Css.CONTENT = [
|
||||
'width: 100%;',
|
||||
'text-align: center;',
|
||||
'display: block;',
|
||||
'box-sizing: border-box;',
|
||||
'}',
|
||||
|
||||
/* Edge and IE introduce a close icon when the input value is longer than a
|
||||
|
||||
@@ -344,22 +344,23 @@ Blockly.Field.prototype.createBorderRect_ = function() {
|
||||
Blockly.Field.prototype.createTextElement_ = function() {
|
||||
var xOffset = this.borderRect_ ?
|
||||
this.constants_.FIELD_BORDER_RECT_X_PADDING : 0;
|
||||
this.size_.height = Math.max(this.size_.height,
|
||||
this.constants_.FIELD_TEXT_BASELINE_CENTER ?
|
||||
this.constants_.FIELD_TEXT_HEIGHT :
|
||||
this.constants_.FIELD_TEXT_BASELINE_Y);
|
||||
var baselineCenter = this.constants_.FIELD_TEXT_BASELINE_CENTER;
|
||||
var baselineY = this.constants_.FIELD_TEXT_BASELINE_Y;
|
||||
this.size_.height = Math.max(this.size_.height, baselineCenter ?
|
||||
this.constants_.FIELD_TEXT_HEIGHT : baselineY);
|
||||
if (this.size_.height > this.constants_.FIELD_TEXT_HEIGHT) {
|
||||
baselineY += (this.size_.height - baselineY) / 2;
|
||||
}
|
||||
this.textElement_ = /** @type {!SVGTextElement} **/
|
||||
(Blockly.utils.dom.createSvgElement('text',
|
||||
{
|
||||
'class': 'blocklyText',
|
||||
'y': this.size_.height / 2,
|
||||
'y': baselineCenter ? this.size_.height / 2 : baselineY,
|
||||
'dy': this.constants_.FIELD_TEXT_Y_OFFSET,
|
||||
'x': xOffset
|
||||
}, this.fieldGroup_));
|
||||
if (this.constants_.FIELD_TEXT_BASELINE_CENTER) {
|
||||
if (baselineCenter) {
|
||||
this.textElement_.setAttribute('dominant-baseline', 'central');
|
||||
} else {
|
||||
this.textElement_.setAttribute('dy',
|
||||
this.constants_.FIELD_TEXT_BASELINE_Y - this.size_.height / 2);
|
||||
}
|
||||
this.textContent_ = document.createTextNode('');
|
||||
this.textElement_.appendChild(this.textContent_);
|
||||
@@ -421,7 +422,7 @@ Blockly.Field.prototype.dispose = function() {
|
||||
* Add or remove the UI indicating if this field is editable or not.
|
||||
*/
|
||||
Blockly.Field.prototype.updateEditable = function() {
|
||||
var group = this.getClickTarget_();
|
||||
var group = this.fieldGroup_;
|
||||
if (!this.EDITABLE || !group) {
|
||||
return;
|
||||
}
|
||||
@@ -673,9 +674,9 @@ Blockly.Field.prototype.getSize = function() {
|
||||
*/
|
||||
Blockly.Field.prototype.getScaledBBox = function() {
|
||||
var bBox = this.borderRect_.getBBox();
|
||||
var scaledHeight = bBox.height * this.sourceBlock_.workspace.scale;
|
||||
var scaledWidth = bBox.width * this.sourceBlock_.workspace.scale;
|
||||
var xy = this.getAbsoluteXY_();
|
||||
var scaledWidth = bBox.width * this.sourceBlock_.workspace.scale;
|
||||
var scaledHeight = bBox.height * this.sourceBlock_.workspace.scale;
|
||||
return {
|
||||
top: xy.y,
|
||||
bottom: xy.y + scaledHeight,
|
||||
|
||||
@@ -146,10 +146,6 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) {
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.initView = function() {
|
||||
this.size_.height = Math.max(this.constants_.FIELD_BORDER_RECT_HEIGHT,
|
||||
this.constants_.FIELD_TEXT_BASELINE_CENTER ?
|
||||
this.constants_.FIELD_TEXT_HEIGHT :
|
||||
this.constants_.FIELD_TEXT_BASELINE_Y);
|
||||
if (this.constants_.FULL_BLOCK_FIELDS) {
|
||||
// Step one: figure out if this is the only field on this block.
|
||||
// Rendering is quite different in that case.
|
||||
@@ -181,9 +177,6 @@ Blockly.FieldTextInput.prototype.initView = function() {
|
||||
this.createBorderRect_();
|
||||
}
|
||||
this.createTextElement_();
|
||||
if (this.constants_.FIELD_TEXT_BASELINE_CENTER) {
|
||||
this.textElement_.setAttribute('dominant-baseline', 'central');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -354,23 +347,33 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() {
|
||||
var htmlInput = /** @type {HTMLInputElement} */ (document.createElement('input'));
|
||||
htmlInput.className = 'blocklyHtmlInput';
|
||||
htmlInput.setAttribute('spellcheck', this.spellcheck_);
|
||||
var scale = this.workspace_.scale;
|
||||
var fontSize =
|
||||
(this.constants_.FIELD_TEXT_FONTSIZE * this.workspace_.scale) + 'pt';
|
||||
(this.constants_.FIELD_TEXT_FONTSIZE * scale) + 'pt';
|
||||
div.style.fontSize = fontSize;
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
var borderRadius =
|
||||
(Blockly.FieldTextInput.BORDERRADIUS * this.workspace_.scale) + 'px';
|
||||
(Blockly.FieldTextInput.BORDERRADIUS * scale) + 'px';
|
||||
|
||||
if (this.fullBlockClickTarget_) {
|
||||
var bBox = this.getScaledBBox();
|
||||
|
||||
// Override border radius.
|
||||
borderRadius = (bBox.bottom - bBox.top) / 2 + 'px';
|
||||
// Pull stroke colour from the existing shadow block
|
||||
var strokeColour = this.sourceBlock_.style.colourTertiary;
|
||||
div.style.borderColor = strokeColour;
|
||||
var strokeColour = this.sourceBlock_.getParent() ?
|
||||
this.sourceBlock_.getParent().style.colourTertiary :
|
||||
this.sourceBlock_.style.colourTertiary;
|
||||
htmlInput.style.border = (1 * scale) + 'px solid ' + strokeColour;
|
||||
div.style.borderRadius = borderRadius;
|
||||
div.style.transition = 'box-shadow 0.25s ease 0s';
|
||||
if (this.constants_.FIELD_TEXTINPUT_BOX_SHADOW) {
|
||||
div.style.boxShadow = 'rgba(255, 255, 255, 0.3) 0px 0px 0px ' +
|
||||
4 * scale + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
htmlInput.style.borderRadius = borderRadius;
|
||||
|
||||
div.appendChild(htmlInput);
|
||||
|
||||
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
|
||||
@@ -406,6 +409,8 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
style.width = 'auto';
|
||||
style.height = 'auto';
|
||||
style.fontSize = '';
|
||||
style.transition = '';
|
||||
style.boxShadow = '';
|
||||
this.htmlInput_ = null;
|
||||
|
||||
Blockly.utils.dom.removeClass(this.getClickTarget_(), 'editing');
|
||||
@@ -634,16 +639,39 @@ Blockly.FieldTextInput.prototype.getValueFromEditorText_ = function(text) {
|
||||
* @override
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.getScaledBBox = function() {
|
||||
if (this.fullBlockClickTarget_) {
|
||||
var xy = this.getClickTarget_().getBoundingClientRect();
|
||||
if (!this.borderRect_) {
|
||||
// Browsers are inconsistent in what they return for a bounding box.
|
||||
// - Webkit / Blink: fill-box / object bounding box
|
||||
// - Gecko / Triden / EdgeHTML: stroke-box
|
||||
var bBox = this.sourceBlock_.getHeightWidth();
|
||||
var scale = this.sourceBlock_.workspace.scale;
|
||||
var xy = this.getAbsoluteXY_();
|
||||
var scaledWidth = bBox.width * scale;
|
||||
var scaledHeight = bBox.height * scale;
|
||||
|
||||
if (Blockly.utils.userAgent.GECKO) {
|
||||
xy.x += 1.5 * scale;
|
||||
xy.y += 1.5 * scale;
|
||||
scaledWidth += 1 * scale;
|
||||
scaledHeight += 1 * scale;
|
||||
} else {
|
||||
if (!Blockly.utils.userAgent.EDGE && !Blockly.utils.userAgent.IE) {
|
||||
xy.x -= 0.5 * scale;
|
||||
xy.y -= 0.5 * scale;
|
||||
}
|
||||
scaledWidth += 1 * scale;
|
||||
scaledHeight += 1 * scale;
|
||||
}
|
||||
} else {
|
||||
var xy = this.borderRect_.getBoundingClientRect();
|
||||
var scaledWidth = xy.width;
|
||||
var scaledHeight = xy.height;
|
||||
}
|
||||
return {
|
||||
top: xy.y,
|
||||
bottom: xy.y + xy.height,
|
||||
bottom: xy.y + scaledHeight,
|
||||
left: xy.x,
|
||||
right: xy.x + xy.width
|
||||
right: xy.x + scaledWidth
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
* Height of text.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_HEIGHT = 13;
|
||||
this.FIELD_TEXT_HEIGHT = 16;
|
||||
|
||||
/**
|
||||
* Text font weight. Should match blocklyText's font-weight in CSS.
|
||||
@@ -207,12 +207,18 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
this.FIELD_BORDER_RECT_Y_PADDING = 3;
|
||||
|
||||
/**
|
||||
* Field text baseline. This is only used if `FIELD_TEXT_BASELINE_CENTER` is
|
||||
* set to false.
|
||||
* Field text baseline.
|
||||
* This is only used if `FIELD_TEXT_BASELINE_CENTER` is false.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_BASELINE_Y = Blockly.utils.userAgent.GECKO ? 12 : 13.09;
|
||||
|
||||
/**
|
||||
* An text offset adjusting the Y position of text after positioning.
|
||||
* @type {number}
|
||||
*/
|
||||
this.FIELD_TEXT_Y_OFFSET = 0;
|
||||
|
||||
/**
|
||||
* A field's text element's dominant baseline.
|
||||
* @type {boolean}
|
||||
@@ -232,6 +238,13 @@ Blockly.blockRendering.ConstantProvider = function() {
|
||||
*/
|
||||
this.FIELD_DROPDOWN_SVG_ARROW = false;
|
||||
|
||||
/**
|
||||
* Whether or not to show a box shadow around the widget div. This is only a
|
||||
* feature of full block fields.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.FIELD_TEXTINPUT_BOX_SHADOW = false;
|
||||
|
||||
/**
|
||||
* Whether or not the colour field should display its colour value on the
|
||||
* entire block.
|
||||
|
||||
@@ -169,6 +169,24 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
*/
|
||||
this.FIELD_TEXT_FONTWEIGHT = 'bold';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_FONTFAMILY =
|
||||
'"Helvetica Neue", "Segoe UI", Helvetica, sans-serif';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_HEIGHT = 13.1;
|
||||
|
||||
/**
|
||||
* Used by positioning text on IE and Edge as they don't support
|
||||
* dominant-baseline:center.
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_BASELINE_Y = 13.1;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -178,6 +196,16 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_BORDER_RECT_X_PADDING = 2 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_BORDER_RECT_Y_PADDING = 1 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_BORDER_RECT_HEIGHT = 8 * this.GRID_UNIT;
|
||||
|
||||
/**
|
||||
* @override
|
||||
@@ -214,6 +242,16 @@ Blockly.zelos.ConstantProvider = function() {
|
||||
'AuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMz' +
|
||||
'dBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=';
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXTINPUT_BOX_SHADOW = true;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
this.FIELD_TEXT_Y_OFFSET = Blockly.utils.userAgent.CHROME ? -.45 : 0;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
|
||||
@@ -51,6 +51,8 @@ goog.require('Blockly.utils.global');
|
||||
// Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44
|
||||
// (KHTML, like Gecko) JavaFX/8.0 Safari/537.44
|
||||
Blockly.utils.userAgent.JAVA_FX = has('JavaFX');
|
||||
Blockly.utils.userAgent.CHROME = (has('Chrome') || has('CriOS')) &&
|
||||
!Blockly.utils.userAgent.EDGE;
|
||||
|
||||
// Engines. Logic from:
|
||||
// https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js
|
||||
|
||||
Reference in New Issue
Block a user