summaryrefslogtreecommitdiff
path: root/assets/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/src')
-rw-r--r--assets/js/src/App.js24
-rw-r--r--assets/js/src/Column.js59
-rw-r--r--assets/js/src/Dropdown.js6
-rw-r--r--assets/js/src/FileUpload.js124
-rw-r--r--assets/js/src/Popover.js57
-rw-r--r--assets/js/src/Project.js10
-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
12 files changed, 447 insertions, 75 deletions
diff --git a/assets/js/src/App.js b/assets/js/src/App.js
index 976b4554..56efd706 100644
--- a/assets/js/src/App.js
+++ b/assets/js/src/App.js
@@ -1,44 +1,38 @@
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();
// Alert box fadeout
- $(".alert-fade-out").delay(4000).fadeOut(800, function() {
+ $(".alert-fade-out").delay(5000).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.autoComplete();
this.datePicker();
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/Dropdown.js b/assets/js/src/Dropdown.js
index 146a3c17..61738da9 100644
--- a/assets/js/src/Dropdown.js
+++ b/assets/js/src/Dropdown.js
@@ -26,11 +26,11 @@ Dropdown.prototype.listen = function() {
var submenuHeight = clone.outerHeight();
var submenuWidth = clone.outerWidth();
- if (offset.top + submenuHeight - $(window).scrollTop() > $(window).height()) {
- clone.css('top', offset.top - submenuHeight - 5);
+ 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 + $(this).height());
+ clone.css('top', offset.top - submenuHeight - 5);
}
if (offset.left + submenuWidth > $(window).width()) {
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/Popover.js b/assets/js/src/Popover.js
index 8d72dec8..3a209e8a 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,52 @@ 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);
+ },
+ beforeSend: function() {
+ var button = $('.popover-form button[type="submit"]');
+ button.html('<i class="fa fa-spinner fa-pulse"></i> ' + button.html());
+ button.attr("disabled", true);
}
});
});
}
+
+ // 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
index e2412412..19941f03 100644
--- a/assets/js/src/Project.js
+++ b/assets/js/src/Project.js
@@ -15,4 +15,14 @@ Project.prototype.listen = function() {
})
});
});
+
+ $('#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/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>';