sidebar_hover.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Sanity-check the conversion and remove this comment.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS102: Remove unnecessary code created because of implicit returns
  6. * DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining
  7. * DS206: Consider reworking classes to avoid initClass
  8. * DS207: Consider shorter variations of null checks
  9. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  10. */
  11. app.views.SidebarHover = class SidebarHover extends app.View {
  12. static initClass() {
  13. this.itemClass = "_list-hover";
  14. this.events = {
  15. focus: "onFocus",
  16. blur: "onBlur",
  17. mouseover: "onMouseover",
  18. mouseout: "onMouseout",
  19. scroll: "onScroll",
  20. click: "onClick",
  21. };
  22. this.routes = { after: "onRoute" };
  23. }
  24. constructor(el) {
  25. super(el);
  26. if (!isPointerEventsSupported()) {
  27. delete this.constructor.events.mouseover;
  28. }
  29. }
  30. show(el) {
  31. if (el !== this.cursor) {
  32. this.hide();
  33. if (this.isTarget(el) && this.isTruncated(el.lastElementChild || el)) {
  34. this.cursor = el;
  35. this.clone = this.makeClone(this.cursor);
  36. $.append(document.body, this.clone);
  37. if (this.offsetTop == null) {
  38. this.offsetTop = this.el.offsetTop;
  39. }
  40. this.position();
  41. }
  42. }
  43. }
  44. hide() {
  45. if (this.cursor) {
  46. $.remove(this.clone);
  47. this.cursor = this.clone = null;
  48. }
  49. }
  50. position() {
  51. if (this.cursor) {
  52. const rect = $.rect(this.cursor);
  53. if (rect.top >= this.offsetTop) {
  54. this.clone.style.top = rect.top + "px";
  55. this.clone.style.left = rect.left + "px";
  56. } else {
  57. this.hide();
  58. }
  59. }
  60. }
  61. makeClone(el) {
  62. const clone = el.cloneNode(true);
  63. clone.classList.add("clone");
  64. return clone;
  65. }
  66. isTarget(el) {
  67. return __guard__(el != null ? el.classList : undefined, (x) =>
  68. x.contains(this.constructor.itemClass),
  69. );
  70. }
  71. isSelected(el) {
  72. return el.classList.contains("active");
  73. }
  74. isTruncated(el) {
  75. return el.scrollWidth > el.offsetWidth;
  76. }
  77. onFocus(event) {
  78. this.focusTime = Date.now();
  79. this.show(event.target);
  80. }
  81. onBlur() {
  82. this.hide();
  83. }
  84. onMouseover(event) {
  85. if (
  86. this.isTarget(event.target) &&
  87. !this.isSelected(event.target) &&
  88. this.mouseActivated()
  89. ) {
  90. this.show(event.target);
  91. }
  92. }
  93. onMouseout(event) {
  94. if (this.isTarget(event.target) && this.mouseActivated()) {
  95. this.hide();
  96. }
  97. }
  98. mouseActivated() {
  99. // Skip mouse events caused by focus events scrolling the sidebar.
  100. return !this.focusTime || Date.now() - this.focusTime > 500;
  101. }
  102. onScroll() {
  103. this.position();
  104. }
  105. onClick(event) {
  106. if (event.target === this.clone) {
  107. $.click(this.cursor);
  108. }
  109. }
  110. onRoute() {
  111. this.hide();
  112. }
  113. };
  114. app.views.SidebarHover.initClass();
  115. var isPointerEventsSupported = function () {
  116. const el = document.createElement("div");
  117. el.style.cssText = "pointer-events: auto";
  118. return el.style.pointerEvents === "auto";
  119. };
  120. function __guard__(value, transform) {
  121. return typeof value !== "undefined" && value !== null
  122. ? transform(value)
  123. : undefined;
  124. }