UNPKG

@elastic/eui

Version:

Elastic UI Component Library

255 lines (251 loc) 11.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.TruncationUtils = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _canvas = require("../../services/canvas"); var _excluded = ["fullText", "ellipsis", "availableWidth"]; function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ /** * Utilities for truncating types at various positions, as well as * determining whether truncation is possible or even necessary. */ var TruncationUtils = exports.TruncationUtils = /*#__PURE__*/function (_CanvasTextUtils) { function TruncationUtils(_ref) { var _this; var fullText = _ref.fullText, ellipsis = _ref.ellipsis, _availableWidth = _ref.availableWidth, rest = (0, _objectWithoutProperties2.default)(_ref, _excluded); (0, _classCallCheck2.default)(this, TruncationUtils); _this = _callSuper(this, TruncationUtils, [rest]); (0, _defineProperty2.default)(_this, "fullText", void 0); (0, _defineProperty2.default)(_this, "ellipsis", void 0); (0, _defineProperty2.default)(_this, "availableWidth", void 0); /** * Performance utilities */ (0, _defineProperty2.default)(_this, "debugPerformance", false); (0, _defineProperty2.default)(_this, "debugCounter", 0); /** * Internal utils for calculating a ratio based on the passed available width * vs the full text width. * This ratio is used to get an initial _approximate_ text string that should * be slightly over the available width, which we can then remove from * character-by-character until the text just fits within the available width. */ (0, _defineProperty2.default)(_this, "widthRatio", 0); (0, _defineProperty2.default)(_this, "setTextWidthRatio", function () { var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.fullText; var textToOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; // Account for reduced available width due to (e.g.) truncation offset var availableWidth = _this.availableWidth; if (textToOffset) { _this.setTextToCheck(textToOffset); availableWidth = availableWidth - _this.textWidth; } _this.setTextToCheck(text); _this.widthRatio = availableWidth / _this.textWidth; }); (0, _defineProperty2.default)(_this, "getTextFromRatio", function (text, type) { var characterRatio = Math.ceil(text.length * _this.widthRatio); var index = type === 'start' ? text.length - characterRatio : characterRatio; var _splitText$at = splitText(text).at(index), _splitText$at2 = (0, _slicedToArray2.default)(_splitText$at, 2), end = _splitText$at2[0], start = _splitText$at2[1]; return type === 'start' ? start : end; }); /** * Early return checks */ (0, _defineProperty2.default)(_this, "checkIfTruncationIsNeeded", function () { _this.setTextToCheck(_this.fullText); if (_this.availableWidth >= _this.textWidth) { return false; } }); (0, _defineProperty2.default)(_this, "checkSufficientEllipsisWidth", function (truncation) { var textToCheck = truncation === 'startEnd' ? "".concat(_this.ellipsis, " ").concat(_this.ellipsis) // startEnd needs a little more space : _this.ellipsis; _this.setTextToCheck(textToCheck); if (_this.textWidth >= _this.availableWidth * 0.9) { console.error('The truncation ellipsis is larger than the available width. No text can be rendered.'); return false; } }); (0, _defineProperty2.default)(_this, "checkTruncationOffsetWidth", function (text) { _this.setTextToCheck(text); if (_this.textWidth > _this.availableWidth) { console.error('The passed truncationOffset is too large for the available width. Truncating the offset instead.'); return false; } }); /** * Truncation types logic. This is where the magic happens */ (0, _defineProperty2.default)(_this, "truncateStart", function (truncationOffset) { var truncatedText = _this.fullText; var leadingText = ''; var combinedText = function combinedText() { return leadingText + truncatedText; }; if (truncationOffset) { var _splitText$at3 = splitText(_this.fullText).at(truncationOffset); var _splitText$at4 = (0, _slicedToArray2.default)(_splitText$at3, 2); leadingText = _splitText$at4[0]; truncatedText = _splitText$at4[1]; var widthCheck = leadingText + _this.ellipsis; if (_this.checkTruncationOffsetWidth(widthCheck) === false) { truncatedText = leadingText; leadingText = ''; } } // Get text width ratio width accounting for any truncation offset text, // and guesstimate an initial truncated string _this.setTextWidthRatio(truncatedText, leadingText); truncatedText = _this.getTextFromRatio(truncatedText, 'start'); leadingText += _this.ellipsis; _this.setTextToCheck(combinedText()); while (_this.textWidth > _this.availableWidth) { truncatedText = removeFirstCharacter(truncatedText); _this.setTextToCheck(combinedText()); } return combinedText(); }); (0, _defineProperty2.default)(_this, "truncateEnd", function (truncationOffset) { var truncatedText = _this.fullText; var trailingText = ''; var combinedText = function combinedText() { return truncatedText + trailingText; }; if (truncationOffset) { var index = _this.fullText.length - truncationOffset; var _splitText$at5 = splitText(_this.fullText).at(index); var _splitText$at6 = (0, _slicedToArray2.default)(_splitText$at5, 2); truncatedText = _splitText$at6[0]; trailingText = _splitText$at6[1]; var widthCheck = _this.ellipsis + trailingText; if (_this.checkTruncationOffsetWidth(widthCheck) === false) { truncatedText = trailingText; trailingText = ''; } } // Get text width ratio width accounting for any truncation offset text, // and guesstimate an initial truncated string _this.setTextWidthRatio(truncatedText, trailingText); truncatedText = _this.getTextFromRatio(truncatedText, 'end'); trailingText = _this.ellipsis + trailingText; _this.setTextToCheck(combinedText()); while (_this.textWidth > _this.availableWidth) { truncatedText = removeLastCharacter(truncatedText); _this.setTextToCheck(combinedText()); } return combinedText(); }); (0, _defineProperty2.default)(_this, "truncateStartEndAtPosition", function (truncationPosition) { // Split the text from the anchor position, using the width ratio // to get the starting and ending indices from the position _this.setTextWidthRatio(); var characterRatio = Math.floor(_this.fullText.length * _this.widthRatio / 2); var truncateStart = truncationPosition - characterRatio; var truncateEnd = truncationPosition + characterRatio; // If either of the approximate start/end truncation indices go beyond the // bounds of the actual text, we can simply use end or start truncation instead if (truncateStart < 0) { return _this.truncateEnd(); } if (truncateEnd >= _this.fullText.length) { return _this.truncateStart(); } var truncatedText = _this.fullText.substring(truncateStart, truncateEnd); var combinedText = function combinedText() { return _this.ellipsis + truncatedText + _this.ellipsis; }; _this.setTextToCheck(combinedText()); var alternating; while (_this.textWidth > _this.availableWidth) { truncatedText = alternating ? removeLastCharacter(truncatedText) : removeFirstCharacter(truncatedText); alternating = !alternating; _this.setTextToCheck(combinedText()); } return combinedText(); }); (0, _defineProperty2.default)(_this, "truncateStartEndAtMiddle", function () { var middlePosition = Math.floor(_this.fullText.length / 2); return _this.truncateStartEndAtPosition(middlePosition); }); (0, _defineProperty2.default)(_this, "truncateMiddle", function () { var middlePosition = Math.floor(_this.fullText.length / 2); var _splitText$at7 = splitText(_this.fullText).at(middlePosition), _splitText$at8 = (0, _slicedToArray2.default)(_splitText$at7, 2), firstHalf = _splitText$at8[0], secondHalf = _splitText$at8[1]; _this.setTextWidthRatio(); firstHalf = _this.getTextFromRatio(firstHalf, 'end'); secondHalf = _this.getTextFromRatio(secondHalf, 'start'); var combinedText = function combinedText() { return firstHalf + _this.ellipsis + secondHalf; }; _this.setTextToCheck(combinedText()); var alternating; while (_this.textWidth > _this.availableWidth) { alternating = !alternating; if (alternating) { firstHalf = removeLastCharacter(firstHalf); } else { secondHalf = removeFirstCharacter(secondHalf); } _this.setTextToCheck(combinedText()); } return combinedText(); }); _this.fullText = fullText; _this.ellipsis = ellipsis; _this.availableWidth = _availableWidth; return _this; } (0, _inherits2.default)(TruncationUtils, _CanvasTextUtils); return (0, _createClass2.default)(TruncationUtils, [{ key: "textWidth", get: function get() { if (this.debugPerformance) { this.debugCounter++; } return (0, _get2.default)((0, _getPrototypeOf2.default)(TruncationUtils.prototype), "textWidth", this); } }]); }(_canvas.CanvasTextUtils); /** * DRY character/substring utils */ var removeLastCharacter = function removeLastCharacter(text) { return text.substring(0, text.length - 1); }; var removeFirstCharacter = function removeFirstCharacter(text) { return text.substring(1); }; var splitText = function splitText(text) { return { at: function at(index) { return [text.substring(0, index), text.substring(index)]; } }; };