diff options
Diffstat (limited to 'app/assets/javascripts/gl_dropdown.js')
-rw-r--r-- | app/assets/javascripts/gl_dropdown.js | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 77b2082cba0..bea141bae51 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -21,12 +21,14 @@ $clearButton = $inputContainer.find('.js-dropdown-input-clear'); this.indeterminateIds = []; $clearButton.on('click', (function(_this) { + // Clear click return function(e) { e.preventDefault(); e.stopPropagation(); return _this.input.val('').trigger('keyup').focus(); }; })(this)); + // Key events timeout = ""; this.input .on('keydown', function (e) { @@ -49,6 +51,7 @@ if (keyCode === 13 && !options.elIsInput) { return false; } + // Only filter asynchronously only if option remote is set if (this.options.remote) { clearTimeout(timeout); return timeout = setTimeout(function() { @@ -79,11 +82,27 @@ if ((data != null) && !this.options.filterByText) { results = data; if (search_text !== '') { + // When data is an array of objects therefore [object Array] e.g. + // [ + // { prop: 'foo' }, + // { prop: 'baz' } + // ] if (_.isArray(data)) { results = fuzzaldrinPlus.filter(data, search_text, { key: this.options.keys }); } else { + // If data is grouped therefore an [object Object]. e.g. + // { + // groupName1: [ + // { prop: 'foo' }, + // { prop: 'baz' } + // ], + // groupName2: [ + // { prop: 'abc' }, + // { prop: 'def' } + // ] + // } if (gl.utils.isObject(data)) { results = {}; for (key in data) { @@ -140,6 +159,7 @@ this.options.beforeSend(); } return this.dataEndpoint("", (function(_this) { + // Fetch the data by calling the data funcfion return function(data) { if (_this.options.success) { _this.options.success(data); @@ -171,6 +191,7 @@ }; })(this) }); + // Fetch the data through ajax if the data is a string }; return GitLabDropdownRemote; @@ -209,13 +230,18 @@ self = this; selector = $(this.el).data("target"); this.dropdown = selector != null ? $(selector) : $(this.el).parent(); + // Set Defaults ref = this.options, this.filterInput = (ref1 = ref.filterInput) != null ? ref1 : this.getElement(FILTER_INPUT), this.highlight = (ref2 = ref.highlight) != null ? ref2 : false, this.filterInputBlur = (ref3 = ref.filterInputBlur) != null ? ref3 : true; + // If no input is passed create a default one self = this; + // If selector was passed if (_.isString(this.filterInput)) { this.filterInput = this.getElement(this.filterInput); } searchFields = this.options.search ? this.options.search.fields : []; if (this.options.data) { + // If we provided data + // data could be an array of objects or a group of arrays if (_.isObject(this.options.data) && !_.isFunction(this.options.data)) { this.fullData = this.options.data; currentIndex = -1; @@ -232,10 +258,12 @@ return _this.filter.input.trigger('keyup'); } }; + // Remote data })(this) }); } } + // Init filterable if (this.options.filterable) { this.filter = new GitLabDropdownFilter(this.filterInput, { elIsInput: $(this.el).is('input'), @@ -278,12 +306,14 @@ })(this) }); } + // Event listeners this.dropdown.on("shown.bs.dropdown", this.opened); this.dropdown.on("hidden.bs.dropdown", this.hidden); $(this.el).on("update.label", this.updateLabel); this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate); this.dropdown.on('keyup', (function(_this) { return function(e) { + // Escape key if (e.which === 27) { return $('.dropdown-menu-close', _this.dropdown).trigger('click'); } @@ -327,6 +357,7 @@ } } + // Finds an element inside wrapper element GitLabDropdown.prototype.getElement = function(selector) { return this.dropdown.find(selector); }; @@ -344,6 +375,7 @@ } } menu.toggleClass(PAGE_TWO_CLASS); + // Focus first visible input on active page return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus(); }; @@ -351,23 +383,28 @@ var full_html, groupData, html, name; this.renderedData = data; if (this.options.filterable && data.length === 0) { + // render no matching results html = [this.noResults()]; } else { + // Handle array groups if (gl.utils.isObject(data)) { html = []; for (name in data) { groupData = data[name]; html.push(this.renderItem({ header: name + // Add header for each group }, name)); this.renderData(groupData, name).map(function(item) { return html.push(item); }); } } else { + // Render each row html = this.renderData(data); } } + // Render the full menu full_html = this.renderMenu(html); return this.appendMenu(full_html); }; @@ -406,6 +443,7 @@ if (this.options.setActiveIds) { this.options.setActiveIds.call(this); } + // Makes indeterminate items effective if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) { this.parseData(this.fullData); } @@ -427,6 +465,8 @@ if (this.options.filterable) { $input.blur().val(""); } + // Triggering 'keyup' will re-render the dropdown which is not always required + // specially if we want to keep the state of the dropdown needed for bulk-assignment if (!this.options.persistWhenHide) { $input.trigger("keyup"); } @@ -439,6 +479,7 @@ return this.dropdown.trigger('hidden.gl.dropdown'); }; + // Render the full menu GitLabDropdown.prototype.renderMenu = function(html) { var menu_html; menu_html = ""; @@ -450,6 +491,7 @@ return menu_html; }; + // Append the menu into the dropdown GitLabDropdown.prototype.appendMenu = function(html) { var selector; selector = '.dropdown-content'; @@ -465,19 +507,24 @@ group = false; } if (index == null) { + // Render the row index = false; } html = ""; + // Divider if (data === "divider") { return "<li class='divider'></li>"; } + // Separator is a full-width divider if (data === "separator") { return "<li class='separator'></li>"; } + // Header if (data.header != null) { return _.template('<li class="dropdown-header"><%- header %></li>')({ header: data.header }); } if (this.options.renderRow) { + // Call the render function html = this.options.renderRow.call(this.options, data, this); } else { if (!selected) { @@ -489,11 +536,13 @@ selected = true; } } + // Set URL if (this.options.url != null) { url = this.options.url(data); } else { url = data.url != null ? data.url : '#'; } + // Set Text if (this.options.text != null) { text = this.options.text(data); } else { @@ -584,6 +633,7 @@ if (value == null) { field.remove(); } + // Toggle active class for the tick mark el.addClass(ACTIVE_CLASS); if (value != null) { if (!field.length && fieldName) { @@ -604,6 +654,7 @@ GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) { var $input; + // Create hidden input for form $input = $('<input>').attr('type', 'hidden').attr('name', fieldName).val(value); if (this.options.inputId != null) { $input.attr('id', this.options.inputId); @@ -625,6 +676,7 @@ if (this.dropdown.find(".dropdown-toggle-page").length) { selector = ".dropdown-page-one " + selector; } + // simulate a click on the first link $el = $(selector, this.dropdown); if ($el.length) { var href = $el.attr('href'); @@ -653,11 +705,15 @@ e.stopImmediatePropagation(); PREV_INDEX = currentIndex; $listItems = $(selector, _this.dropdown); + // if @options.filterable + // $input.blur() if (currentKeyCode === 40) { + // Move down if (currentIndex < ($listItems.length - 1)) { currentIndex += 1; } } else if (currentKeyCode === 38) { + // Move up if (currentIndex > 0) { currentIndex -= 1; } @@ -685,24 +741,32 @@ GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) { var $dropdownContent, $listItem, dropdownContentBottom, dropdownContentHeight, dropdownContentTop, dropdownScrollTop, listItemBottom, listItemHeight, listItemTop; + // Remove the class for the previously focused row $('.is-focused', this.dropdown).removeClass('is-focused'); + // Update the class for the row at the specific index $listItem = $listItems.eq(index); $listItem.find('a:first-child').addClass("is-focused"); + // Dropdown content scroll area $dropdownContent = $listItem.closest('.dropdown-content'); dropdownScrollTop = $dropdownContent.scrollTop(); dropdownContentHeight = $dropdownContent.outerHeight(); dropdownContentTop = $dropdownContent.prop('offsetTop'); dropdownContentBottom = dropdownContentTop + dropdownContentHeight; + // Get the offset bottom of the list item listItemHeight = $listItem.outerHeight(); listItemTop = $listItem.prop('offsetTop'); listItemBottom = listItemTop + listItemHeight; if (!index) { + // Scroll the dropdown content to the top $dropdownContent.scrollTop(0) } else if (index === ($listItems.length - 1)) { + // Scroll the dropdown content to the bottom $dropdownContent.scrollTop($dropdownContent.prop('scrollHeight')); } else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) { + // Scroll the dropdown content down $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING); } else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) { + // Scroll the dropdown content up return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING); } }; |