discourse/app/assets/javascripts/select-kit/mixins/events.js.es6

404 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export default Ember.Mixin.create({
init() {
this._super();
this.keys = {
TAB: 9,
ENTER: 13,
ESC: 27,
UP: 38,
DOWN: 40,
BACKSPACE: 8,
LEFT: 37,
RIGHT: 39,
A: 65
};
},
willDestroyElement() {
this._super(...arguments);
$(document).off("mousedown.select-kit");
if (this.$header().length) {
this.$header()
.off("blur.select-kit")
.off("focus.select-kit")
.off("keypress.select-kit")
.off("keydown.select-kit");
}
if (this.$filterInput().length) {
this.$filterInput()
.off("change.select-kit")
.off("keydown.select-kit")
.off("keypress.select-kit")
.off("focusout.select-kit");
}
},
didInsertElement() {
this._super(...arguments);
$(document).on("mousedown.select-kit", event => {
if (!this.element || this.isDestroying || this.isDestroyed) {
return true;
}
if (Ember.$.contains(this.element, event.target)) {
event.stopPropagation();
if (!this.get("renderedBodyOnce")) return;
if (!this.get("isFocused")) return;
} else {
this.didClickOutside(event);
}
return true;
});
this.$header()
.on("blur.select-kit", () => {
if (!this.get("isExpanded") && this.get("isFocused")) {
this.close();
}
})
.on("focus.select-kit", event => {
this.set("isFocused", true);
this._destroyEvent(event);
})
.on("keydown.select-kit", event => {
if (document.activeElement !== this.$header()[0]) return event;
const keyCode = event.keyCode || event.which;
if (keyCode === this.keys.TAB && event.shiftKey) {
this.unfocus(event);
}
if (keyCode === this.keys.TAB && !event.shiftKey)
this.tabFromHeader(event);
if (
Ember.isEmpty(this.get("filter")) &&
keyCode === this.keys.BACKSPACE
)
this.backspaceFromHeader(event);
if (keyCode === this.keys.ESC) this.escapeFromHeader(event);
if (keyCode === this.keys.ENTER) this.enterFromHeader(event);
if ([this.keys.UP, this.keys.DOWN].includes(keyCode))
this.upAndDownFromHeader(event);
if (
Ember.isEmpty(this.get("filter")) &&
[this.keys.LEFT, this.keys.RIGHT].includes(keyCode)
) {
this.leftAndRightFromHeader(event);
}
return event;
})
.on("keypress.select-kit", event => {
const keyCode = event.keyCode || event.which;
if (keyCode === this.keys.ENTER) return true;
if (keyCode === this.keys.TAB) return true;
this.expand(event);
if (this.get("filterable") || this.get("autoFilterable")) {
this.set("renderedFilterOnce", true);
}
Ember.run.schedule("afterRender", () => {
this.$filterInput()
.focus()
.val(this.$filterInput().val() + String.fromCharCode(keyCode));
});
return false;
});
this.$filterInput()
.on("change.select-kit", event => {
this.send("onFilterComputedContent", $(event.target).val());
})
.on("keypress.select-kit", event => {
event.stopPropagation();
})
.on("focusout.select-kit", event => {
this.onFilterInputFocusout(event);
})
.on("keydown.select-kit", event => {
const keyCode = event.keyCode || event.which;
if (
Ember.isEmpty(this.get("filter")) &&
keyCode === this.keys.BACKSPACE &&
typeof this.didPressBackspaceFromFilter === "function"
) {
this.didPressBackspaceFromFilter(event);
}
if (keyCode === this.keys.TAB && event.shiftKey) {
this.unfocus(event);
}
if (keyCode === this.keys.TAB && !event.shiftKey)
this.tabFromFilter(event);
if (keyCode === this.keys.ESC) this.escapeFromFilter(event);
if (keyCode === this.keys.ENTER) this.enterFromFilter(event);
if ([this.keys.UP, this.keys.DOWN].includes(keyCode))
this.upAndDownFromFilter(event);
if (
Ember.isEmpty(this.get("filter")) &&
[this.keys.LEFT, this.keys.RIGHT].includes(keyCode)
) {
this.leftAndRightFromFilter(event);
}
});
},
didPressTab(event) {
if (this.$highlightedRow().length && this.get("isExpanded")) {
this.close(event);
this.$header().focus();
const guid = this.$highlightedRow().attr("data-guid");
this.select(this._findComputedContentItemByGuid(guid));
return true;
}
if (Ember.isEmpty(this.get("filter"))) {
this.close(event);
return true;
}
return true;
},
didPressEnter(event) {
if (!this.get("isExpanded")) {
this.expand(event);
} else if (this.$highlightedRow().length) {
this.close(event);
this.$header().focus();
const guid = this.$highlightedRow().attr("data-guid");
this.select(this._findComputedContentItemByGuid(guid));
}
return true;
},
didClickSelectionItem(computedContentItem) {
this.focus();
this.deselect(computedContentItem);
},
didClickRow(computedContentItem) {
this.close();
this.focus();
this.select(computedContentItem);
},
didPressEscape(event) {
this._destroyEvent(event);
if (this.get("highlightedSelection").length && this.get("isExpanded")) {
this.clearHighlightSelection();
} else {
this.unfocus(event);
}
},
didPressUpAndDownArrows(event) {
this._destroyEvent(event);
this.clearHighlightSelection();
const keyCode = event.keyCode || event.which;
if (!this.get("isExpanded")) {
this.expand(event);
if (this.$selectedRow().length === 1) {
this._highlightRow(this.$selectedRow());
return;
}
return;
}
const $rows = this.$rows();
if (!$rows.length) {
return;
}
if ($rows.length === 1) {
this._rowSelection($rows, 0);
return;
}
const direction = keyCode === 38 ? -1 : 1;
Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32);
},
didPressBackspaceFromFilter(event) {
this.didPressBackspace(event);
},
didPressBackspace(event) {
if (!this.get("isExpanded")) {
this.expand();
if (event) event.stopImmediatePropagation();
return;
}
if (!this.get("selection").length) return;
if (!Ember.isEmpty(this.get("filter"))) {
this.clearHighlightSelection();
return;
}
if (!this.get("highlightedSelection").length) {
// try to highlight the last non locked item from the current selection
Ember.makeArray(this.get("selection"))
.slice()
.reverse()
.some(selection => {
if (!Ember.get(selection, "locked")) {
this.highlightSelection(selection);
return true;
}
});
if (event) event.stopImmediatePropagation();
} else {
this.deselect(this.get("highlightedSelection"));
if (event) event.stopImmediatePropagation();
}
},
didPressSelectAll() {
this.highlightSelection(Ember.makeArray(this.get("selection")));
},
didClickOutside(event) {
if (
this.get("isExpanded") &&
$(event.target).parents(".select-kit").length
) {
this.close(event);
return false;
}
this.close(event);
return;
},
// make sure we dont propagate a click outside component
// to avoid closing a modal containing the component for example
click(event) {
this._destroyEvent(event);
},
didPressLeftAndRightArrows(event) {
if (!this.get("isExpanded")) {
this.expand();
event.stopImmediatePropagation();
return;
}
if (Ember.isEmpty(this.get("selection"))) return;
const keyCode = event.keyCode || event.which;
if (keyCode === this.keys.LEFT) {
const prev = this.get("highlightedSelection.lastObject");
const indexOfPrev = this.get("selection").indexOf(prev);
if (this.get("selection")[indexOfPrev - 1]) {
this.highlightSelection(this.get("selection")[indexOfPrev - 1]);
} else {
this.highlightSelection(this.get("selection.lastObject"));
}
} else {
const prev = this.get("highlightedSelection.firstObject");
const indexOfNext = this.get("selection").indexOf(prev);
if (this.get("selection")[indexOfNext + 1]) {
this.highlightSelection(this.get("selection")[indexOfNext + 1]);
} else {
this.highlightSelection(this.get("selection.firstObject"));
}
}
},
tabFromHeader(event) {
this.didPressTab(event);
},
tabFromFilter(event) {
this.didPressTab(event);
},
escapeFromHeader(event) {
this.didPressEscape(event);
},
escapeFromFilter(event) {
this.didPressEscape(event);
},
upAndDownFromHeader(event) {
this.didPressUpAndDownArrows(event);
},
upAndDownFromFilter(event) {
this.didPressUpAndDownArrows(event);
},
leftAndRightFromHeader(event) {
this.didPressLeftAndRightArrows(event);
},
leftAndRightFromFilter(event) {
this.didPressLeftAndRightArrows(event);
},
backspaceFromHeader(event) {
this.didPressBackspace(event);
},
enterFromHeader(event) {
this.didPressEnter(event);
},
enterFromFilter(event) {
this.didPressEnter(event);
},
onFilterInputFocusout(event) {
if (!Ember.$.contains(this.element, event.relatedTarget)) {
this.close(event);
}
},
_moveHighlight(direction, $rows) {
const currentIndex = $rows.index(this.$highlightedRow());
let nextIndex = currentIndex + direction;
if (nextIndex < 0) {
nextIndex = $rows.length - 1;
} else if (nextIndex >= $rows.length) {
nextIndex = 0;
}
this._rowSelection($rows, nextIndex);
},
_rowSelection($rows, nextIndex) {
const highlightableValue = $rows.eq(nextIndex).attr("data-value");
const $highlightableRow = this.$findRowByValue(highlightableValue);
this._highlightRow($highlightableRow);
},
_highlightRow($row) {
Ember.run.schedule("afterRender", () => {
$row.trigger("mouseover").focus();
this.focus();
});
}
});