diff --git a/core/utils/dom.js b/core/utils/dom.js index 57843c8b9..5ec684acf 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -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, @@ -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} name Element's tag name. + * @param {string|Svg} 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) { e.setAttribute(key, attrs[key]); } // IE defines a unique attribute "runtimeStyle", it is NOT applied to @@ -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') || ''; if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) { return false; } @@ -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]); } }; @@ -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--; @@ -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; }; @@ -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; }; @@ -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.'); } @@ -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); }; /** @@ -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; }; @@ -229,10 +229,10 @@ 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); } }; @@ -240,10 +240,10 @@ Blockly.utils.dom.startTextWidthCache = function() { * 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; } }; @@ -252,13 +252,13 @@ 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; } @@ -266,7 +266,7 @@ Blockly.utils.dom.getTextWidth = function(textElement) { // 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(); @@ -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; }; @@ -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); }; /** @@ -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; }; @@ -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); @@ -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, +}; diff --git a/tests/deps.js b/tests/deps.js index 59f2bceee..20fb4e48e 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -179,7 +179,7 @@ goog.addDependency('../../core/utils/aria.js', ['Blockly.utils.aria'], []); goog.addDependency('../../core/utils/colour.js', ['Blockly.utils.colour'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/coordinate.js', ['Blockly.utils.Coordinate'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/deprecation.js', ['Blockly.utils.deprecation'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/utils/dom.js', ['Blockly.utils.dom'], ['Blockly.utils.Svg', 'Blockly.utils.userAgent']); +goog.addDependency('../../core/utils/dom.js', ['Blockly.utils.dom'], ['Blockly.utils.Svg', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/global.js', ['Blockly.utils.global'], []); goog.addDependency('../../core/utils/idgenerator.js', ['Blockly.utils.IdGenerator'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/keycodes.js', ['Blockly.utils.KeyCodes'], [], {'lang': 'es6', 'module': 'goog'});