diff options
author | Bryce Johnson <bryce@gitlab.com> | 2016-11-10 13:43:09 +0100 |
---|---|---|
committer | Bryce Johnson <bryce@gitlab.com> | 2016-11-10 13:43:09 +0100 |
commit | d571cbf16133390c171964775526f4237f187afd (patch) | |
tree | 3deafe51368bb65a512d94c4e1ab737192ce7dd8 | |
parent | b7aaef3eb9c7b3f917779e69ecdbc67b2213160f (diff) | |
download | gitlab-ce-sidebar-tidying.tar.gz |
Break up milestone select according to SRP.sidebar-tidying
-rw-r--r-- | app/assets/javascripts/milestone_select.js.es6 | 300 |
1 files changed, 167 insertions, 133 deletions
diff --git a/app/assets/javascripts/milestone_select.js.es6 b/app/assets/javascripts/milestone_select.js.es6 index 5e00e7b9a78..debc8fdfb9d 100644 --- a/app/assets/javascripts/milestone_select.js.es6 +++ b/app/assets/javascripts/milestone_select.js.es6 @@ -2,165 +2,209 @@ (function (global) { class MilestoneSelect { constructor(currentProject) { - this.currentProject = currentProject ? JSON.parse(currentProject) : null; - this.dropdown = document.querySelectorAll('.js-milestone-select'); - this.dataset = this.dropdown.dataset; - // worth checking if this is being run for each time it's called. + this.$el = {}; + this.state = {}; + this.templates = {}; + this.config = {}; + + this.storeDomRefs(); + this.initConfig(); + this.storePageContext(); + this.initTemplates(); + this.initDropdown(); + } + + storeDomRefs() { + const $document = $(document); + const $body = $document.find('body'); + const $dropdown = $document.find('.js-milestone-select'); const $selectbox = $dropdown.closest('.selectbox'); const $block = $selectbox.closest('.block'); - const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); const $value = $block.find('.value'); - const $loading = $block.find('.block-loading').fadeOut(); - // either make member or lookup as needed. - // one dom query total plus jquery plugin - // hasClass add it to the utils - // get rid of all the dom queries + const $loading = $block.find('.block-loading'); + const $collapsedValue = $block.find('.sidebar-collapsed-icon'); - let milestoneLinkTemplate; - let milestoneLinkNoneTemplate; - let collapsedSidebarLabelTemplate; + _.extend(this.$el, { + body: $body, + document: $document, + dropdown: $dropdown, + dropdownSelectBox: $selectbox, + containerBlock: $block, + valueDisplay: $value + loadingDisplay: $loading, + collapsedValue: $collapsedValue + }); + } - - this.initTemplates(); - this.initDropdown(); + storePageContext() { + const $dropdown = this.$el.dropdown; + const currentPage = this.$el.body.data('page'); + + this.config.page = { + isIssueIndex: currentPage === 'projects:issues:index', + isMRIndex: currentPage === 'projects:merge_requests:index', + isBoardSidebar: $dropdown.hasClass('js-issue-board-sidebar'), + isSubmittableNonIndex: $dropdown.hasClass('js-filter-submit'), + isSubmittableIndex: $dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex), + isBoardIndex: $('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar'), + isInvalidMilestone: this.dropdown.hasClass('js-filter-bulk-update') || this.dropdown.hasClass('js-issuable-form-dropdown'), + }; + + const dataset = this.config.dataset = this.$el.dropdown.dataset; + + this.config.display = { + showMenuAbove: dataset['showMenuAbove'], + showNo: dataset['showNo'], + showAny: dataset['showAny'], + showUpcoming: dataset['showUpcoming'], + extraOptions: [] + }; + } + + initState() { + this.state.currentProject = currentProject ? JSON.parse(currentProject) : null; } + initTemplates() { if (this.dataset.issueUpdateURL) { - this.tpl = { - milestoneLinkTemplate: _.template(` - <a href='/<%- namespace %>/ <%- path %>/milestones/<%- iid %>' class='bold has-tooltip' + this.templates = { + milestoneLink: _.template(` + <a href='/<%- namespace %>/ <%- path %>/milestones/<%- iid %>' class='bold has-tooltip' data-container='body' title='<%- remaining %>'><%- title %> </a> `), - milestoneLinkNoneTemplate: `<span class='no-value'>None</span>`, - collapsedSidebarLabelTemplate: _.template(` - <span class='has-tooltip' data-container='body' title='<%- remaining %>' - data-placement='left'> <%- title %> + milestoneLinkNone: `<span class='no-value'>None</span>`, + collapsedSidebarLabel: _.template(` + <span class='has-tooltip' data-container='body' title='<%- remaining %>' + data-placement='left'> <%- title %> </span>` ), - }; + }; } } initDropdown() { - const showMenuAbove = this.dataset['showMenuAbove']; - const fieldName = this.dataset['fieldName']; - const selectedMilestone = this.dataset['selected']; - const isSelected = milestone => milestone.name === selectedMilestone; - const vue = this.dropdown.hasClass('js-issue-board-sidebar'); + const dataset = this.config.dataset; + const selectedMilestone = dataset['selected']; const searchFields = { fields: ['title'] }; - const defaultLabel = dropdownDataset['defaultLabel']; + const isSelected = milestone => milestone.name === selectedMilestone; $(this.dropdown).glDropdown({ - vue, - showMenuAbove, - defaultLabel, - fieldName, isSelected, filterable: true, selectable: true, - id: this.idFilter, search: searchFields, - data: this.fetchData, + defaultLabel: dataset.defaultLabel, + fieldName: dataset.fieldName, + vue: this.config.page.isBoardSidebar, + showMenuAbove: this.config.display.showMenuAbove, + id: this.filterSelected, + data: this.fetchMilestones, text: this.escapeText, - hidden: this.hideStuff, + hidden: this.renderDisplayState, toggleLabel: this.toggleLabel, clicked: this.handleDropdownClick, }); } - hideStuff() { + renderDisplayState() { $selectbox.hide(); // display:block overrides the hide-collapse rule $value.css('display', ''); } - + escapeText(milestone) { return _.escape(milestone.title); } - - idFilter(milestone) { + + filterSelected(milestone) { const useId = this.dataset['useId']; - return (!useId && !$dropdown.is('.js-issuable-form-dropdown')) ? milestone.name : milestone.id; + return (!useId && !this.$el.dropdown.is('.js-issuable-form-dropdown')) ? milestone.name : milestone.id; } - - fetchData(term, callback) { + + fetchMilestones(term, callback) { const milestonesUrl = this.dataset['milestonesUrl']; return $.ajax({ url: milestonesUrl }) .done((data) => { - const extraOptions = prepExtraOptions(); - callback(extraOptions.concat(data)); + this.prepExtraOptions(); + callback(this.config.extraOptions.concat(data)); this.positionMenuAbove(); }); } - + toggleLabel() { - // Question: What are the main datastructures at work. How are the classes organized? const defaultLabel = dropdownDataset['defaultLabel']; - return (selected, el, e) => (selected && selected.id && el.hasClass('is-active')) ? + return (selected, el, e) => (selected && selected.id && el.hasClass('is-active')) ? selected.title : defaultLabel; } - + positionMenuAbove() { - if (showMenuAbove) { - this.dropdown.positionMenuAbove(); + if (this.config.display.showMenuAbove) { + this.$el.dropdown.positionMenuAbove(); } } - - pushExtraOptions(extraOptions, id, name, title) { + + prepExtraOptions() { + if (showAny) this.storeExtraDropdownOptions(0, '', 'Any Milestone'); + if (showNo) this.storeExtraDropdownOptions(-1, 'No Milestone', 'No Milestone'); + if (showUpcoming) this.storeExtraDropdownOptions(-2, '#upcoming', 'Upcoming'); + if (extraOptions.length) this.storeExtraDropdownOptions('divider'); + } + + storeExtraDropdownOptions(id, name, title) { const divider = 'divider'; const pushable = id === divider ? divider : { id, name, title }; - extraOptions.push(pushable); + this.extraOptions.push(pushable); } - - prepExtraOptions() { - const showNo = this.dataset['showNo']; - const showAny = this.dataset['showAny']; - const showMenuAbove = this.dataset['showMenuAbove']; - const showUpcoming = this.dataset['showUpcoming']; - - var extraOptions = []; - if (showAny) { - pushExtraOptions(extraOptions, 0, '', 'Any Milestone'); + + renderLoadingState() { + this.$el.loadingDisplay.fadeIn(); + $dropdown.trigger('loading.gl.dropdown'); + } + + renderLoadedState() { + this.$el.loadingDisplay.fadeOut(); + $dropdown.trigger('loaded.gl.dropdown'); + } + + handleDropdownClick(selected, $el, e) { + const pageConfig = this.config.page; + + if (pageConfig.isInvalidMilestone) { + return e.preventDefault(); } - if (showNo) { - pushExtraOptions(extraOptions, -1, 'No Milestone', 'No Milestone'); + + if (pageConfig.isBoardPage) { + return this.putIssueBoardPage(); } - // DRY ME UP (these configs) - if (showUpcoming) { - pushExtraOptions(extraOptions, -2, '#upcoming', 'Upcoming') + + if (pageConfig.isSubmittableIndex) { + return this.putSubmittableIndex(); } - if (extraOptions.length) { - pushExtraOptions(extraOptions, 'divider'); + + if (pageConfig.isSubmittableNonIndex) { + return this.putSubmittableNonIndex(); } - } - - initLoadingUi() { - $loading.fadeIn(); - $dropdown.trigger('loading.gl.dropdown'); - } - // much better method name - // adds documention to configuration - handlePut(data) { - $dropdown.trigger('loaded.gl.dropdown'); - $loading.fadeOut(); - $selectbox.hide(); - $value.css('display', ''); - if (data.milestone != null) { - data.milestone.namespace = this.currentProject.namespace; - data.milestone.path = this.currentProject.path; - data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date); - $value.html(milestoneLinkTemplate(data.milestone)); - return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone)); - } else { - $value.html(milestoneLinkNoneTemplate); - return $sidebarCollapsedValue.find('span').text('No'); + + if (pageConfig.isBoardSidebar) { + return this.putIssueBoardSidebar(); } + + return this.putGeneric(); + } + + putGeneric() { + const abilityName = this.config.dataset['abilityName']; + const milestone_id = this.$el.dropdownSelectBox.find('input[type="hidden"]').val(); + const milestonePayload = { [abilityName]: { milestone_id } }; + // Swap out for vue resource. + $.ajax({ type: 'PUT', url: issueUpdateURL, data: milestonePayload }) + .done(data => this.handlePut); } - + putIssueBoardPage() { gl.issueBoards.BoardsStore.state.filters[this.dataset['fieldName']] = selected.name; gl.issueBoards.BoardsStore.updateFiltersUrl(); @@ -177,14 +221,10 @@ Vue.delete(gl.issueBoards.BoardsStore.detail.issue, 'milestone'); } - $dropdown.trigger('loading.gl.dropdown'); - $loading.fadeIn(); + this.renderLoadingState(); - gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) - .then(function () { - $dropdown.trigger('loaded.gl.dropdown'); - $loading.fadeOut(); - }); + gl.issueBoards.BoardsStore.detail.issue.update(this.config.dataset('issueUpdate')) + .then(() => this.renderLoadedState()); } putSubmittableIndex() { @@ -198,42 +238,36 @@ return $dropdown.closest('form').submit(); } - handleDropdownClick(selected, $el, e) { - // No jq needed here. - const page = $('body').data('page'); - const isIssueIndex = page === 'projects:issues:index'; - const isMRIndex = page === 'projects:merge_requests:index'; - const isInvalidMilestone = this.dropdown.hasClass('js-filter-bulk-update') || this.dropdown.hasClass('js-issuable-form-dropdown'); + handlePutSuccess(data) { + this.renderLoadedState(); + this.$el.dropdownSelectBox.hide(); + this.$el.selectedMilestone.css('display', ''); - if (isInvalidMilestone) { - return e.preventDefault(); + const newMilestone = this.parsePutValue(); + this.writePutValue(newMilestone); + } + + parsePutValue() { + if (data.milestone != null) { + data.milestone.namespace = this.currentProject.namespace; + data.milestone.path = this.currentProject.path; + data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date); } + return data.milestone; + } - const isBoardPage = $('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar'); - const isSubmittableIndex = $dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex); - const isSubmittableNonIndex = $dropdown.hasClass('js-filter-submit'); - const isBoardSidebar = $dropdown.hasClass('js-issue-board-sidebar'); - // all reasons not to PUT ^^ - if (isBoardPage) { - this.putIssueBoardPage(); - } else if (isSubmittableIndex) { - this.putSubmittableIndex(); - } else if (isSubmittableNonIndex) { - this.putSubmittableNonIndex(); - } else if (isBoardSidebar) { - this.putIssueBoardSidebar(); - } else { - // PUT it - const abilityName = this.dataset['abilityName']; - - const milestone_id = $selectbox.find('input[type="hidden"]').val(); - const milestonePayload = { [abilityName]: { milestone_id } }; - // Swap out for vue resource. - $.ajax({ type: 'PUT', url: issueUpdateURL, data: milestonePayload }) - .done(data => this.handlePut); + writePutValue(newMilestone) { + const $valueDisplay = this.$el.valueDisplay; + const $collapsedValue = this.$el.collapsedValue; + + if (newMilestone != null) { + $valueDisplay.html(this.templates.milestoneLink(data.milestone)); + $sidebarCollapsedValue.find('span').html(this.templates.collapsedSidebarLabel(data.milestone)); + } else { + $valueDisplay.html(this.templates.milestoneLinkNone); + $sidebarCollapsedValue.find('span').text('No'); } } } - global.MilestoneSelect = MilestoneSelect; })(window.gl || (window.gl = {})); |