summaryrefslogtreecommitdiff
path: root/assets/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/src')
-rw-r--r--assets/js/src/App.js69
-rw-r--r--assets/js/src/Board.js74
-rw-r--r--assets/js/src/Column.js59
-rw-r--r--assets/js/src/CompareHoursColumnChart.js39
-rw-r--r--assets/js/src/Dropdown.js41
-rw-r--r--assets/js/src/FileUpload.js124
-rw-r--r--assets/js/src/Gantt.js34
-rw-r--r--assets/js/src/Popover.js52
-rw-r--r--assets/js/src/Project.js28
-rw-r--r--assets/js/src/Router.js1
-rw-r--r--assets/js/src/Search.js9
-rw-r--r--assets/js/src/Sidebar.js25
-rw-r--r--assets/js/src/Subtask.js94
-rw-r--r--assets/js/src/Swimlane.js56
-rw-r--r--assets/js/src/Task.js43
-rw-r--r--assets/js/src/Tooltip.js15
16 files changed, 633 insertions, 130 deletions
diff --git a/assets/js/src/App.js b/assets/js/src/App.js
index 7651b3ec..b20a73c1 100644
--- a/assets/js/src/App.js
+++ b/assets/js/src/App.js
@@ -1,13 +1,16 @@
function App() {
this.board = new Board(this);
this.markdown = new Markdown();
- this.sidebar = new Sidebar();
this.search = new Search(this);
- this.swimlane = new Swimlane();
+ this.swimlane = new Swimlane(this);
this.dropdown = new Dropdown();
this.tooltip = new Tooltip(this);
this.popover = new Popover(this);
- this.task = new Task();
+ this.task = new Task(this);
+ this.project = new Project();
+ this.subtask = new Subtask(this);
+ this.column = new Column(this);
+ this.file = new FileUpload(this);
this.keyboardShortcuts();
this.chosen();
this.poll();
@@ -16,29 +19,22 @@ function App() {
$(".alert-fade-out").delay(4000).fadeOut(800, function() {
$(this).remove();
});
-
- // Reload page when a destination project is changed
- var reloading_project = false;
- $("select.task-reload-project-destination").change(function() {
- if (! reloading_project) {
- $(".loading-icon").show();
- reloading_project = true;
- window.location = $(this).data("redirect").replace(/PROJECT_ID/g, $(this).val());
- }
- });
}
App.prototype.listen = function() {
+ this.project.listen();
this.popover.listen();
this.markdown.listen();
- this.sidebar.listen();
this.tooltip.listen();
this.dropdown.listen();
this.search.listen();
this.task.listen();
this.swimlane.listen();
+ this.subtask.listen();
+ this.column.listen();
+ this.file.listen();
this.search.focus();
- this.taskAutoComplete();
+ this.autoComplete();
this.datePicker();
this.focus();
};
@@ -125,36 +121,47 @@ App.prototype.datePicker = function() {
// timeFormat: 'h:mm tt',
constrainInput: false
});
-
- $(".hasDatepicker").on("blur", function(e) { $(this).datepicker("hide"); });
};
-App.prototype.taskAutoComplete = function() {
- // Task auto-completion
- if ($(".task-autocomplete").length) {
+App.prototype.autoComplete = function() {
+ $(".autocomplete").each(function() {
+ var input = $(this);
+ var field = input.data("dst-field");
+ var extraField = input.data("dst-extra-field");
- if ($('.opposite_task_id').val() == '') {
- $(".task-autocomplete").parent().find("input[type=submit]").attr('disabled','disabled');
+ if ($('#form-' + field).val() == '') {
+ input.parent().find("input[type=submit]").attr('disabled','disabled');
}
- $(".task-autocomplete").autocomplete({
- source: $(".task-autocomplete").data("search-url"),
+ input.autocomplete({
+ source: input.data("search-url"),
minLength: 1,
select: function(event, ui) {
- var field = $(".task-autocomplete").data("dst-field");
$("input[name=" + field + "]").val(ui.item.id);
- $(".task-autocomplete").parent().find("input[type=submit]").removeAttr('disabled');
+ if (extraField) {
+ $("input[name=" + extraField + "]").val(ui.item[extraField]);
+ }
+
+ input.parent().find("input[type=submit]").removeAttr('disabled');
}
});
- }
+ });
};
App.prototype.chosen = function() {
- $(".chosen-select").chosen({
- width: "180px",
- no_results_text: $(".chosen-select").data("notfound"),
- disable_search_threshold: 10
+ $(".chosen-select").each(function() {
+ var searchThreshold = $(this).data("search-threshold");
+
+ if (searchThreshold === undefined) {
+ searchThreshold = 10;
+ }
+
+ $(this).chosen({
+ width: "180px",
+ no_results_text: $(this).data("notfound"),
+ disable_search_threshold: searchThreshold
+ });
});
$(".select-auto-redirect").change(function() {
diff --git a/assets/js/src/Board.js b/assets/js/src/Board.js
index b98aa366..c99f3cd3 100644
--- a/assets/js/src/Board.js
+++ b/assets/js/src/Board.js
@@ -1,18 +1,19 @@
function Board(app) {
this.app = app;
this.checkInterval = null;
+ this.savingInProgress = false;
}
Board.prototype.execute = function() {
this.app.swimlane.refresh();
this.restoreColumnViewMode();
this.compactView();
- this.columnScrolling();
this.poll();
this.keyboardShortcuts();
this.listen();
this.dragAndDrop();
+ $(window).on("load", this.columnScrolling);
$(window).resize(this.columnScrolling);
};
@@ -42,8 +43,7 @@ Board.prototype.reloadFilters = function(search) {
};
Board.prototype.check = function() {
- if (this.app.isVisible()) {
-
+ if (this.app.isVisible() && ! this.savingInProgress) {
var self = this;
this.app.showLoadingIcon();
@@ -59,7 +59,9 @@ Board.prototype.check = function() {
};
Board.prototype.save = function(taskId, columnId, position, swimlaneId) {
+ var self = this;
this.app.showLoadingIcon();
+ this.savingInProgress = true;
$.ajax({
cache: false,
@@ -73,8 +75,14 @@ Board.prototype.save = function(taskId, columnId, position, swimlaneId) {
"swimlane_id": swimlaneId,
"position": position
}),
- success: this.refresh.bind(this),
- error: this.app.hideLoadingIcon.bind(this)
+ success: function(data) {
+ self.refresh(data);
+ this.savingInProgress = false;
+ },
+ error: function() {
+ self.app.hideLoadingIcon();
+ this.savingInProgress = false;
+ }
});
};
@@ -83,12 +91,12 @@ Board.prototype.refresh = function(data) {
this.app.refresh();
this.app.swimlane.refresh();
- this.columnScrolling();
this.app.hideLoadingIcon();
this.listen();
this.dragAndDrop();
this.compactView();
this.restoreColumnViewMode();
+ this.columnScrolling();
};
Board.prototype.dragAndDrop = function() {
@@ -100,13 +108,22 @@ Board.prototype.dragAndDrop = function() {
placeholder: "draggable-placeholder",
items: ".draggable-item",
stop: function(event, ui) {
- ui.item.removeClass("draggable-item-selected");
- self.save(
- ui.item.attr('data-task-id'),
- ui.item.parent().attr("data-column-id"),
- ui.item.index() + 1,
- ui.item.parent().attr('data-swimlane-id')
- );
+ var task = ui.item;
+ var taskId = task.attr('data-task-id');
+ var taskPosition = task.attr('data-position');
+ var taskColumnId = task.attr('data-column-id');
+ var taskSwimlaneId = task.attr('data-swimlane-id');
+
+ var newColumnId = task.parent().attr("data-column-id");
+ var newSwimlaneId = task.parent().attr('data-swimlane-id');
+ var newPosition = task.index() + 1;
+
+ task.removeClass("draggable-item-selected");
+
+ if (newColumnId != taskColumnId || newSwimlaneId != taskSwimlaneId || newPosition != taskPosition) {
+ self.changeTaskState(taskId);
+ self.save(taskId, newColumnId, newPosition, newSwimlaneId);
+ }
},
start: function(event, ui) {
ui.item.addClass("draggable-item-selected");
@@ -122,6 +139,12 @@ Board.prototype.dragAndDrop = function() {
$(".board-task-list").sortable(params);
};
+Board.prototype.changeTaskState = function(taskId) {
+ var task = $("div[data-task-id=" + taskId + "]");
+ task.addClass('task-board-saving-state');
+ task.find('.task-board-saving-icon').show();
+};
+
Board.prototype.listen = function() {
var self = this;
@@ -141,27 +164,40 @@ Board.prototype.listen = function() {
self.toggleColumnScrolling();
});
- $(document).on("click", ".board-column-title", function() {
+ $(document).on("click", ".board-toggle-column-view", function() {
self.toggleColumnViewMode($(this).data("column-id"));
});
};
Board.prototype.toggleColumnScrolling = function() {
- var scrolling = localStorage.getItem("column_scroll") || 1;
+ var scrolling = localStorage.getItem("column_scroll");
+
+ if (scrolling == undefined) {
+ scrolling = 1;
+ }
+
localStorage.setItem("column_scroll", scrolling == 0 ? 1 : 0);
this.columnScrolling();
};
Board.prototype.columnScrolling = function() {
if (localStorage.getItem("column_scroll") == 0) {
+ var height = 80;
+
$(".filter-max-height").show();
$(".filter-min-height").hide();
+ $(".board-rotation-wrapper").css("min-height", '');
$(".board-task-list").each(function() {
- $(this).css("min-height", 80);
- $(this).css("height", '');
- $(".board-rotation-wrapper").css("min-height", '');
+ var columnHeight = $(this).height();
+
+ if (columnHeight > height) {
+ height = columnHeight;
+ }
});
+
+ $(".board-task-list").css("min-height", height);
+ $(".board-task-list").css("height", '');
}
else {
@@ -180,7 +216,7 @@ Board.prototype.columnScrolling = function() {
});
}
else {
- var height = $(window).height() - 145;
+ var height = $(window).height() - 170;
$(".board-task-list").css("height", height);
$(".board-rotation-wrapper").css("min-height", height);
diff --git a/assets/js/src/Column.js b/assets/js/src/Column.js
new file mode 100644
index 00000000..2c8ebbd2
--- /dev/null
+++ b/assets/js/src/Column.js
@@ -0,0 +1,59 @@
+function Column(app) {
+ this.app = app;
+}
+
+Column.prototype.listen = function() {
+ this.dragAndDrop();
+};
+
+Column.prototype.dragAndDrop = function() {
+ var self = this;
+
+ $(".draggable-row-handle").mouseenter(function() {
+ $(this).parent().parent().addClass("draggable-item-hover");
+ }).mouseleave(function() {
+ $(this).parent().parent().removeClass("draggable-item-hover");
+ });
+
+ $(".columns-table tbody").sortable({
+ forcePlaceholderSize: true,
+ handle: "td:first i",
+ helper: function(e, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+
+ return ui;
+ },
+ stop: function(event, ui) {
+ var column = ui.item;
+ column.removeClass("draggable-item-selected");
+ self.savePosition(column.data("column-id"), column.index() + 1);
+ },
+ start: function(event, ui) {
+ ui.item.addClass("draggable-item-selected");
+ }
+ }).disableSelection();
+};
+
+Column.prototype.savePosition = function(columnId, position) {
+ var url = $(".columns-table").data("save-position-url");
+ var self = this;
+
+ this.app.showLoadingIcon();
+
+ $.ajax({
+ cache: false,
+ url: url,
+ contentType: "application/json",
+ type: "POST",
+ processData: false,
+ data: JSON.stringify({
+ "column_id": columnId,
+ "position": position
+ }),
+ complete: function() {
+ self.app.hideLoadingIcon();
+ }
+ });
+};
diff --git a/assets/js/src/CompareHoursColumnChart.js b/assets/js/src/CompareHoursColumnChart.js
new file mode 100644
index 00000000..bed16144
--- /dev/null
+++ b/assets/js/src/CompareHoursColumnChart.js
@@ -0,0 +1,39 @@
+function CompareHoursColumnChart(app) {
+ this.app = app;
+}
+
+CompareHoursColumnChart.prototype.execute = function() {
+ var metrics = $("#chart").data("metrics");
+ var labelOpen = $("#chart").data("label-open");
+ var labelClosed = $("#chart").data("label-closed");
+ var spent = [$("#chart").data("label-spent")];
+ var estimated = [$("#chart").data("label-estimated")];
+ var categories = [];
+
+ for (var status in metrics) {
+ spent.push(parseFloat(metrics[status].time_spent));
+ estimated.push(parseFloat(metrics[status].time_estimated));
+ categories.push(status == 'open' ? labelOpen : labelClosed);
+ }
+
+ c3.generate({
+ data: {
+ columns: [spent, estimated],
+ type: 'bar'
+ },
+ bar: {
+ width: {
+ ratio: 0.2
+ }
+ },
+ axis: {
+ x: {
+ type: 'category',
+ categories: categories
+ }
+ },
+ legend: {
+ show: true
+ }
+ });
+};
diff --git a/assets/js/src/Dropdown.js b/assets/js/src/Dropdown.js
index e04603d8..61738da9 100644
--- a/assets/js/src/Dropdown.js
+++ b/assets/js/src/Dropdown.js
@@ -14,26 +14,53 @@ Dropdown.prototype.listen = function() {
self.close();
var submenu = $(this).next('ul');
- var submenuHeight = 240;
var offset = $(this).offset();
- var height = $(this).height();
// Clone the submenu outside of the column to avoid clipping issue with overflow
$("body").append(jQuery("<div>", {"id": "dropdown"}));
submenu.clone().appendTo("#dropdown");
var clone = $("#dropdown ul");
- clone.css('left', offset.left);
+ clone.addClass('dropdown-submenu-open');
+
+ var submenuHeight = clone.outerHeight();
+ var submenuWidth = clone.outerWidth();
- if (offset.top + submenuHeight - $(window).scrollTop() > $(window).height()) {
- clone.css('top', offset.top - submenuHeight - height);
+ if (offset.top + submenuHeight - $(window).scrollTop() < $(window).height() || $(window).scrollTop() + offset.top < submenuHeight) {
+ clone.css('top', offset.top + $(this).height());
}
else {
- clone.css('top', offset.top + height);
+ clone.css('top', offset.top - submenuHeight - 5);
}
- clone.addClass('dropdown-submenu-open');
+ if (offset.left + submenuWidth > $(window).width()) {
+ clone.css('left', offset.left - submenuWidth + $(this).outerWidth());
+ }
+ else {
+ clone.css('left', offset.left);
+ }
});
+
+ $(document).on('click', '.dropdown-submenu-open li', function(e) {
+ if ($(e.target).is('li')) {
+ $(this).find('a:visible')[0].click(); // Calling native click() not the jQuery one
+ }
+ });
+
+ // User mention autocomplete
+ $('textarea[data-mention-search-url]').textcomplete([{
+ match: /(^|\s)@(\w*)$/,
+ search: function (term, callback) {
+ var url = $('textarea[data-mention-search-url]').data('mention-search-url');
+ $.getJSON(url, { q: term })
+ .done(function (resp) { callback(resp); })
+ .fail(function () { callback([]); });
+ },
+ replace: function (value) {
+ return '$1@' + value + ' ';
+ },
+ cache: true
+ }], {className: "textarea-dropdown"});
};
Dropdown.prototype.close = function() {
diff --git a/assets/js/src/FileUpload.js b/assets/js/src/FileUpload.js
new file mode 100644
index 00000000..a8816bcd
--- /dev/null
+++ b/assets/js/src/FileUpload.js
@@ -0,0 +1,124 @@
+function FileUpload(app) {
+ this.app = app;
+ this.files = [];
+ this.currentFile = 0;
+}
+
+FileUpload.prototype.listen = function() {
+ var dropzone = document.getElementById("file-dropzone");
+ var self = this;
+
+ if (dropzone) {
+ dropzone.ondragover = dropzone.ondragenter = function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ dropzone.ondrop = function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ self.files = e.dataTransfer.files;
+ self.show();
+ $("#file-error-max-size").hide();
+ }
+
+ $(document).on("click", "#file-browser", function(e) {
+ e.preventDefault();
+ $("#file-form-element").get(0).click();
+ });
+
+ $(document).on("click", "#file-upload-button", function(e) {
+ e.preventDefault();
+ self.currentFile = 0;
+ self.checkFiles();
+ });
+
+ $("#file-form-element").change(function() {
+ self.files = document.getElementById("file-form-element").files;
+ self.show();
+ $("#file-error-max-size").hide();
+ });
+ }
+};
+
+FileUpload.prototype.show = function() {
+ $("#file-list").remove();
+
+ if (this.files.length > 0) {
+ $("#file-upload-button").prop("disabled", false);
+ $("#file-dropzone-inner").hide();
+
+ var ul = jQuery("<ul>", {"id": "file-list"});
+
+ for (var i = 0; i < this.files.length; i++) {
+ var percentage = jQuery("<span>", {"id": "file-percentage-" + i}).append("(0%)");
+ var progress = jQuery("<progress>", {"id": "file-progress-" + i, "value": 0});
+ var li = jQuery("<li>", {"id": "file-label-" + i})
+ .append(progress)
+ .append("&nbsp;")
+ .append(this.files[i].name)
+ .append("&nbsp;")
+ .append(percentage);
+
+ ul.append(li);
+ }
+
+ $("#file-dropzone").append(ul);
+ } else {
+ $("#file-dropzone-inner").show();
+ }
+};
+
+FileUpload.prototype.checkFiles = function() {
+ var max = parseInt($("#file-dropzone").data("max-size"));
+
+ for (var i = 0; i < this.files.length; i++) {
+ if (this.files[i].size > max) {
+ $("#file-error-max-size").show();
+ $("#file-label-" + i).addClass("file-error");
+ $("#file-upload-button").prop("disabled", true);
+ return;
+ }
+ }
+
+ this.uploadFiles();
+};
+
+FileUpload.prototype.uploadFiles = function() {
+ if (this.files.length > 0) {
+ this.uploadFile(this.files[this.currentFile]);
+ }
+};
+
+FileUpload.prototype.uploadFile = function(file) {
+ var dropzone = document.getElementById("file-dropzone");
+ var url = dropzone.dataset.url;
+ var xhr = new XMLHttpRequest();
+ var fd = new FormData();
+
+ xhr.upload.addEventListener("progress", this.updateProgress.bind(this));
+ xhr.upload.addEventListener("load", this.transferComplete.bind(this));
+
+ xhr.open("POST", url, true);
+ fd.append('files[]', file);
+ xhr.send(fd);
+};
+
+FileUpload.prototype.updateProgress = function(e) {
+ if (e.lengthComputable) {
+ $("#file-progress-" + this.currentFile).val(e.loaded / e.total);
+ $("#file-percentage-" + this.currentFile).text('(' + Math.floor((e.loaded / e.total) * 100) + '%)');
+ }
+};
+
+FileUpload.prototype.transferComplete = function() {
+ this.currentFile++;
+
+ if (this.currentFile < this.files.length) {
+ this.uploadFile(this.files[this.currentFile]);
+ } else {
+ $("#file-upload-button").prop("disabled", true);
+ $("#file-upload-button").parent().hide();
+ $("#file-done").show();
+ }
+};
diff --git a/assets/js/src/Gantt.js b/assets/js/src/Gantt.js
index 380371d1..6f536552 100644
--- a/assets/js/src/Gantt.js
+++ b/assets/js/src/Gantt.js
@@ -185,7 +185,7 @@ Gantt.prototype.addBlocks = function(slider, start) {
var block = jQuery("<div>", {
"class": "ganttview-block tooltip" + (this.options.allowMoves ? " ganttview-block-movable" : ""),
- "title": this.getBarTooltip(this.data[i]),
+ "title": this.getBarTooltip(series),
"css": {
"width": ((size * this.options.cellWidth) - 9) + "px",
"margin-left": (offset * this.options.cellWidth) + "px"
@@ -193,23 +193,25 @@ Gantt.prototype.addBlocks = function(slider, start) {
}).append(text);
if (size >= 2) {
- text.append(this.data[i].progress);
+ text.append(series.progress);
}
- block.data("record", this.data[i]);
- this.setBarColor(block, this.data[i]);
-
- block.append(jQuery("<div>", {
- "css": {
- "z-index": 0,
- "position": "absolute",
- "top": 0,
- "bottom": 0,
- "background-color": series.color.border,
- "width": series.progress,
- "opacity": 0.4
- }
- }));
+ block.data("record", series);
+ this.setBarColor(block, series);
+
+ if (series.progress != "0%") {
+ block.append(jQuery("<div>", {
+ "css": {
+ "z-index": 0,
+ "position": "absolute",
+ "top": 0,
+ "bottom": 0,
+ "background-color": series.color.border,
+ "width": series.progress,
+ "opacity": 0.4
+ }
+ }));
+ }
jQuery(rows[rowIdx]).append(block);
rowIdx = rowIdx + 1;
diff --git a/assets/js/src/Popover.js b/assets/js/src/Popover.js
index 8d72dec8..5614de85 100644
--- a/assets/js/src/Popover.js
+++ b/assets/js/src/Popover.js
@@ -13,7 +13,7 @@ Popover.prototype.open = function(link) {
self.app.dropdown.close();
$.get(link, function(content) {
- $("body").append('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
+ $("body").prepend('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
self.app.refresh();
self.router.dispatch(this.app);
self.afterOpen();
@@ -35,10 +35,11 @@ Popover.prototype.onClick = function(e) {
e.preventDefault();
e.stopPropagation();
- var link = e.target.getAttribute("href");
+ var target = e.currentTarget || e.target;
+ var link = target.getAttribute("href");
if (! link) {
- link = e.target.getAttribute("data-href");
+ link = target.getAttribute("data-href");
}
if (link) {
@@ -55,26 +56,47 @@ Popover.prototype.listen = function() {
Popover.prototype.afterOpen = function() {
var self = this;
- var taskForm = $("#task-form");
+ var popoverForm = $("#popover-content .popover-form");
- if (taskForm) {
- taskForm.on("submit", function(e) {
+ // Submit forms with Ajax request
+ if (popoverForm) {
+ popoverForm.on("submit", function(e) {
e.preventDefault();
$.ajax({
type: "POST",
- url: taskForm.attr("action"),
- data: taskForm.serialize(),
+ url: popoverForm.attr("action"),
+ data: popoverForm.serialize(),
success: function(data, textStatus, request) {
- if (request.getResponseHeader("X-Ajax-Redirect")) {
- window.location = request.getResponseHeader("X-Ajax-Redirect");
- }
- else {
- $("#popover-content").html(data);
- self.afterOpen();
- }
+ self.afterSubmit(data, request, self);
}
});
});
}
+
+ // Submit link with Ajax request
+ $(document).on("click", ".popover-link", function(e) {
+ e.preventDefault();
+
+ $.ajax({
+ type: "GET",
+ url: $(this).attr("href"),
+ success: function(data, textStatus, request) {
+ self.afterSubmit(data, request, self);
+ }
+ });
+ });
+};
+
+Popover.prototype.afterSubmit = function(data, request, self) {
+ var redirect = request.getResponseHeader("X-Ajax-Redirect");
+
+ if (redirect) {
+ window.location = redirect === 'self' ? window.location.href.split("#")[0] : redirect;
+ }
+ else {
+ $("#popover-content").html(data);
+ $("#popover-content input[autofocus]").focus();
+ self.afterOpen();
+ }
};
diff --git a/assets/js/src/Project.js b/assets/js/src/Project.js
new file mode 100644
index 00000000..19941f03
--- /dev/null
+++ b/assets/js/src/Project.js
@@ -0,0 +1,28 @@
+function Project() {
+}
+
+Project.prototype.listen = function() {
+ $('.project-change-role').on('change', function() {
+ $.ajax({
+ cache: false,
+ url: $(this).data('url'),
+ contentType: "application/json",
+ type: "POST",
+ processData: false,
+ data: JSON.stringify({
+ "id": $(this).data('id'),
+ "role": $(this).val()
+ })
+ });
+ });
+
+ $('#project-creation-form #form-src_project_id').on('change', function() {
+ var srcProjectId = $(this).val();
+
+ if (srcProjectId == 0) {
+ $(".project-creation-options").hide();
+ } else {
+ $(".project-creation-options").show();
+ }
+ });
+};
diff --git a/assets/js/src/Router.js b/assets/js/src/Router.js
index 0c96262c..ab23c0fd 100644
--- a/assets/js/src/Router.js
+++ b/assets/js/src/Router.js
@@ -30,6 +30,7 @@ jQuery(document).ready(function() {
router.addRoute('analytic-avg-time-column', AvgTimeColumnChart);
router.addRoute('analytic-task-time-column', TaskTimeColumnChart);
router.addRoute('analytic-lead-cycle-time', LeadCycleTimeChart);
+ router.addRoute('analytic-compare-hours', CompareHoursColumnChart);
router.addRoute('gantt-chart', Gantt);
router.dispatch(app);
app.listen();
diff --git a/assets/js/src/Search.js b/assets/js/src/Search.js
index de4d5959..4fbfee46 100644
--- a/assets/js/src/Search.js
+++ b/assets/js/src/Search.js
@@ -40,6 +40,15 @@ Search.prototype.listen = function() {
Search.prototype.keyboardShortcuts = function() {
var self = this;
+ // Switch view mode for projects: go to the overview page
+ Mousetrap.bind("v o", function(e) {
+ var link = $(".view-overview");
+
+ if (link.length) {
+ window.location = link.attr('href');
+ }
+ });
+
// Switch view mode for projects: go to the board
Mousetrap.bind("v b", function(e) {
var link = $(".view-board");
diff --git a/assets/js/src/Sidebar.js b/assets/js/src/Sidebar.js
deleted file mode 100644
index 0794d6b3..00000000
--- a/assets/js/src/Sidebar.js
+++ /dev/null
@@ -1,25 +0,0 @@
-function Sidebar() {
-}
-
-Sidebar.prototype.expand = function(e) {
- e.preventDefault();
- $(".sidebar-container").removeClass("sidebar-collapsed");
- $(".sidebar-collapse").show();
- $(".sidebar h2").show();
- $(".sidebar ul").show();
- $(".sidebar-expand").hide();
-};
-
-Sidebar.prototype.collapse = function(e) {
- e.preventDefault();
- $(".sidebar-container").addClass("sidebar-collapsed");
- $(".sidebar-expand").show();
- $(".sidebar h2").hide();
- $(".sidebar ul").hide();
- $(".sidebar-collapse").hide();
-};
-
-Sidebar.prototype.listen = function() {
- $(document).on("click", ".sidebar-collapse", this.collapse);
- $(document).on("click", ".sidebar-expand", this.expand);
-};
diff --git a/assets/js/src/Subtask.js b/assets/js/src/Subtask.js
new file mode 100644
index 00000000..7670095e
--- /dev/null
+++ b/assets/js/src/Subtask.js
@@ -0,0 +1,94 @@
+function Subtask(app) {
+ this.app = app;
+}
+
+Subtask.prototype.listen = function() {
+ var self = this;
+
+ this.dragAndDrop();
+
+ $(document).on("click", ".subtask-toggle-status", function(e) {
+ e.preventDefault();
+ var el = $(this);
+
+ $.ajax({
+ cache: false,
+ url: el.attr("href"),
+ success: function(data) {
+ if (el.hasClass("subtask-refresh-table")) {
+ $(".subtasks-table").replaceWith(data);
+ } else {
+ el.replaceWith(data);
+ }
+
+ self.dragAndDrop();
+ }
+ });
+ });
+
+ $(document).on("click", ".subtask-toggle-timer", function(e) {
+ e.preventDefault();
+ var el = $(this);
+
+ $.ajax({
+ cache: false,
+ url: el.attr("href"),
+ success: function(data) {
+ $(".subtasks-table").replaceWith(data);
+ self.dragAndDrop();
+ }
+ });
+ });
+};
+
+Subtask.prototype.dragAndDrop = function() {
+ var self = this;
+
+ $(".draggable-row-handle").mouseenter(function() {
+ $(this).parent().parent().addClass("draggable-item-hover");
+ }).mouseleave(function() {
+ $(this).parent().parent().removeClass("draggable-item-hover");
+ });
+
+ $(".subtasks-table tbody").sortable({
+ forcePlaceholderSize: true,
+ handle: "td:first i",
+ helper: function(e, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+
+ return ui;
+ },
+ stop: function(event, ui) {
+ var subtask = ui.item;
+ subtask.removeClass("draggable-item-selected");
+ self.savePosition(subtask.data("subtask-id"), subtask.index() + 1);
+ },
+ start: function(event, ui) {
+ ui.item.addClass("draggable-item-selected");
+ }
+ }).disableSelection();
+};
+
+Subtask.prototype.savePosition = function(subtaskId, position) {
+ var url = $(".subtasks-table").data("save-position-url");
+ var self = this;
+
+ this.app.showLoadingIcon();
+
+ $.ajax({
+ cache: false,
+ url: url,
+ contentType: "application/json",
+ type: "POST",
+ processData: false,
+ data: JSON.stringify({
+ "subtask_id": subtaskId,
+ "position": position
+ }),
+ complete: function() {
+ self.app.hideLoadingIcon();
+ }
+ });
+};
diff --git a/assets/js/src/Swimlane.js b/assets/js/src/Swimlane.js
index 340b40a0..60dbf41f 100644
--- a/assets/js/src/Swimlane.js
+++ b/assets/js/src/Swimlane.js
@@ -1,4 +1,5 @@
-function Swimlane() {
+function Swimlane(app) {
+ this.app = app;
}
Swimlane.prototype.getStorageKey = function() {
@@ -53,6 +54,7 @@ Swimlane.prototype.refresh = function() {
Swimlane.prototype.listen = function() {
var self = this;
+ self.dragAndDrop();
$(document).on('click', ".board-swimlane-toggle", function(e) {
e.preventDefault();
@@ -67,3 +69,55 @@ Swimlane.prototype.listen = function() {
}
});
};
+
+Swimlane.prototype.dragAndDrop = function() {
+ var self = this;
+
+ $(".draggable-row-handle").mouseenter(function() {
+ $(this).parent().parent().addClass("draggable-item-hover");
+ }).mouseleave(function() {
+ $(this).parent().parent().removeClass("draggable-item-hover");
+ });
+
+ $(".swimlanes-table tbody").sortable({
+ forcePlaceholderSize: true,
+ handle: "td:first i",
+ helper: function(e, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+
+ return ui;
+ },
+ stop: function(event, ui) {
+ var swimlane = ui.item;
+ swimlane.removeClass("draggable-item-selected");
+ self.savePosition(swimlane.data("swimlane-id"), swimlane.index() + 1);
+ },
+ start: function(event, ui) {
+ ui.item.addClass("draggable-item-selected");
+ }
+ }).disableSelection();
+};
+
+Swimlane.prototype.savePosition = function(swimlaneId, position) {
+ var url = $(".swimlanes-table").data("save-position-url");
+ var self = this;
+
+ this.app.showLoadingIcon();
+
+ $.ajax({
+ cache: false,
+ url: url,
+ contentType: "application/json",
+ type: "POST",
+ processData: false,
+ data: JSON.stringify({
+ "swimlane_id": swimlaneId,
+ "position": position
+ }),
+ complete: function() {
+ self.app.hideLoadingIcon();
+ }
+ });
+};
diff --git a/assets/js/src/Task.js b/assets/js/src/Task.js
index b3dc1b63..955a5752 100644
--- a/assets/js/src/Task.js
+++ b/assets/js/src/Task.js
@@ -1,10 +1,51 @@
-function Task() {
+function Task(app) {
+ this.app = app;
}
Task.prototype.listen = function() {
+ var self = this;
+ var reloadingProjectId = 0;
+
+ // Change color
$(document).on("click", ".color-square", function() {
$(".color-square-selected").removeClass("color-square-selected");
$(this).addClass("color-square-selected");
$("#form-color_id").val($(this).data("color-id"));
});
+
+ // Assign to me
+ $(document).on("click", ".assign-me", function(e) {
+ e.preventDefault();
+
+ var currentId = $(this).data("current-id");
+ var dropdownId = "#" + $(this).data("target-id");
+
+ if ($(dropdownId + ' option[value=' + currentId + ']').length) {
+ $(dropdownId).val(currentId);
+ }
+ });
+
+ // Reload page when a destination project is changed
+ $(document).on("change", "select.task-reload-project-destination", function() {
+ if (reloadingProjectId > 0) {
+ $(this).val(reloadingProjectId);
+ }
+ else {
+ reloadingProjectId = $(this).val();
+ var url = $(this).data("redirect").replace(/PROJECT_ID/g, reloadingProjectId);
+
+ $(".loading-icon").show();
+
+ $.ajax({
+ type: "GET",
+ url: url,
+ success: function(data, textStatus, request) {
+ reloadingProjectId = 0;
+ $(".loading-icon").hide();
+
+ self.app.popover.afterSubmit(data, request, self.app.popover);
+ }
+ });
+ }
+ });
};
diff --git a/assets/js/src/Tooltip.js b/assets/js/src/Tooltip.js
index 0ec8b268..f3ef55f9 100644
--- a/assets/js/src/Tooltip.js
+++ b/assets/js/src/Tooltip.js
@@ -48,21 +48,6 @@ Tooltip.prototype.listen = function() {
var position = $(_this).tooltip("option", "position");
position.of = $(_this);
tooltip.position(position);
-
- // Toggle subtasks status
- $('#tooltip-subtasks a').not(".popover").click(function(e) {
-
- e.preventDefault();
- e.stopPropagation();
-
- if ($(this).hasClass("popover-subtask-restriction")) {
- self.app.popover.open($(this).attr('href'));
- $(_this).tooltip('close');
- }
- else {
- $.get($(this).attr('href'), setTooltipContent);
- }
- });
});
return '<i class="fa fa-spinner fa-spin"></i>';