summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryce Johnson <bryce@gitlab.com>2016-11-10 13:43:09 +0100
committerBryce Johnson <bryce@gitlab.com>2016-11-10 13:43:09 +0100
commitd571cbf16133390c171964775526f4237f187afd (patch)
tree3deafe51368bb65a512d94c4e1ab737192ce7dd8
parentb7aaef3eb9c7b3f917779e69ecdbc67b2213160f (diff)
downloadgitlab-ce-sidebar-tidying.tar.gz
Break up milestone select according to SRP.sidebar-tidying
-rw-r--r--app/assets/javascripts/milestone_select.js.es6300
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 = {}));