"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const browser = require("../../browser.js");
const dnd = require("../../dnd.js");
const dom = require("../../dom.js");
const event$1 = require("../../event.js");
const touch = require("../../touch.js");
const scrollableElement = require("../scrollbar/scrollableElement.js");
const arrays = require("../../../common/arrays.js");
const async = require("../../../common/async.js");
const decorators = require("../../../common/decorators.js");
const event = require("../../../common/event.js");
const lifecycle = require("../../../common/lifecycle.js");
const objects = require("../../../common/objects.js");
const range = require("../../../common/range.js");
const scrollable = require("../../../common/scrollable.js");
const rangeMap = require("./rangeMap.js");
const rowCache = require("./rowCache.js");
var __decorate = globalThis && globalThis.__decorate || function(decorators2, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators2, target, key, desc);
  else
    for (var i = decorators2.length - 1; i >= 0; i--)
      if (d = decorators2[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const DefaultOptions = {
  useShadows: true,
  verticalScrollMode: 1,
  setRowLineHeight: true,
  setRowHeight: true,
  supportDynamicHeights: false,
  dnd: {
    getDragElements(e) {
      return [e];
    },
    getDragURI() {
      return null;
    },
    onDragStart() {
    },
    onDragOver() {
      return false;
    },
    drop() {
    }
  },
  horizontalScrolling: false,
  transformOptimization: true,
  alwaysConsumeMouseWheel: true
};
class ElementsDragAndDropData {
  constructor(elements) {
    this.elements = elements;
  }
  update() {
  }
  getData() {
    return this.elements;
  }
}
class ExternalElementsDragAndDropData {
  constructor(elements) {
    this.elements = elements;
  }
  update() {
  }
  getData() {
    return this.elements;
  }
}
class NativeDragAndDropData {
  constructor() {
    this.types = [];
    this.files = [];
  }
  update(dataTransfer) {
    if (dataTransfer.types) {
      this.types.splice(0, this.types.length, ...dataTransfer.types);
    }
    if (dataTransfer.files) {
      this.files.splice(0, this.files.length);
      for (let i = 0; i < dataTransfer.files.length; i++) {
        const file = dataTransfer.files.item(i);
        if (file && (file.size || file.type)) {
          this.files.push(file);
        }
      }
    }
  }
  getData() {
    return {
      types: this.types,
      files: this.files
    };
  }
}
function equalsDragFeedback(f1, f2) {
  if (Array.isArray(f1) && Array.isArray(f2)) {
    return arrays.equals(f1, f2);
  }
  return f1 === f2;
}
class ListViewAccessibilityProvider {
  constructor(accessibilityProvider) {
    if (accessibilityProvider === null || accessibilityProvider === void 0 ? void 0 : accessibilityProvider.getSetSize) {
      this.getSetSize = accessibilityProvider.getSetSize.bind(accessibilityProvider);
    } else {
      this.getSetSize = (e, i, l) => l;
    }
    if (accessibilityProvider === null || accessibilityProvider === void 0 ? void 0 : accessibilityProvider.getPosInSet) {
      this.getPosInSet = accessibilityProvider.getPosInSet.bind(accessibilityProvider);
    } else {
      this.getPosInSet = (e, i) => i + 1;
    }
    if (accessibilityProvider === null || accessibilityProvider === void 0 ? void 0 : accessibilityProvider.getRole) {
      this.getRole = accessibilityProvider.getRole.bind(accessibilityProvider);
    } else {
      this.getRole = (_) => "listitem";
    }
    if (accessibilityProvider === null || accessibilityProvider === void 0 ? void 0 : accessibilityProvider.isChecked) {
      this.isChecked = accessibilityProvider.isChecked.bind(accessibilityProvider);
    } else {
      this.isChecked = (_) => void 0;
    }
  }
}
class ListView {
  constructor(container, virtualDelegate, renderers, options = DefaultOptions) {
    this.virtualDelegate = virtualDelegate;
    this.domId = `list_id_${++ListView.InstanceCount}`;
    this.renderers = /* @__PURE__ */ new Map();
    this.renderWidth = 0;
    this._scrollHeight = 0;
    this.scrollableElementUpdateDisposable = null;
    this.scrollableElementWidthDelayer = new async.Delayer(50);
    this.splicing = false;
    this.dragOverAnimationStopDisposable = lifecycle.Disposable.None;
    this.dragOverMouseY = 0;
    this.canDrop = false;
    this.currentDragFeedbackDisposable = lifecycle.Disposable.None;
    this.onDragLeaveTimeout = lifecycle.Disposable.None;
    this.disposables = new lifecycle.DisposableStore();
    this._onDidChangeContentHeight = new event.Emitter();
    this._horizontalScrolling = false;
    if (options.horizontalScrolling && options.supportDynamicHeights) {
      throw new Error("Horizontal scrolling and dynamic heights not supported simultaneously");
    }
    this.items = [];
    this.itemId = 0;
    this.rangeMap = new rangeMap.RangeMap();
    for (const renderer of renderers) {
      this.renderers.set(renderer.templateId, renderer);
    }
    this.cache = this.disposables.add(new rowCache.RowCache(this.renderers));
    this.lastRenderTop = 0;
    this.lastRenderHeight = 0;
    this.domNode = document.createElement("div");
    this.domNode.className = "monaco-list";
    this.domNode.classList.add(this.domId);
    this.domNode.tabIndex = 0;
    this.domNode.classList.toggle("mouse-support", typeof options.mouseSupport === "boolean" ? options.mouseSupport : true);
    this._horizontalScrolling = objects.getOrDefault(options, (o) => o.horizontalScrolling, DefaultOptions.horizontalScrolling);
    this.domNode.classList.toggle("horizontal-scrolling", this._horizontalScrolling);
    this.additionalScrollHeight = typeof options.additionalScrollHeight === "undefined" ? 0 : options.additionalScrollHeight;
    this.accessibilityProvider = new ListViewAccessibilityProvider(options.accessibilityProvider);
    this.rowsContainer = document.createElement("div");
    this.rowsContainer.className = "monaco-list-rows";
    const transformOptimization = objects.getOrDefault(options, (o) => o.transformOptimization, DefaultOptions.transformOptimization);
    if (transformOptimization) {
      this.rowsContainer.style.transform = "translate3d(0px, 0px, 0px)";
    }
    this.disposables.add(touch.Gesture.addTarget(this.rowsContainer));
    this.scrollable = new scrollable.Scrollable({
      forceIntegerValues: true,
      smoothScrollDuration: objects.getOrDefault(options, (o) => o.smoothScrolling, false) ? 125 : 0,
      scheduleAtNextAnimationFrame: (cb) => dom.scheduleAtNextAnimationFrame(cb)
    });
    this.scrollableElement = this.disposables.add(new scrollableElement.SmoothScrollableElement(this.rowsContainer, {
      alwaysConsumeMouseWheel: objects.getOrDefault(options, (o) => o.alwaysConsumeMouseWheel, DefaultOptions.alwaysConsumeMouseWheel),
      horizontal: 1,
      vertical: objects.getOrDefault(options, (o) => o.verticalScrollMode, DefaultOptions.verticalScrollMode),
      useShadows: objects.getOrDefault(options, (o) => o.useShadows, DefaultOptions.useShadows),
      mouseWheelScrollSensitivity: options.mouseWheelScrollSensitivity,
      fastScrollSensitivity: options.fastScrollSensitivity
    }, this.scrollable));
    this.domNode.appendChild(this.scrollableElement.getDomNode());
    container.appendChild(this.domNode);
    this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
    this.disposables.add(dom.addDisposableListener(this.rowsContainer, touch.EventType.Change, (e) => this.onTouchChange(e)));
    this.disposables.add(dom.addDisposableListener(this.scrollableElement.getDomNode(), "scroll", (e) => e.target.scrollTop = 0));
    this.disposables.add(dom.addDisposableListener(this.domNode, "dragover", (e) => this.onDragOver(this.toDragEvent(e))));
    this.disposables.add(dom.addDisposableListener(this.domNode, "drop", (e) => this.onDrop(this.toDragEvent(e))));
    this.disposables.add(dom.addDisposableListener(this.domNode, "dragleave", (e) => this.onDragLeave(this.toDragEvent(e))));
    this.disposables.add(dom.addDisposableListener(this.domNode, "dragend", (e) => this.onDragEnd(e)));
    this.setRowLineHeight = objects.getOrDefault(options, (o) => o.setRowLineHeight, DefaultOptions.setRowLineHeight);
    this.setRowHeight = objects.getOrDefault(options, (o) => o.setRowHeight, DefaultOptions.setRowHeight);
    this.supportDynamicHeights = objects.getOrDefault(options, (o) => o.supportDynamicHeights, DefaultOptions.supportDynamicHeights);
    this.dnd = objects.getOrDefault(options, (o) => o.dnd, DefaultOptions.dnd);
    this.layout();
  }
  get contentHeight() {
    return this.rangeMap.size;
  }
  get horizontalScrolling() {
    return this._horizontalScrolling;
  }
  set horizontalScrolling(value) {
    if (value === this._horizontalScrolling) {
      return;
    }
    if (value && this.supportDynamicHeights) {
      throw new Error("Horizontal scrolling and dynamic heights not supported simultaneously");
    }
    this._horizontalScrolling = value;
    this.domNode.classList.toggle("horizontal-scrolling", this._horizontalScrolling);
    if (this._horizontalScrolling) {
      for (const item of this.items) {
        this.measureItemWidth(item);
      }
      this.updateScrollWidth();
      this.scrollableElement.setScrollDimensions({ width: dom.getContentWidth(this.domNode) });
      this.rowsContainer.style.width = `${Math.max(this.scrollWidth || 0, this.renderWidth)}px`;
    } else {
      this.scrollableElementWidthDelayer.cancel();
      this.scrollableElement.setScrollDimensions({ width: this.renderWidth, scrollWidth: this.renderWidth });
      this.rowsContainer.style.width = "";
    }
  }
  updateOptions(options) {
    if (options.additionalScrollHeight !== void 0) {
      this.additionalScrollHeight = options.additionalScrollHeight;
      this.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });
    }
    if (options.smoothScrolling !== void 0) {
      this.scrollable.setSmoothScrollDuration(options.smoothScrolling ? 125 : 0);
    }
    if (options.horizontalScrolling !== void 0) {
      this.horizontalScrolling = options.horizontalScrolling;
    }
    if (options.mouseWheelScrollSensitivity !== void 0) {
      this.scrollableElement.updateOptions({ mouseWheelScrollSensitivity: options.mouseWheelScrollSensitivity });
    }
    if (options.fastScrollSensitivity !== void 0) {
      this.scrollableElement.updateOptions({ fastScrollSensitivity: options.fastScrollSensitivity });
    }
  }
  splice(start, deleteCount, elements = []) {
    if (this.splicing) {
      throw new Error("Can't run recursive splices.");
    }
    this.splicing = true;
    try {
      return this._splice(start, deleteCount, elements);
    } finally {
      this.splicing = false;
      this._onDidChangeContentHeight.fire(this.contentHeight);
    }
  }
  _splice(start, deleteCount, elements = []) {
    const previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);
    const deleteRange = { start, end: start + deleteCount };
    const removeRange = range.Range.intersect(previousRenderRange, deleteRange);
    const rowsToDispose = /* @__PURE__ */ new Map();
    for (let i = removeRange.end - 1; i >= removeRange.start; i--) {
      const item = this.items[i];
      item.dragStartDisposable.dispose();
      if (item.row) {
        let rows = rowsToDispose.get(item.templateId);
        if (!rows) {
          rows = [];
          rowsToDispose.set(item.templateId, rows);
        }
        const renderer = this.renderers.get(item.templateId);
        if (renderer && renderer.disposeElement) {
          renderer.disposeElement(item.element, i, item.row.templateData, item.size);
        }
        rows.push(item.row);
      }
      item.row = null;
    }
    const previousRestRange = { start: start + deleteCount, end: this.items.length };
    const previousRenderedRestRange = range.Range.intersect(previousRestRange, previousRenderRange);
    const previousUnrenderedRestRanges = range.Range.relativeComplement(previousRestRange, previousRenderRange);
    const inserted = elements.map((element) => ({
      id: String(this.itemId++),
      element,
      templateId: this.virtualDelegate.getTemplateId(element),
      size: this.virtualDelegate.getHeight(element),
      width: void 0,
      hasDynamicHeight: !!this.virtualDelegate.hasDynamicHeight && this.virtualDelegate.hasDynamicHeight(element),
      lastDynamicHeightWidth: void 0,
      row: null,
      uri: void 0,
      dropTarget: false,
      dragStartDisposable: lifecycle.Disposable.None,
      checkedDisposable: lifecycle.Disposable.None
    }));
    let deleted;
    if (start === 0 && deleteCount >= this.items.length) {
      this.rangeMap = new rangeMap.RangeMap();
      this.rangeMap.splice(0, 0, inserted);
      deleted = this.items;
      this.items = inserted;
    } else {
      this.rangeMap.splice(start, deleteCount, inserted);
      deleted = this.items.splice(start, deleteCount, ...inserted);
    }
    const delta = elements.length - deleteCount;
    const renderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);
    const renderedRestRange = rangeMap.shift(previousRenderedRestRange, delta);
    const updateRange = range.Range.intersect(renderRange, renderedRestRange);
    for (let i = updateRange.start; i < updateRange.end; i++) {
      this.updateItemInDOM(this.items[i], i);
    }
    const removeRanges = range.Range.relativeComplement(renderedRestRange, renderRange);
    for (const range2 of removeRanges) {
      for (let i = range2.start; i < range2.end; i++) {
        this.removeItemFromDOM(i);
      }
    }
    const unrenderedRestRanges = previousUnrenderedRestRanges.map((r) => rangeMap.shift(r, delta));
    const elementsRange = { start, end: start + elements.length };
    const insertRanges = [elementsRange, ...unrenderedRestRanges].map((r) => range.Range.intersect(renderRange, r));
    const beforeElement = this.getNextToLastElement(insertRanges);
    for (const range2 of insertRanges) {
      for (let i = range2.start; i < range2.end; i++) {
        const item = this.items[i];
        const rows = rowsToDispose.get(item.templateId);
        const row = rows === null || rows === void 0 ? void 0 : rows.pop();
        this.insertItemInDOM(i, beforeElement, row);
      }
    }
    for (const rows of rowsToDispose.values()) {
      for (const row of rows) {
        this.cache.release(row);
      }
    }
    this.eventuallyUpdateScrollDimensions();
    if (this.supportDynamicHeights) {
      this._rerender(this.scrollTop, this.renderHeight);
    }
    return deleted.map((i) => i.element);
  }
  eventuallyUpdateScrollDimensions() {
    this._scrollHeight = this.contentHeight;
    this.rowsContainer.style.height = `${this._scrollHeight}px`;
    if (!this.scrollableElementUpdateDisposable) {
      this.scrollableElementUpdateDisposable = dom.scheduleAtNextAnimationFrame(() => {
        this.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });
        this.updateScrollWidth();
        this.scrollableElementUpdateDisposable = null;
      });
    }
  }
  eventuallyUpdateScrollWidth() {
    if (!this.horizontalScrolling) {
      this.scrollableElementWidthDelayer.cancel();
      return;
    }
    this.scrollableElementWidthDelayer.trigger(() => this.updateScrollWidth());
  }
  updateScrollWidth() {
    if (!this.horizontalScrolling) {
      return;
    }
    let scrollWidth = 0;
    for (const item of this.items) {
      if (typeof item.width !== "undefined") {
        scrollWidth = Math.max(scrollWidth, item.width);
      }
    }
    this.scrollWidth = scrollWidth;
    this.scrollableElement.setScrollDimensions({ scrollWidth: scrollWidth === 0 ? 0 : scrollWidth + 10 });
  }
  rerender() {
    if (!this.supportDynamicHeights) {
      return;
    }
    for (const item of this.items) {
      item.lastDynamicHeightWidth = void 0;
    }
    this._rerender(this.lastRenderTop, this.lastRenderHeight);
  }
  get length() {
    return this.items.length;
  }
  get renderHeight() {
    const scrollDimensions = this.scrollableElement.getScrollDimensions();
    return scrollDimensions.height;
  }
  element(index) {
    return this.items[index].element;
  }
  domElement(index) {
    const row = this.items[index].row;
    return row && row.domNode;
  }
  elementHeight(index) {
    return this.items[index].size;
  }
  elementTop(index) {
    return this.rangeMap.positionAt(index);
  }
  indexAt(position) {
    return this.rangeMap.indexAt(position);
  }
  indexAfter(position) {
    return this.rangeMap.indexAfter(position);
  }
  layout(height, width) {
    let scrollDimensions = {
      height: typeof height === "number" ? height : dom.getContentHeight(this.domNode)
    };
    if (this.scrollableElementUpdateDisposable) {
      this.scrollableElementUpdateDisposable.dispose();
      this.scrollableElementUpdateDisposable = null;
      scrollDimensions.scrollHeight = this.scrollHeight;
    }
    this.scrollableElement.setScrollDimensions(scrollDimensions);
    if (typeof width !== "undefined") {
      this.renderWidth = width;
      if (this.supportDynamicHeights) {
        this._rerender(this.scrollTop, this.renderHeight);
      }
    }
    if (this.horizontalScrolling) {
      this.scrollableElement.setScrollDimensions({
        width: typeof width === "number" ? width : dom.getContentWidth(this.domNode)
      });
    }
  }
  // Render
  render(previousRenderRange, renderTop, renderHeight, renderLeft, scrollWidth, updateItemsInDOM = false) {
    const renderRange = this.getRenderRange(renderTop, renderHeight);
    const rangesToInsert = range.Range.relativeComplement(renderRange, previousRenderRange);
    const rangesToRemove = range.Range.relativeComplement(previousRenderRange, renderRange);
    const beforeElement = this.getNextToLastElement(rangesToInsert);
    if (updateItemsInDOM) {
      const rangesToUpdate = range.Range.intersect(previousRenderRange, renderRange);
      for (let i = rangesToUpdate.start; i < rangesToUpdate.end; i++) {
        this.updateItemInDOM(this.items[i], i);
      }
    }
    for (const range2 of rangesToInsert) {
      for (let i = range2.start; i < range2.end; i++) {
        this.insertItemInDOM(i, beforeElement);
      }
    }
    for (const range2 of rangesToRemove) {
      for (let i = range2.start; i < range2.end; i++) {
        this.removeItemFromDOM(i);
      }
    }
    if (renderLeft !== void 0) {
      this.rowsContainer.style.left = `-${renderLeft}px`;
    }
    this.rowsContainer.style.top = `-${renderTop}px`;
    if (this.horizontalScrolling && scrollWidth !== void 0) {
      this.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`;
    }
    this.lastRenderTop = renderTop;
    this.lastRenderHeight = renderHeight;
  }
  // DOM operations
  insertItemInDOM(index, beforeElement, row) {
    const item = this.items[index];
    if (!item.row) {
      item.row = row !== null && row !== void 0 ? row : this.cache.alloc(item.templateId);
    }
    const role = this.accessibilityProvider.getRole(item.element) || "listitem";
    item.row.domNode.setAttribute("role", role);
    const checked = this.accessibilityProvider.isChecked(item.element);
    if (typeof checked === "boolean") {
      item.row.domNode.setAttribute("aria-checked", String(!!checked));
    } else if (checked) {
      const update = (checked2) => item.row.domNode.setAttribute("aria-checked", String(!!checked2));
      update(checked.value);
      item.checkedDisposable = checked.onDidChange(update);
    }
    if (!item.row.domNode.parentElement) {
      if (beforeElement) {
        this.rowsContainer.insertBefore(item.row.domNode, beforeElement);
      } else {
        this.rowsContainer.appendChild(item.row.domNode);
      }
    }
    this.updateItemInDOM(item, index);
    const renderer = this.renderers.get(item.templateId);
    if (!renderer) {
      throw new Error(`No renderer found for template id ${item.templateId}`);
    }
    if (renderer) {
      renderer.renderElement(item.element, index, item.row.templateData, item.size);
    }
    const uri = this.dnd.getDragURI(item.element);
    item.dragStartDisposable.dispose();
    item.row.domNode.draggable = !!uri;
    if (uri) {
      item.dragStartDisposable = dom.addDisposableListener(item.row.domNode, "dragstart", (event2) => this.onDragStart(item.element, uri, event2));
    }
    if (this.horizontalScrolling) {
      this.measureItemWidth(item);
      this.eventuallyUpdateScrollWidth();
    }
  }
  measureItemWidth(item) {
    if (!item.row || !item.row.domNode) {
      return;
    }
    item.row.domNode.style.width = browser.isFirefox ? "-moz-fit-content" : "fit-content";
    item.width = dom.getContentWidth(item.row.domNode);
    const style = window.getComputedStyle(item.row.domNode);
    if (style.paddingLeft) {
      item.width += parseFloat(style.paddingLeft);
    }
    if (style.paddingRight) {
      item.width += parseFloat(style.paddingRight);
    }
    item.row.domNode.style.width = "";
  }
  updateItemInDOM(item, index) {
    item.row.domNode.style.top = `${this.elementTop(index)}px`;
    if (this.setRowHeight) {
      item.row.domNode.style.height = `${item.size}px`;
    }
    if (this.setRowLineHeight) {
      item.row.domNode.style.lineHeight = `${item.size}px`;
    }
    item.row.domNode.setAttribute("data-index", `${index}`);
    item.row.domNode.setAttribute("data-last-element", index === this.length - 1 ? "true" : "false");
    item.row.domNode.setAttribute("data-parity", index % 2 === 0 ? "even" : "odd");
    item.row.domNode.setAttribute("aria-setsize", String(this.accessibilityProvider.getSetSize(item.element, index, this.length)));
    item.row.domNode.setAttribute("aria-posinset", String(this.accessibilityProvider.getPosInSet(item.element, index)));
    item.row.domNode.setAttribute("id", this.getElementDomId(index));
    item.row.domNode.classList.toggle("drop-target", item.dropTarget);
  }
  removeItemFromDOM(index) {
    const item = this.items[index];
    item.dragStartDisposable.dispose();
    item.checkedDisposable.dispose();
    if (item.row) {
      const renderer = this.renderers.get(item.templateId);
      if (renderer && renderer.disposeElement) {
        renderer.disposeElement(item.element, index, item.row.templateData, item.size);
      }
      this.cache.release(item.row);
      item.row = null;
    }
    if (this.horizontalScrolling) {
      this.eventuallyUpdateScrollWidth();
    }
  }
  getScrollTop() {
    const scrollPosition = this.scrollableElement.getScrollPosition();
    return scrollPosition.scrollTop;
  }
  setScrollTop(scrollTop, reuseAnimation) {
    if (this.scrollableElementUpdateDisposable) {
      this.scrollableElementUpdateDisposable.dispose();
      this.scrollableElementUpdateDisposable = null;
      this.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });
    }
    this.scrollableElement.setScrollPosition({ scrollTop, reuseAnimation });
  }
  get scrollTop() {
    return this.getScrollTop();
  }
  set scrollTop(scrollTop) {
    this.setScrollTop(scrollTop);
  }
  get scrollHeight() {
    return this._scrollHeight + (this.horizontalScrolling ? 10 : 0) + this.additionalScrollHeight;
  }
  // Events
  get onMouseClick() {
    return event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "click")).event, (e) => this.toMouseEvent(e));
  }
  get onMouseDblClick() {
    return event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "dblclick")).event, (e) => this.toMouseEvent(e));
  }
  get onMouseMiddleClick() {
    return event.Event.filter(event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "auxclick")).event, (e) => this.toMouseEvent(e)), (e) => e.browserEvent.button === 1);
  }
  get onMouseDown() {
    return event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "mousedown")).event, (e) => this.toMouseEvent(e));
  }
  get onContextMenu() {
    return event.Event.any(event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "contextmenu")).event, (e) => this.toMouseEvent(e)), event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, touch.EventType.Contextmenu)).event, (e) => this.toGestureEvent(e)));
  }
  get onTouchStart() {
    return event.Event.map(this.disposables.add(new event$1.DomEmitter(this.domNode, "touchstart")).event, (e) => this.toTouchEvent(e));
  }
  get onTap() {
    return event.Event.map(this.disposables.add(new event$1.DomEmitter(this.rowsContainer, touch.EventType.Tap)).event, (e) => this.toGestureEvent(e));
  }
  toMouseEvent(browserEvent) {
    const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
    const item = typeof index === "undefined" ? void 0 : this.items[index];
    const element = item && item.element;
    return { browserEvent, index, element };
  }
  toTouchEvent(browserEvent) {
    const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
    const item = typeof index === "undefined" ? void 0 : this.items[index];
    const element = item && item.element;
    return { browserEvent, index, element };
  }
  toGestureEvent(browserEvent) {
    const index = this.getItemIndexFromEventTarget(browserEvent.initialTarget || null);
    const item = typeof index === "undefined" ? void 0 : this.items[index];
    const element = item && item.element;
    return { browserEvent, index, element };
  }
  toDragEvent(browserEvent) {
    const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
    const item = typeof index === "undefined" ? void 0 : this.items[index];
    const element = item && item.element;
    return { browserEvent, index, element };
  }
  onScroll(e) {
    try {
      const previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);
      this.render(previousRenderRange, e.scrollTop, e.height, e.scrollLeft, e.scrollWidth);
      if (this.supportDynamicHeights) {
        this._rerender(e.scrollTop, e.height, e.inSmoothScrolling);
      }
    } catch (err) {
      console.error("Got bad scroll event:", e);
      throw err;
    }
  }
  onTouchChange(event2) {
    event2.preventDefault();
    event2.stopPropagation();
    this.scrollTop -= event2.translationY;
  }
  // DND
  onDragStart(element, uri, event2) {
    if (!event2.dataTransfer) {
      return;
    }
    const elements = this.dnd.getDragElements(element);
    event2.dataTransfer.effectAllowed = "copyMove";
    event2.dataTransfer.setData(dnd.DataTransfers.TEXT, uri);
    if (event2.dataTransfer.setDragImage) {
      let label;
      if (this.dnd.getDragLabel) {
        label = this.dnd.getDragLabel(elements, event2);
      }
      if (typeof label === "undefined") {
        label = String(elements.length);
      }
      const dragImage = dom.$(".monaco-drag-image");
      dragImage.textContent = label;
      document.body.appendChild(dragImage);
      event2.dataTransfer.setDragImage(dragImage, -10, -10);
      setTimeout(() => document.body.removeChild(dragImage), 0);
    }
    this.currentDragData = new ElementsDragAndDropData(elements);
    dnd.StaticDND.CurrentDragAndDropData = new ExternalElementsDragAndDropData(elements);
    if (this.dnd.onDragStart) {
      this.dnd.onDragStart(this.currentDragData, event2);
    }
  }
  onDragOver(event2) {
    event2.browserEvent.preventDefault();
    this.onDragLeaveTimeout.dispose();
    if (dnd.StaticDND.CurrentDragAndDropData && dnd.StaticDND.CurrentDragAndDropData.getData() === "vscode-ui") {
      return false;
    }
    this.setupDragAndDropScrollTopAnimation(event2.browserEvent);
    if (!event2.browserEvent.dataTransfer) {
      return false;
    }
    if (!this.currentDragData) {
      if (dnd.StaticDND.CurrentDragAndDropData) {
        this.currentDragData = dnd.StaticDND.CurrentDragAndDropData;
      } else {
        if (!event2.browserEvent.dataTransfer.types) {
          return false;
        }
        this.currentDragData = new NativeDragAndDropData();
      }
    }
    const result = this.dnd.onDragOver(this.currentDragData, event2.element, event2.index, event2.browserEvent);
    this.canDrop = typeof result === "boolean" ? result : result.accept;
    if (!this.canDrop) {
      this.currentDragFeedback = void 0;
      this.currentDragFeedbackDisposable.dispose();
      return false;
    }
    event2.browserEvent.dataTransfer.dropEffect = typeof result !== "boolean" && result.effect === 0 ? "copy" : "move";
    let feedback;
    if (typeof result !== "boolean" && result.feedback) {
      feedback = result.feedback;
    } else {
      if (typeof event2.index === "undefined") {
        feedback = [-1];
      } else {
        feedback = [event2.index];
      }
    }
    feedback = arrays.distinct(feedback).filter((i) => i >= -1 && i < this.length).sort((a, b) => a - b);
    feedback = feedback[0] === -1 ? [-1] : feedback;
    if (equalsDragFeedback(this.currentDragFeedback, feedback)) {
      return true;
    }
    this.currentDragFeedback = feedback;
    this.currentDragFeedbackDisposable.dispose();
    if (feedback[0] === -1) {
      this.domNode.classList.add("drop-target");
      this.rowsContainer.classList.add("drop-target");
      this.currentDragFeedbackDisposable = lifecycle.toDisposable(() => {
        this.domNode.classList.remove("drop-target");
        this.rowsContainer.classList.remove("drop-target");
      });
    } else {
      for (const index of feedback) {
        const item = this.items[index];
        item.dropTarget = true;
        if (item.row) {
          item.row.domNode.classList.add("drop-target");
        }
      }
      this.currentDragFeedbackDisposable = lifecycle.toDisposable(() => {
        for (const index of feedback) {
          const item = this.items[index];
          item.dropTarget = false;
          if (item.row) {
            item.row.domNode.classList.remove("drop-target");
          }
        }
      });
    }
    return true;
  }
  onDragLeave(event2) {
    var _a, _b;
    this.onDragLeaveTimeout.dispose();
    this.onDragLeaveTimeout = async.disposableTimeout(() => this.clearDragOverFeedback(), 100);
    if (this.currentDragData) {
      (_b = (_a = this.dnd).onDragLeave) === null || _b === void 0 ? void 0 : _b.call(_a, this.currentDragData, event2.element, event2.index, event2.browserEvent);
    }
  }
  onDrop(event2) {
    if (!this.canDrop) {
      return;
    }
    const dragData = this.currentDragData;
    this.teardownDragAndDropScrollTopAnimation();
    this.clearDragOverFeedback();
    this.currentDragData = void 0;
    dnd.StaticDND.CurrentDragAndDropData = void 0;
    if (!dragData || !event2.browserEvent.dataTransfer) {
      return;
    }
    event2.browserEvent.preventDefault();
    dragData.update(event2.browserEvent.dataTransfer);
    this.dnd.drop(dragData, event2.element, event2.index, event2.browserEvent);
  }
  onDragEnd(event2) {
    this.canDrop = false;
    this.teardownDragAndDropScrollTopAnimation();
    this.clearDragOverFeedback();
    this.currentDragData = void 0;
    dnd.StaticDND.CurrentDragAndDropData = void 0;
    if (this.dnd.onDragEnd) {
      this.dnd.onDragEnd(event2);
    }
  }
  clearDragOverFeedback() {
    this.currentDragFeedback = void 0;
    this.currentDragFeedbackDisposable.dispose();
    this.currentDragFeedbackDisposable = lifecycle.Disposable.None;
  }
  // DND scroll top animation
  setupDragAndDropScrollTopAnimation(event2) {
    if (!this.dragOverAnimationDisposable) {
      const viewTop = dom.getTopLeftOffset(this.domNode).top;
      this.dragOverAnimationDisposable = dom.animate(this.animateDragAndDropScrollTop.bind(this, viewTop));
    }
    this.dragOverAnimationStopDisposable.dispose();
    this.dragOverAnimationStopDisposable = async.disposableTimeout(() => {
      if (this.dragOverAnimationDisposable) {
        this.dragOverAnimationDisposable.dispose();
        this.dragOverAnimationDisposable = void 0;
      }
    }, 1e3);
    this.dragOverMouseY = event2.pageY;
  }
  animateDragAndDropScrollTop(viewTop) {
    if (this.dragOverMouseY === void 0) {
      return;
    }
    const diff = this.dragOverMouseY - viewTop;
    const upperLimit = this.renderHeight - 35;
    if (diff < 35) {
      this.scrollTop += Math.max(-14, Math.floor(0.3 * (diff - 35)));
    } else if (diff > upperLimit) {
      this.scrollTop += Math.min(14, Math.floor(0.3 * (diff - upperLimit)));
    }
  }
  teardownDragAndDropScrollTopAnimation() {
    this.dragOverAnimationStopDisposable.dispose();
    if (this.dragOverAnimationDisposable) {
      this.dragOverAnimationDisposable.dispose();
      this.dragOverAnimationDisposable = void 0;
    }
  }
  // Util
  getItemIndexFromEventTarget(target) {
    const scrollableElement2 = this.scrollableElement.getDomNode();
    let element = target;
    while (element instanceof HTMLElement && element !== this.rowsContainer && scrollableElement2.contains(element)) {
      const rawIndex = element.getAttribute("data-index");
      if (rawIndex) {
        const index = Number(rawIndex);
        if (!isNaN(index)) {
          return index;
        }
      }
      element = element.parentElement;
    }
    return void 0;
  }
  getRenderRange(renderTop, renderHeight) {
    return {
      start: this.rangeMap.indexAt(renderTop),
      end: this.rangeMap.indexAfter(renderTop + renderHeight - 1)
    };
  }
  /**
   * Given a stable rendered state, checks every rendered element whether it needs
   * to be probed for dynamic height. Adjusts scroll height and top if necessary.
   */
  _rerender(renderTop, renderHeight, inSmoothScrolling) {
    const previousRenderRange = this.getRenderRange(renderTop, renderHeight);
    let anchorElementIndex;
    let anchorElementTopDelta;
    if (renderTop === this.elementTop(previousRenderRange.start)) {
      anchorElementIndex = previousRenderRange.start;
      anchorElementTopDelta = 0;
    } else if (previousRenderRange.end - previousRenderRange.start > 1) {
      anchorElementIndex = previousRenderRange.start + 1;
      anchorElementTopDelta = this.elementTop(anchorElementIndex) - renderTop;
    }
    let heightDiff = 0;
    while (true) {
      const renderRange = this.getRenderRange(renderTop, renderHeight);
      let didChange = false;
      for (let i = renderRange.start; i < renderRange.end; i++) {
        const diff = this.probeDynamicHeight(i);
        if (diff !== 0) {
          this.rangeMap.splice(i, 1, [this.items[i]]);
        }
        heightDiff += diff;
        didChange = didChange || diff !== 0;
      }
      if (!didChange) {
        if (heightDiff !== 0) {
          this.eventuallyUpdateScrollDimensions();
        }
        const unrenderRanges = range.Range.relativeComplement(previousRenderRange, renderRange);
        for (const range2 of unrenderRanges) {
          for (let i = range2.start; i < range2.end; i++) {
            if (this.items[i].row) {
              this.removeItemFromDOM(i);
            }
          }
        }
        const renderRanges = range.Range.relativeComplement(renderRange, previousRenderRange);
        for (const range2 of renderRanges) {
          for (let i = range2.start; i < range2.end; i++) {
            const afterIndex = i + 1;
            const beforeRow = afterIndex < this.items.length ? this.items[afterIndex].row : null;
            const beforeElement = beforeRow ? beforeRow.domNode : null;
            this.insertItemInDOM(i, beforeElement);
          }
        }
        for (let i = renderRange.start; i < renderRange.end; i++) {
          if (this.items[i].row) {
            this.updateItemInDOM(this.items[i], i);
          }
        }
        if (typeof anchorElementIndex === "number") {
          const deltaScrollTop = this.scrollable.getFutureScrollPosition().scrollTop - renderTop;
          const newScrollTop = this.elementTop(anchorElementIndex) - anchorElementTopDelta + deltaScrollTop;
          this.setScrollTop(newScrollTop, inSmoothScrolling);
        }
        this._onDidChangeContentHeight.fire(this.contentHeight);
        return;
      }
    }
  }
  probeDynamicHeight(index) {
    const item = this.items[index];
    if (!!this.virtualDelegate.getDynamicHeight) {
      const newSize = this.virtualDelegate.getDynamicHeight(item.element);
      if (newSize !== null) {
        const size2 = item.size;
        item.size = newSize;
        item.lastDynamicHeightWidth = this.renderWidth;
        return newSize - size2;
      }
    }
    if (!item.hasDynamicHeight || item.lastDynamicHeightWidth === this.renderWidth) {
      return 0;
    }
    if (!!this.virtualDelegate.hasDynamicHeight && !this.virtualDelegate.hasDynamicHeight(item.element)) {
      return 0;
    }
    const size = item.size;
    if (!this.setRowHeight && item.row) {
      let newSize = item.row.domNode.offsetHeight;
      item.size = newSize;
      item.lastDynamicHeightWidth = this.renderWidth;
      return newSize - size;
    }
    const row = this.cache.alloc(item.templateId);
    row.domNode.style.height = "";
    this.rowsContainer.appendChild(row.domNode);
    const renderer = this.renderers.get(item.templateId);
    if (renderer) {
      renderer.renderElement(item.element, index, row.templateData, void 0);
      if (renderer.disposeElement) {
        renderer.disposeElement(item.element, index, row.templateData, void 0);
      }
    }
    item.size = row.domNode.offsetHeight;
    if (this.virtualDelegate.setDynamicHeight) {
      this.virtualDelegate.setDynamicHeight(item.element, item.size);
    }
    item.lastDynamicHeightWidth = this.renderWidth;
    this.rowsContainer.removeChild(row.domNode);
    this.cache.release(row);
    return item.size - size;
  }
  getNextToLastElement(ranges) {
    const lastRange = ranges[ranges.length - 1];
    if (!lastRange) {
      return null;
    }
    const nextToLastItem = this.items[lastRange.end];
    if (!nextToLastItem) {
      return null;
    }
    if (!nextToLastItem.row) {
      return null;
    }
    return nextToLastItem.row.domNode;
  }
  getElementDomId(index) {
    return `${this.domId}_${index}`;
  }
  // Dispose
  dispose() {
    if (this.items) {
      for (const item of this.items) {
        if (item.row) {
          const renderer = this.renderers.get(item.row.templateId);
          if (renderer) {
            if (renderer.disposeElement) {
              renderer.disposeElement(item.element, -1, item.row.templateData, void 0);
            }
            renderer.disposeTemplate(item.row.templateData);
          }
        }
      }
      this.items = [];
    }
    if (this.domNode && this.domNode.parentNode) {
      this.domNode.parentNode.removeChild(this.domNode);
    }
    lifecycle.dispose(this.disposables);
  }
}
ListView.InstanceCount = 0;
__decorate([
  decorators.memoize
], ListView.prototype, "onMouseClick", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onMouseDblClick", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onMouseMiddleClick", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onMouseDown", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onContextMenu", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onTouchStart", null);
__decorate([
  decorators.memoize
], ListView.prototype, "onTap", null);
exports.ElementsDragAndDropData = ElementsDragAndDropData;
exports.ExternalElementsDragAndDropData = ExternalElementsDragAndDropData;
exports.ListView = ListView;
exports.NativeDragAndDropData = NativeDragAndDropData;
