Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate core/utils/dom.js to goog.module syntax #5075

Merged
merged 6 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 98 additions & 79 deletions core/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,37 @@
* @name Blockly.utils.dom
* @namespace
*/
goog.provide('Blockly.utils.dom');
goog.module('Blockly.utils.dom');
goog.module.declareLegacyNamespace();

goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
const Svg = goog.require('Blockly.utils.Svg');
const userAgent = goog.require('Blockly.utils.userAgent');


/**
* Required name space for SVG elements.
* @const
*/
Blockly.utils.dom.SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_NS = 'http://www.w3.org/2000/svg';

/**
* Required name space for HTML elements.
* @const
*/
Blockly.utils.dom.HTML_NS = 'http://www.w3.org/1999/xhtml';
const HTML_NS = 'http://www.w3.org/1999/xhtml';

/**
* Required name space for XLINK elements.
* @const
*/
Blockly.utils.dom.XLINK_NS = 'http://www.w3.org/1999/xlink';
const XLINK_NS = 'http://www.w3.org/1999/xlink';

/**
* Node type constants.
* https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
* @enum {number}
*/
Blockly.utils.dom.NodeType = {
const NodeType = {
ELEMENT_NODE: 1,
TEXT_NODE: 3,
COMMENT_NODE: 8,
Expand All @@ -57,36 +58,35 @@ Blockly.utils.dom.NodeType = {
* @type {Object}
* @private
*/
Blockly.utils.dom.cacheWidths_ = null;
let cacheWidths = null;

/**
* Number of current references to cache.
* @type {number}
* @private
*/
Blockly.utils.dom.cacheReference_ = 0;
let cacheReference = 0;

/**
* A HTML canvas context used for computing text width.
* @type {CanvasRenderingContext2D}
* @private
*/
Blockly.utils.dom.canvasContext_ = null;
let canvasContext = null;

/**
* Helper method for creating SVG elements.
* @param {string|Blockly.utils.Svg<T>} name Element's tag name.
* @param {string|Svg<T>} name Element's tag name.
* @param {!Object} attrs Dictionary of attribute names and values.
* @param {Element=} opt_parent Optional parent on which to append the element.
* @return {T} Newly created SVG element. The return type is {!SVGElement} if
* name is a string or a more specific type if it a member of
* Blockly.utils.Svg
* name is a string or a more specific type if it a member of Svg.
* @template T
*/
Blockly.utils.dom.createSvgElement = function(name, attrs, opt_parent) {
var e = /** @type {T} */
(document.createElementNS(Blockly.utils.dom.SVG_NS, String(name)));
for (var key in attrs) {
const createSvgElement = function(name, attrs, opt_parent) {
const e = /** @type {T} */
(document.createElementNS(SVG_NS, String(name)));
for (const key in attrs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this let since it is redefined every loop iteration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because it is redefined every iteration; it's not the same variable taking on a new value, it's a new variable entirely each time through the loop.

e.setAttribute(key, attrs[key]);
}
// IE defines a unique attribute "runtimeStyle", it is NOT applied to
Expand All @@ -108,8 +108,8 @@ Blockly.utils.dom.createSvgElement = function(name, attrs, opt_parent) {
* @param {string} className Name of class to add.
* @return {boolean} True if class was added, false if already present.
*/
Blockly.utils.dom.addClass = function(element, className) {
var classes = element.getAttribute('class') || '';
const addClass = function(element, className) {
let classes = element.getAttribute('class') || '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this const?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, on line 117 it gets mutated.

if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) {
return false;
}
Expand All @@ -126,11 +126,10 @@ Blockly.utils.dom.addClass = function(element, className) {
* @param {string} classNames A string of one or multiple class names for an
* element.
*/
Blockly.utils.dom.removeClasses = function(element, classNames) {
var classList = classNames.split(' ');
for (var i = 0; i < classList.length; i++) {
var cssName = classList[i];
Blockly.utils.dom.removeClass(element, cssName);
const removeClasses = function(element, classNames) {
const classList = classNames.split(' ');
for (let i = 0; i < classList.length; i++) {
removeClass(element, classList[i]);
}
};

Expand All @@ -141,13 +140,13 @@ Blockly.utils.dom.removeClasses = function(element, classNames) {
* @param {string} className Name of class to remove.
* @return {boolean} True if class was removed, false if never present.
*/
Blockly.utils.dom.removeClass = function(element, className) {
var classes = element.getAttribute('class');
const removeClass = function(element, className) {
const classes = element.getAttribute('class');
if ((' ' + classes + ' ').indexOf(' ' + className + ' ') == -1) {
return false;
}
var classList = classes.split(/\s+/);
for (var i = 0; i < classList.length; i++) {
const classList = classes.split(/\s+/);
for (let i = 0; i < classList.length; i++) {
if (!classList[i] || classList[i] == className) {
classList.splice(i, 1);
i--;
Expand All @@ -168,8 +167,8 @@ Blockly.utils.dom.removeClass = function(element, className) {
* @param {string} className Name of class to check.
* @return {boolean} True if class exists, false otherwise.
*/
Blockly.utils.dom.hasClass = function(element, className) {
var classes = element.getAttribute('class');
const hasClass = function(element, className) {
const classes = element.getAttribute('class');
return (' ' + classes + ' ').indexOf(' ' + className + ' ') != -1;
};

Expand All @@ -179,7 +178,7 @@ Blockly.utils.dom.hasClass = function(element, className) {
* @return {?Node} The node removed if removed; else, null.
*/
// Copied from Closure goog.dom.removeNode
Blockly.utils.dom.removeNode = function(node) {
const removeNode = function(node) {
return node && node.parentNode ? node.parentNode.removeChild(node) : null;
};

Expand All @@ -189,9 +188,9 @@ Blockly.utils.dom.removeNode = function(node) {
* @param {!Element} newNode New element to insert.
* @param {!Element} refNode Existing element to precede new node.
*/
Blockly.utils.dom.insertAfter = function(newNode, refNode) {
var siblingNode = refNode.nextSibling;
var parentNode = refNode.parentNode;
const insertAfter = function(newNode, refNode) {
const siblingNode = refNode.nextSibling;
const parentNode = refNode.parentNode;
if (!parentNode) {
throw Error('Reference node has no parent.');
}
Expand All @@ -208,9 +207,10 @@ Blockly.utils.dom.insertAfter = function(newNode, refNode) {
* @param {!Node} descendant The node to test presence of.
* @return {boolean} Whether the parent node contains the descendant node.
*/
Blockly.utils.dom.containsNode = function(parent, descendant) {
return !!(parent.compareDocumentPosition(descendant) &
Blockly.utils.dom.NodeType.DOCUMENT_POSITION_CONTAINED_BY);
const containsNode = function(parent, descendant) {
return !!(
parent.compareDocumentPosition(descendant) &
NodeType.DOCUMENT_POSITION_CONTAINED_BY);
};

/**
Expand All @@ -220,7 +220,7 @@ Blockly.utils.dom.containsNode = function(parent, descendant) {
* @param {!Element} element Element to which the CSS transform will be applied.
* @param {string} transform The value of the CSS `transform` property.
*/
Blockly.utils.dom.setCssTransform = function(element, transform) {
const setCssTransform = function(element, transform) {
element.style['transform'] = transform;
element.style['-webkit-transform'] = transform;
};
Expand All @@ -229,21 +229,21 @@ Blockly.utils.dom.setCssTransform = function(element, transform) {
* Start caching text widths. Every call to this function MUST also call
* stopTextWidthCache. Caches must not survive between execution threads.
*/
Blockly.utils.dom.startTextWidthCache = function() {
Blockly.utils.dom.cacheReference_++;
if (!Blockly.utils.dom.cacheWidths_) {
Blockly.utils.dom.cacheWidths_ = Object.create(null);
const startTextWidthCache = function() {
cacheReference++;
if (!cacheWidths) {
cacheWidths = Object.create(null);
}
};

/**
* Stop caching field widths. Unless caching was already on when the
* corresponding call to startTextWidthCache was made.
*/
Blockly.utils.dom.stopTextWidthCache = function() {
Blockly.utils.dom.cacheReference_--;
if (!Blockly.utils.dom.cacheReference_) {
Blockly.utils.dom.cacheWidths_ = null;
const stopTextWidthCache = function() {
cacheReference--;
if (!cacheReference) {
cacheWidths = null;
}
};

Expand All @@ -252,21 +252,21 @@ Blockly.utils.dom.stopTextWidthCache = function() {
* @param {!Element} textElement An SVG 'text' element.
* @return {number} Width of element.
*/
Blockly.utils.dom.getTextWidth = function(textElement) {
var key = textElement.textContent + '\n' + textElement.className.baseVal;
var width;
const getTextWidth = function(textElement) {
const key = textElement.textContent + '\n' + textElement.className.baseVal;
let width;

// Return the cached width if it exists.
if (Blockly.utils.dom.cacheWidths_) {
width = Blockly.utils.dom.cacheWidths_[key];
if (cacheWidths) {
width = cacheWidths[key];
if (width) {
return width;
}
}

// Attempt to compute fetch the width of the SVG text element.
try {
if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) {
if (userAgent.IE || userAgent.EDGE) {
width = textElement.getBBox().width;
} else {
width = textElement.getComputedTextLength();
Expand All @@ -280,8 +280,8 @@ Blockly.utils.dom.getTextWidth = function(textElement) {
}

// Cache the computed width and return.
if (Blockly.utils.dom.cacheWidths_) {
Blockly.utils.dom.cacheWidths_[key] = width;
if (cacheWidths) {
cacheWidths[key] = width;
}
return width;
};
Expand All @@ -296,10 +296,10 @@ Blockly.utils.dom.getTextWidth = function(textElement) {
* @param {string} fontFamily The font family to use.
* @return {number} Width of element.
*/
Blockly.utils.dom.getFastTextWidth = function(textElement,
fontSize, fontWeight, fontFamily) {
return Blockly.utils.dom.getFastTextWidthWithSizeString(textElement,
fontSize + 'pt', fontWeight, fontFamily);
const getFastTextWidth = function(
textElement, fontSize, fontWeight, fontFamily) {
return getFastTextWidthWithSizeString(
textElement, fontSize + 'pt', fontWeight, fontFamily);
};

/**
Expand All @@ -314,41 +314,40 @@ Blockly.utils.dom.getFastTextWidth = function(textElement,
* @param {string} fontFamily The font family to use.
* @return {number} Width of element.
*/
Blockly.utils.dom.getFastTextWidthWithSizeString = function(textElement,
fontSize, fontWeight, fontFamily) {
var text = textElement.textContent;
var key = text + '\n' + textElement.className.baseVal;
var width;
const getFastTextWidthWithSizeString = function(
textElement, fontSize, fontWeight, fontFamily) {
const text = textElement.textContent;
const key = text + '\n' + textElement.className.baseVal;
let width;

// Return the cached width if it exists.
if (Blockly.utils.dom.cacheWidths_) {
width = Blockly.utils.dom.cacheWidths_[key];
if (cacheWidths) {
width = cacheWidths[key];
if (width) {
return width;
}
}

if (!Blockly.utils.dom.canvasContext_) {
if (!canvasContext) {
// Inject the canvas element used for computing text widths.
var computeCanvas = document.createElement('canvas');
const computeCanvas = document.createElement('canvas');
computeCanvas.className = 'blocklyComputeCanvas';
document.body.appendChild(computeCanvas);

// Initialize the HTML canvas context and set the font.
// The context font must match blocklyText's fontsize and font-family
// set in CSS.
Blockly.utils.dom.canvasContext_ = computeCanvas.getContext('2d');
canvasContext = computeCanvas.getContext('2d');
}
// Set the desired font size and family.
Blockly.utils.dom.canvasContext_.font =
fontWeight + ' ' + fontSize + ' ' + fontFamily;
canvasContext.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;

// Measure the text width using the helper canvas context.
width = Blockly.utils.dom.canvasContext_.measureText(text).width;
width = canvasContext.measureText(text).width;

// Cache the computed width and return.
if (Blockly.utils.dom.cacheWidths_) {
Blockly.utils.dom.cacheWidths_[key] = width;
if (cacheWidths) {
cacheWidths[key] = width;
}
return width;
};
Expand All @@ -361,18 +360,16 @@ Blockly.utils.dom.getFastTextWidthWithSizeString = function(textElement,
* @param {string} fontFamily The font family to use.
* @return {{height: number, baseline: number}} Font measurements.
*/
Blockly.utils.dom.measureFontMetrics = function(text, fontSize, fontWeight,
fontFamily) {

var span = document.createElement('span');
const measureFontMetrics = function(text, fontSize, fontWeight, fontFamily) {
const span = document.createElement('span');
span.style.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;
span.textContent = text;

var block = document.createElement('div');
const block = document.createElement('div');
block.style.width = '1px';
block.style.height = 0;

var div = document.createElement('div');
const div = document.createElement('div');
div.setAttribute('style', 'position: fixed; top: 0; left: 0; display: flex;');
div.appendChild(span);
div.appendChild(block);
Expand All @@ -389,3 +386,25 @@ Blockly.utils.dom.measureFontMetrics = function(text, fontSize, fontWeight,
}
return result;
};

exports = {
SVG_NS,
HTML_NS,
XLINK_NS,
NodeType,
createSvgElement,
addClass,
removeClasses,
removeClass,
hasClass,
removeNode,
insertAfter,
containsNode,
setCssTransform,
startTextWidthCache,
stopTextWidthCache,
getTextWidth,
getFastTextWidth,
getFastTextWidthWithSizeString,
measureFontMetrics,
};
2 changes: 1 addition & 1 deletion tests/deps.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.