Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/components/Linkifier.js

Issue 2644753002: DevTools: untruncate links on copy (Closed)
Patch Set: simpler Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 * @param {!Element} anchor 296 * @param {!Element} anchor
297 * @param {!Bindings.LiveLocation} liveLocation 297 * @param {!Bindings.LiveLocation} liveLocation
298 */ 298 */
299 _updateAnchor(anchor, liveLocation) { 299 _updateAnchor(anchor, liveLocation) {
300 Components.Linkifier._unbindUILocation(anchor); 300 Components.Linkifier._unbindUILocation(anchor);
301 var uiLocation = liveLocation.uiLocation(); 301 var uiLocation = liveLocation.uiLocation();
302 if (!uiLocation) 302 if (!uiLocation)
303 return; 303 return;
304 304
305 Components.Linkifier._bindUILocation(anchor, uiLocation); 305 Components.Linkifier._bindUILocation(anchor, uiLocation);
306 var text = uiLocation.linkText(); 306 var text = uiLocation.linkText(true /* skipTrim */);
307 var info = Components.Linkifier._linkInfo(anchor); 307 Components.Linkifier._setTrimmedText(anchor, text, true /* trimHashes */, th is._maxLength);
308 info.originalLinkText = text;
309 text = text.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g, '$1\u2026');
310 if (this._maxLength)
311 text = text.trimMiddle(this._maxLength);
312 anchor.textContent = text;
313 308
314 var titleText = uiLocation.uiSourceCode.url(); 309 var titleText = uiLocation.uiSourceCode.url();
315 if (typeof uiLocation.lineNumber === 'number') 310 if (typeof uiLocation.lineNumber === 'number')
316 titleText += ':' + (uiLocation.lineNumber + 1); 311 titleText += ':' + (uiLocation.lineNumber + 1);
317 anchor.title = titleText; 312 anchor.title = titleText;
318 anchor.classList.toggle('webkit-html-blackbox-link', liveLocation.isBlackbox ed()); 313 anchor.classList.toggle('webkit-html-blackbox-link', liveLocation.isBlackbox ed());
319 Components.Linkifier._updateLinkDecorations(anchor); 314 Components.Linkifier._updateLinkDecorations(anchor);
320 } 315 }
321 316
322 /** 317 /**
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 * @param {boolean=} preventClick 384 * @param {boolean=} preventClick
390 * @returns{!Element} 385 * @returns{!Element}
391 */ 386 */
392 static _createLink(text, className, maxLength, title, href, preventClick) { 387 static _createLink(text, className, maxLength, title, href, preventClick) {
393 var link = createElementWithClass('span', className); 388 var link = createElementWithClass('span', className);
394 link.classList.add('devtools-link'); 389 link.classList.add('devtools-link');
395 if (title) 390 if (title)
396 link.title = title; 391 link.title = title;
397 if (href) 392 if (href)
398 link.href = href; 393 link.href = href;
399 link.textContent = text; 394 Components.Linkifier._setTrimmedText(link, text, false /* trimHashes */, max Length);
lushnikov 2017/04/22 01:11:48 can we always trim hashes?
luoe 2017/04/22 05:43:16 I'm all for consistency! Tried it out and it seem
400 if (maxLength)
401 link.textContent = link.textContent.trimMiddle(maxLength);
402 link[Components.Linkifier._infoSymbol] = { 395 link[Components.Linkifier._infoSymbol] = {
403 icon: null, 396 icon: null,
404 enableDecorator: false, 397 enableDecorator: false,
405 uiLocation: null, 398 uiLocation: null,
406 liveLocation: null, 399 liveLocation: null,
407 url: href || null, 400 url: href || null,
408 lineNumber: null, 401 lineNumber: null,
409 columnNumber: null, 402 columnNumber: null,
410 revealable: null, 403 revealable: null,
411 fallback: null, 404 fallback: null
412 originalLinkText: text
413 }; 405 };
414 if (!preventClick) 406 if (!preventClick)
415 link.addEventListener('click', Components.Linkifier._handleClick, false); 407 link.addEventListener('click', Components.Linkifier._handleClick, false);
416 else 408 else
417 link.classList.add('devtools-link-prevent-click'); 409 link.classList.add('devtools-link-prevent-click');
418 return link; 410 return link;
419 } 411 }
420 412
421 /** 413 /**
422 * @param {?Element} link 414 * @param {!Element} link
423 * @return {?string} 415 * @param {string} text
416 * @param {boolean=} trimHashes
417 * @param {number=} maxLength
424 */ 418 */
425 static originalLinkText(link) { 419 static _setTrimmedText(link, text, trimHashes, maxLength) {
426 var info = this._linkInfo(link); 420 // Find the indices which define the hidden substring.
427 return info ? info.originalLinkText : null; 421 var hiddenIndices = [Math.floor(text.length / 2), Math.floor(text.length / 2 )];
422 if (maxLength && text.length > maxLength) {
423 var maxLengthIndices = middleTruncatedIndices(text, maxLength);
424 hiddenIndices[0] = Math.min(hiddenIndices[0], maxLengthIndices[0]);
425 hiddenIndices[1] = Math.max(hiddenIndices[1], maxLengthIndices[1]);
426 }
427 if (trimHashes) {
428 var hashIndices = hashTruncatedIndices(text);
429 hiddenIndices[0] = Math.min(hiddenIndices[0], hashIndices[0]);
430 hiddenIndices[1] = Math.max(hiddenIndices[1], hashIndices[1]);
lushnikov 2017/04/22 01:11:48 in case of: 1. text.length < maxLength 2. text has
luoe 2017/04/22 05:43:16 I see, so my "max/min from the center" approach do
431 }
432 var leftIndex = hiddenIndices[0];
433 var rightIndex = hiddenIndices[1];
434
435 if (leftIndex < rightIndex) {
436 link.removeChildren();
437 link.createTextChild(text.substr(0, leftIndex));
lushnikov 2017/04/22 01:11:48 nit: text.substring(0, leftIndex) we try to use s
luoe 2017/04/22 05:43:16 Done.
438 var ellipsisNode = link.createChild('span', 'devtools-link-ellipsis').crea teTextChild('\u200B');
439 ellipsisNode[Components.Linkifier._untruncatedNodeTextSymbol] = text.subst r(leftIndex, rightIndex - leftIndex);
440 link.createTextChild(text.substr(rightIndex, text.length - rightIndex));
lushnikov 2017/04/22 01:11:48 nit: text.substring(rightIndex)
luoe 2017/04/22 05:43:16 Done.
441 } else {
442 link.textContent = text;
443 }
444
445 /**
446 * @param {string} text
447 * @param {number} maxLength
448 * @return {!Array<number>}
449 */
450 function middleTruncatedIndices(text, maxLength) {
451 var leftIndex = Math.floor(maxLength / 2);
452 var rightIndex = text.length - Math.ceil(maxLength / 2) + 1;
453
454 // Do not truncate between characters that use multiple code points (emoji s).
455 if (text.codePointAt(rightIndex - 1) >= 0x10000) {
456 rightIndex++;
457 leftIndex++;
458 }
459 if (leftIndex > 0 && text.codePointAt(leftIndex - 1) >= 0x10000)
460 leftIndex--;
461 return [leftIndex, rightIndex];
462 }
463
464 /**
465 * @param {string} text
466 * @return {!Array<number>}
467 */
468 function hashTruncatedIndices(text) {
469 var leftIndex = text.length;
470 var rightIndex = 0;
471 var hashRegex = /[a-f0-9]{20,}/g;
472 var match = hashRegex.exec(text);
473 while (match !== null) {
474 leftIndex = Math.min(leftIndex, match.index + 7);
475 rightIndex = Math.max(rightIndex, match.index + match[0].length);
476 match = hashRegex.exec(text);
477 }
478 return [leftIndex, rightIndex];
479 }
428 } 480 }
429 481
430 /** 482 /**
483 * @param {!Node} node
484 * @return {string}
485 */
486 static untruncatedNodeText(node) {
487 return node[Components.Linkifier._untruncatedNodeTextSymbol] || node.textCon tent;
488 }
489
490 /**
431 * @param {?Element} link 491 * @param {?Element} link
432 * @return {?Components._LinkInfo} 492 * @return {?Components._LinkInfo}
433 */ 493 */
434 static _linkInfo(link) { 494 static _linkInfo(link) {
435 return /** @type {?Components._LinkInfo} */ (link ? link[Components.Linkifie r._infoSymbol] || null : null); 495 return /** @type {?Components._LinkInfo} */ (link ? link[Components.Linkifie r._infoSymbol] || null : null);
436 } 496 }
437 497
438 /** 498 /**
439 * @param {!Event} event 499 * @param {!Event} event
440 */ 500 */
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 } 602 }
543 }; 603 };
544 604
545 /** @type {!Set<!Components.Linkifier>} */ 605 /** @type {!Set<!Components.Linkifier>} */
546 Components.Linkifier._instances = new Set(); 606 Components.Linkifier._instances = new Set();
547 /** @type {?Components.LinkDecorator} */ 607 /** @type {?Components.LinkDecorator} */
548 Components.Linkifier._decorator = null; 608 Components.Linkifier._decorator = null;
549 609
550 Components.Linkifier._sourceCodeAnchors = Symbol('Linkifier.anchors'); 610 Components.Linkifier._sourceCodeAnchors = Symbol('Linkifier.anchors');
551 Components.Linkifier._infoSymbol = Symbol('Linkifier.info'); 611 Components.Linkifier._infoSymbol = Symbol('Linkifier.info');
612 Components.Linkifier._untruncatedNodeTextSymbol = Symbol('Linkifier.untruncatedN odeText');
552 613
553 /** 614 /**
554 * @typedef {{ 615 * @typedef {{
555 * icon: ?UI.Icon, 616 * icon: ?UI.Icon,
556 * enableDecorator: boolean, 617 * enableDecorator: boolean,
557 * uiLocation: ?Workspace.UILocation, 618 * uiLocation: ?Workspace.UILocation,
558 * liveLocation: ?Bindings.LiveLocation, 619 * liveLocation: ?Bindings.LiveLocation,
559 * url: ?string, 620 * url: ?string,
560 * lineNumber: ?number, 621 * lineNumber: ?number,
561 * columnNumber: ?number, 622 * columnNumber: ?number,
562 * revealable: ?Object, 623 * revealable: ?Object,
563 * fallback: ?Element, 624 * fallback: ?Element
564 * originalLinkText: string
565 * }} 625 * }}
566 */ 626 */
567 Components._LinkInfo; 627 Components._LinkInfo;
568 628
569 /** 629 /**
570 * The maximum length before strings are considered too long for finding URLs. 630 * The maximum length before strings are considered too long for finding URLs.
571 * @const 631 * @const
572 * @type {number} 632 * @type {number}
573 */ 633 */
574 Components.Linkifier.MaxLengthToIgnoreLinkifier = 10000; 634 Components.Linkifier.MaxLengthToIgnoreLinkifier = 10000;
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
780 contextMenu.appendSeparator(); 840 contextMenu.appendSeparator();
781 contextMenu.appendItem(Common.UIString('Save'), save.bind(null, false)); 841 contextMenu.appendItem(Common.UIString('Save'), save.bind(null, false));
782 842
783 if (contentProvider instanceof Workspace.UISourceCode) { 843 if (contentProvider instanceof Workspace.UISourceCode) {
784 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (contentProvider ); 844 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (contentProvider );
785 if (!uiSourceCode.project().canSetFileContent()) 845 if (!uiSourceCode.project().canSetFileContent())
786 contextMenu.appendItem(Common.UIString.capitalize('Save ^as...'), save.b ind(null, true)); 846 contextMenu.appendItem(Common.UIString.capitalize('Save ^as...'), save.b ind(null, true));
787 } 847 }
788 } 848 }
789 }; 849 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698