UNPKG

@elastic/eui

Version:

Elastic UI Component Library

267 lines (263 loc) 15.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TruncationUtils = void 0; var _canvas = require("../../services/canvas"); var _excluded = ["fullText", "ellipsis", "availableWidth"]; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _get() { return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) { var p = _superPropBase(e, t); if (p) { var n = Object.getOwnPropertyDescriptor(p, t); return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value; } }, _get.apply(null, arguments); } function _superPropBase(t, o) { for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t));); return t; } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(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 = _objectWithoutProperties(_ref, _excluded); _classCallCheck(this, TruncationUtils); _this = _callSuper(this, TruncationUtils, [rest]); _defineProperty(_this, "fullText", void 0); _defineProperty(_this, "ellipsis", void 0); _defineProperty(_this, "availableWidth", void 0); /** * Performance utilities */ _defineProperty(_this, "debugPerformance", false); _defineProperty(_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. */ _defineProperty(_this, "widthRatio", 0); _defineProperty(_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; }); _defineProperty(_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 = _slicedToArray(_splitText$at, 2), end = _splitText$at2[0], start = _splitText$at2[1]; return type === 'start' ? start : end; }); /** * Early return checks */ _defineProperty(_this, "checkIfTruncationIsNeeded", function () { _this.setTextToCheck(_this.fullText); if (_this.availableWidth >= _this.textWidth) { return false; } }); _defineProperty(_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; } }); _defineProperty(_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 */ _defineProperty(_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 = _slicedToArray(_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(); }); _defineProperty(_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 = _slicedToArray(_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(); }); _defineProperty(_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(); }); _defineProperty(_this, "truncateStartEndAtMiddle", function () { var middlePosition = Math.floor(_this.fullText.length / 2); return _this.truncateStartEndAtPosition(middlePosition); }); _defineProperty(_this, "truncateMiddle", function () { var middlePosition = Math.floor(_this.fullText.length / 2); var _splitText$at7 = splitText(_this.fullText).at(middlePosition), _splitText$at8 = _slicedToArray(_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; } _inherits(TruncationUtils, _CanvasTextUtils); return _createClass(TruncationUtils, [{ key: "textWidth", get: function get() { if (this.debugPerformance) { this.debugCounter++; } return _get(_getPrototypeOf(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)]; } }; };