Added Markdown editor and Javascript code refactoring

This commit is contained in:
Frederic Guillot
2016-03-20 15:45:02 -04:00
parent 787e91ca41
commit f77d6c590b
64 changed files with 1154 additions and 3644 deletions

View File

@@ -1,11 +1,11 @@
function Accordion(app) {
Kanboard.Accordion = function(app) {
this.app = app;
}
};
Accordion.prototype.listen = function() {
Kanboard.Accordion.prototype.listen = function() {
$(document).on("click", ".accordion-toggle", function(e) {
e.preventDefault();
var section = $(this).parents(".accordion-section");
e.preventDefault();
if (section.hasClass("accordion-collapsed")) {
section.find(".accordion-content").show();

View File

@@ -1,75 +1,43 @@
function App() {
this.board = new Board(this);
this.markdown = new Markdown();
this.search = new Search(this);
this.swimlane = new Swimlane(this);
this.dropdown = new Dropdown();
this.tooltip = new Tooltip(this);
this.popover = new Popover(this);
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.accordion = new Accordion(this);
this.keyboardShortcuts();
this.task.keyboardShortcuts();
this.chosen();
this.poll();
Kanboard.App = function() {
this.controllers = {};
};
// Alert box fadeout
$(".alert-fade-out").delay(5000).fadeOut(800, function() {
$(this).remove();
});
}
Kanboard.App.prototype.get = function(controller) {
return this.controllers[controller];
};
Kanboard.App.prototype.execute = function() {
for (var className in Kanboard) {
if (className !== "App") {
var controller = new Kanboard[className](this);
this.controllers[className] = controller;
if (typeof controller.execute === "function") {
controller.execute();
}
if (typeof controller.listen === "function") {
controller.listen();
}
if (typeof controller.focus === "function") {
controller.focus();
}
if (typeof controller.keyboardShortcuts === "function") {
controller.keyboardShortcuts();
}
}
}
App.prototype.listen = function() {
this.project.listen();
this.popover.listen();
this.markdown.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.accordion.listen();
this.search.focus();
this.autoComplete();
this.datePicker();
this.focus();
this.chosen();
this.keyboardShortcuts();
this.datePicker();
this.autoComplete();
};
App.prototype.refresh = function() {
$(document).off();
this.listen();
};
App.prototype.focus = function() {
// Autofocus fields (html5 autofocus works only with page onload)
$("[autofocus]").each(function(index, element) {
$(this).focus();
})
// Auto-select input fields
$(document).on('focus', '.auto-select', function() {
$(this).select();
});
// Workaround for chrome
$(document).on('mouseup', '.auto-select', function(e) {
e.preventDefault();
});
};
App.prototype.poll = function() {
window.setInterval(this.checkSession, 60000);
};
App.prototype.keyboardShortcuts = function() {
Kanboard.App.prototype.keyboardShortcuts = function() {
var self = this;
// Submit form
@@ -85,31 +53,50 @@ App.prototype.keyboardShortcuts = function() {
// Close popover and dropdown
Mousetrap.bindGlobal("esc", function() {
self.popover.close();
self.dropdown.close();
self.get("Popover").close();
self.get("Dropdown").close();
});
// Show keyboard shortcut
Mousetrap.bind("?", function() {
self.popover.open($("body").data("keyboard-shortcut-url"));
self.get("Popover").open($("body").data("keyboard-shortcut-url"));
});
};
App.prototype.checkSession = function() {
if (! $(".form-login").length) {
$.ajax({
cache: false,
url: $("body").data("status-url"),
statusCode: {
401: function() {
window.location = $("body").data("login-url");
}
}
});
}
Kanboard.App.prototype.focus = function() {
// Auto-select input fields
$(document).on('focus', '.auto-select', function() {
$(this).select();
});
// Workaround for chrome
$(document).on('mouseup', '.auto-select', function(e) {
e.preventDefault();
});
};
App.prototype.datePicker = function() {
Kanboard.App.prototype.chosen = function() {
$(".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() {
var regex = new RegExp($(this).data('redirect-regex'), 'g');
window.location = $(this).data('redirect-url').replace(regex, $(this).val());
});
};
Kanboard.App.prototype.datePicker = function() {
// Datepicker translation
$.datepicker.setDefaults($.datepicker.regional[$("body").data("js-lang")]);
@@ -131,7 +118,7 @@ App.prototype.datePicker = function() {
});
};
App.prototype.autoComplete = function() {
Kanboard.App.prototype.autoComplete = function() {
$(".autocomplete").each(function() {
var input = $(this);
var field = input.data("dst-field");
@@ -157,36 +144,33 @@ App.prototype.autoComplete = function() {
});
};
App.prototype.chosen = function() {
$(".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() {
var regex = new RegExp($(this).data('redirect-regex'), 'g');
window.location = $(this).data('redirect-url').replace(regex, $(this).val());
});
Kanboard.App.prototype.hasId = function(id) {
return !!document.getElementById(id);
};
App.prototype.showLoadingIcon = function() {
Kanboard.App.prototype.showLoadingIcon = function() {
$("body").append('<span id="app-loading-icon">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>');
};
App.prototype.hideLoadingIcon = function() {
Kanboard.App.prototype.hideLoadingIcon = function() {
$("#app-loading-icon").remove();
};
App.prototype.isVisible = function() {
Kanboard.App.prototype.formatDuration = function(d) {
if (d >= 86400) {
return Math.round(d/86400) + "d";
}
else if (d >= 3600) {
return Math.round(d/3600) + "h";
}
else if (d >= 60) {
return Math.round(d/60) + "m";
}
return d + "s";
};
Kanboard.App.prototype.isVisible = function() {
var property = "";
if (typeof document.hidden !== "undefined") {
@@ -205,17 +189,3 @@ App.prototype.isVisible = function() {
return true;
};
App.prototype.formatDuration = function(d) {
if (d >= 86400) {
return Math.round(d/86400) + "d";
}
else if (d >= 3600) {
return Math.round(d/3600) + "h";
}
else if (d >= 60) {
return Math.round(d/60) + "m";
}
return d + "s";
};

View File

@@ -1,10 +1,17 @@
function AvgTimeColumnChart(app) {
Kanboard.AvgTimeColumnChart = function(app) {
this.app = app;
}
};
AvgTimeColumnChart.prototype.execute = function() {
var metrics = $("#chart").data("metrics");
var plots = [$("#chart").data("label")];
Kanboard.AvgTimeColumnChart.prototype.execute = function() {
if (this.app.hasId("analytic-avg-time-column")) {
this.show();
}
};
Kanboard.AvgTimeColumnChart.prototype.show = function() {
var chart = $("#chart");
var metrics = chart.data("metrics");
var plots = [chart.data("label")];
var categories = [];
for (var column_id in metrics) {

View File

@@ -1,336 +0,0 @@
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.poll();
this.keyboardShortcuts();
this.listen();
this.dragAndDrop();
$(window).on("load", this.columnScrolling);
$(window).resize(this.columnScrolling);
};
Board.prototype.poll = function() {
var interval = parseInt($("#board").attr("data-check-interval"));
if (interval > 0) {
this.checkInterval = window.setInterval(this.check.bind(this), interval * 1000);
}
};
Board.prototype.reloadFilters = function(search) {
this.app.showLoadingIcon();
$.ajax({
cache: false,
url: $("#board").data("reload-url"),
contentType: "application/json",
type: "POST",
processData: false,
data: JSON.stringify({
search: search
}),
success: this.refresh.bind(this),
error: this.app.hideLoadingIcon.bind(this)
});
};
Board.prototype.check = function() {
if (this.app.isVisible() && ! this.savingInProgress) {
var self = this;
this.app.showLoadingIcon();
$.ajax({
cache: false,
url: $("#board").data("check-url"),
statusCode: {
200: function(data) { self.refresh(data); },
304: function () { self.app.hideLoadingIcon(); }
}
});
}
};
Board.prototype.save = function(taskId, columnId, position, swimlaneId) {
var self = this;
this.app.showLoadingIcon();
this.savingInProgress = true;
$.ajax({
cache: false,
url: $("#board").data("save-url"),
contentType: "application/json",
type: "POST",
processData: false,
data: JSON.stringify({
"task_id": taskId,
"column_id": columnId,
"swimlane_id": swimlaneId,
"position": position
}),
success: function(data) {
self.refresh(data);
this.savingInProgress = false;
},
error: function() {
self.app.hideLoadingIcon();
this.savingInProgress = false;
}
});
};
Board.prototype.refresh = function(data) {
$("#board-container").replaceWith(data);
this.app.refresh();
this.app.swimlane.refresh();
this.app.hideLoadingIcon();
this.listen();
this.dragAndDrop();
this.compactView();
this.restoreColumnViewMode();
this.columnScrolling();
};
Board.prototype.dragAndDrop = function() {
var self = this;
var params = {
forcePlaceholderSize: true,
tolerance: "pointer",
connectWith: ".board-task-list",
placeholder: "draggable-placeholder",
items: ".draggable-item",
stop: function(event, ui) {
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");
ui.placeholder.height(ui.item.height());
}
};
if ($.support.touch) {
$(".task-board-sort-handle").css("display", "inline");
params["handle"] = ".task-board-sort-handle";
}
$(".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;
$(document).on("click", ".task-board-change-assignee", function(e) {
e.preventDefault();
self.app.popover.open($(this).data('url'));
});
$(document).on("click", ".task-board", function(e) {
if (e.target.tagName != "A" && e.target.tagName != "IMG") {
window.location = $(this).data("task-url");
}
});
$(document).on('click', ".filter-toggle-scrolling", function(e) {
e.preventDefault();
self.toggleCompactView();
});
$(document).on('click', ".filter-toggle-height", function(e) {
e.preventDefault();
self.toggleColumnScrolling();
});
$(document).on("click", ".board-toggle-column-view", function() {
self.toggleColumnViewMode($(this).data("column-id"));
});
};
Board.prototype.toggleColumnScrolling = function() {
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() {
var columnHeight = $(this).height();
if (columnHeight > height) {
height = columnHeight;
}
});
$(".board-task-list").css("min-height", height);
$(".board-task-list").css("height", '');
}
else {
$(".filter-max-height").hide();
$(".filter-min-height").show();
if ($(".board-swimlane").length > 1) {
$(".board-task-list").each(function() {
if ($(this).height() > 500) {
$(this).css("height", 500);
}
else {
$(this).css("min-height", 320); // Height of the dropdown menu
$(".board-rotation-wrapper").css("min-height", 320);
}
});
}
else {
var height = $(window).height() - 170;
$(".board-task-list").css("height", height);
$(".board-rotation-wrapper").css("min-height", height);
}
}
};
Board.prototype.toggleCompactView = function() {
var scrolling = localStorage.getItem("horizontal_scroll") || 1;
localStorage.setItem("horizontal_scroll", scrolling == 0 ? 1 : 0);
this.compactView();
};
Board.prototype.compactView = function() {
if (localStorage.getItem("horizontal_scroll") == 0) {
$(".filter-wide").show();
$(".filter-compact").hide();
$("#board-container").addClass("board-container-compact");
$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact");
}
else {
$(".filter-wide").hide();
$(".filter-compact").show();
$("#board-container").removeClass("board-container-compact");
$("#board th").removeClass("board-column-compact");
}
};
Board.prototype.toggleCollapsedMode = function() {
var self = this;
this.app.showLoadingIcon();
$.ajax({
cache: false,
url: $('.filter-display-mode:not([style="display: none;"]) a').attr('href'),
success: function(data) {
$('.filter-display-mode').toggle();
self.refresh(data);
}
});
};
Board.prototype.restoreColumnViewMode = function() {
var self = this;
$(".board-column-header").each(function() {
var columnId = $(this).data('column-id');
if (localStorage.getItem("hidden_column_" + columnId)) {
self.hideColumn(columnId);
}
});
};
Board.prototype.toggleColumnViewMode = function(columnId) {
if (localStorage.getItem("hidden_column_" + columnId)) {
this.showColumn(columnId);
}
else {
this.hideColumn(columnId);
}
};
Board.prototype.hideColumn = function(columnId) {
$(".board-column-" + columnId + " .board-column-expanded").hide();
$(".board-column-" + columnId + " .board-column-collapsed").show();
$(".board-column-header-" + columnId + " .board-column-expanded").hide();
$(".board-column-header-" + columnId + " .board-column-collapsed").show();
$(".board-column-header-" + columnId).each(function() {
$(this).removeClass("board-column-compact");
$(this).addClass("board-column-header-collapsed");
});
$(".board-column-" + columnId ).each(function() {
$(this).addClass("board-column-task-collapsed");
});
$(".board-column-" + columnId + " .board-rotation").each(function() {
$(this).css("width", $(".board-column-" + columnId + "").height());
});
localStorage.setItem("hidden_column_" + columnId, 1);
};
Board.prototype.showColumn = function(columnId) {
$(".board-column-" + columnId + " .board-column-expanded").show();
$(".board-column-" + columnId + " .board-column-collapsed").hide();
$(".board-column-header-" + columnId + " .board-column-expanded").show();
$(".board-column-header-" + columnId + " .board-column-collapsed").hide();
$(".board-column-header-" + columnId).removeClass("board-column-header-collapsed");
$(".board-column-" + columnId).removeClass("board-column-task-collapsed");
if (localStorage.getItem("horizontal_scroll") == 0) {
$(".board-column-header-" + columnId).addClass("board-column-compact");
}
localStorage.removeItem("hidden_column_" + columnId);
};
Board.prototype.keyboardShortcuts = function() {
var self = this;
Mousetrap.bind("c", function() { self.toggleCompactView(); });
Mousetrap.bind("s", function() { self.toggleCollapsedMode(); });
Mousetrap.bind("n", function() {
self.app.popover.open($("#board").data("task-creation-url"));
});
};

View File

@@ -0,0 +1,25 @@
Kanboard.BoardCollapsedMode = function(app) {
this.app = app;
};
Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts = function() {
var self = this;
Mousetrap.bind("s", function() {
self.toggle();
});
};
Kanboard.BoardCollapsedMode.prototype.toggle = function() {
var self = this;
this.app.showLoadingIcon();
$.ajax({
cache: false,
url: $('.filter-display-mode:not([style="display: none;"]) a').attr('href'),
success: function(data) {
$('.filter-display-mode').toggle();
self.app.get("BoardDragAndDrop").refresh(data);
}
});
};

View File

@@ -0,0 +1,85 @@
Kanboard.BoardColumnScrolling = function(app) {
this.app = app;
};
Kanboard.BoardColumnScrolling.prototype.execute = function() {
if (this.app.hasId("board")) {
this.render();
$(window).on("load", this.render);
$(window).resize(this.render);
}
};
Kanboard.BoardColumnScrolling.prototype.listen = function() {
var self = this;
$(document).on('click', ".filter-toggle-height", function(e) {
e.preventDefault();
self.toggle();
});
};
Kanboard.BoardColumnScrolling.prototype.onBoardRendered = function() {
this.render();
};
Kanboard.BoardColumnScrolling.prototype.toggle = function() {
var scrolling = localStorage.getItem("column_scroll");
if (scrolling == undefined) {
scrolling = 1;
}
localStorage.setItem("column_scroll", scrolling == 0 ? 1 : 0);
this.render();
};
Kanboard.BoardColumnScrolling.prototype.render = function() {
var taskList = $(".board-task-list");
var rotationWrapper = $(".board-rotation-wrapper");
var filterMax = $(".filter-max-height");
var filterMin = $(".filter-min-height");
if (localStorage.getItem("column_scroll") == 0) {
var height = 80;
filterMax.show();
filterMin.hide();
rotationWrapper.css("min-height", '');
taskList.each(function() {
var columnHeight = $(this).height();
if (columnHeight > height) {
height = columnHeight;
}
});
taskList.css("min-height", height);
taskList.css("height", '');
}
else {
filterMax.hide();
filterMin.show();
if ($(".board-swimlane").length > 1) {
taskList.each(function() {
if ($(this).height() > 500) {
$(this).css("height", 500);
}
else {
$(this).css("min-height", 320); // Height of the dropdown menu
rotationWrapper.css("min-height", 320);
}
});
}
else {
var height = $(window).height() - 170;
taskList.css("height", height);
rotationWrapper.css("min-height", height);
}
}
};

View File

@@ -0,0 +1,79 @@
Kanboard.BoardColumnView = function(app) {
this.app = app;
};
Kanboard.BoardColumnView.prototype.execute = function() {
if (this.app.hasId("board")) {
this.render();
}
};
Kanboard.BoardColumnView.prototype.listen = function() {
var self = this;
$(document).on("click", ".board-toggle-column-view", function() {
self.toggle($(this).data("column-id"));
});
};
Kanboard.BoardColumnView.prototype.onBoardRendered = function() {
this.render();
};
Kanboard.BoardColumnView.prototype.render = function() {
var self = this;
$(".board-column-header").each(function() {
var columnId = $(this).data('column-id');
if (localStorage.getItem("hidden_column_" + columnId)) {
self.hideColumn(columnId);
}
});
};
Kanboard.BoardColumnView.prototype.toggle = function(columnId) {
if (localStorage.getItem("hidden_column_" + columnId)) {
this.showColumn(columnId);
}
else {
this.hideColumn(columnId);
}
};
Kanboard.BoardColumnView.prototype.hideColumn = function(columnId) {
$(".board-column-" + columnId + " .board-column-expanded").hide();
$(".board-column-" + columnId + " .board-column-collapsed").show();
$(".board-column-header-" + columnId + " .board-column-expanded").hide();
$(".board-column-header-" + columnId + " .board-column-collapsed").show();
$(".board-column-header-" + columnId).each(function() {
$(this).removeClass("board-column-compact");
$(this).addClass("board-column-header-collapsed");
});
$(".board-column-" + columnId).each(function() {
$(this).addClass("board-column-task-collapsed");
});
$(".board-column-" + columnId + " .board-rotation").each(function() {
$(this).css("width", $(".board-column-" + columnId + "").height());
});
localStorage.setItem("hidden_column_" + columnId, 1);
};
Kanboard.BoardColumnView.prototype.showColumn = function(columnId) {
$(".board-column-" + columnId + " .board-column-expanded").show();
$(".board-column-" + columnId + " .board-column-collapsed").hide();
$(".board-column-header-" + columnId + " .board-column-expanded").show();
$(".board-column-header-" + columnId + " .board-column-collapsed").hide();
$(".board-column-header-" + columnId).removeClass("board-column-header-collapsed");
$(".board-column-" + columnId).removeClass("board-column-task-collapsed");
if (localStorage.getItem("horizontal_scroll") == 0) {
$(".board-column-header-" + columnId).addClass("board-column-compact");
}
localStorage.removeItem("hidden_column_" + columnId);
};

View File

@@ -0,0 +1,103 @@
Kanboard.BoardDragAndDrop = function(app) {
this.app = app;
this.savingInProgress = false;
};
Kanboard.BoardDragAndDrop.prototype.execute = function() {
if (this.app.hasId("board")) {
this.dragAndDrop();
this.executeListeners();
}
};
Kanboard.BoardDragAndDrop.prototype.dragAndDrop = function() {
var self = this;
var params = {
forcePlaceholderSize: true,
tolerance: "pointer",
connectWith: ".board-task-list",
placeholder: "draggable-placeholder",
items: ".draggable-item",
stop: function(event, ui) {
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");
ui.placeholder.height(ui.item.height());
}
};
if ($.support.touch) {
$(".task-board-sort-handle").css("display", "inline");
params["handle"] = ".task-board-sort-handle";
}
$(".board-task-list").sortable(params);
};
Kanboard.BoardDragAndDrop.prototype.changeTaskState = function(taskId) {
var task = $("div[data-task-id=" + taskId + "]");
task.addClass('task-board-saving-state');
task.find('.task-board-saving-icon').show();
};
Kanboard.BoardDragAndDrop.prototype.save = function(taskId, columnId, position, swimlaneId) {
var self = this;
self.app.showLoadingIcon();
self.savingInProgress = true;
$.ajax({
cache: false,
url: $("#board").data("save-url"),
contentType: "application/json",
type: "POST",
processData: false,
data: JSON.stringify({
"task_id": taskId,
"column_id": columnId,
"swimlane_id": swimlaneId,
"position": position
}),
success: function(data) {
self.refresh(data);
self.savingInProgress = false;
},
error: function() {
self.app.hideLoadingIcon();
self.savingInProgress = false;
}
});
};
Kanboard.BoardDragAndDrop.prototype.refresh = function(data) {
$("#board-container").replaceWith(data);
this.app.hideLoadingIcon();
this.dragAndDrop();
this.executeListeners();
};
Kanboard.BoardDragAndDrop.prototype.executeListeners = function() {
for (var className in this.app.controllers) {
var controller = this.app.get(className);
if (typeof controller.onBoardRendered === "function") {
controller.onBoardRendered();
}
}
};

View File

@@ -0,0 +1,53 @@
Kanboard.BoardHorizontalScrolling = function(app) {
this.app = app;
};
Kanboard.BoardHorizontalScrolling.prototype.execute = function() {
if (this.app.hasId("board")) {
this.render();
}
};
Kanboard.BoardHorizontalScrolling.prototype.listen = function() {
var self = this;
$(document).on('click', ".filter-toggle-scrolling", function(e) {
e.preventDefault();
self.toggle();
});
};
Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts = function() {
var self = this;
Mousetrap.bind("c", function() {
self.toggle();
});
};
Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered = function() {
this.render();
};
Kanboard.BoardHorizontalScrolling.prototype.toggle = function() {
var scrolling = localStorage.getItem("horizontal_scroll") || 1;
localStorage.setItem("horizontal_scroll", scrolling == 0 ? 1 : 0);
this.render();
};
Kanboard.BoardHorizontalScrolling.prototype.render = function() {
if (localStorage.getItem("horizontal_scroll") == 0) {
$(".filter-wide").show();
$(".filter-compact").hide();
$("#board-container").addClass("board-container-compact");
$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact");
}
else {
$(".filter-wide").hide();
$(".filter-compact").show();
$("#board-container").removeClass("board-container-compact");
$("#board th").removeClass("board-column-compact");
}
};

View File

@@ -0,0 +1,33 @@
Kanboard.BoardPolling = function(app) {
this.app = app;
};
Kanboard.BoardPolling.prototype.execute = function() {
if (this.app.hasId("board")) {
var interval = parseInt($("#board").attr("data-check-interval"));
if (interval > 0) {
window.setInterval(this.check.bind(this), interval * 1000);
}
}
};
Kanboard.BoardPolling.prototype.check = function() {
if (this.app.isVisible() && !this.app.get("BoardDragAndDrop").savingInProgress) {
var self = this;
this.app.showLoadingIcon();
$.ajax({
cache: false,
url: $("#board").data("check-url"),
statusCode: {
200: function(data) {
self.app.get("BoardDragAndDrop").refresh(data);
},
304: function () {
self.app.hideLoadingIcon();
}
}
});
}
};

View File

@@ -0,0 +1,27 @@
Kanboard.BoardTask = function(app) {
this.app = app;
};
Kanboard.BoardTask.prototype.listen = function() {
var self = this;
$(document).on("click", ".task-board-change-assignee", function(e) {
e.preventDefault();
e.stopPropagation();
self.app.get("Popover").open($(this).data('url'));
});
$(document).on("click", ".task-board", function(e) {
if (e.target.tagName != "A" && e.target.tagName != "IMG") {
window.location = $(this).data("task-url");
}
});
};
Kanboard.BoardTask.prototype.keyboardShortcuts = function() {
var self = this;
Mousetrap.bind("n", function() {
self.app.get("Popover").open($("#board").data("task-creation-url"));
});
};

View File

@@ -1,12 +1,20 @@
function BurndownChart() {
}
Kanboard.BurndownChart = function(app) {
this.app = app;
};
BurndownChart.prototype.execute = function() {
var metrics = $("#chart").data("metrics");
var columns = [[$("#chart").data("label-total")]];
Kanboard.BurndownChart.prototype.execute = function() {
if (this.app.hasId("analytic-burndown")) {
this.show();
}
};
Kanboard.BurndownChart.prototype.show = function() {
var chart = $("#chart");
var metrics = chart.data("metrics");
var columns = [[chart.data("label-total")]];
var categories = [];
var inputFormat = d3.time.format("%Y-%m-%d");
var outputFormat = d3.time.format($("#chart").data("date-format"));
var outputFormat = d3.time.format(chart.data("date-format"));
for (var i = 0; i < metrics.length; i++) {

View File

@@ -1,10 +1,16 @@
function Calendar() {
Kanboard.Calendar = function(app) {
this.app = app;
};
}
Calendar.prototype.execute = function() {
Kanboard.Calendar.prototype.execute = function() {
var calendar = $('#calendar');
if (calendar.length == 1) {
this.show(calendar);
}
};
Kanboard.Calendar.prototype.show = function(calendar) {
calendar.fullCalendar({
lang: $("body").data("js-lang"),
editable: true,

View File

@@ -1,12 +1,12 @@
function Column(app) {
Kanboard.Column = function(app) {
this.app = app;
}
};
Column.prototype.listen = function() {
Kanboard.Column.prototype.listen = function() {
this.dragAndDrop();
};
Column.prototype.dragAndDrop = function() {
Kanboard.Column.prototype.dragAndDrop = function() {
var self = this;
$(".draggable-row-handle").mouseenter(function() {
@@ -36,7 +36,7 @@ Column.prototype.dragAndDrop = function() {
}).disableSelection();
};
Column.prototype.savePosition = function(columnId, position) {
Kanboard.Column.prototype.savePosition = function(columnId, position) {
var url = $(".columns-table").data("save-position-url");
var self = this;

View File

@@ -1,13 +1,20 @@
function CompareHoursColumnChart(app) {
Kanboard.CompareHoursColumnChart = function(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")];
Kanboard.CompareHoursColumnChart.prototype.execute = function() {
if (this.app.hasId("analytic-compare-hours")) {
this.show();
}
};
Kanboard.CompareHoursColumnChart.prototype.show = function() {
var chart = $("#chart");
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) {

View File

@@ -1,14 +1,21 @@
function CumulativeFlowDiagram() {
}
Kanboard.CumulativeFlowDiagram = function(app) {
this.app = app;
};
CumulativeFlowDiagram.prototype.execute = function() {
Kanboard.CumulativeFlowDiagram.prototype.execute = function() {
if (this.app.hasId("analytic-cfd")) {
this.show();
}
};
var metrics = $("#chart").data("metrics");
Kanboard.CumulativeFlowDiagram.prototype.show = function() {
var chart = $("#chart");
var metrics = chart.data("metrics");
var columns = [];
var groups = [];
var categories = [];
var inputFormat = d3.time.format("%Y-%m-%d");
var outputFormat = d3.time.format($("#chart").data("date-format"));
var outputFormat = d3.time.format(chart.data("date-format"));
for (var i = 0; i < metrics.length; i++) {

View File

@@ -1,7 +1,8 @@
function Dropdown() {
}
Kanboard.Dropdown = function(app) {
this.app = app;
};
Dropdown.prototype.listen = function() {
Kanboard.Dropdown.prototype.listen = function() {
var self = this;
$(document).on('click', function() {
@@ -46,23 +47,12 @@ Dropdown.prototype.listen = function() {
$(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() {
Kanboard.Dropdown.prototype.close = function() {
$("#dropdown").remove();
};
Kanboard.Dropdown.prototype.onPopoverOpened = function() {
this.close();
};

View File

@@ -1,10 +1,10 @@
function FileUpload(app) {
Kanboard.FileUpload = function(app) {
this.app = app;
this.files = [];
this.currentFile = 0;
}
};
FileUpload.prototype.listen = function() {
Kanboard.FileUpload.prototype.onPopoverOpened = function() {
var dropzone = document.getElementById("file-dropzone");
var self = this;
@@ -12,7 +12,7 @@ FileUpload.prototype.listen = function() {
dropzone.ondragover = dropzone.ondragenter = function(e) {
e.stopPropagation();
e.preventDefault();
}
};
dropzone.ondrop = function(e) {
e.stopPropagation();
@@ -20,7 +20,7 @@ FileUpload.prototype.listen = function() {
self.files = e.dataTransfer.files;
self.show();
$("#file-error-max-size").hide();
}
};
$(document).on("click", "#file-browser", function(e) {
e.preventDefault();
@@ -41,7 +41,7 @@ FileUpload.prototype.listen = function() {
}
};
FileUpload.prototype.show = function() {
Kanboard.FileUpload.prototype.show = function() {
$("#file-list").remove();
if (this.files.length > 0) {
@@ -69,7 +69,7 @@ FileUpload.prototype.show = function() {
}
};
FileUpload.prototype.checkFiles = function() {
Kanboard.FileUpload.prototype.checkFiles = function() {
var max = parseInt($("#file-dropzone").data("max-size"));
for (var i = 0; i < this.files.length; i++) {
@@ -84,13 +84,13 @@ FileUpload.prototype.checkFiles = function() {
this.uploadFiles();
};
FileUpload.prototype.uploadFiles = function() {
Kanboard.FileUpload.prototype.uploadFiles = function() {
if (this.files.length > 0) {
this.uploadFile(this.files[this.currentFile]);
}
};
FileUpload.prototype.uploadFile = function(file) {
Kanboard.FileUpload.prototype.uploadFile = function(file) {
var dropzone = document.getElementById("file-dropzone");
var url = dropzone.dataset.url;
var xhr = new XMLHttpRequest();
@@ -104,21 +104,22 @@ FileUpload.prototype.uploadFile = function(file) {
xhr.send(fd);
};
FileUpload.prototype.updateProgress = function(e) {
Kanboard.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() {
Kanboard.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();
var uploadButton = $("#file-upload-button");
uploadButton.prop("disabled", true);
uploadButton.parent().hide();
$("#file-done").show();
}
};

View File

@@ -1,5 +1,5 @@
// Based on jQuery.ganttView v.0.8.8 Copyright (c) 2010 JC Grubbs - jc.grubbs@devmynd.com - MIT License
function Gantt(app) {
Kanboard.Gantt = function(app) {
this.app = app;
this.data = [];
@@ -13,10 +13,16 @@ function Gantt(app) {
slideWidth: 1000,
vHeaderWidth: 200
};
}
};
Kanboard.Gantt.prototype.execute = function() {
if (this.app.hasId("gantt-chart")) {
this.show();
}
};
// Save record after a resize or move
Gantt.prototype.saveRecord = function(record) {
Kanboard.Gantt.prototype.saveRecord = function(record) {
this.app.showLoadingIcon();
$.ajax({
@@ -31,7 +37,7 @@ Gantt.prototype.saveRecord = function(record) {
};
// Build the Gantt chart
Gantt.prototype.execute = function() {
Kanboard.Gantt.prototype.show = function() {
this.data = this.prepareData($(this.options.container).data('records'));
var minDays = Math.floor((this.options.slideWidth / this.options.cellWidth) + 5);
@@ -60,7 +66,7 @@ Gantt.prototype.execute = function() {
};
// Render record list on the left
Gantt.prototype.renderVerticalHeader = function() {
Kanboard.Gantt.prototype.renderVerticalHeader = function() {
var headerDiv = jQuery("<div>", { "class": "ganttview-vtheader" });
var itemDiv = jQuery("<div>", { "class": "ganttview-vtheader-item" });
var seriesDiv = jQuery("<div>", { "class": "ganttview-vtheader-series" });
@@ -92,7 +98,7 @@ Gantt.prototype.renderVerticalHeader = function() {
};
// Render right part of the chart (top header + grid + bars)
Gantt.prototype.renderSlider = function(startDate, endDate) {
Kanboard.Gantt.prototype.renderSlider = function(startDate, endDate) {
var slideDiv = jQuery("<div>", {"class": "ganttview-slide-container"});
var dates = this.getDates(startDate, endDate);
@@ -105,7 +111,7 @@ Gantt.prototype.renderSlider = function(startDate, endDate) {
};
// Render top header (days)
Gantt.prototype.renderHorizontalHeader = function(dates) {
Kanboard.Gantt.prototype.renderHorizontalHeader = function(dates) {
var headerDiv = jQuery("<div>", { "class": "ganttview-hzheader" });
var monthsDiv = jQuery("<div>", { "class": "ganttview-hzheader-months" });
var daysDiv = jQuery("<div>", { "class": "ganttview-hzheader-days" });
@@ -135,7 +141,7 @@ Gantt.prototype.renderHorizontalHeader = function(dates) {
};
// Render grid
Gantt.prototype.renderGrid = function(dates) {
Kanboard.Gantt.prototype.renderGrid = function(dates) {
var gridDiv = jQuery("<div>", { "class": "ganttview-grid" });
var rowDiv = jQuery("<div>", { "class": "ganttview-grid-row" });
@@ -162,7 +168,7 @@ Gantt.prototype.renderGrid = function(dates) {
};
// Render bar containers
Gantt.prototype.addBlockContainers = function() {
Kanboard.Gantt.prototype.addBlockContainers = function() {
var blocksDiv = jQuery("<div>", { "class": "ganttview-blocks" });
for (var i = 0; i < this.data.length; i++) {
@@ -173,7 +179,7 @@ Gantt.prototype.addBlockContainers = function() {
};
// Render bars
Gantt.prototype.addBlocks = function(slider, start) {
Kanboard.Gantt.prototype.addBlocks = function(slider, start) {
var rows = jQuery("div.ganttview-blocks div.ganttview-block-container", slider);
var rowIdx = 0;
@@ -219,7 +225,7 @@ Gantt.prototype.addBlocks = function(slider, start) {
};
// Get tooltip for vertical header
Gantt.prototype.getVerticalHeaderTooltip = function(record) {
Kanboard.Gantt.prototype.getVerticalHeaderTooltip = function(record) {
var tooltip = "";
if (record.type == "task") {
@@ -246,7 +252,7 @@ Gantt.prototype.getVerticalHeaderTooltip = function(record) {
};
// Get tooltip for bars
Gantt.prototype.getBarTooltip = function(record) {
Kanboard.Gantt.prototype.getBarTooltip = function(record) {
var tooltip = "";
if (record.not_defined) {
@@ -266,7 +272,7 @@ Gantt.prototype.getBarTooltip = function(record) {
};
// Set bar color
Gantt.prototype.setBarColor = function(block, record) {
Kanboard.Gantt.prototype.setBarColor = function(block, record) {
if (record.not_defined) {
block.addClass("ganttview-block-not-defined");
}
@@ -277,7 +283,7 @@ Gantt.prototype.setBarColor = function(block, record) {
};
// Setup jquery-ui resizable
Gantt.prototype.listenForBlockResize = function(startDate) {
Kanboard.Gantt.prototype.listenForBlockResize = function(startDate) {
var self = this;
jQuery("div.ganttview-block", this.options.container).resizable({
@@ -293,7 +299,7 @@ Gantt.prototype.listenForBlockResize = function(startDate) {
};
// Setup jquery-ui drag and drop
Gantt.prototype.listenForBlockMove = function(startDate) {
Kanboard.Gantt.prototype.listenForBlockMove = function(startDate) {
var self = this;
jQuery("div.ganttview-block", this.options.container).draggable({
@@ -309,7 +315,7 @@ Gantt.prototype.listenForBlockMove = function(startDate) {
};
// Update the record data and the position on the chart
Gantt.prototype.updateDataAndPosition = function(block, startDate) {
Kanboard.Gantt.prototype.updateDataAndPosition = function(block, startDate) {
var container = jQuery("div.ganttview-slide-container", this.options.container);
var scroll = container.scrollLeft();
var offset = block.offset().left - container.offset().left - 1 + scroll;
@@ -349,7 +355,7 @@ Gantt.prototype.updateDataAndPosition = function(block, startDate) {
// Creates a 3 dimensional array [year][month][day] of every day
// between the given start and end dates
Gantt.prototype.getDates = function(start, end) {
Kanboard.Gantt.prototype.getDates = function(start, end) {
var dates = [];
dates[start.getFullYear()] = [];
dates[start.getFullYear()][start.getMonth()] = [start];
@@ -374,7 +380,7 @@ Gantt.prototype.getDates = function(start, end) {
};
// Convert data to Date object
Gantt.prototype.prepareData = function(data) {
Kanboard.Gantt.prototype.prepareData = function(data) {
for (var i = 0; i < data.length; i++) {
var start = new Date(data[i].start[0], data[i].start[1] - 1, data[i].start[2], 0, 0, 0, 0);
data[i].start = start;
@@ -387,7 +393,7 @@ Gantt.prototype.prepareData = function(data) {
};
// Get the start and end date from the data provided
Gantt.prototype.getDateRange = function(minDays) {
Kanboard.Gantt.prototype.getDateRange = function(minDays) {
var minStart = new Date();
var maxEnd = new Date();
@@ -425,7 +431,7 @@ Gantt.prototype.getDateRange = function(minDays) {
};
// Returns the number of day between 2 dates
Gantt.prototype.daysBetween = function(start, end) {
Kanboard.Gantt.prototype.daysBetween = function(start, end) {
if (! start || ! end) {
return 0;
}
@@ -441,17 +447,17 @@ Gantt.prototype.daysBetween = function(start, end) {
};
// Return true if it's the weekend
Gantt.prototype.isWeekend = function(date) {
Kanboard.Gantt.prototype.isWeekend = function(date) {
return date.getDay() % 6 == 0;
};
// Clone Date object
Gantt.prototype.cloneDate = function(date) {
Kanboard.Gantt.prototype.cloneDate = function(date) {
return new Date(date.getTime());
};
// Add days to a Date object
Gantt.prototype.addDays = function(date, value) {
Kanboard.Gantt.prototype.addDays = function(date, value) {
date.setDate(date.getDate() + value * 1);
return date;
};
@@ -463,7 +469,7 @@ Gantt.prototype.addDays = function(date, value) {
* 0 = values are equal
* 1 = date1 is greaterthan date2.
*/
Gantt.prototype.compareDate = function(date1, date2) {
Kanboard.Gantt.prototype.compareDate = function(date1, date2) {
if (isNaN(date1) || isNaN(date2)) {
throw new Error(date1 + " - " + date2);
} else if (date1 instanceof Date && date2 instanceof Date) {

View File

@@ -1,20 +1,27 @@
function LeadCycleTimeChart(app) {
Kanboard.LeadCycleTimeChart = function(app) {
this.app = app;
}
};
LeadCycleTimeChart.prototype.execute = function() {
var metrics = $("#chart").data("metrics");
var cycle = [$("#chart").data("label-cycle")];
var lead = [$("#chart").data("label-lead")];
Kanboard.LeadCycleTimeChart.prototype.execute = function() {
if (this.app.hasId("analytic-lead-cycle-time")) {
this.show();
}
};
Kanboard.LeadCycleTimeChart.prototype.show = function() {
var chart = $("#chart");
var metrics = chart.data("metrics");
var cycle = [chart.data("label-cycle")];
var lead = [chart.data("label-lead")];
var categories = [];
var types = {};
types[$("#chart").data("label-cycle")] = 'area';
types[$("#chart").data("label-lead")] = 'area-spline';
types[chart.data("label-cycle")] = 'area';
types[chart.data("label-lead")] = 'area-spline';
var colors = {};
colors[$("#chart").data("label-lead")] = '#afb42b';
colors[$("#chart").data("label-cycle")] = '#4e342e';
colors[chart.data("label-lead")] = '#afb42b';
colors[chart.data("label-cycle")] = '#4e342e';
for (var i = 0; i < metrics.length; i++) {
cycle.push(parseInt(metrics[i].avg_cycle_time));

View File

@@ -1,48 +1,59 @@
function Markdown() {
}
Kanboard.Markdown = function(app) {
this.app = app;
this.editor = null;
};
Markdown.prototype.showPreview = function(e) {
e.preventDefault();
Kanboard.Markdown.prototype.onPopoverOpened = function() {
this.listen();
};
var write = $(".write-area");
var preview = $(".preview-area");
var textarea = $("textarea");
Kanboard.Markdown.prototype.onPopoverClosed = function() {
this.listen();
};
$("#markdown-write").parent().removeClass("form-tab-selected");
$("#markdown-preview").parent().addClass("form-tab-selected");
Kanboard.Markdown.prototype.listen = function() {
var editors = $(".markdown-editor");
var request = $.ajax({
url: $("body").data("markdown-preview-url"),
contentType: "application/json",
type: "POST",
processData: false,
dataType: "html",
data: JSON.stringify({
"text": textarea.val()
})
});
if (this.editor) {
this.destroy();
}
request.done(function(data) {
preview.find(".markdown").html(data)
preview.css("height", textarea.css("height"));
preview.css("width", textarea.css("width"));
if (editors.length > 0) {
this.show(editors[0]);
}
};
write.hide();
preview.show();
Kanboard.Markdown.prototype.destroy = function() {
var cm = this.editor.codemirror;
var wrapper = cm.getWrapperElement();
for (var item in ["toolbar", "statusbar", "sideBySide"]) {
if (this.editor.gui[item]) {
wrapper.parentNode.removeChild(this.editor.gui[item]);
}
}
cm.toTextArea();
this.editor = null;
};
Kanboard.Markdown.prototype.show = function(textarea) {
var toolbar = ["bold", "italic", "strikethrough", "heading", "|", "unordered-list", "ordered-list", "link", "|", "code", "table"];
this.editor = new SimpleMDE({
element: textarea,
status: false,
toolbarTips: false,
autoDownloadFontAwesome: false,
spellChecker: false,
autosave: {
enabled: false
},
forceSync: true,
blockStyles: {
italic: "_"
},
toolbar: textarea.hasAttribute("data-markdown-editor-disable-toolbar") ? false : toolbar,
placeholder: textarea.getAttribute("placeholder")
});
};
Markdown.prototype.showWriter = function(e) {
e.preventDefault();
$("#markdown-write").parent().addClass("form-tab-selected");
$("#markdown-preview").parent().removeClass("form-tab-selected");
$(".write-area").show();
$(".preview-area").hide();
};
Markdown.prototype.listen = function() {
$(document).on("click", "#markdown-preview", this.showPreview.bind(this));
$(document).on("click", "#markdown-write", this.showWriter.bind(this));
};

View File

@@ -0,0 +1,3 @@
'use strict';
var Kanboard = {};

View File

@@ -0,0 +1,9 @@
Kanboard.Notification = function(app) {
this.app = app;
};
Kanboard.Notification.prototype.execute = function() {
$(".alert-fade-out").delay(4000).fadeOut(800, function() {
$(this).remove();
});
};

View File

@@ -1,35 +1,28 @@
function Popover(app) {
Kanboard.Popover = function(app) {
this.app = app;
this.router = new Router();
this.router.addRoute('screenshot-zone', Screenshot);
}
Popover.prototype.isOpen = function() {
return $('#popover-container').size() > 0;
};
Popover.prototype.open = function(link) {
Kanboard.Popover.prototype.listen = function() {
var self = this;
self.app.dropdown.close();
$.get(link, function(content) {
$("body").prepend('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
self.afterOpen();
$(document).on("click", ".popover", function(e) {
self.onClick(e);
});
$(document).on("click", ".close-popover", function(e) {
self.close(e);
});
$(document).on("click", "#popover-container", function(e) {
self.close(e);
});
$(document).on("click", "#popover-content", function(e) {
e.stopPropagation();
});
};
Popover.prototype.close = function(e) {
if (this.isOpen()) {
if (e) {
e.preventDefault();
}
$('#popover-container').remove();
}
};
Popover.prototype.onClick = function(e) {
Kanboard.Popover.prototype.onClick = function(e) {
e.preventDefault();
e.stopPropagation();
@@ -45,20 +38,69 @@ Popover.prototype.onClick = function(e) {
}
};
Popover.prototype.listen = function() {
$(document).on("click", ".popover", this.onClick.bind(this));
$(document).on("click", ".close-popover", this.close.bind(this));
$(document).on("click", "#popover-container", this.close.bind(this));
$(document).on("click", "#popover-content", function(e) { e.stopPropagation(); });
Kanboard.Popover.prototype.isOpen = function() {
return $('#popover-container').size() > 0;
};
Popover.prototype.afterOpen = function() {
Kanboard.Popover.prototype.open = function(link) {
var self = this;
$.get(link, function(content) {
$("body").prepend('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
self.executeOnOpenedListeners();
});
};
Kanboard.Popover.prototype.close = function(e) {
if (this.isOpen()) {
if (e) {
e.preventDefault();
}
$("#popover-container").remove();
this.executeOnClosedListeners();
}
};
Kanboard.Popover.prototype.ajaxReload = 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.executeOnOpenedListeners();
}
};
Kanboard.Popover.prototype.executeOnOpenedListeners = function() {
for (var className in this.app.controllers) {
var controller = this.app.get(className);
if (typeof controller.onPopoverOpened === "function") {
controller.onPopoverOpened();
}
}
this.afterOpen();
};
Kanboard.Popover.prototype.executeOnClosedListeners = function() {
for (var className in this.app.controllers) {
var controller = this.app.get(className);
if (typeof controller.onPopoverClosed === "function") {
controller.onPopoverClosed();
}
}
};
Kanboard.Popover.prototype.afterOpen = function() {
var self = this;
var popoverForm = $("#popover-content .popover-form");
self.app.refresh();
self.router.dispatch(this.app);
// Submit forms with Ajax request
if (popoverForm) {
popoverForm.on("submit", function(e) {
@@ -69,7 +111,7 @@ Popover.prototype.afterOpen = function() {
url: popoverForm.attr("action"),
data: popoverForm.serialize(),
success: function(data, textStatus, request) {
self.afterSubmit(data, request, self);
self.ajaxReload(data, request, self);
},
beforeSend: function() {
var button = $('.popover-form button[type="submit"]');
@@ -88,21 +130,16 @@ Popover.prototype.afterOpen = function() {
type: "GET",
url: $(this).attr("href"),
success: function(data, textStatus, request) {
self.afterSubmit(data, request, self);
self.ajaxReload(data, request, self);
}
});
});
};
Popover.prototype.afterSubmit = function(data, request, self) {
var redirect = request.getResponseHeader("X-Ajax-Redirect");
// Autofocus fields (html5 autofocus works only with page onload)
$("[autofocus]").each(function() {
$(this).focus();
});
if (redirect) {
window.location = redirect === 'self' ? window.location.href.split("#")[0] : redirect;
}
else {
$("#popover-content").html(data);
$("#popover-content input[autofocus]").focus();
self.afterOpen();
}
this.app.datePicker();
this.app.autoComplete();
};

View File

@@ -1,28 +0,0 @@
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();
}
});
};

View File

@@ -0,0 +1,15 @@
Kanboard.ProjectCreation = function(app) {
this.app = app;
};
Kanboard.ProjectCreation.prototype.onPopoverOpened = 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();
}
});
};

View File

@@ -0,0 +1,19 @@
Kanboard.ProjectPermission = function(app) {
this.app = app;
};
Kanboard.ProjectPermission.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()
})
});
});
};

View File

@@ -1,37 +0,0 @@
function Router() {
this.routes = {};
}
Router.prototype.addRoute = function(id, controller) {
this.routes[id] = controller;
};
Router.prototype.dispatch = function(app) {
for (var id in this.routes) {
if (document.getElementById(id)) {
var controller = Object.create(this.routes[id].prototype);
this.routes[id].apply(controller, [app]);
controller.execute();
break;
}
}
};
jQuery(document).ready(function() {
var app = new App();
var router = new Router();
router.addRoute('board', Board);
router.addRoute('calendar', Calendar);
router.addRoute('screenshot-zone', Screenshot);
router.addRoute('analytic-task-repartition', TaskRepartitionChart);
router.addRoute('analytic-user-repartition', UserRepartitionChart);
router.addRoute('analytic-cfd', CumulativeFlowDiagram);
router.addRoute('analytic-burndown', BurndownChart);
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();
});

View File

@@ -1,13 +1,16 @@
function Screenshot() {
Kanboard.Screenshot = function(app) {
this.app = app;
this.pasteCatcher = null;
}
};
Screenshot.prototype.execute = function() {
this.initialize();
Kanboard.Screenshot.prototype.onPopoverOpened = function() {
if (this.app.hasId("screenshot-zone")) {
this.initialize();
}
};
// Setup event listener and workarounds
Screenshot.prototype.initialize = function() {
Kanboard.Screenshot.prototype.initialize = function() {
this.destroy();
if (! window.Clipboard) {
@@ -40,7 +43,7 @@ Screenshot.prototype.initialize = function() {
};
// Destroy contentEditable element
Screenshot.prototype.destroy = function() {
Kanboard.Screenshot.prototype.destroy = function() {
if (this.pasteCatcher != null) {
document.body.removeChild(this.pasteCatcher);
}
@@ -53,14 +56,14 @@ Screenshot.prototype.destroy = function() {
};
// Set focus on contentEditable element
Screenshot.prototype.setFocus = function() {
Kanboard.Screenshot.prototype.setFocus = function() {
if (this.pasteCatcher !== null) {
this.pasteCatcher.focus();
}
};
// Paste event callback
Screenshot.prototype.pasteHandler = function(e) {
Kanboard.Screenshot.prototype.pasteHandler = function(e) {
// Firefox doesn't have the property e.clipboardData.items (only Chrome)
if (e.clipboardData && e.clipboardData.items) {
@@ -95,7 +98,7 @@ Screenshot.prototype.pasteHandler = function(e) {
};
// Parse the input in the paste catcher element
Screenshot.prototype.checkInput = function() {
Kanboard.Screenshot.prototype.checkInput = function() {
var child = this.pasteCatcher.childNodes[0];
if (child) {
@@ -110,7 +113,7 @@ Screenshot.prototype.checkInput = function() {
};
// Creates a new image from a given source
Screenshot.prototype.createImage = function(blob) {
Kanboard.Screenshot.prototype.createImage = function(blob) {
var pastedImage = new Image();
pastedImage.src = blob;

View File

@@ -1,18 +1,21 @@
function Search(app) {
Kanboard.Search = function(app) {
this.app = app;
this.keyboardShortcuts();
}
};
Kanboard.Search.prototype.focus = function() {
Search.prototype.focus = function() {
// Place cursor at the end when focusing on the search box
$(document).on("focus", "#form-search", function() {
if ($("#form-search")[0].setSelectionRange) {
$('#form-search')[0].setSelectionRange($('#form-search').val().length, $('#form-search').val().length);
var input = $("#form-search");
if (input[0].setSelectionRange) {
var len = input.val().length * 2;
input[0].setSelectionRange(len, len);
}
});
};
Search.prototype.listen = function() {
Kanboard.Search.prototype.listen = function() {
var self = this;
// Filter helper for search
@@ -21,68 +24,51 @@ Search.prototype.listen = function() {
var filter = $(this).data("filter");
var appendFilter = $(this).data("append-filter");
var input = $("#form-search");
if (appendFilter) {
filter = $("#form-search").val() + " " + appendFilter;
filter = input.val() + " " + appendFilter;
}
$("#form-search").val(filter);
if ($('#board').length) {
self.app.board.reloadFilters(filter);
}
else {
$("form.search").submit();
}
input.val(filter);
$("form.search").submit();
});
};
Search.prototype.keyboardShortcuts = function() {
Kanboard.Search.prototype.goToView = function(label) {
var link = $(label);
if (link.length) {
window.location = link.attr('href');
}
};
Kanboard.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');
}
Mousetrap.bind("v o", function() {
self.goToView(".view-overview");
});
// Switch view mode for projects: go to the board
Mousetrap.bind("v b", function(e) {
var link = $(".view-board");
if (link.length) {
window.location = link.attr('href');
}
Mousetrap.bind("v b", function() {
self.goToView(".view-board");
});
// Switch view mode for projects: go to the calendar
Mousetrap.bind("v c", function(e) {
var link = $(".view-calendar");
if (link.length) {
window.location = link.attr('href');
}
Mousetrap.bind("v c", function() {
self.goToView(".view-calendar");
});
// Switch view mode for projects: go to the listing
Mousetrap.bind("v l", function(e) {
var link = $(".view-listing");
if (link.length) {
window.location = link.attr('href');
}
Mousetrap.bind("v l", function() {
self.goToView(".view-listing");
});
// Switch view mode for projects: go to the gantt chart
Mousetrap.bind("v g", function(e) {
var link = $(".view-gantt");
if (link.length) {
window.location = link.attr('href');
}
Mousetrap.bind("v g", function() {
self.goToView(".view-gantt");
});
// Focus to the search field
@@ -99,14 +85,9 @@ Search.prototype.keyboardShortcuts = function() {
Mousetrap.bind("r", function(e) {
e.preventDefault();
var reset = $(".filter-reset").data("filter");
var input = $("#form-search");
$("#form-search").val(reset);
if ($('#board').length) {
self.app.board.reloadFilters(reset);
}
else {
$("form.search").submit();
}
input.val(reset);
$("form.search").submit();
});
};

21
assets/js/src/Session.js Normal file
View File

@@ -0,0 +1,21 @@
Kanboard.Session = function(app) {
this.app = app;
};
Kanboard.Session.prototype.execute = function() {
window.setInterval(this.checkSession, 60000);
};
Kanboard.Session.prototype.checkSession = function() {
if (! $(".form-login").length) {
$.ajax({
cache: false,
url: $("body").data("status-url"),
statusCode: {
401: function() {
window.location = $("body").data("login-url");
}
}
});
}
};

View File

@@ -1,15 +1,14 @@
function Subtask(app) {
Kanboard.Subtask = function(app) {
this.app = app;
}
};
Subtask.prototype.listen = function() {
Kanboard.Subtask.prototype.listen = function() {
var self = this;
this.dragAndDrop();
$(document).on("click", ".subtask-toggle-status", function(e) {
e.preventDefault();
var el = $(this);
e.preventDefault();
$.ajax({
cache: false,
@@ -27,8 +26,8 @@ Subtask.prototype.listen = function() {
});
$(document).on("click", ".subtask-toggle-timer", function(e) {
e.preventDefault();
var el = $(this);
e.preventDefault();
$.ajax({
cache: false,
@@ -41,7 +40,7 @@ Subtask.prototype.listen = function() {
});
};
Subtask.prototype.dragAndDrop = function() {
Kanboard.Subtask.prototype.dragAndDrop = function() {
var self = this;
$(".draggable-row-handle").mouseenter(function() {
@@ -71,7 +70,7 @@ Subtask.prototype.dragAndDrop = function() {
}).disableSelection();
};
Subtask.prototype.savePosition = function(subtaskId, position) {
Kanboard.Subtask.prototype.savePosition = function(subtaskId, position) {
var url = $(".subtasks-table").data("save-position-url");
var self = this;

View File

@@ -1,60 +1,15 @@
function Swimlane(app) {
Kanboard.Swimlane = function(app) {
this.app = app;
}
Swimlane.prototype.getStorageKey = function() {
return "hidden_swimlanes_" + $("#board").data("project-id");
};
Swimlane.prototype.expand = function(swimlaneId) {
var swimlaneIds = this.getAllCollapsed();
var index = swimlaneIds.indexOf(swimlaneId);
if (index > -1) {
swimlaneIds.splice(index, 1);
}
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
$('.board-swimlane-columns-' + swimlaneId).css('display', 'table-row');
$('.board-swimlane-tasks-' + swimlaneId).css('display', 'table-row');
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'inline');
$('.show-icon-swimlane-' + swimlaneId).css('display', 'none');
};
Swimlane.prototype.collapse = function(swimlaneId) {
var swimlaneIds = this.getAllCollapsed();
if (swimlaneIds.indexOf(swimlaneId) < 0) {
swimlaneIds.push(swimlaneId);
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
}
$('.board-swimlane-columns-' + swimlaneId + ':not(:first-child)').css('display', 'none');
$('.board-swimlane-tasks-' + swimlaneId).css('display', 'none');
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'none');
$('.show-icon-swimlane-' + swimlaneId).css('display', 'inline');
};
Swimlane.prototype.isCollapsed = function(swimlaneId) {
return this.getAllCollapsed().indexOf(swimlaneId) > -1;
};
Swimlane.prototype.getAllCollapsed = function() {
return JSON.parse(localStorage.getItem(this.getStorageKey())) || [];
};
Swimlane.prototype.refresh = function() {
var swimlaneIds = this.getAllCollapsed();
for (var i = 0; i < swimlaneIds.length; i++) {
this.collapse(swimlaneIds[i]);
Kanboard.Swimlane.prototype.execute = function() {
if ($(".swimlanes-table").length) {
this.dragAndDrop();
}
};
Swimlane.prototype.listen = function() {
Kanboard.Swimlane.prototype.listen = function() {
var self = this;
self.dragAndDrop();
$(document).on('click', ".board-swimlane-toggle", function(e) {
e.preventDefault();
@@ -70,7 +25,57 @@ Swimlane.prototype.listen = function() {
});
};
Swimlane.prototype.dragAndDrop = function() {
Kanboard.Swimlane.prototype.onBoardRendered = function() {
var swimlaneIds = this.getAllCollapsed();
for (var i = 0; i < swimlaneIds.length; i++) {
this.collapse(swimlaneIds[i]);
}
};
Kanboard.Swimlane.prototype.getStorageKey = function() {
return "hidden_swimlanes_" + $("#board").data("project-id");
};
Kanboard.Swimlane.prototype.expand = function(swimlaneId) {
var swimlaneIds = this.getAllCollapsed();
var index = swimlaneIds.indexOf(swimlaneId);
if (index > -1) {
swimlaneIds.splice(index, 1);
}
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
$('.board-swimlane-columns-' + swimlaneId).css('display', 'table-row');
$('.board-swimlane-tasks-' + swimlaneId).css('display', 'table-row');
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'inline');
$('.show-icon-swimlane-' + swimlaneId).css('display', 'none');
};
Kanboard.Swimlane.prototype.collapse = function(swimlaneId) {
var swimlaneIds = this.getAllCollapsed();
if (swimlaneIds.indexOf(swimlaneId) < 0) {
swimlaneIds.push(swimlaneId);
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
}
$('.board-swimlane-columns-' + swimlaneId + ':not(:first-child)').css('display', 'none');
$('.board-swimlane-tasks-' + swimlaneId).css('display', 'none');
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'none');
$('.show-icon-swimlane-' + swimlaneId).css('display', 'inline');
};
Kanboard.Swimlane.prototype.isCollapsed = function(swimlaneId) {
return this.getAllCollapsed().indexOf(swimlaneId) > -1;
};
Kanboard.Swimlane.prototype.getAllCollapsed = function() {
return JSON.parse(localStorage.getItem(this.getStorageKey())) || [];
};
Kanboard.Swimlane.prototype.dragAndDrop = function() {
var self = this;
$(".draggable-row-handle").mouseenter(function() {
@@ -100,7 +105,7 @@ Swimlane.prototype.dragAndDrop = function() {
}).disableSelection();
};
Swimlane.prototype.savePosition = function(swimlaneId, position) {
Kanboard.Swimlane.prototype.savePosition = function(swimlaneId, position) {
var url = $(".swimlanes-table").data("save-position-url");
var self = this;

View File

@@ -1,31 +1,31 @@
function Task(app) {
Kanboard.Task = function(app) {
this.app = app;
}
};
Task.prototype.keyboardShortcuts = function() {
Kanboard.Task.prototype.keyboardShortcuts = function() {
var taskView = $("#task-view");
var self = this;
if (taskView.length) {
if (this.app.hasId("task-view")) {
Mousetrap.bind("e", function() {
self.app.popover.open(taskView.data("edit-url"));
self.app.get("Popover").open(taskView.data("edit-url"));
});
Mousetrap.bind("c", function() {
self.app.popover.open(taskView.data("comment-url"));
self.app.get("Popover").open(taskView.data("comment-url"));
});
Mousetrap.bind("s", function() {
self.app.popover.open(taskView.data("subtask-url"));
self.app.get("Popover").open(taskView.data("subtask-url"));
});
Mousetrap.bind("l", function() {
self.app.popover.open(taskView.data("internal-link-url"));
self.app.get("Popover").open(taskView.data("internal-link-url"));
});
}
};
Task.prototype.listen = function() {
Kanboard.Task.prototype.onPopoverOpened = function() {
var self = this;
var reloadingProjectId = 0;
@@ -38,11 +38,11 @@ Task.prototype.listen = function() {
// Assign to me
$(document).on("click", ".assign-me", function(e) {
e.preventDefault();
var currentId = $(this).data("current-id");
var dropdownId = "#" + $(this).data("target-id");
e.preventDefault();
if ($(dropdownId + ' option[value=' + currentId + ']').length) {
$(dropdownId).val(currentId);
}
@@ -65,8 +65,7 @@ Task.prototype.listen = function() {
success: function(data, textStatus, request) {
reloadingProjectId = 0;
$(".loading-icon").hide();
self.app.popover.afterSubmit(data, request, self.app.popover);
self.app.get("Popover").ajaxReload(data, request, self.app.get("Popover"));
}
});
}

View File

@@ -1,7 +1,14 @@
function TaskRepartitionChart() {
}
Kanboard.TaskRepartitionChart = function(app) {
this.app = app;
};
TaskRepartitionChart.prototype.execute = function() {
Kanboard.TaskRepartitionChart.prototype.execute = function() {
if (this.app.hasId("analytic-task-repartition")) {
this.show();
}
};
Kanboard.TaskRepartitionChart.prototype.show = function() {
var metrics = $("#chart").data("metrics");
var columns = [];

View File

@@ -1,10 +1,17 @@
function TaskTimeColumnChart(app) {
Kanboard.TaskTimeColumnChart = function(app) {
this.app = app;
}
};
TaskTimeColumnChart.prototype.execute = function() {
var metrics = $("#chart").data("metrics");
var plots = [$("#chart").data("label")];
Kanboard.TaskTimeColumnChart.prototype.execute = function() {
if (this.app.hasId("analytic-task-time-column")) {
this.show();
}
};
Kanboard.TaskTimeColumnChart.prototype.show = function() {
var chart = $("#chart");
var metrics = chart.data("metrics");
var plots = [chart.data("label")];
var categories = [];
for (var i = 0; i < metrics.length; i++) {

View File

@@ -1,10 +1,8 @@
function Tooltip(app) {
Kanboard.Tooltip = function(app) {
this.app = app;
}
Tooltip.prototype.listen = function() {
var self = this;
};
Kanboard.Tooltip.prototype.execute = function() {
$(".tooltip").tooltip({
track: false,
show: false,

View File

@@ -1,7 +1,14 @@
function UserRepartitionChart() {
}
Kanboard.UserRepartitionChart = function(app) {
this.app = app;
};
UserRepartitionChart.prototype.execute = function() {
Kanboard.UserRepartitionChart.prototype.execute = function() {
if (this.app.hasId("analytic-user-repartition")) {
this.show();
}
};
Kanboard.UserRepartitionChart.prototype.show = function() {
var metrics = $("#chart").data("metrics");
var columns = [];

4
assets/js/src/bootstrap.js vendored Normal file
View File

@@ -0,0 +1,4 @@
jQuery(document).ready(function() {
var app = new Kanboard.App();
app.execute();
});