summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Tang <dtang@gitlab.com>2018-06-01 18:24:53 -0700
committerDennis Tang <dtang@gitlab.com>2018-06-01 18:24:53 -0700
commita174a0dd22159f893606835ffa4328760d41936d (patch)
treef168ccabe57dd9db005307e6938306b7af08b130
parentf8bd8f4f062e518ab855a83f38965df51ec3b073 (diff)
downloadgitlab-ce-3969-weight-issue-search-filter.tar.gz
port 3969-weight-issue-search-filter to CE3969-weight-issue-search-filter
-rw-r--r--app/assets/javascripts/droplab/plugins/custom_number.js62
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_weight.js37
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js28
3 files changed, 118 insertions, 9 deletions
diff --git a/app/assets/javascripts/droplab/plugins/custom_number.js b/app/assets/javascripts/droplab/plugins/custom_number.js
new file mode 100644
index 00000000000..bf22bae8e7f
--- /dev/null
+++ b/app/assets/javascripts/droplab/plugins/custom_number.js
@@ -0,0 +1,62 @@
+const CustomNumber = {
+ keydown(e) {
+ if (this.destroyed) return;
+
+ const { list } = e.detail.hook;
+ const value = parseInt(e.detail.hook.trigger.value, 0);
+ const config = e.detail.hook.config.CustomNumber;
+ const { defaultOptions } = config;
+
+ const isOutOfBounds = defaultOptions.indexOf(value) === -1;
+ const isValidNumber = !Number.isNaN(value);
+ const customOption = [{ id: value, title: value }];
+ const defaultDropdownOptions = defaultOptions.map(o => ({ id: o, title: o }));
+
+ list.setData(isValidNumber && isOutOfBounds ? customOption : defaultDropdownOptions);
+ list.currentIndex = 0;
+ },
+
+ debounceKeydown: function debounceKeydown(e) {
+ if (
+ [
+ 13, // enter
+ 16, // shift
+ 17, // ctrl
+ 18, // alt
+ 20, // caps lock
+ 37, // left arrow
+ 38, // up arrow
+ 39, // right arrow
+ 40, // down arrow
+ 91, // left window
+ 92, // right window
+ 93, // select
+ ].indexOf(e.detail.which || e.detail.keyCode) > -1
+ )
+ return;
+
+ if (this.timeout) clearTimeout(this.timeout);
+ this.timeout = setTimeout(this.keydown.bind(this, e), 200);
+ },
+
+ init: function init(hook) {
+ this.hook = hook;
+ this.destroyed = false;
+
+ this.eventWrapper = {};
+ this.eventWrapper.debounceKeydown = this.debounceKeydown.bind(this);
+
+ this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
+ this.hook.trigger.addEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
+ },
+
+ destroy: function destroy() {
+ if (this.timeout) clearTimeout(this.timeout);
+ this.destroyed = true;
+
+ this.hook.trigger.removeEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
+ this.hook.trigger.removeEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
+ },
+};
+
+export default CustomNumber;
diff --git a/app/assets/javascripts/filtered_search/dropdown_weight.js b/app/assets/javascripts/filtered_search/dropdown_weight.js
new file mode 100644
index 00000000000..ebafca2548e
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/dropdown_weight.js
@@ -0,0 +1,37 @@
+import FilteredSearchDropdown from './filtered_search_dropdown';
+import DropdownUtils from './dropdown_utils';
+import CustomNumber from '../droplab/plugins/custom_number';
+
+export default class DropdownWeight extends FilteredSearchDropdown {
+ constructor(options = {}) {
+ super(options);
+
+ this.defaultOptions = Array.from(Array(21).keys());
+
+ this.config = {
+ CustomNumber: {
+ defaultOptions: this.defaultOptions,
+ },
+ };
+ }
+
+ itemClicked(e) {
+ super.itemClicked(e, selected => {
+ const title = selected.querySelector('.js-data-value').innerText.trim();
+ return `${DropdownUtils.getEscapedText(title)}`;
+ });
+ }
+
+ renderContent(forceShowList = false) {
+ this.droplab.changeHookList(this.hookId, this.dropdown, [CustomNumber], this.config);
+
+ const defaultDropdownOptions = this.defaultOptions.map(o => ({ id: o, title: o }));
+ this.droplab.setData(defaultDropdownOptions);
+
+ super.renderContent(forceShowList);
+ }
+
+ init() {
+ this.droplab.addHook(this.input, this.dropdown, [CustomNumber], this.config).init();
+ }
+}
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index d7e1de18d09..18b292cfc0d 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -7,6 +7,7 @@ import DropdownHint from './dropdown_hint';
import DropdownEmoji from './dropdown_emoji';
import DropdownNonUser from './dropdown_non_user';
import DropdownUser from './dropdown_user';
+import DropdownWeight from './dropdown_weight';
import FilteredSearchVisualTokens from './filtered_search_visual_tokens';
export default class FilteredSearchDropdownManager {
@@ -90,9 +91,14 @@ export default class FilteredSearchDropdownManager {
gl: DropdownEmoji,
element: this.container.querySelector('#js-dropdown-my-reaction'),
},
+ weight: {
+ reference: null,
+ gl: DropdownWeight,
+ element: this.container.querySelector('#js-dropdown-weight'),
+ },
};
- supportedTokens.forEach((type) => {
+ supportedTokens.forEach(type => {
if (availableMappings[type]) {
allowedMappings[type] = availableMappings[type];
}
@@ -142,13 +148,16 @@ export default class FilteredSearchDropdownManager {
updateDropdownOffset(key) {
// Always align dropdown with the input field
- let offset = this.filteredSearchInput.getBoundingClientRect().left - this.container.querySelector('.scroll-container').getBoundingClientRect().left;
+ let offset =
+ this.filteredSearchInput.getBoundingClientRect().left -
+ this.container.querySelector('.scroll-container').getBoundingClientRect().left;
const maxInputWidth = 240;
const currentDropdownWidth = this.mapping[key].element.clientWidth || maxInputWidth;
// Make sure offset never exceeds the input container
- const offsetMaxWidth = this.container.querySelector('.scroll-container').clientWidth - currentDropdownWidth;
+ const offsetMaxWidth =
+ this.container.querySelector('.scroll-container').clientWidth - currentDropdownWidth;
if (offsetMaxWidth < offset) {
offset = offsetMaxWidth;
}
@@ -174,8 +183,7 @@ export default class FilteredSearchDropdownManager {
const glArguments = Object.assign({}, defaultArguments, extraArguments);
// Passing glArguments to `new glClass(<arguments>)`
- mappingKey.reference =
- new (Function.prototype.bind.apply(glClass, [null, glArguments]))();
+ mappingKey.reference = new (Function.prototype.bind.apply(glClass, [null, glArguments]))();
}
if (firstLoad) {
@@ -202,8 +210,8 @@ export default class FilteredSearchDropdownManager {
}
const match = this.filteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
- const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key
- && this.mapping[match.key];
+ const shouldOpenFilterDropdown =
+ match && this.currentDropdown !== match.key && this.mapping[match.key];
const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint';
if (shouldOpenFilterDropdown || shouldOpenHintDropdown) {
@@ -214,8 +222,10 @@ export default class FilteredSearchDropdownManager {
setDropdown() {
const query = DropdownUtils.getSearchQuery(true);
- const { lastToken, searchToken } =
- this.tokenizer.processTokens(query, this.filteredSearchTokenKeys.getKeys());
+ const { lastToken, searchToken } = this.tokenizer.processTokens(
+ query,
+ this.filteredSearchTokenKeys.getKeys(),
+ );
if (this.currentDropdown) {
this.updateCurrentDropdownOffset();