UNPKG

8.52 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _typeof = require("@babel/runtime/helpers/typeof");
6
7Object.defineProperty(exports, "__esModule", {
8 value: true
9});
10exports["default"] = void 0;
11
12var _reactDom = require("react-dom");
13
14var React = _interopRequireWildcard(require("react"));
15
16var _toArray = _interopRequireDefault(require("rc-util/lib/Children/toArray"));
17
18function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
19
20function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
21
22// We only handle element & text node.
23var ELEMENT_NODE = 1;
24var TEXT_NODE = 3;
25var COMMENT_NODE = 8;
26var ellipsisContainer;
27var wrapperStyle = {
28 padding: 0,
29 margin: 0,
30 display: 'inline',
31 lineHeight: 'inherit'
32};
33
34function pxToNumber(value) {
35 if (!value) return 0;
36 var match = value.match(/^\d*(\.\d*)?/);
37 return match ? Number(match[0]) : 0;
38}
39
40function styleToString(style) {
41 // There are some different behavior between Firefox & Chrome.
42 // We have to handle this ourself.
43 var styleNames = Array.prototype.slice.apply(style);
44 return styleNames.map(function (name) {
45 return "".concat(name, ": ").concat(style.getPropertyValue(name), ";");
46 }).join('');
47}
48
49function mergeChildren(children) {
50 var childList = [];
51 children.forEach(function (child) {
52 var prevChild = childList[childList.length - 1];
53
54 if (typeof child === 'string' && typeof prevChild === 'string') {
55 childList[childList.length - 1] += child;
56 } else {
57 childList.push(child);
58 }
59 });
60 return childList;
61}
62
63var _default = function _default(originEle, option, content, fixedContent, ellipsisStr) {
64 if (!ellipsisContainer) {
65 ellipsisContainer = document.createElement('div');
66 ellipsisContainer.setAttribute('aria-hidden', 'true');
67 } // HMR will remove this from body which should patch back
68
69
70 if (!ellipsisContainer.parentNode) {
71 document.body.appendChild(ellipsisContainer);
72 }
73
74 var rows = option.rows,
75 _option$suffix = option.suffix,
76 suffix = _option$suffix === void 0 ? '' : _option$suffix; // Get origin style
77
78 var originStyle = window.getComputedStyle(originEle);
79 var originCSS = styleToString(originStyle);
80 var lineHeight = pxToNumber(originStyle.lineHeight);
81 var maxHeight = Math.floor(lineHeight) * (rows + 1) + pxToNumber(originStyle.paddingTop) + pxToNumber(originStyle.paddingBottom); // Set shadow
82
83 ellipsisContainer.setAttribute('style', originCSS);
84 ellipsisContainer.style.position = 'fixed';
85 ellipsisContainer.style.left = '0';
86 ellipsisContainer.style.height = 'auto';
87 ellipsisContainer.style.minHeight = 'auto';
88 ellipsisContainer.style.maxHeight = 'auto';
89 ellipsisContainer.style.top = '-999999px';
90 ellipsisContainer.style.zIndex = '-1000'; // clean up css overflow
91
92 ellipsisContainer.style.textOverflow = 'clip';
93 ellipsisContainer.style.whiteSpace = 'normal';
94 ellipsisContainer.style.webkitLineClamp = 'none'; // Render in the fake container
95
96 var contentList = mergeChildren((0, _toArray["default"])(content));
97 (0, _reactDom.render)( /*#__PURE__*/React.createElement("div", {
98 style: wrapperStyle
99 }, /*#__PURE__*/React.createElement("span", {
100 style: wrapperStyle
101 }, contentList, suffix), /*#__PURE__*/React.createElement("span", {
102 style: wrapperStyle
103 }, fixedContent)), ellipsisContainer); // wrap in an div for old version react
104 // Check if ellipsis in measure div is height enough for content
105
106 function inRange() {
107 return ellipsisContainer.offsetHeight < maxHeight;
108 } // Skip ellipsis if already match
109
110
111 if (inRange()) {
112 (0, _reactDom.unmountComponentAtNode)(ellipsisContainer);
113 return {
114 content: content,
115 text: ellipsisContainer.innerHTML,
116 ellipsis: false
117 };
118 } // We should clone the childNode since they're controlled by React and we can't reuse it without warning
119
120
121 var childNodes = Array.prototype.slice.apply(ellipsisContainer.childNodes[0].childNodes[0].cloneNode(true).childNodes).filter(function (_ref) {
122 var nodeType = _ref.nodeType;
123 return nodeType !== COMMENT_NODE;
124 });
125 var fixedNodes = Array.prototype.slice.apply(ellipsisContainer.childNodes[0].childNodes[1].cloneNode(true).childNodes);
126 (0, _reactDom.unmountComponentAtNode)(ellipsisContainer); // ========================= Find match ellipsis content =========================
127
128 var ellipsisChildren = [];
129 ellipsisContainer.innerHTML = ''; // Create origin content holder
130
131 var ellipsisContentHolder = document.createElement('span');
132 ellipsisContainer.appendChild(ellipsisContentHolder);
133 var ellipsisTextNode = document.createTextNode(ellipsisStr + suffix);
134 ellipsisContentHolder.appendChild(ellipsisTextNode);
135 fixedNodes.forEach(function (childNode) {
136 ellipsisContainer.appendChild(childNode);
137 }); // Append before fixed nodes
138
139 function appendChildNode(node) {
140 ellipsisContentHolder.insertBefore(node, ellipsisTextNode);
141 } // Get maximum text
142
143
144 function measureText(textNode, fullText) {
145 var startLoc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
146 var endLoc = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : fullText.length;
147 var lastSuccessLoc = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
148 var midLoc = Math.floor((startLoc + endLoc) / 2);
149 var currentText = fullText.slice(0, midLoc);
150 textNode.textContent = currentText;
151
152 if (startLoc >= endLoc - 1) {
153 // Loop when step is small
154 for (var step = endLoc; step >= startLoc; step -= 1) {
155 var currentStepText = fullText.slice(0, step);
156 textNode.textContent = currentStepText;
157
158 if (inRange() || !currentStepText) {
159 return step === fullText.length ? {
160 finished: false,
161 reactNode: fullText
162 } : {
163 finished: true,
164 reactNode: currentStepText
165 };
166 }
167 }
168 }
169
170 if (inRange()) {
171 return measureText(textNode, fullText, midLoc, endLoc, midLoc);
172 }
173
174 return measureText(textNode, fullText, startLoc, midLoc, lastSuccessLoc);
175 }
176
177 function measureNode(childNode, index) {
178 var type = childNode.nodeType;
179
180 if (type === ELEMENT_NODE) {
181 // We don't split element, it will keep if whole element can be displayed.
182 appendChildNode(childNode);
183
184 if (inRange()) {
185 return {
186 finished: false,
187 reactNode: contentList[index]
188 };
189 } // Clean up if can not pull in
190
191
192 ellipsisContentHolder.removeChild(childNode);
193 return {
194 finished: true,
195 reactNode: null
196 };
197 }
198
199 if (type === TEXT_NODE) {
200 var fullText = childNode.textContent || '';
201 var textNode = document.createTextNode(fullText);
202 appendChildNode(textNode);
203 return measureText(textNode, fullText);
204 } // Not handle other type of content
205 // PS: This code should not be attached after react 16
206
207 /* istanbul ignore next */
208
209
210 return {
211 finished: false,
212 reactNode: null
213 };
214 }
215
216 childNodes.some(function (childNode, index) {
217 var _measureNode = measureNode(childNode, index),
218 finished = _measureNode.finished,
219 reactNode = _measureNode.reactNode;
220
221 if (reactNode) {
222 ellipsisChildren.push(reactNode);
223 }
224
225 return finished;
226 });
227 return {
228 content: ellipsisChildren,
229 text: ellipsisContainer.innerHTML,
230 ellipsis: true
231 };
232};
233
234exports["default"] = _default;
\No newline at end of file