diff options
Diffstat (limited to 'assets/js/src')
-rw-r--r-- | assets/js/src/App.js | 24 | ||||
-rw-r--r-- | assets/js/src/Column.js | 59 | ||||
-rw-r--r-- | assets/js/src/Dropdown.js | 6 | ||||
-rw-r--r-- | assets/js/src/FileUpload.js | 124 | ||||
-rw-r--r-- | assets/js/src/Popover.js | 57 | ||||
-rw-r--r-- | assets/js/src/Project.js | 10 | ||||
-rw-r--r-- | assets/js/src/Search.js | 9 | ||||
-rw-r--r-- | assets/js/src/Sidebar.js | 25 | ||||
-rw-r--r-- | assets/js/src/Subtask.js | 94 | ||||
-rw-r--r-- | assets/js/src/Swimlane.js | 56 | ||||
-rw-r--r-- | assets/js/src/Task.js | 43 | ||||
-rw-r--r-- | assets/js/src/Tooltip.js | 15 |
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(" ") + .append(this.files[i].name) + .append(" ") + .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>'; |