From 0f7cc21e2479762975c4416148105e876c85d8cd Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Mon, 10 Oct 2016 17:09:48 +0100 Subject: Formatted all app/assets/javascripts to underscore naming convention --- app/assets/javascripts/LabelManager.js.es6 | 106 ------ app/assets/javascripts/commit/image-file.js | 177 --------- app/assets/javascripts/commit/image_file.js | 177 +++++++++ app/assets/javascripts/cycle-analytics.js.es6 | 93 ----- app/assets/javascripts/cycle_analytics.js.es6 | 93 +++++ .../javascripts/issues-bulk-assignment.js.es6 | 149 -------- .../javascripts/issues_bulk_assignment.js.es6 | 149 ++++++++ app/assets/javascripts/label_manager.js.es6 | 106 ++++++ app/assets/javascripts/network/branch-graph.js | 417 --------------------- app/assets/javascripts/network/branch_graph.js | 417 +++++++++++++++++++++ 10 files changed, 942 insertions(+), 942 deletions(-) delete mode 100644 app/assets/javascripts/LabelManager.js.es6 delete mode 100644 app/assets/javascripts/commit/image-file.js create mode 100644 app/assets/javascripts/commit/image_file.js delete mode 100644 app/assets/javascripts/cycle-analytics.js.es6 create mode 100644 app/assets/javascripts/cycle_analytics.js.es6 delete mode 100644 app/assets/javascripts/issues-bulk-assignment.js.es6 create mode 100644 app/assets/javascripts/issues_bulk_assignment.js.es6 create mode 100644 app/assets/javascripts/label_manager.js.es6 delete mode 100644 app/assets/javascripts/network/branch-graph.js create mode 100644 app/assets/javascripts/network/branch_graph.js diff --git a/app/assets/javascripts/LabelManager.js.es6 b/app/assets/javascripts/LabelManager.js.es6 deleted file mode 100644 index bc68e53504f..00000000000 --- a/app/assets/javascripts/LabelManager.js.es6 +++ /dev/null @@ -1,106 +0,0 @@ -((global) => { - - class LabelManager { - constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) { - this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority'); - this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels'); - this.otherLabels = otherLabels || $('.js-other-labels'); - this.errorMessage = 'Unable to update label prioritization at this time'; - this.prioritizedLabels.sortable({ - items: 'li', - placeholder: 'list-placeholder', - axis: 'y', - update: this.onPrioritySortUpdate.bind(this) - }); - this.bindEvents(); - } - - bindEvents() { - return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick); - } - - onTogglePriorityClick(e) { - e.preventDefault(); - const _this = e.data; - const $btn = $(e.currentTarget); - const $label = $(`#${$btn.data('domId')}`); - const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; - const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); - $tooltip.tooltip('destroy'); - return _this.toggleLabelPriority($label, action); - } - - toggleLabelPriority($label, action, persistState) { - if (persistState == null) { - persistState = true; - } - let xhr; - const _this = this; - const url = $label.find('.js-toggle-priority').data('url'); - let $target = this.prioritizedLabels; - let $from = this.otherLabels; - if (action === 'remove') { - $target = this.otherLabels; - $from = this.prioritizedLabels; - } - if ($from.find('li').length === 1) { - $from.find('.empty-message').removeClass('hidden'); - } - if (!$target.find('li').length) { - $target.find('.empty-message').addClass('hidden'); - } - $label.detach().appendTo($target); - // Return if we are not persisting state - if (!persistState) { - return; - } - if (action === 'remove') { - xhr = $.ajax({ - url, - type: 'DELETE' - }); - // Restore empty message - if (!$from.find('li').length) { - $from.find('.empty-message').removeClass('hidden'); - } - } else { - xhr = this.savePrioritySort($label, action); - } - return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action)); - } - - onPrioritySortUpdate() { - const xhr = this.savePrioritySort(); - return xhr.fail(function() { - return new Flash(this.errorMessage, 'alert'); - }); - } - - savePrioritySort() { - return $.post({ - url: this.prioritizedLabels.data('url'), - data: { - label_ids: this.getSortedLabelsIds() - } - }); - } - - rollbackLabelPosition($label, originalAction) { - const action = originalAction === 'remove' ? 'add' : 'remove'; - this.toggleLabelPriority($label, action, false); - return new Flash(this.errorMessage, 'alert'); - } - - getSortedLabelsIds() { - const sortedIds = []; - this.prioritizedLabels.find('li').each(function() { - sortedIds.push($(this).data('id')); - }); - return sortedIds; - } - } - - gl.LabelManager = LabelManager; - -})(window.gl || (window.gl = {})); - diff --git a/app/assets/javascripts/commit/image-file.js b/app/assets/javascripts/commit/image-file.js deleted file mode 100644 index e893491b19b..00000000000 --- a/app/assets/javascripts/commit/image-file.js +++ /dev/null @@ -1,177 +0,0 @@ -(function() { - this.ImageFile = (function() { - var prepareFrames; - - // Width where images must fits in, for 2-up this gets divided by 2 - ImageFile.availWidth = 900; - - ImageFile.viewModes = ['two-up', 'swipe']; - - function ImageFile(file) { - this.file = file; - this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { - // Determine if old and new file has same dimensions, if not show 'two-up' view - return function(deletedWidth, deletedHeight) { - return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { - if (width === deletedWidth && height === deletedHeight) { - return _this.initViewModes(); - } else { - return _this.initView('two-up'); - } - }); - }; - })(this)); - } - - ImageFile.prototype.initViewModes = function() { - var viewMode; - viewMode = ImageFile.viewModes[0]; - $('.view-modes', this.file).removeClass('hide'); - $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { - return function(event) { - if (!$(event.currentTarget).hasClass('active')) { - return _this.activateViewMode(event.currentTarget.className); - } - }; - })(this)); - return this.activateViewMode(viewMode); - }; - - ImageFile.prototype.activateViewMode = function(viewMode) { - $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); - return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { - return function() { - $(".view." + viewMode, _this.file).fadeIn(200); - return _this.initView(viewMode); - }; - })(this)); - }; - - ImageFile.prototype.initView = function(viewMode) { - return this.views[viewMode].call(this); - }; - - prepareFrames = function(view) { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - $('.frame', view).each((function(_this) { - return function(index, frame) { - var height, width; - width = $(frame).width(); - height = $(frame).height(); - maxWidth = width > maxWidth ? width : maxWidth; - return maxHeight = height > maxHeight ? height : maxHeight; - }; - })(this)).css({ - width: maxWidth, - height: maxHeight - }); - return [maxWidth, maxHeight]; - }; - - ImageFile.prototype.views = { - 'two-up': function() { - return $('.two-up.view .wrap', this.file).each((function(_this) { - return function(index, wrap) { - $('img', wrap).each(function() { - var currentWidth; - currentWidth = $(this).width(); - if (currentWidth > ImageFile.availWidth / 2) { - return $(this).width(ImageFile.availWidth / 2); - } - }); - return _this.requestImageInfo($('img', wrap), function(width, height) { - $('.image-info .meta-width', wrap).text(width + "px"); - $('.image-info .meta-height', wrap).text(height + "px"); - return $('.image-info', wrap).removeClass('hide'); - }); - }; - })(this)); - }, - 'swipe': function() { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - return $('.swipe.view', this.file).each((function(_this) { - return function(index, view) { - var ref; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $('.swipe-frame', view).css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $('.swipe-wrap', view).css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - return $('.swipe-bar', view).css({ - left: 0 - }).draggable({ - axis: 'x', - containment: 'parent', - drag: function(event) { - return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left); - }, - stop: function(event) { - return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left); - } - }); - }; - })(this)); - }, - 'onion-skin': function() { - var dragTrackWidth, maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); - return $('.onion-skin.view', this.file).each((function(_this) { - return function(index, view) { - var ref; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $('.onion-skin-frame', view).css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $('.swipe-wrap', view).css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - return $('.dragger', view).css({ - left: dragTrackWidth - }).draggable({ - axis: 'x', - containment: 'parent', - drag: function(event) { - return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth); - }, - stop: function(event) { - return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth); - } - }); - }; - })(this)); - } - }; - - ImageFile.prototype.requestImageInfo = function(img, callback) { - var domImg; - domImg = img.get(0); - if (domImg) { - if (domImg.complete) { - return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); - } else { - return img.on('load', (function(_this) { - return function() { - return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); - }; - })(this)); - } - } - }; - - return ImageFile; - - })(); - -}).call(this); diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js new file mode 100644 index 00000000000..e893491b19b --- /dev/null +++ b/app/assets/javascripts/commit/image_file.js @@ -0,0 +1,177 @@ +(function() { + this.ImageFile = (function() { + var prepareFrames; + + // Width where images must fits in, for 2-up this gets divided by 2 + ImageFile.availWidth = 900; + + ImageFile.viewModes = ['two-up', 'swipe']; + + function ImageFile(file) { + this.file = file; + this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { + // Determine if old and new file has same dimensions, if not show 'two-up' view + return function(deletedWidth, deletedHeight) { + return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { + if (width === deletedWidth && height === deletedHeight) { + return _this.initViewModes(); + } else { + return _this.initView('two-up'); + } + }); + }; + })(this)); + } + + ImageFile.prototype.initViewModes = function() { + var viewMode; + viewMode = ImageFile.viewModes[0]; + $('.view-modes', this.file).removeClass('hide'); + $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { + return function(event) { + if (!$(event.currentTarget).hasClass('active')) { + return _this.activateViewMode(event.currentTarget.className); + } + }; + })(this)); + return this.activateViewMode(viewMode); + }; + + ImageFile.prototype.activateViewMode = function(viewMode) { + $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); + return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { + return function() { + $(".view." + viewMode, _this.file).fadeIn(200); + return _this.initView(viewMode); + }; + })(this)); + }; + + ImageFile.prototype.initView = function(viewMode) { + return this.views[viewMode].call(this); + }; + + prepareFrames = function(view) { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + $('.frame', view).each((function(_this) { + return function(index, frame) { + var height, width; + width = $(frame).width(); + height = $(frame).height(); + maxWidth = width > maxWidth ? width : maxWidth; + return maxHeight = height > maxHeight ? height : maxHeight; + }; + })(this)).css({ + width: maxWidth, + height: maxHeight + }); + return [maxWidth, maxHeight]; + }; + + ImageFile.prototype.views = { + 'two-up': function() { + return $('.two-up.view .wrap', this.file).each((function(_this) { + return function(index, wrap) { + $('img', wrap).each(function() { + var currentWidth; + currentWidth = $(this).width(); + if (currentWidth > ImageFile.availWidth / 2) { + return $(this).width(ImageFile.availWidth / 2); + } + }); + return _this.requestImageInfo($('img', wrap), function(width, height) { + $('.image-info .meta-width', wrap).text(width + "px"); + $('.image-info .meta-height', wrap).text(height + "px"); + return $('.image-info', wrap).removeClass('hide'); + }); + }; + })(this)); + }, + 'swipe': function() { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + return $('.swipe.view', this.file).each((function(_this) { + return function(index, view) { + var ref; + ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $('.swipe-frame', view).css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $('.swipe-wrap', view).css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + return $('.swipe-bar', view).css({ + left: 0 + }).draggable({ + axis: 'x', + containment: 'parent', + drag: function(event) { + return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left); + }, + stop: function(event) { + return $('.swipe-wrap', view).width((maxWidth + 1) - $(this).position().left); + } + }); + }; + })(this)); + }, + 'onion-skin': function() { + var dragTrackWidth, maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); + return $('.onion-skin.view', this.file).each((function(_this) { + return function(index, view) { + var ref; + ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $('.onion-skin-frame', view).css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $('.swipe-wrap', view).css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + return $('.dragger', view).css({ + left: dragTrackWidth + }).draggable({ + axis: 'x', + containment: 'parent', + drag: function(event) { + return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth); + }, + stop: function(event) { + return $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth); + } + }); + }; + })(this)); + } + }; + + ImageFile.prototype.requestImageInfo = function(img, callback) { + var domImg; + domImg = img.get(0); + if (domImg) { + if (domImg.complete) { + return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); + } else { + return img.on('load', (function(_this) { + return function() { + return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); + }; + })(this)); + } + } + }; + + return ImageFile; + + })(); + +}).call(this); diff --git a/app/assets/javascripts/cycle-analytics.js.es6 b/app/assets/javascripts/cycle-analytics.js.es6 deleted file mode 100644 index cd9886ba58d..00000000000 --- a/app/assets/javascripts/cycle-analytics.js.es6 +++ /dev/null @@ -1,93 +0,0 @@ -((global) => { - - const COOKIE_NAME = 'cycle_analytics_help_dismissed'; - const store = gl.cycleAnalyticsStore = { - isLoading: true, - hasError: false, - isHelpDismissed: $.cookie(COOKIE_NAME), - analytics: {} - }; - - gl.CycleAnalytics = class CycleAnalytics { - constructor() { - const that = this; - - this.vue = new Vue({ - el: '#cycle-analytics', - name: 'CycleAnalytics', - created: this.fetchData(), - data: store, - methods: { - dismissLanding() { - that.dismissLanding(); - } - } - }); - } - - fetchData(options) { - store.isLoading = true; - options = options || { startDate: 30 }; - - $.ajax({ - url: $('#cycle-analytics').data('request-path'), - method: 'GET', - dataType: 'json', - contentType: 'application/json', - data: { start_date: options.startDate } - }).done((data) => { - this.decorateData(data); - this.initDropdown(); - }) - .error((data) => { - this.handleError(data); - }) - .always(() => { - store.isLoading = false; - }) - } - - decorateData(data) { - data.summary = data.summary || []; - data.stats = data.stats || []; - - data.summary.forEach((item) => { - item.value = item.value || '-'; - }); - - data.stats.forEach((item) => { - item.value = item.value || '- - -'; - }); - - store.analytics = data; - } - - handleError(data) { - store.hasError = true; - new Flash('There was an error while fetching cycle analytics data.', 'alert'); - } - - dismissLanding() { - store.isHelpDismissed = true; - $.cookie(COOKIE_NAME, true, { - path: gon.relative_url_root || '/' - }); - } - - initDropdown() { - const $dropdown = $('.js-ca-dropdown'); - const $label = $dropdown.find('.dropdown-label'); - - $dropdown.find('li a').off('click').on('click', (e) => { - e.preventDefault(); - const $target = $(e.currentTarget); - const value = $target.data('value'); - - $label.text($target.text().trim()); - this.fetchData({ startDate: value }); - }) - } - - } - -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/cycle_analytics.js.es6 b/app/assets/javascripts/cycle_analytics.js.es6 new file mode 100644 index 00000000000..cd9886ba58d --- /dev/null +++ b/app/assets/javascripts/cycle_analytics.js.es6 @@ -0,0 +1,93 @@ +((global) => { + + const COOKIE_NAME = 'cycle_analytics_help_dismissed'; + const store = gl.cycleAnalyticsStore = { + isLoading: true, + hasError: false, + isHelpDismissed: $.cookie(COOKIE_NAME), + analytics: {} + }; + + gl.CycleAnalytics = class CycleAnalytics { + constructor() { + const that = this; + + this.vue = new Vue({ + el: '#cycle-analytics', + name: 'CycleAnalytics', + created: this.fetchData(), + data: store, + methods: { + dismissLanding() { + that.dismissLanding(); + } + } + }); + } + + fetchData(options) { + store.isLoading = true; + options = options || { startDate: 30 }; + + $.ajax({ + url: $('#cycle-analytics').data('request-path'), + method: 'GET', + dataType: 'json', + contentType: 'application/json', + data: { start_date: options.startDate } + }).done((data) => { + this.decorateData(data); + this.initDropdown(); + }) + .error((data) => { + this.handleError(data); + }) + .always(() => { + store.isLoading = false; + }) + } + + decorateData(data) { + data.summary = data.summary || []; + data.stats = data.stats || []; + + data.summary.forEach((item) => { + item.value = item.value || '-'; + }); + + data.stats.forEach((item) => { + item.value = item.value || '- - -'; + }); + + store.analytics = data; + } + + handleError(data) { + store.hasError = true; + new Flash('There was an error while fetching cycle analytics data.', 'alert'); + } + + dismissLanding() { + store.isHelpDismissed = true; + $.cookie(COOKIE_NAME, true, { + path: gon.relative_url_root || '/' + }); + } + + initDropdown() { + const $dropdown = $('.js-ca-dropdown'); + const $label = $dropdown.find('.dropdown-label'); + + $dropdown.find('li a').off('click').on('click', (e) => { + e.preventDefault(); + const $target = $(e.currentTarget); + const value = $target.data('value'); + + $label.text($target.text().trim()); + this.fetchData({ startDate: value }); + }) + } + + } + +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/issues-bulk-assignment.js.es6 b/app/assets/javascripts/issues-bulk-assignment.js.es6 deleted file mode 100644 index 0808f538f01..00000000000 --- a/app/assets/javascripts/issues-bulk-assignment.js.es6 +++ /dev/null @@ -1,149 +0,0 @@ -((global) => { - - class IssuableBulkActions { - constructor({ container, form, issues } = {}) { - this.container = container || $('.content'), - this.form = form || this.getElement('.bulk-update'); - this.issues = issues || this.getElement('.issues-list .issue'); - this.form.data('bulkActions', this); - this.willUpdateLabels = false; - this.bindEvents(); - // Fixes bulk-assign not working when navigating through pages - Issuable.initChecks(); - } - - getElement(selector) { - return this.container.find(selector); - } - - bindEvents() { - return this.form.off('submit').on('submit', this.onFormSubmit.bind(this)); - } - - onFormSubmit(e) { - e.preventDefault(); - return this.submit(); - } - - submit() { - const _this = this; - const xhr = $.ajax({ - url: this.form.attr('action'), - method: this.form.attr('method'), - dataType: 'JSON', - data: this.getFormDataAsObject() - }); - xhr.done(() => window.location.reload()); - xhr.fail(() => new Flash("Issue update failed")); - return xhr.always(this.onFormSubmitAlways.bind(this)); - } - - onFormSubmitAlways() { - return this.form.find('[type="submit"]').enable(); - } - - getSelectedIssues() { - return this.issues.has('.selected_issue:checked'); - } - - getLabelsFromSelection() { - const labels = []; - this.getSelectedIssues().map(function() { - const labelsData = $(this).data('labels'); - if (labelsData) { - return labelsData.map(function(labelId) { - if (labels.indexOf(labelId) === -1) { - return labels.push(labelId); - } - }); - } - }); - return labels; - } - - - /** - * Will return only labels that were marked previously and the user has unmarked - * @return {Array} Label IDs - */ - - getUnmarkedIndeterminedLabels() { - const result = []; - const labelsToKeep = []; - - this.getElement('.labels-filter .is-indeterminate') - .each((i, el) => labelsToKeep.push($(el).data('labelId'))); - - this.getLabelsFromSelection().forEach((id) => { - if (labelsToKeep.indexOf(id) === -1) { - result.push(id); - } - }); - - return result; - } - - - /** - * Simple form serialization, it will return just what we need - * Returns key/value pairs from form data - */ - - getFormDataAsObject() { - const formData = { - update: { - state_event: this.form.find('input[name="update[state_event]"]').val(), - assignee_id: this.form.find('input[name="update[assignee_id]"]').val(), - milestone_id: this.form.find('input[name="update[milestone_id]"]').val(), - issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(), - subscription_event: this.form.find('input[name="update[subscription_event]"]').val(), - add_label_ids: [], - remove_label_ids: [] - } - }; - if (this.willUpdateLabels) { - this.getLabelsToApply().map(function(id) { - return formData.update.add_label_ids.push(id); - }); - this.getLabelsToRemove().map(function(id) { - return formData.update.remove_label_ids.push(id); - }); - } - return formData; - } - - getLabelsToApply() { - const labelIds = []; - const $labels = this.form.find('.labels-filter input[name="update[label_ids][]"]'); - $labels.each(function(k, label) { - if (label) { - return labelIds.push(parseInt($(label).val())); - } - }); - return labelIds; - } - - - /** - * Returns Label IDs that will be removed from issue selection - * @return {Array} Array of labels IDs - */ - - getLabelsToRemove() { - const result = []; - const indeterminatedLabels = this.getUnmarkedIndeterminedLabels(); - const labelsToApply = this.getLabelsToApply(); - indeterminatedLabels.map(function(id) { - // We need to exclude label IDs that will be applied - // By not doing this will cause issues from selection to not add labels at all - if (labelsToApply.indexOf(id) === -1) { - return result.push(id); - } - }); - return result; - } - } - - global.IssuableBulkActions = IssuableBulkActions; - -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/issues_bulk_assignment.js.es6 b/app/assets/javascripts/issues_bulk_assignment.js.es6 new file mode 100644 index 00000000000..0808f538f01 --- /dev/null +++ b/app/assets/javascripts/issues_bulk_assignment.js.es6 @@ -0,0 +1,149 @@ +((global) => { + + class IssuableBulkActions { + constructor({ container, form, issues } = {}) { + this.container = container || $('.content'), + this.form = form || this.getElement('.bulk-update'); + this.issues = issues || this.getElement('.issues-list .issue'); + this.form.data('bulkActions', this); + this.willUpdateLabels = false; + this.bindEvents(); + // Fixes bulk-assign not working when navigating through pages + Issuable.initChecks(); + } + + getElement(selector) { + return this.container.find(selector); + } + + bindEvents() { + return this.form.off('submit').on('submit', this.onFormSubmit.bind(this)); + } + + onFormSubmit(e) { + e.preventDefault(); + return this.submit(); + } + + submit() { + const _this = this; + const xhr = $.ajax({ + url: this.form.attr('action'), + method: this.form.attr('method'), + dataType: 'JSON', + data: this.getFormDataAsObject() + }); + xhr.done(() => window.location.reload()); + xhr.fail(() => new Flash("Issue update failed")); + return xhr.always(this.onFormSubmitAlways.bind(this)); + } + + onFormSubmitAlways() { + return this.form.find('[type="submit"]').enable(); + } + + getSelectedIssues() { + return this.issues.has('.selected_issue:checked'); + } + + getLabelsFromSelection() { + const labels = []; + this.getSelectedIssues().map(function() { + const labelsData = $(this).data('labels'); + if (labelsData) { + return labelsData.map(function(labelId) { + if (labels.indexOf(labelId) === -1) { + return labels.push(labelId); + } + }); + } + }); + return labels; + } + + + /** + * Will return only labels that were marked previously and the user has unmarked + * @return {Array} Label IDs + */ + + getUnmarkedIndeterminedLabels() { + const result = []; + const labelsToKeep = []; + + this.getElement('.labels-filter .is-indeterminate') + .each((i, el) => labelsToKeep.push($(el).data('labelId'))); + + this.getLabelsFromSelection().forEach((id) => { + if (labelsToKeep.indexOf(id) === -1) { + result.push(id); + } + }); + + return result; + } + + + /** + * Simple form serialization, it will return just what we need + * Returns key/value pairs from form data + */ + + getFormDataAsObject() { + const formData = { + update: { + state_event: this.form.find('input[name="update[state_event]"]').val(), + assignee_id: this.form.find('input[name="update[assignee_id]"]').val(), + milestone_id: this.form.find('input[name="update[milestone_id]"]').val(), + issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(), + subscription_event: this.form.find('input[name="update[subscription_event]"]').val(), + add_label_ids: [], + remove_label_ids: [] + } + }; + if (this.willUpdateLabels) { + this.getLabelsToApply().map(function(id) { + return formData.update.add_label_ids.push(id); + }); + this.getLabelsToRemove().map(function(id) { + return formData.update.remove_label_ids.push(id); + }); + } + return formData; + } + + getLabelsToApply() { + const labelIds = []; + const $labels = this.form.find('.labels-filter input[name="update[label_ids][]"]'); + $labels.each(function(k, label) { + if (label) { + return labelIds.push(parseInt($(label).val())); + } + }); + return labelIds; + } + + + /** + * Returns Label IDs that will be removed from issue selection + * @return {Array} Array of labels IDs + */ + + getLabelsToRemove() { + const result = []; + const indeterminatedLabels = this.getUnmarkedIndeterminedLabels(); + const labelsToApply = this.getLabelsToApply(); + indeterminatedLabels.map(function(id) { + // We need to exclude label IDs that will be applied + // By not doing this will cause issues from selection to not add labels at all + if (labelsToApply.indexOf(id) === -1) { + return result.push(id); + } + }); + return result; + } + } + + global.IssuableBulkActions = IssuableBulkActions; + +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/label_manager.js.es6 b/app/assets/javascripts/label_manager.js.es6 new file mode 100644 index 00000000000..bc68e53504f --- /dev/null +++ b/app/assets/javascripts/label_manager.js.es6 @@ -0,0 +1,106 @@ +((global) => { + + class LabelManager { + constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) { + this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority'); + this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels'); + this.otherLabels = otherLabels || $('.js-other-labels'); + this.errorMessage = 'Unable to update label prioritization at this time'; + this.prioritizedLabels.sortable({ + items: 'li', + placeholder: 'list-placeholder', + axis: 'y', + update: this.onPrioritySortUpdate.bind(this) + }); + this.bindEvents(); + } + + bindEvents() { + return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick); + } + + onTogglePriorityClick(e) { + e.preventDefault(); + const _this = e.data; + const $btn = $(e.currentTarget); + const $label = $(`#${$btn.data('domId')}`); + const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; + const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); + $tooltip.tooltip('destroy'); + return _this.toggleLabelPriority($label, action); + } + + toggleLabelPriority($label, action, persistState) { + if (persistState == null) { + persistState = true; + } + let xhr; + const _this = this; + const url = $label.find('.js-toggle-priority').data('url'); + let $target = this.prioritizedLabels; + let $from = this.otherLabels; + if (action === 'remove') { + $target = this.otherLabels; + $from = this.prioritizedLabels; + } + if ($from.find('li').length === 1) { + $from.find('.empty-message').removeClass('hidden'); + } + if (!$target.find('li').length) { + $target.find('.empty-message').addClass('hidden'); + } + $label.detach().appendTo($target); + // Return if we are not persisting state + if (!persistState) { + return; + } + if (action === 'remove') { + xhr = $.ajax({ + url, + type: 'DELETE' + }); + // Restore empty message + if (!$from.find('li').length) { + $from.find('.empty-message').removeClass('hidden'); + } + } else { + xhr = this.savePrioritySort($label, action); + } + return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action)); + } + + onPrioritySortUpdate() { + const xhr = this.savePrioritySort(); + return xhr.fail(function() { + return new Flash(this.errorMessage, 'alert'); + }); + } + + savePrioritySort() { + return $.post({ + url: this.prioritizedLabels.data('url'), + data: { + label_ids: this.getSortedLabelsIds() + } + }); + } + + rollbackLabelPosition($label, originalAction) { + const action = originalAction === 'remove' ? 'add' : 'remove'; + this.toggleLabelPriority($label, action, false); + return new Flash(this.errorMessage, 'alert'); + } + + getSortedLabelsIds() { + const sortedIds = []; + this.prioritizedLabels.find('li').each(function() { + sortedIds.push($(this).data('id')); + }); + return sortedIds; + } + } + + gl.LabelManager = LabelManager; + +})(window.gl || (window.gl = {})); + diff --git a/app/assets/javascripts/network/branch-graph.js b/app/assets/javascripts/network/branch-graph.js deleted file mode 100644 index 91132af273a..00000000000 --- a/app/assets/javascripts/network/branch-graph.js +++ /dev/null @@ -1,417 +0,0 @@ -(function() { - var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - this.BranchGraph = (function() { - function BranchGraph(element1, options1) { - this.element = element1; - this.options = options1; - this.scrollTop = bind(this.scrollTop, this); - this.scrollBottom = bind(this.scrollBottom, this); - this.scrollRight = bind(this.scrollRight, this); - this.scrollLeft = bind(this.scrollLeft, this); - this.scrollUp = bind(this.scrollUp, this); - this.scrollDown = bind(this.scrollDown, this); - this.preparedCommits = {}; - this.mtime = 0; - this.mspace = 0; - this.parents = {}; - this.colors = ["#000"]; - this.offsetX = 150; - this.offsetY = 20; - this.unitTime = 30; - this.unitSpace = 10; - this.prev_start = -1; - this.load(); - } - - BranchGraph.prototype.load = function() { - return $.ajax({ - url: this.options.url, - method: "get", - dataType: "json", - success: $.proxy(function(data) { - $(".loading", this.element).hide(); - this.prepareData(data.days, data.commits); - return this.buildGraph(); - }, this) - }); - }; - - BranchGraph.prototype.prepareData = function(days, commits) { - var c, ch, cw, j, len, ref; - this.days = days; - this.commits = commits; - this.collectParents(); - this.graphHeight = $(this.element).height(); - this.graphWidth = $(this.element).width(); - ch = Math.max(this.graphHeight, this.offsetY + this.unitTime * this.mtime + 150); - cw = Math.max(this.graphWidth, this.offsetX + this.unitSpace * this.mspace + 300); - this.r = Raphael(this.element.get(0), cw, ch); - this.top = this.r.set(); - this.barHeight = Math.max(this.graphHeight, this.unitTime * this.days.length + 320); - ref = this.commits; - for (j = 0, len = ref.length; j < len; j++) { - c = ref[j]; - if (c.id in this.parents) { - c.isParent = true; - } - this.preparedCommits[c.id] = c; - this.markCommit(c); - } - return this.collectColors(); - }; - - BranchGraph.prototype.collectParents = function() { - var c, j, len, p, ref, results; - ref = this.commits; - results = []; - for (j = 0, len = ref.length; j < len; j++) { - c = ref[j]; - this.mtime = Math.max(this.mtime, c.time); - this.mspace = Math.max(this.mspace, c.space); - results.push((function() { - var l, len1, ref1, results1; - ref1 = c.parents; - results1 = []; - for (l = 0, len1 = ref1.length; l < len1; l++) { - p = ref1[l]; - this.parents[p[0]] = true; - results1.push(this.mspace = Math.max(this.mspace, p[1])); - } - return results1; - }).call(this)); - } - return results; - }; - - BranchGraph.prototype.collectColors = function() { - var k, results; - k = 0; - results = []; - while (k < this.mspace) { - this.colors.push(Raphael.getColor(.8)); - // Skipping a few colors in the spectrum to get more contrast between colors - Raphael.getColor(); - Raphael.getColor(); - results.push(k++); - } - return results; - }; - - BranchGraph.prototype.buildGraph = function() { - var cuday, cumonth, day, j, len, mm, r, ref; - r = this.r; - cuday = 0; - cumonth = ""; - r.rect(0, 0, 40, this.barHeight).attr({ - fill: "#222" - }); - r.rect(40, 0, 30, this.barHeight).attr({ - fill: "#444" - }); - ref = this.days; - for (mm = j = 0, len = ref.length; j < len; mm = ++j) { - day = ref[mm]; - if (cuday !== day[0] || cumonth !== day[1]) { - // Dates - r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({ - font: "12px Monaco, monospace", - fill: "#BBB" - }); - cuday = day[0]; - } - if (cumonth !== day[1]) { - // Months - r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({ - font: "12px Monaco, monospace", - fill: "#EEE" - }); - cumonth = day[1]; - } - } - this.renderPartialGraph(); - return this.bindEvents(); - }; - - BranchGraph.prototype.renderPartialGraph = function() { - var commit, end, i, isGraphEdge, start, x, y; - start = Math.floor((this.element.scrollTop() - this.offsetY) / this.unitTime) - 10; - if (start < 0) { - isGraphEdge = true; - start = 0; - } - end = start + 40; - if (this.commits.length < end) { - isGraphEdge = true; - end = this.commits.length; - } - if (this.prev_start === -1 || Math.abs(this.prev_start - start) > 10 || isGraphEdge) { - i = start; - this.prev_start = start; - while (i < end) { - commit = this.commits[i]; - i += 1; - if (commit.hasDrawn !== true) { - x = this.offsetX + this.unitSpace * (this.mspace - commit.space); - y = this.offsetY + this.unitTime * commit.time; - this.drawDot(x, y, commit); - this.drawLines(x, y, commit); - this.appendLabel(x, y, commit); - this.appendAnchor(x, y, commit); - commit.hasDrawn = true; - } - } - return this.top.toFront(); - } - }; - - BranchGraph.prototype.bindEvents = function() { - var element; - element = this.element; - return $(element).scroll((function(_this) { - return function(event) { - return _this.renderPartialGraph(); - }; - })(this)); - }; - - BranchGraph.prototype.scrollDown = function() { - this.element.scrollTop(this.element.scrollTop() + 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollUp = function() { - this.element.scrollTop(this.element.scrollTop() - 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollLeft = function() { - this.element.scrollLeft(this.element.scrollLeft() - 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollRight = function() { - this.element.scrollLeft(this.element.scrollLeft() + 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollBottom = function() { - return this.element.scrollTop(this.element.find('svg').height()); - }; - - BranchGraph.prototype.scrollTop = function() { - return this.element.scrollTop(0); - }; - - BranchGraph.prototype.appendLabel = function(x, y, commit) { - var label, r, rect, shortrefs, text, textbox, triangle; - if (!commit.refs) { - return; - } - r = this.r; - shortrefs = commit.refs; - // Truncate if longer than 15 chars - if (shortrefs.length > 17) { - shortrefs = shortrefs.substr(0, 15) + "…"; - } - text = r.text(x + 4, y, shortrefs).attr({ - "text-anchor": "start", - font: "10px Monaco, monospace", - fill: "#FFF", - title: commit.refs - }); - textbox = text.getBBox(); - // Create rectangle based on the size of the textbox - rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - label = r.set(rect, text); - label.transform(["t", -rect.getBBox().width - 15, 0]); - // Set text to front - return text.toFront(); - }; - - BranchGraph.prototype.appendAnchor = function(x, y, commit) { - var anchor, options, r, top; - r = this.r; - top = this.top; - options = this.options; - anchor = r.circle(x, y, 10).attr({ - fill: "#000", - opacity: 0, - cursor: "pointer" - }).click(function() { - return window.open(options.commit_url.replace("%s", commit.id), "_blank"); - }).hover(function() { - this.tooltip = r.commitTooltip(x + 5, y, commit); - return top.push(this.tooltip.insertBefore(this)); - }, function() { - return this.tooltip && this.tooltip.remove() && delete this.tooltip; - }); - return top.push(anchor); - }; - - BranchGraph.prototype.drawDot = function(x, y, commit) { - var avatar_box_x, avatar_box_y, r; - r = this.r; - r.circle(x, y, 3).attr({ - fill: this.colors[commit.space], - stroke: "none" - }); - avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10; - avatar_box_y = y - 10; - r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({ - stroke: this.colors[commit.space], - "stroke-width": 2 - }); - r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20); - return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({ - "text-anchor": "start", - font: "14px Monaco, monospace" - }); - }; - - BranchGraph.prototype.drawLines = function(x, y, commit) { - var arrow, color, i, j, len, offset, parent, parentCommit, parentX1, parentX2, parentY, r, ref, results, route; - r = this.r; - ref = commit.parents; - results = []; - for (i = j = 0, len = ref.length; j < len; i = ++j) { - parent = ref[i]; - parentCommit = this.preparedCommits[parent[0]]; - parentY = this.offsetY + this.unitTime * parentCommit.time; - parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space); - parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]); - // Set line color - if (parentCommit.space <= commit.space) { - color = this.colors[commit.space]; - } else { - color = this.colors[parentCommit.space]; - } - // Build line shape - if (parent[1] === commit.space) { - offset = [0, 5]; - arrow = "l-2,5,4,0,-2,-5,0,5"; - } else if (parent[1] < commit.space) { - offset = [3, 3]; - arrow = "l5,0,-2,4,-3,-4,4,2"; - } else { - offset = [-3, 3]; - arrow = "l-5,0,2,4,3,-4,-4,2"; - } - // Start point - route = ["M", x + offset[0], y + offset[1]]; - // Add arrow if not first parent - if (i > 0) { - route.push(arrow); - } - // Circumvent if overlap - if (commit.space !== parentCommit.space || commit.space !== parent[1]) { - route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5); - } - // End point - route.push("L", parentX1, parentY); - results.push(r.path(route).attr({ - stroke: color, - "stroke-width": 2 - })); - } - return results; - }; - - BranchGraph.prototype.markCommit = function(commit) { - var r, x, y; - if (commit.id === this.options.commit_id) { - r = this.r; - x = this.offsetX + this.unitSpace * (this.mspace - commit.space); - y = this.offsetY + this.unitTime * commit.time; - r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - // Displayed in the center - return this.element.scrollTop(y - this.graphHeight / 2); - } - }; - - return BranchGraph; - - })(); - - Raphael.prototype.commitTooltip = function(x, y, commit) { - var boxHeight, boxWidth, icon, idText, messageText, nameText, rect, textSet, tooltip; - boxWidth = 300; - boxHeight = 200; - icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20); - nameText = this.text(x + 25, y + 10, commit.author.name); - idText = this.text(x, y + 35, commit.id); - messageText = this.text(x, y + 50, commit.message); - textSet = this.set(icon, nameText, idText, messageText).attr({ - "text-anchor": "start", - font: "12px Monaco, monospace" - }); - nameText.attr({ - font: "14px Arial", - "font-weight": "bold" - }); - idText.attr({ - fill: "#AAA" - }); - this.textWrap(messageText, boxWidth - 50); - rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ - fill: "#FFF", - stroke: "#000", - "stroke-linecap": "round", - "stroke-width": 2 - }); - tooltip = this.set(rect, textSet); - rect.attr({ - height: tooltip.getBBox().height + 10, - width: tooltip.getBBox().width + 10 - }); - tooltip.transform(["t", 20, 20]); - return tooltip; - }; - - Raphael.prototype.textWrap = function(t, width) { - var abc, b, content, h, j, len, letterWidth, s, word, words, x; - content = t.attr("text"); - abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - t.attr({ - text: abc - }); - letterWidth = t.getBBox().width / abc.length; - t.attr({ - text: content - }); - words = content.split(" "); - x = 0; - s = []; - for (j = 0, len = words.length; j < len; j++) { - word = words[j]; - if (x + (word.length * letterWidth) > width) { - s.push("\n"); - x = 0; - } - x += word.length * letterWidth; - s.push(word + " "); - } - t.attr({ - text: s.join("") - }); - b = t.getBBox(); - h = Math.abs(b.y2) - Math.abs(b.y) + 1; - return t.attr({ - y: b.y + h - }); - }; - -}).call(this); diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js new file mode 100644 index 00000000000..91132af273a --- /dev/null +++ b/app/assets/javascripts/network/branch_graph.js @@ -0,0 +1,417 @@ +(function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + this.BranchGraph = (function() { + function BranchGraph(element1, options1) { + this.element = element1; + this.options = options1; + this.scrollTop = bind(this.scrollTop, this); + this.scrollBottom = bind(this.scrollBottom, this); + this.scrollRight = bind(this.scrollRight, this); + this.scrollLeft = bind(this.scrollLeft, this); + this.scrollUp = bind(this.scrollUp, this); + this.scrollDown = bind(this.scrollDown, this); + this.preparedCommits = {}; + this.mtime = 0; + this.mspace = 0; + this.parents = {}; + this.colors = ["#000"]; + this.offsetX = 150; + this.offsetY = 20; + this.unitTime = 30; + this.unitSpace = 10; + this.prev_start = -1; + this.load(); + } + + BranchGraph.prototype.load = function() { + return $.ajax({ + url: this.options.url, + method: "get", + dataType: "json", + success: $.proxy(function(data) { + $(".loading", this.element).hide(); + this.prepareData(data.days, data.commits); + return this.buildGraph(); + }, this) + }); + }; + + BranchGraph.prototype.prepareData = function(days, commits) { + var c, ch, cw, j, len, ref; + this.days = days; + this.commits = commits; + this.collectParents(); + this.graphHeight = $(this.element).height(); + this.graphWidth = $(this.element).width(); + ch = Math.max(this.graphHeight, this.offsetY + this.unitTime * this.mtime + 150); + cw = Math.max(this.graphWidth, this.offsetX + this.unitSpace * this.mspace + 300); + this.r = Raphael(this.element.get(0), cw, ch); + this.top = this.r.set(); + this.barHeight = Math.max(this.graphHeight, this.unitTime * this.days.length + 320); + ref = this.commits; + for (j = 0, len = ref.length; j < len; j++) { + c = ref[j]; + if (c.id in this.parents) { + c.isParent = true; + } + this.preparedCommits[c.id] = c; + this.markCommit(c); + } + return this.collectColors(); + }; + + BranchGraph.prototype.collectParents = function() { + var c, j, len, p, ref, results; + ref = this.commits; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + c = ref[j]; + this.mtime = Math.max(this.mtime, c.time); + this.mspace = Math.max(this.mspace, c.space); + results.push((function() { + var l, len1, ref1, results1; + ref1 = c.parents; + results1 = []; + for (l = 0, len1 = ref1.length; l < len1; l++) { + p = ref1[l]; + this.parents[p[0]] = true; + results1.push(this.mspace = Math.max(this.mspace, p[1])); + } + return results1; + }).call(this)); + } + return results; + }; + + BranchGraph.prototype.collectColors = function() { + var k, results; + k = 0; + results = []; + while (k < this.mspace) { + this.colors.push(Raphael.getColor(.8)); + // Skipping a few colors in the spectrum to get more contrast between colors + Raphael.getColor(); + Raphael.getColor(); + results.push(k++); + } + return results; + }; + + BranchGraph.prototype.buildGraph = function() { + var cuday, cumonth, day, j, len, mm, r, ref; + r = this.r; + cuday = 0; + cumonth = ""; + r.rect(0, 0, 40, this.barHeight).attr({ + fill: "#222" + }); + r.rect(40, 0, 30, this.barHeight).attr({ + fill: "#444" + }); + ref = this.days; + for (mm = j = 0, len = ref.length; j < len; mm = ++j) { + day = ref[mm]; + if (cuday !== day[0] || cumonth !== day[1]) { + // Dates + r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({ + font: "12px Monaco, monospace", + fill: "#BBB" + }); + cuday = day[0]; + } + if (cumonth !== day[1]) { + // Months + r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({ + font: "12px Monaco, monospace", + fill: "#EEE" + }); + cumonth = day[1]; + } + } + this.renderPartialGraph(); + return this.bindEvents(); + }; + + BranchGraph.prototype.renderPartialGraph = function() { + var commit, end, i, isGraphEdge, start, x, y; + start = Math.floor((this.element.scrollTop() - this.offsetY) / this.unitTime) - 10; + if (start < 0) { + isGraphEdge = true; + start = 0; + } + end = start + 40; + if (this.commits.length < end) { + isGraphEdge = true; + end = this.commits.length; + } + if (this.prev_start === -1 || Math.abs(this.prev_start - start) > 10 || isGraphEdge) { + i = start; + this.prev_start = start; + while (i < end) { + commit = this.commits[i]; + i += 1; + if (commit.hasDrawn !== true) { + x = this.offsetX + this.unitSpace * (this.mspace - commit.space); + y = this.offsetY + this.unitTime * commit.time; + this.drawDot(x, y, commit); + this.drawLines(x, y, commit); + this.appendLabel(x, y, commit); + this.appendAnchor(x, y, commit); + commit.hasDrawn = true; + } + } + return this.top.toFront(); + } + }; + + BranchGraph.prototype.bindEvents = function() { + var element; + element = this.element; + return $(element).scroll((function(_this) { + return function(event) { + return _this.renderPartialGraph(); + }; + })(this)); + }; + + BranchGraph.prototype.scrollDown = function() { + this.element.scrollTop(this.element.scrollTop() + 50); + return this.renderPartialGraph(); + }; + + BranchGraph.prototype.scrollUp = function() { + this.element.scrollTop(this.element.scrollTop() - 50); + return this.renderPartialGraph(); + }; + + BranchGraph.prototype.scrollLeft = function() { + this.element.scrollLeft(this.element.scrollLeft() - 50); + return this.renderPartialGraph(); + }; + + BranchGraph.prototype.scrollRight = function() { + this.element.scrollLeft(this.element.scrollLeft() + 50); + return this.renderPartialGraph(); + }; + + BranchGraph.prototype.scrollBottom = function() { + return this.element.scrollTop(this.element.find('svg').height()); + }; + + BranchGraph.prototype.scrollTop = function() { + return this.element.scrollTop(0); + }; + + BranchGraph.prototype.appendLabel = function(x, y, commit) { + var label, r, rect, shortrefs, text, textbox, triangle; + if (!commit.refs) { + return; + } + r = this.r; + shortrefs = commit.refs; + // Truncate if longer than 15 chars + if (shortrefs.length > 17) { + shortrefs = shortrefs.substr(0, 15) + "…"; + } + text = r.text(x + 4, y, shortrefs).attr({ + "text-anchor": "start", + font: "10px Monaco, monospace", + fill: "#FFF", + title: commit.refs + }); + textbox = text.getBBox(); + // Create rectangle based on the size of the textbox + rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" + }); + triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" + }); + label = r.set(rect, text); + label.transform(["t", -rect.getBBox().width - 15, 0]); + // Set text to front + return text.toFront(); + }; + + BranchGraph.prototype.appendAnchor = function(x, y, commit) { + var anchor, options, r, top; + r = this.r; + top = this.top; + options = this.options; + anchor = r.circle(x, y, 10).attr({ + fill: "#000", + opacity: 0, + cursor: "pointer" + }).click(function() { + return window.open(options.commit_url.replace("%s", commit.id), "_blank"); + }).hover(function() { + this.tooltip = r.commitTooltip(x + 5, y, commit); + return top.push(this.tooltip.insertBefore(this)); + }, function() { + return this.tooltip && this.tooltip.remove() && delete this.tooltip; + }); + return top.push(anchor); + }; + + BranchGraph.prototype.drawDot = function(x, y, commit) { + var avatar_box_x, avatar_box_y, r; + r = this.r; + r.circle(x, y, 3).attr({ + fill: this.colors[commit.space], + stroke: "none" + }); + avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10; + avatar_box_y = y - 10; + r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({ + stroke: this.colors[commit.space], + "stroke-width": 2 + }); + r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20); + return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({ + "text-anchor": "start", + font: "14px Monaco, monospace" + }); + }; + + BranchGraph.prototype.drawLines = function(x, y, commit) { + var arrow, color, i, j, len, offset, parent, parentCommit, parentX1, parentX2, parentY, r, ref, results, route; + r = this.r; + ref = commit.parents; + results = []; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + parent = ref[i]; + parentCommit = this.preparedCommits[parent[0]]; + parentY = this.offsetY + this.unitTime * parentCommit.time; + parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space); + parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]); + // Set line color + if (parentCommit.space <= commit.space) { + color = this.colors[commit.space]; + } else { + color = this.colors[parentCommit.space]; + } + // Build line shape + if (parent[1] === commit.space) { + offset = [0, 5]; + arrow = "l-2,5,4,0,-2,-5,0,5"; + } else if (parent[1] < commit.space) { + offset = [3, 3]; + arrow = "l5,0,-2,4,-3,-4,4,2"; + } else { + offset = [-3, 3]; + arrow = "l-5,0,2,4,3,-4,-4,2"; + } + // Start point + route = ["M", x + offset[0], y + offset[1]]; + // Add arrow if not first parent + if (i > 0) { + route.push(arrow); + } + // Circumvent if overlap + if (commit.space !== parentCommit.space || commit.space !== parent[1]) { + route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5); + } + // End point + route.push("L", parentX1, parentY); + results.push(r.path(route).attr({ + stroke: color, + "stroke-width": 2 + })); + } + return results; + }; + + BranchGraph.prototype.markCommit = function(commit) { + var r, x, y; + if (commit.id === this.options.commit_id) { + r = this.r; + x = this.offsetX + this.unitSpace * (this.mspace - commit.space); + y = this.offsetY + this.unitTime * commit.time; + r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" + }); + // Displayed in the center + return this.element.scrollTop(y - this.graphHeight / 2); + } + }; + + return BranchGraph; + + })(); + + Raphael.prototype.commitTooltip = function(x, y, commit) { + var boxHeight, boxWidth, icon, idText, messageText, nameText, rect, textSet, tooltip; + boxWidth = 300; + boxHeight = 200; + icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20); + nameText = this.text(x + 25, y + 10, commit.author.name); + idText = this.text(x, y + 35, commit.id); + messageText = this.text(x, y + 50, commit.message); + textSet = this.set(icon, nameText, idText, messageText).attr({ + "text-anchor": "start", + font: "12px Monaco, monospace" + }); + nameText.attr({ + font: "14px Arial", + "font-weight": "bold" + }); + idText.attr({ + fill: "#AAA" + }); + this.textWrap(messageText, boxWidth - 50); + rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ + fill: "#FFF", + stroke: "#000", + "stroke-linecap": "round", + "stroke-width": 2 + }); + tooltip = this.set(rect, textSet); + rect.attr({ + height: tooltip.getBBox().height + 10, + width: tooltip.getBBox().width + 10 + }); + tooltip.transform(["t", 20, 20]); + return tooltip; + }; + + Raphael.prototype.textWrap = function(t, width) { + var abc, b, content, h, j, len, letterWidth, s, word, words, x; + content = t.attr("text"); + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + text: abc + }); + letterWidth = t.getBBox().width / abc.length; + t.attr({ + text: content + }); + words = content.split(" "); + x = 0; + s = []; + for (j = 0, len = words.length; j < len; j++) { + word = words[j]; + if (x + (word.length * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += word.length * letterWidth; + s.push(word + " "); + } + t.attr({ + text: s.join("") + }); + b = t.getBBox(); + h = Math.abs(b.y2) - Math.abs(b.y) + 1; + return t.attr({ + y: b.y + h + }); + }; + +}).call(this); -- cgit v1.2.1