Javascript refactoring
This commit is contained in:
parent
f04ec0700c
commit
e13872fc2e
|
|
@ -167,8 +167,10 @@ class ProjectAnalytic extends Base
|
|||
$sums[$task['column_id']] += ($task['date_completed'] ?: time()) - $task['date_moved'];
|
||||
|
||||
foreach ($sums as $column_id => $time_spent) {
|
||||
$stats[$column_id]['count']++;
|
||||
$stats[$column_id]['time_spent'] += $time_spent;
|
||||
if (isset($stats[$column_id])) {
|
||||
$stats[$column_id]['count']++;
|
||||
$stats[$column_id]['time_spent'] += $time_spent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<th class="board-column-header">
|
||||
<?php if (! $not_editable): ?>
|
||||
<div class="board-add-icon">
|
||||
<?= $this->url->link('+', 'taskcreation', 'create', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'task-board-popover', t('Add a new task')) ?>
|
||||
<?= $this->url->link('+', 'taskcreation', 'create', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover', t('Add a new task')) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
'changeCategory',
|
||||
array('task_id' => $task['id'], 'project_id' => $task['project_id']),
|
||||
false,
|
||||
'task-board-popover' . (! empty($task['category_description']) ? ' tooltip' : ''),
|
||||
'popover' . (! empty($task['category_description']) ? ' tooltip' : ''),
|
||||
! empty($task['category_description']) ? $this->text->markdown($task['category_description']) : t('Change category')
|
||||
) ?>
|
||||
<?php endif ?>
|
||||
|
|
@ -27,31 +27,31 @@
|
|||
<?php endif ?>
|
||||
|
||||
<?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PENDING): ?>
|
||||
<span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
|
||||
<span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90"></i></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($task['recurrence_status'] == \Model\Task::RECURRING_STATUS_PROCESSED): ?>
|
||||
<span title="<?= t('Recurrence') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
|
||||
<span title="<?= t('Recurrence') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-refresh fa-rotate-90 fa-inverse"></i></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_links'])): ?>
|
||||
<span title="<?= t('Links') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i> <?= $task['nb_links'] ?></span>
|
||||
<span title="<?= t('Links') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i> <?= $task['nb_links'] ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_subtasks'])): ?>
|
||||
<span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i> <?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
|
||||
<span title="<?= t('Sub-Tasks') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i> <?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_files'])): ?>
|
||||
<span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i> <?= $task['nb_files'] ?></span>
|
||||
<span title="<?= t('Attachments') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i> <?= $task['nb_files'] ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['nb_comments'])): ?>
|
||||
<span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i> <?= $task['nb_comments'] ?></span>
|
||||
<span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="tooltip" data-href="<?= $this->url->href('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i> <?= $task['nb_comments'] ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (! empty($task['description'])): ?>
|
||||
<span title="<?= t('Description') ?>" class="task-board-tooltip" data-href="<?= $this->url->href('board', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
|
||||
<span title="<?= t('Description') ?>" class="tooltip" data-href="<?= $this->url->href('board', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
|
||||
<i class="fa fa-file-text-o"></i>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
<span>
|
||||
<a href="#" class="dropdown-menu"><?= '#'.$task['id'] ?></a>
|
||||
<ul>
|
||||
<li><i class="fa fa-user"></i> <?= $this->url->link(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-tag"></i> <?= $this->url->link(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-align-left"></i> <?= $this->url->link(t('Change description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-pencil-square-o"></i> <?= $this->url->link(t('Edit this task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-comment-o"></i> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-code-fork"></i> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-camera"></i> <?= $this->url->link(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-close"></i> <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
|
||||
<li><i class="fa fa-user"></i> <?= $this->url->link(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-tag"></i> <?= $this->url->link(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-align-left"></i> <?= $this->url->link(t('Change description'), 'taskmodification', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-pencil-square-o"></i> <?= $this->url->link(t('Edit this task'), 'taskmodification', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-comment-o"></i> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-code-fork"></i> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-camera"></i> <?= $this->url->link(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?></li>
|
||||
<li><i class="fa fa-close"></i> <?= $this->url->link(t('Close this task'), 'taskstatus', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'popover') ?></li>
|
||||
</ul>
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
'changeAssignee',
|
||||
array('task_id' => $task['id'], 'project_id' => $task['project_id']),
|
||||
false,
|
||||
'task-board-popover',
|
||||
'popover',
|
||||
t('Change assignee')
|
||||
) ?>
|
||||
</span>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,196 @@
|
|||
function App() {
|
||||
this.popover = new Popover(this);
|
||||
this.markdown = new Markdown();
|
||||
this.sidebar = new Sidebar();
|
||||
this.search = new Search();
|
||||
this.tooltip = new Tooltip(this);
|
||||
this.swimlane = new Swimlane();
|
||||
this.keyboardShortcuts();
|
||||
this.boardSelector();
|
||||
this.listen();
|
||||
this.poll();
|
||||
|
||||
// Alert box fadeout
|
||||
$(".alert-fade-out").delay(4000).fadeOut(800, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
// Reload page when a destination project is changed
|
||||
var reloading_project = false;
|
||||
$("select.task-reload-project-destination").change(function() {
|
||||
if (! reloading_project) {
|
||||
$(".loading-icon").show();
|
||||
reloading_project = true;
|
||||
window.location = $(this).data("redirect").replace(/PROJECT_ID/g, $(this).val());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
App.prototype.listen = function() {
|
||||
$(document).off();
|
||||
|
||||
this.popover.listen();
|
||||
this.markdown.listen();
|
||||
this.sidebar.listen();
|
||||
this.tooltip.listen();
|
||||
this.search.listen();
|
||||
this.search.focus();
|
||||
this.taskAutoComplete();
|
||||
this.datePicker();
|
||||
this.focus();
|
||||
|
||||
// Dropdown
|
||||
$(".dropit-submenu").hide();
|
||||
$('.dropdown').not(".dropit").dropit({ triggerParentEl : "span" });
|
||||
};
|
||||
|
||||
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() {
|
||||
// Submit form
|
||||
Mousetrap.bindGlobal("mod+enter", function() {
|
||||
$("form").submit();
|
||||
});
|
||||
|
||||
// Open board selector
|
||||
Mousetrap.bind("b", function(e) {
|
||||
e.preventDefault();
|
||||
$('#board-selector').trigger('chosen:open');
|
||||
});
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
App.prototype.datePicker = function() {
|
||||
// Datepicker translation
|
||||
$.datepicker.setDefaults($.datepicker.regional[$("body").data("js-lang")]);
|
||||
|
||||
// Datepicker
|
||||
$(".form-date").datepicker({
|
||||
showOtherMonths: true,
|
||||
selectOtherMonths: true,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
constrainInput: false
|
||||
});
|
||||
|
||||
// Datetime picker
|
||||
$(".form-datetime").datetimepicker({
|
||||
controlType: 'select',
|
||||
oneLine: true,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
// timeFormat: 'h:mm tt',
|
||||
constrainInput: false
|
||||
});
|
||||
};
|
||||
|
||||
App.prototype.taskAutoComplete = function() {
|
||||
// Task auto-completion
|
||||
if ($(".task-autocomplete").length) {
|
||||
|
||||
if ($('.opposite_task_id').val() == '') {
|
||||
$(".task-autocomplete").parent().find("input[type=submit]").attr('disabled','disabled');
|
||||
}
|
||||
|
||||
$(".task-autocomplete").autocomplete({
|
||||
source: $(".task-autocomplete").data("search-url"),
|
||||
minLength: 1,
|
||||
select: function(event, ui) {
|
||||
var field = $(".task-autocomplete").data("dst-field");
|
||||
$("input[name=" + field + "]").val(ui.item.id);
|
||||
|
||||
$(".task-autocomplete").parent().find("input[type=submit]").removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
App.prototype.boardSelector = function() {
|
||||
$(".chosen-select").chosen({
|
||||
width: "200px",
|
||||
no_results_text: $(".chosen-select").data("notfound"),
|
||||
disable_search_threshold: 10
|
||||
});
|
||||
|
||||
$("#board-selector").chosen({
|
||||
width: 180,
|
||||
no_results_text: $("#board-selector").data("notfound")
|
||||
});
|
||||
|
||||
$("#board-selector").change(function() {
|
||||
window.location = $(this).attr("data-board-url").replace(/PROJECT_ID/g, $(this).val());
|
||||
});
|
||||
};
|
||||
|
||||
App.prototype.showLoadingIcon = function() {
|
||||
$("body").append('<span id="app-loading-icon"> <i class="fa fa-spinner fa-spin"></i></span>');
|
||||
};
|
||||
|
||||
App.prototype.hideLoadingIcon = function() {
|
||||
$("#app-loading-icon").remove();
|
||||
};
|
||||
|
||||
App.prototype.isVisible = function() {
|
||||
var property = "";
|
||||
|
||||
if (typeof document.hidden !== "undefined") {
|
||||
property = "visibilityState";
|
||||
} else if (typeof document.mozHidden !== "undefined") {
|
||||
property = "mozVisibilityState";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
property = "msVisibilityState";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
property = "webkitVisibilityState";
|
||||
}
|
||||
|
||||
if (property != "") {
|
||||
return document[property] == "visible";
|
||||
}
|
||||
|
||||
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";
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
function AvgTimeColumnChart() {
|
||||
}
|
||||
|
||||
AvgTimeColumnChart.prototype.execute = function(app) {
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var plots = [$("#chart").data("label")];
|
||||
var categories = [];
|
||||
|
||||
for (var column_id in metrics) {
|
||||
plots.push(metrics[column_id].average);
|
||||
categories.push(metrics[column_id].title);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [plots],
|
||||
type: 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.5
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: app.formatDuration
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
function BudgetChart() {
|
||||
}
|
||||
|
||||
BudgetChart.prototype.execute = function() {
|
||||
var categories = [];
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var labels = $("#chart").data("labels");
|
||||
var inputFormat = d3.time.format("%Y-%m-%d");
|
||||
var outputFormat = d3.time.format($("#chart").data("date-format"));
|
||||
|
||||
var columns = [
|
||||
[labels["in"]],
|
||||
[labels["left"]],
|
||||
[labels["out"]]
|
||||
];
|
||||
|
||||
var colors = {};
|
||||
colors[labels["in"]] = '#5858FA';
|
||||
colors[labels["left"]] = '#04B404';
|
||||
colors[labels["out"]] = '#DF3A01';
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i]["date"])));
|
||||
columns[0].push(metrics[i]["in"]);
|
||||
columns[1].push(metrics[i]["left"]);
|
||||
columns[2].push(metrics[i]["out"]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
colors: colors,
|
||||
type : 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.25
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
x: {
|
||||
show: true
|
||||
},
|
||||
y: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
function BurndownChart() {
|
||||
}
|
||||
|
||||
BurndownChart.prototype.execute = function() {
|
||||
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"));
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
|
||||
for (var j = 0; j < metrics[i].length; j++) {
|
||||
|
||||
if (i == 0) {
|
||||
columns.push([metrics[i][j]]);
|
||||
}
|
||||
else {
|
||||
columns[j + 1].push(metrics[i][j]);
|
||||
|
||||
if (j > 0) {
|
||||
|
||||
if (columns[0][i] == undefined) {
|
||||
columns[0].push(0);
|
||||
}
|
||||
|
||||
columns[0][i] += metrics[i][j];
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
function CumulativeFlowDiagram() {
|
||||
}
|
||||
|
||||
CumulativeFlowDiagram.prototype.execute = function() {
|
||||
|
||||
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"));
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
|
||||
for (var j = 0; j < metrics[i].length; j++) {
|
||||
|
||||
if (i == 0) {
|
||||
columns.push([metrics[i][j]]);
|
||||
|
||||
if (j > 0) {
|
||||
groups.push(metrics[i][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
columns[j].push(metrics[i][j]);
|
||||
|
||||
if (j == 0) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type: 'area-spline',
|
||||
groups: [groups]
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
function LeadCycleTimeChart() {
|
||||
}
|
||||
|
||||
LeadCycleTimeChart.prototype.execute = function(app) {
|
||||
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';
|
||||
|
||||
var colors = {};
|
||||
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));
|
||||
lead.push(parseInt(metrics[i].avg_lead_time));
|
||||
categories.push(metrics[i].day);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [
|
||||
lead,
|
||||
cycle
|
||||
],
|
||||
types: types,
|
||||
colors: colors
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: app.formatDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
function Markdown() {
|
||||
}
|
||||
|
||||
Markdown.prototype.showPreview = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var link = $(this);
|
||||
var nav = $(this).closest("ul");
|
||||
var write = $(".write-area");
|
||||
var preview = $(".preview-area");
|
||||
var textarea = $("textarea");
|
||||
|
||||
var request = $.ajax({
|
||||
url: "?controller=app&action=preview", // TODO: remoe harcoded url
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
processData: false,
|
||||
dataType: "html",
|
||||
data: JSON.stringify({
|
||||
"text": textarea.val()
|
||||
})
|
||||
});
|
||||
|
||||
request.done(function(data) {
|
||||
nav.find("li").removeClass("form-tab-selected");
|
||||
link.parent().addClass("form-tab-selected");
|
||||
|
||||
preview.find(".markdown").html(data)
|
||||
preview.css("height", textarea.css("height"));
|
||||
preview.css("width", textarea.css("width"));
|
||||
|
||||
write.hide();
|
||||
preview.show();
|
||||
});
|
||||
};
|
||||
|
||||
Markdown.prototype.showWriter = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$(this).closest("ul").find("li").removeClass("form-tab-selected")
|
||||
$(this).parent().addClass("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));
|
||||
};
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
function Popover(app) {
|
||||
this.app = app;
|
||||
this.router = new Router();
|
||||
this.router.addRoute('screenshot-zone', Screenshot);
|
||||
Mousetrap.bindGlobal("esc", this.close);
|
||||
}
|
||||
|
||||
Popover.prototype.isOpen = function() {
|
||||
return $('#popover-container').size() > 0;
|
||||
};
|
||||
|
||||
Popover.prototype.open = function(link) {
|
||||
var self = this;
|
||||
|
||||
$.get(link, function(content) {
|
||||
$("body").append('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
|
||||
self.router.dispatch();
|
||||
self.app.listen();
|
||||
});
|
||||
};
|
||||
|
||||
Popover.prototype.close = function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
$('#popover-container').remove();
|
||||
};
|
||||
|
||||
Popover.prototype.onClick = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var link = e.target.getAttribute("href");
|
||||
|
||||
if (! link) {
|
||||
link = e.target.getAttribute("data-href");
|
||||
}
|
||||
|
||||
if (link) {
|
||||
this.open(link);
|
||||
}
|
||||
};
|
||||
|
||||
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(); });
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
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);
|
||||
controller.execute(app);
|
||||
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('budget-chart', BudgetChart);
|
||||
router.addRoute('analytic-avg-time-column', AvgTimeColumnChart);
|
||||
router.addRoute('analytic-task-time-column', TaskTimeColumnChart);
|
||||
router.addRoute('analytic-lead-cycle-time', LeadCycleTimeChart);
|
||||
router.dispatch(app);
|
||||
});
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
function Search() {
|
||||
this.keyboardShortcuts();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Search.prototype.listen = function() {
|
||||
// Filter helper for search
|
||||
$(document).on("click", ".filter-helper", function (e) {
|
||||
e.preventDefault();
|
||||
$("#form-search").val($(this).data("filter"));
|
||||
$("form.search").submit();
|
||||
});
|
||||
};
|
||||
|
||||
Search.prototype.keyboardShortcuts = function() {
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// Focus to the search field
|
||||
Mousetrap.bind("f", function(e) {
|
||||
e.preventDefault();
|
||||
var input = document.getElementById("form-search");
|
||||
|
||||
if (input) {
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
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);
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
function TaskRepartitionChart() {
|
||||
}
|
||||
|
||||
TaskRepartitionChart.prototype.execute = function() {
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
columns.push([metrics[i].column_title, metrics[i].nb_tasks]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
function TaskTimeColumnChart() {
|
||||
}
|
||||
|
||||
TaskTimeColumnChart.prototype.execute = function(app) {
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var plots = [$("#chart").data("label")];
|
||||
var categories = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
plots.push(metrics[i].time_spent);
|
||||
categories.push(metrics[i].title);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [plots],
|
||||
type: 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.5
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: app.formatDuration
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
function Tooltip(app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
Tooltip.prototype.listen = function() {
|
||||
var self = this;
|
||||
|
||||
$(".tooltip").tooltip({
|
||||
track: false,
|
||||
show: false,
|
||||
position: {
|
||||
my: 'left-20 top',
|
||||
at: 'center bottom+9',
|
||||
using: function(position, feedback) {
|
||||
|
||||
$(this).css(position);
|
||||
|
||||
var arrow_pos = feedback.target.left + feedback.target.width / 2 - feedback.element.left - 20;
|
||||
|
||||
$("<div>")
|
||||
.addClass("tooltip-arrow")
|
||||
.addClass(feedback.vertical)
|
||||
.addClass(arrow_pos < 1 ? "align-left" : "align-right")
|
||||
.appendTo(this);
|
||||
}
|
||||
},
|
||||
content: function() {
|
||||
var _this = this;
|
||||
var href = $(this).attr('data-href');
|
||||
|
||||
if (! href) {
|
||||
return '<div class="markdown">' + $(this).attr("title") + '</div>';
|
||||
}
|
||||
|
||||
$.get(href, function setTooltipContent(data) {
|
||||
var tooltip = $('.ui-tooltip:visible');
|
||||
|
||||
$('.ui-tooltip-content:visible').html(data);
|
||||
|
||||
// Clear previous position, it interferes with the updated position computation
|
||||
tooltip.css({ top: '', left: '' });
|
||||
|
||||
// Remove arrow, it will be added when repositionning
|
||||
tooltip.children('.tooltip-arrow').remove();
|
||||
|
||||
// Reposition the tooltip
|
||||
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>';
|
||||
}
|
||||
})
|
||||
.on("mouseenter", function() {
|
||||
var _this = this;
|
||||
$(this).tooltip("open");
|
||||
|
||||
$(".ui-tooltip").on("mouseleave", function() {
|
||||
$(_this).tooltip('close');
|
||||
});
|
||||
}).on("mouseleave focusout", function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
var _this = this;
|
||||
|
||||
setTimeout(function() {
|
||||
if (! $(".ui-tooltip:hover").length) {
|
||||
$(_this).tooltip("close");
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
function UserRepartitionChart() {
|
||||
}
|
||||
|
||||
UserRepartitionChart.prototype.execute = function() {
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
columns.push([metrics[i].user, metrics[i].nb_tasks]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -1,355 +0,0 @@
|
|||
(function() {
|
||||
|
||||
// CFD diagram
|
||||
function drawCfd()
|
||||
{
|
||||
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"));
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
|
||||
for (var j = 0; j < metrics[i].length; j++) {
|
||||
|
||||
if (i == 0) {
|
||||
columns.push([metrics[i][j]]);
|
||||
|
||||
if (j > 0) {
|
||||
groups.push(metrics[i][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
columns[j].push(metrics[i][j]);
|
||||
|
||||
if (j == 0) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type: 'area-spline',
|
||||
groups: [groups]
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Burndown chart
|
||||
function drawBurndown()
|
||||
{
|
||||
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"));
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
|
||||
for (var j = 0; j < metrics[i].length; j++) {
|
||||
|
||||
if (i == 0) {
|
||||
columns.push([metrics[i][j]]);
|
||||
}
|
||||
else {
|
||||
columns[j + 1].push(metrics[i][j]);
|
||||
|
||||
if (j > 0) {
|
||||
|
||||
if (columns[0][i] == undefined) {
|
||||
columns[0].push(0);
|
||||
}
|
||||
|
||||
columns[0][i] += metrics[i][j];
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw task repartition chart
|
||||
function drawTaskRepartition()
|
||||
{
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
columns.push([metrics[i].column_title, metrics[i].nb_tasks]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw user repartition chart
|
||||
function drawUserRepartition()
|
||||
{
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
columns.push([metrics[i].user, metrics[i].nb_tasks]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw budget chart
|
||||
function drawBudget()
|
||||
{
|
||||
var categories = [];
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var labels = $("#chart").data("labels");
|
||||
var inputFormat = d3.time.format("%Y-%m-%d");
|
||||
var outputFormat = d3.time.format($("#chart").data("date-format"));
|
||||
|
||||
var columns = [
|
||||
[labels["in"]],
|
||||
[labels["left"]],
|
||||
[labels["out"]]
|
||||
];
|
||||
|
||||
var colors = {};
|
||||
colors[labels["in"]] = '#5858FA';
|
||||
colors[labels["left"]] = '#04B404';
|
||||
colors[labels["out"]] = '#DF3A01';
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
categories.push(outputFormat(inputFormat.parse(metrics[i]["date"])));
|
||||
columns[0].push(metrics[i]["in"]);
|
||||
columns[1].push(metrics[i]["left"]);
|
||||
columns[2].push(metrics[i]["out"]);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
colors: colors,
|
||||
type : 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.25
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
x: {
|
||||
show: true
|
||||
},
|
||||
y: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw chart for average time spent into each column
|
||||
function drawAvgTimeColumn()
|
||||
{
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var plots = [$("#chart").data("label")];
|
||||
var categories = [];
|
||||
|
||||
for (var column_id in metrics) {
|
||||
plots.push(metrics[column_id].average);
|
||||
categories.push(metrics[column_id].title);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [plots],
|
||||
type: 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.5
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: formatDuration
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw chart for average time spent into each column
|
||||
function drawTaskTimeColumn()
|
||||
{
|
||||
var metrics = $("#chart").data("metrics");
|
||||
var plots = [$("#chart").data("label")];
|
||||
var categories = [];
|
||||
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
plots.push(metrics[i].time_spent);
|
||||
categories.push(metrics[i].title);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [plots],
|
||||
type: 'bar'
|
||||
},
|
||||
bar: {
|
||||
width: {
|
||||
ratio: 0.5
|
||||
}
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: formatDuration
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Draw lead and cycle time for the project
|
||||
function drawLeadAndCycleTime()
|
||||
{
|
||||
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';
|
||||
|
||||
var colors = {};
|
||||
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));
|
||||
lead.push(parseInt(metrics[i].avg_lead_time));
|
||||
categories.push(metrics[i].day);
|
||||
}
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [
|
||||
lead,
|
||||
cycle
|
||||
],
|
||||
types: types,
|
||||
colors: colors
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
type: 'category',
|
||||
categories: categories
|
||||
},
|
||||
y: {
|
||||
tick: {
|
||||
format: formatDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function formatDuration(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";
|
||||
}
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
|
||||
if (Kanboard.Exists("analytic-task-repartition")) {
|
||||
drawTaskRepartition();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-user-repartition")) {
|
||||
drawUserRepartition();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-cfd")) {
|
||||
drawCfd();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-burndown")) {
|
||||
drawBurndown();
|
||||
}
|
||||
else if (Kanboard.Exists("budget-chart")) {
|
||||
drawBudget();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-avg-time-column")) {
|
||||
drawAvgTimeColumn();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-task-time-column")) {
|
||||
drawTaskTimeColumn();
|
||||
}
|
||||
else if (Kanboard.Exists("analytic-lead-cycle-time")) {
|
||||
drawLeadAndCycleTime();
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
@ -1,394 +0,0 @@
|
|||
var Kanboard = (function() {
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
Kanboard.Init();
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
ShowLoadingIcon: function() {
|
||||
$("body").append('<span id="app-loading-icon"> <i class="fa fa-spinner fa-spin"></i></span>');
|
||||
},
|
||||
|
||||
HideLoadingIcon: function() {
|
||||
$("#app-loading-icon").remove();
|
||||
},
|
||||
|
||||
// Return true if the element#id exists
|
||||
Exists: function(id) {
|
||||
if (document.getElementById(id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Open a popup on a link click
|
||||
Popover: function(e, callback) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var link = e.target.getAttribute("href");
|
||||
|
||||
if (! link) {
|
||||
link = e.target.getAttribute("data-href");
|
||||
}
|
||||
|
||||
if (link) {
|
||||
Kanboard.OpenPopover(link, callback);
|
||||
}
|
||||
},
|
||||
|
||||
// Display a popup
|
||||
OpenPopover: function(link, callback) {
|
||||
|
||||
$.get(link, function(content) {
|
||||
|
||||
$("body").append('<div id="popover-container"><div id="popover-content">' + content + '</div></div>');
|
||||
|
||||
$("#popover-container").click(function() {
|
||||
Kanboard.ClosePopover();
|
||||
});
|
||||
|
||||
$("#popover-content").click(function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(".close-popover").click(function(e) {
|
||||
e.preventDefault();
|
||||
Kanboard.ClosePopover();
|
||||
});
|
||||
|
||||
Mousetrap.bindGlobal("esc", function() {
|
||||
Kanboard.ClosePopover();
|
||||
});
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
ClosePopover: function() {
|
||||
$('#popover-container').remove();
|
||||
Kanboard.Screenshot.Destroy();
|
||||
},
|
||||
|
||||
// Return true if the page is visible
|
||||
IsVisible: function() {
|
||||
|
||||
var property = "";
|
||||
|
||||
if (typeof document.hidden !== "undefined") {
|
||||
property = "visibilityState";
|
||||
} else if (typeof document.mozHidden !== "undefined") {
|
||||
property = "mozVisibilityState";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
property = "msVisibilityState";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
property = "webkitVisibilityState";
|
||||
}
|
||||
|
||||
if (property != "") {
|
||||
return document[property] == "visible";
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// Save preferences in local storage
|
||||
SetStorageItem: function(key, value) {
|
||||
if (typeof(Storage) !== "undefined") {
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
},
|
||||
|
||||
GetStorageItem: function(key) {
|
||||
|
||||
if (typeof(Storage) !== "undefined") {
|
||||
return localStorage.getItem(key);
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
// Generate Markdown preview
|
||||
MarkdownPreview: function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
var link = $(this);
|
||||
var nav = $(this).closest("ul");
|
||||
var write = $(".write-area");
|
||||
var preview = $(".preview-area");
|
||||
var textarea = $("textarea");
|
||||
|
||||
var request = $.ajax({
|
||||
url: "?controller=app&action=preview",
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
processData: false,
|
||||
dataType: "html",
|
||||
data: JSON.stringify({
|
||||
"text": textarea.val()
|
||||
})
|
||||
});
|
||||
|
||||
request.done(function(data) {
|
||||
|
||||
nav.find("li").removeClass("form-tab-selected");
|
||||
link.parent().addClass("form-tab-selected");
|
||||
|
||||
preview.find(".markdown").html(data)
|
||||
preview.css("height", textarea.css("height"));
|
||||
preview.css("width", textarea.css("width"));
|
||||
|
||||
write.hide();
|
||||
preview.show();
|
||||
});
|
||||
},
|
||||
|
||||
// Show the Markdown textarea
|
||||
MarkdownWriter: function(e) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$(this).closest("ul").find("li").removeClass("form-tab-selected")
|
||||
$(this).parent().addClass("form-tab-selected");
|
||||
|
||||
$(".write-area").show();
|
||||
$(".preview-area").hide();
|
||||
},
|
||||
|
||||
// Check session and redirect to the login page if not logged
|
||||
CheckSession: function() {
|
||||
|
||||
if (! $(".form-login").length) {
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: $("body").data("status-url"),
|
||||
statusCode: {
|
||||
401: function() {
|
||||
window.location = $("body").data("login-url");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
Init: function() {
|
||||
|
||||
// Chosen select
|
||||
$(".chosen-select").chosen({
|
||||
width: "200px",
|
||||
no_results_text: $(".chosen-select").data("notfound"),
|
||||
disable_search_threshold: 10
|
||||
});
|
||||
|
||||
// Project select box
|
||||
$("#board-selector").chosen({
|
||||
width: 180,
|
||||
no_results_text: $("#board-selector").data("notfound")
|
||||
});
|
||||
|
||||
$("#board-selector").change(function() {
|
||||
window.location = $(this).attr("data-board-url").replace(/PROJECT_ID/g, $(this).val());
|
||||
});
|
||||
|
||||
// Check the session every 60s
|
||||
window.setInterval(Kanboard.CheckSession, 60000);
|
||||
|
||||
// Submit form
|
||||
Mousetrap.bindGlobal("mod+enter", function() {
|
||||
$("form").submit();
|
||||
});
|
||||
|
||||
// Open board selector
|
||||
Mousetrap.bind("b", function(e) {
|
||||
e.preventDefault();
|
||||
$('#board-selector').trigger('chosen:open');
|
||||
});
|
||||
|
||||
// Focus to the search box
|
||||
Mousetrap.bind("f", function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var input = document.getElementById("form-search");
|
||||
|
||||
if (input) {
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter helper for search
|
||||
$(document).on("click", ".filter-helper", function (e) {
|
||||
e.preventDefault();
|
||||
$("#form-search").val($(this).data("filter"));
|
||||
$("form.search").submit();
|
||||
});
|
||||
|
||||
// Collapse sidebar
|
||||
$(document).on("click", ".sidebar-collapse", function (e) {
|
||||
e.preventDefault();
|
||||
$(".sidebar-container").addClass("sidebar-collapsed");
|
||||
$(".sidebar-expand").show();
|
||||
$(".sidebar h2").hide();
|
||||
$(".sidebar ul").hide();
|
||||
$(".sidebar-collapse").hide();
|
||||
});
|
||||
|
||||
// Expand sidebar
|
||||
$(document).on("click", ".sidebar-expand", function (e) {
|
||||
e.preventDefault();
|
||||
$(".sidebar-container").removeClass("sidebar-collapsed");
|
||||
$(".sidebar-collapse").show();
|
||||
$(".sidebar h2").show();
|
||||
$(".sidebar ul").show();
|
||||
$(".sidebar-expand").hide();
|
||||
});
|
||||
|
||||
// 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());
|
||||
}
|
||||
});
|
||||
|
||||
// Datepicker translation
|
||||
$.datepicker.setDefaults($.datepicker.regional[$("body").data("js-lang")]);
|
||||
|
||||
// Alert box fadeout
|
||||
$(".alert-fade-out").delay(4000).fadeOut(800, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
Kanboard.InitAfterAjax();
|
||||
},
|
||||
|
||||
InitAfterAjax: function() {
|
||||
|
||||
// Popover
|
||||
$(document).on("click", ".popover", Kanboard.Popover);
|
||||
|
||||
// Autofocus fields (html5 autofocus works only with page onload)
|
||||
$("[autofocus]").each(function(index, element) {
|
||||
$(this).focus();
|
||||
})
|
||||
|
||||
// Datepicker
|
||||
$(".form-date").datepicker({
|
||||
showOtherMonths: true,
|
||||
selectOtherMonths: true,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
constrainInput: false
|
||||
});
|
||||
|
||||
// Datetime picker
|
||||
$(".form-datetime").datetimepicker({
|
||||
controlType: 'select',
|
||||
oneLine: true,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
// timeFormat: 'h:mm tt',
|
||||
constrainInput: false
|
||||
});
|
||||
|
||||
// Markdown Preview for textareas
|
||||
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
||||
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
||||
|
||||
// Auto-select input fields
|
||||
$(".auto-select").focus(function() {
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
// Dropdown
|
||||
$(".dropit-submenu").hide();
|
||||
$('.dropdown').not(".dropit").dropit({ triggerParentEl : "span" });
|
||||
|
||||
// Task auto-completion
|
||||
if ($(".task-autocomplete").length) {
|
||||
|
||||
if ($('.opposite_task_id').val() == '') {
|
||||
$(".task-autocomplete").parent().find("input[type=submit]").attr('disabled','disabled');
|
||||
}
|
||||
|
||||
$(".task-autocomplete").autocomplete({
|
||||
source: $(".task-autocomplete").data("search-url"),
|
||||
minLength: 1,
|
||||
select: function(event, ui) {
|
||||
var field = $(".task-autocomplete").data("dst-field");
|
||||
$("input[name=" + field + "]").val(ui.item.id);
|
||||
|
||||
$(".task-autocomplete").parent().find("input[type=submit]").removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Tooltip for column description
|
||||
$(".tooltip").tooltip({
|
||||
content: function() {
|
||||
return '<div class="markdown">' + $(this).attr("title") + '</div>';
|
||||
},
|
||||
position: {
|
||||
my: 'left-20 top',
|
||||
at: 'center bottom+9',
|
||||
using: function(position, feedback) {
|
||||
|
||||
$(this).css(position);
|
||||
|
||||
var arrow_pos = feedback.target.left + feedback.target.width / 2 - feedback.element.left - 20;
|
||||
|
||||
$("<div>")
|
||||
.addClass("tooltip-arrow")
|
||||
.addClass(feedback.vertical)
|
||||
.addClass(arrow_pos < 1 ? "align-left" : "align-right")
|
||||
.appendTo(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Screenshot
|
||||
if (Kanboard.Exists("screenshot-zone")) {
|
||||
Kanboard.Screenshot.Init();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
@ -1,278 +1,164 @@
|
|||
(function() {
|
||||
function Board() {
|
||||
this.app = null;
|
||||
this.checkInterval = null;
|
||||
}
|
||||
|
||||
var checkInterval = null;
|
||||
Board.prototype.execute = function(app) {
|
||||
this.app = app;
|
||||
this.app.swimlane.refresh();
|
||||
this.app.swimlane.listen();
|
||||
this.poll();
|
||||
this.keyboardShortcuts();
|
||||
this.resizeColumnHeight();
|
||||
this.listen();
|
||||
this.dragAndDrop();
|
||||
this.compactView();
|
||||
|
||||
function on_popover(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$(window).resize(this.resizeColumnHeight);
|
||||
};
|
||||
|
||||
Kanboard.Popover(e, Kanboard.InitAfterAjax);
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
function keyboard_shortcuts()
|
||||
{
|
||||
Mousetrap.bind("n", function() {
|
||||
Kanboard.OpenPopover(
|
||||
$("#board").data("task-creation-url"),
|
||||
Kanboard.InitAfterAjax
|
||||
);
|
||||
});
|
||||
Board.prototype.check = function() {
|
||||
if (this.app.isVisible()) {
|
||||
|
||||
Mousetrap.bind("s", function() {
|
||||
Kanboard.ShowLoadingIcon();
|
||||
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: $('.filter-display-mode:not([style="display: none;"]) a').attr('href'),
|
||||
success: function(data) {
|
||||
$("#board-container").remove();
|
||||
$("#main").append(data);
|
||||
Kanboard.InitAfterAjax();
|
||||
board_unload_events();
|
||||
board_load_events();
|
||||
compactview_reload();
|
||||
$('.filter-display-mode').toggle();
|
||||
Kanboard.HideLoadingIcon();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Mousetrap.bind("c", function() {
|
||||
compactview_toggle();
|
||||
});
|
||||
}
|
||||
|
||||
function resize_column()
|
||||
{
|
||||
var position = $(".board-swimlane").position();
|
||||
$(".board-task-list").height($(window).height() - position.top);
|
||||
}
|
||||
|
||||
// Setup the board
|
||||
function board_load_events()
|
||||
{
|
||||
// Resize column height
|
||||
resize_column();
|
||||
|
||||
// Drag and drop
|
||||
$(".board-task-list").sortable({
|
||||
delay: 300,
|
||||
distance: 5,
|
||||
connectWith: ".column",
|
||||
placeholder: "draggable-placeholder",
|
||||
items: ".draggable-item",
|
||||
stop: function(event, ui) {
|
||||
board_save(
|
||||
ui.item.attr('data-task-id'),
|
||||
ui.item.parent().attr("data-column-id"),
|
||||
ui.item.index() + 1,
|
||||
ui.item.parent().attr('data-swimlane-id')
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Task popover
|
||||
$("#board").on("click", ".task-board-popover", on_popover);
|
||||
|
||||
// Redirect to the task details page
|
||||
$("#board").on("click", ".task-board", function() {
|
||||
window.location = $(this).data("task-url");
|
||||
});
|
||||
|
||||
// Tooltips for tasks
|
||||
$(".task-board-tooltip").tooltip({
|
||||
track: false,
|
||||
position: {
|
||||
my: 'left-20 top',
|
||||
at: 'center bottom+9',
|
||||
using: function(position, feedback) {
|
||||
|
||||
$(this).css(position);
|
||||
|
||||
var arrow_pos = feedback.target.left + feedback.target.width / 2 - feedback.element.left - 20;
|
||||
|
||||
$("<div>")
|
||||
.addClass("tooltip-arrow")
|
||||
.addClass(feedback.vertical)
|
||||
.addClass(arrow_pos < 1 ? "align-left" : "align-right")
|
||||
.appendTo(this);
|
||||
}
|
||||
},
|
||||
content: function(e) {
|
||||
var href = $(this).attr('data-href');
|
||||
|
||||
if (! href) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
$.get(href, function setTooltipContent(data) {
|
||||
|
||||
$('.ui-tooltip-content:visible').html(data);
|
||||
|
||||
var tooltip = $('.ui-tooltip:visible');
|
||||
|
||||
// Clear previous position, it interferes with the updated position computation
|
||||
tooltip.css({ top: '', left: '' });
|
||||
|
||||
// Remove arrow, it will be added when repositionning
|
||||
tooltip.children('.tooltip-arrow').remove();
|
||||
|
||||
// Reposition the tooltip
|
||||
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")) {
|
||||
Kanboard.OpenPopover($(this).attr('href'));
|
||||
$(_this).tooltip('close');
|
||||
}
|
||||
else {
|
||||
$.get($(this).attr('href'), setTooltipContent);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return '<i class="fa fa-spinner fa-spin"></i>';
|
||||
}
|
||||
}).on("mouseenter", function() {
|
||||
|
||||
var _this = this;
|
||||
$(this).tooltip("open");
|
||||
|
||||
$(".ui-tooltip").on("mouseleave", function () {
|
||||
$(_this).tooltip('close');
|
||||
});
|
||||
|
||||
}).on("mouseleave focusout", function (e) {
|
||||
|
||||
e.stopImmediatePropagation();
|
||||
var _this = this;
|
||||
|
||||
setTimeout(function () {
|
||||
if (! $(".ui-tooltip:hover").length) {
|
||||
$(_this).tooltip("close");
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Automatic refresh
|
||||
var interval = parseInt($("#board").attr("data-check-interval"));
|
||||
|
||||
if (interval > 0) {
|
||||
checkInterval = window.setInterval(board_check, interval * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop events
|
||||
function board_unload_events()
|
||||
{
|
||||
clearInterval(checkInterval);
|
||||
}
|
||||
|
||||
// Save and refresh the board
|
||||
function board_save(taskId, columnId, position, swimlaneId)
|
||||
{
|
||||
board_unload_events();
|
||||
Kanboard.ShowLoadingIcon();
|
||||
var self = this;
|
||||
this.app.showLoadingIcon();
|
||||
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: $("#board").attr("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) {
|
||||
$("#board-container").remove();
|
||||
$("#main").append(data);
|
||||
Kanboard.InitAfterAjax();
|
||||
board_load_events();
|
||||
compactview_reload();
|
||||
Kanboard.HideLoadingIcon();
|
||||
url: $("#board").attr("data-check-url"),
|
||||
statusCode: {
|
||||
200: function(data) { self.refresh(data); },
|
||||
304: function () { self.app.hideLoadingIcon(); }
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the board have been changed by someone else
|
||||
function board_check()
|
||||
{
|
||||
if (Kanboard.IsVisible()) {
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: $("#board").attr("data-check-url"),
|
||||
statusCode: {
|
||||
200: function(data) {
|
||||
$("#board-container").remove();
|
||||
$("#main").append(data);
|
||||
Kanboard.InitAfterAjax();
|
||||
board_unload_events();
|
||||
board_load_events();
|
||||
compactview_reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Board.prototype.save = function(taskId, columnId, position, swimlaneId) {
|
||||
this.app.showLoadingIcon();
|
||||
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: $("#board").attr("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: this.refresh.bind(this),
|
||||
error: this.app.hideLoadingIcon.bind(this)
|
||||
});
|
||||
};
|
||||
|
||||
Board.prototype.refresh = function(data) {
|
||||
$("#board-container").replaceWith(data);
|
||||
|
||||
this.app.listen();
|
||||
this.app.swimlane.refresh();
|
||||
this.app.swimlane.listen();
|
||||
this.resizeColumnHeight();
|
||||
this.app.hideLoadingIcon();
|
||||
this.listen();
|
||||
this.dragAndDrop();
|
||||
this.compactView();
|
||||
};
|
||||
|
||||
Board.prototype.resizeColumnHeight = function() {
|
||||
var position = $(".board-swimlane").position();
|
||||
|
||||
if (position) {
|
||||
$(".board-task-list").height($(window).height() - position.top);
|
||||
}
|
||||
};
|
||||
|
||||
function compactview_load_events()
|
||||
{
|
||||
jQuery(document).on('click', ".filter-toggle-scrolling", function(e) {
|
||||
e.preventDefault();
|
||||
compactview_toggle();
|
||||
});
|
||||
|
||||
compactview_reload();
|
||||
}
|
||||
|
||||
function compactview_toggle()
|
||||
{
|
||||
var scrolling = Kanboard.GetStorageItem("horizontal_scroll") || 1;
|
||||
Kanboard.SetStorageItem("horizontal_scroll", scrolling == 0 ? 1 : 0);
|
||||
compactview_reload();
|
||||
}
|
||||
|
||||
function compactview_reload()
|
||||
{
|
||||
if (Kanboard.GetStorageItem("horizontal_scroll") == 0) {
|
||||
|
||||
$(".filter-wide").show();
|
||||
$(".filter-compact").hide();
|
||||
|
||||
$("#board-container").addClass("board-container-compact");
|
||||
$("#board th").addClass("board-column-compact");
|
||||
}
|
||||
else {
|
||||
|
||||
$(".filter-wide").hide();
|
||||
$(".filter-compact").show();
|
||||
|
||||
$("#board-container").removeClass("board-container-compact");
|
||||
$("#board th").removeClass("board-column-compact");
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
|
||||
if (Kanboard.Exists("board")) {
|
||||
board_load_events();
|
||||
compactview_load_events();
|
||||
keyboard_shortcuts();
|
||||
|
||||
$(window).resize(resize_column);
|
||||
Board.prototype.dragAndDrop = function() {
|
||||
var self = this;
|
||||
$(".board-task-list").sortable({
|
||||
delay: 300,
|
||||
distance: 5,
|
||||
connectWith: ".board-task-list",
|
||||
placeholder: "draggable-placeholder",
|
||||
items: ".draggable-item",
|
||||
stop: function(event, ui) {
|
||||
self.save(
|
||||
ui.item.attr('data-task-id'),
|
||||
ui.item.parent().attr("data-column-id"),
|
||||
ui.item.index() + 1,
|
||||
ui.item.parent().attr('data-swimlane-id')
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
Board.prototype.listen = function() {
|
||||
var self = this;
|
||||
|
||||
$(document).on("click", ".task-board", function() {
|
||||
window.location = $(this).data("task-url");
|
||||
});
|
||||
|
||||
$(document).on('click', ".filter-toggle-scrolling", function(e) {
|
||||
e.preventDefault();
|
||||
self.toggleCompactView();
|
||||
});
|
||||
};
|
||||
|
||||
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").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.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"));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,51 +1,49 @@
|
|||
(function() {
|
||||
function Calendar() {
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
if (Kanboard.Exists("calendar")) {
|
||||
var calendar = $('#calendar');
|
||||
}
|
||||
|
||||
calendar.fullCalendar({
|
||||
lang: $("body").data("js-lang"),
|
||||
editable: true,
|
||||
eventLimit: true,
|
||||
defaultView: "month",
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,agendaDay'
|
||||
},
|
||||
eventDrop: function(event) {
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: calendar.data("save-url"),
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
processData: false,
|
||||
data: JSON.stringify({
|
||||
"task_id": event.id,
|
||||
"date_due": event.start.format()
|
||||
})
|
||||
});
|
||||
},
|
||||
viewRender: function() {
|
||||
var url = calendar.data("check-url");
|
||||
var params = {
|
||||
"start": calendar.fullCalendar('getView').start.format(),
|
||||
"end": calendar.fullCalendar('getView').end.format()
|
||||
};
|
||||
Calendar.prototype.execute = function() {
|
||||
var calendar = $('#calendar');
|
||||
|
||||
for (var key in params) {
|
||||
url += "&" + key + "=" + params[key];
|
||||
}
|
||||
calendar.fullCalendar({
|
||||
lang: $("body").data("js-lang"),
|
||||
editable: true,
|
||||
eventLimit: true,
|
||||
defaultView: "month",
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,agendaDay'
|
||||
},
|
||||
eventDrop: function(event) {
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: calendar.data("save-url"),
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
processData: false,
|
||||
data: JSON.stringify({
|
||||
"task_id": event.id,
|
||||
"date_due": event.start.format()
|
||||
})
|
||||
});
|
||||
},
|
||||
viewRender: function() {
|
||||
var url = calendar.data("check-url");
|
||||
var params = {
|
||||
"start": calendar.fullCalendar('getView').start.format(),
|
||||
"end": calendar.fullCalendar('getView').end.format()
|
||||
};
|
||||
|
||||
$.getJSON(url, function(events) {
|
||||
calendar.fullCalendar('removeEvents');
|
||||
calendar.fullCalendar('addEventSource', events);
|
||||
calendar.fullCalendar('rerenderEvents');
|
||||
});
|
||||
}
|
||||
for (var key in params) {
|
||||
url += "&" + key + "=" + params[key];
|
||||
}
|
||||
|
||||
$.getJSON(url, function(events) {
|
||||
calendar.fullCalendar('removeEvents');
|
||||
calendar.fullCalendar('addEventSource', events);
|
||||
calendar.fullCalendar('rerenderEvents');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,145 +1,131 @@
|
|||
Kanboard.Screenshot = (function() {
|
||||
function Screenshot() {
|
||||
this.pasteCatcher = null;
|
||||
}
|
||||
|
||||
var pasteCatcher = null;
|
||||
Screenshot.prototype.execute = function() {
|
||||
this.initialize();
|
||||
};
|
||||
|
||||
// Setup event listener and workarounds
|
||||
function init()
|
||||
{
|
||||
destroy();
|
||||
// Setup event listener and workarounds
|
||||
Screenshot.prototype.initialize = function() {
|
||||
this.destroy();
|
||||
|
||||
if (! window.Clipboard) {
|
||||
if (! window.Clipboard) {
|
||||
|
||||
// Create a contenteditable element
|
||||
pasteCatcher = document.createElement("div");
|
||||
pasteCatcher.id = "screenshot-pastezone";
|
||||
pasteCatcher.contentEditable = "true";
|
||||
// Create a contenteditable element
|
||||
this.pasteCatcher = document.createElement("div");
|
||||
this.pasteCatcher.id = "screenshot-pastezone";
|
||||
this.pasteCatcher.contentEditable = "true";
|
||||
|
||||
// Insert the content editable at the top to avoid scrolling down in the board view
|
||||
pasteCatcher.style.opacity = 0;
|
||||
pasteCatcher.style.position = "fixed";
|
||||
pasteCatcher.style.top = 0;
|
||||
pasteCatcher.style.right = 0;
|
||||
pasteCatcher.style.width = 0;
|
||||
// Insert the content editable at the top to avoid scrolling down in the board view
|
||||
this.pasteCatcher.style.opacity = 0;
|
||||
this.pasteCatcher.style.position = "fixed";
|
||||
this.pasteCatcher.style.top = 0;
|
||||
this.pasteCatcher.style.right = 0;
|
||||
this.pasteCatcher.style.width = 0;
|
||||
|
||||
document.body.insertBefore(pasteCatcher, document.body.firstChild);
|
||||
document.body.insertBefore(this.pasteCatcher, document.body.firstChild);
|
||||
|
||||
// Set focus on the contenteditable element
|
||||
pasteCatcher.focus();
|
||||
// Set focus on the contenteditable element
|
||||
this.pasteCatcher.focus();
|
||||
|
||||
// Set the focus when clicked anywhere in the document
|
||||
document.addEventListener("click", setFocus);
|
||||
// Set the focus when clicked anywhere in the document
|
||||
document.addEventListener("click", this.setFocus.bind(this));
|
||||
|
||||
// Set the focus when clicked in screenshot dropzone (popover)
|
||||
document.getElementById("screenshot-zone").addEventListener("click", setFocus);
|
||||
}
|
||||
|
||||
window.addEventListener("paste", pasteHandler);
|
||||
// Set the focus when clicked in screenshot dropzone (popover)
|
||||
document.getElementById("screenshot-zone").addEventListener("click", this.setFocus.bind(this));
|
||||
}
|
||||
|
||||
// Set focus on the contentEditable element
|
||||
function setFocus()
|
||||
{
|
||||
if (pasteCatcher !== null) {
|
||||
pasteCatcher.focus();
|
||||
}
|
||||
window.addEventListener("paste", this.pasteHandler.bind(this));
|
||||
};
|
||||
|
||||
// Destroy contentEditable element
|
||||
Screenshot.prototype.destroy = function() {
|
||||
if (this.pasteCatcher != null) {
|
||||
document.body.removeChild(this.pasteCatcher);
|
||||
}
|
||||
else if (document.getElementById("screenshot-pastezone")) {
|
||||
document.body.removeChild(document.getElementById("screenshot-pastezone"));
|
||||
}
|
||||
|
||||
// Destroy contenteditable
|
||||
function destroy()
|
||||
{
|
||||
if (pasteCatcher != null) {
|
||||
document.body.removeChild(pasteCatcher);
|
||||
}
|
||||
else if (document.getElementById("screenshot-pastezone")) {
|
||||
document.body.removeChild(document.getElementById("screenshot-pastezone"));
|
||||
}
|
||||
document.removeEventListener("click", this.setFocus.bind(this));
|
||||
this.pasteCatcher = null;
|
||||
};
|
||||
|
||||
document.removeEventListener("click", setFocus);
|
||||
pasteCatcher = null;
|
||||
// Set focus on contentEditable element
|
||||
Screenshot.prototype.setFocus = function() {
|
||||
if (this.pasteCatcher !== null) {
|
||||
this.pasteCatcher.focus();
|
||||
}
|
||||
};
|
||||
|
||||
// Paste event callback
|
||||
function pasteHandler(e)
|
||||
{
|
||||
// Firefox doesn't have the property e.clipboardData.items (only Chrome)
|
||||
if (e.clipboardData && e.clipboardData.items) {
|
||||
// Paste event callback
|
||||
Screenshot.prototype.pasteHandler = function(e) {
|
||||
// Firefox doesn't have the property e.clipboardData.items (only Chrome)
|
||||
if (e.clipboardData && e.clipboardData.items) {
|
||||
|
||||
var items = e.clipboardData.items;
|
||||
var items = e.clipboardData.items;
|
||||
|
||||
if (items) {
|
||||
if (items) {
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
|
||||
// Find an image in pasted elements
|
||||
if (items[i].type.indexOf("image") !== -1) {
|
||||
// Find an image in pasted elements
|
||||
if (items[i].type.indexOf("image") !== -1) {
|
||||
|
||||
var blob = items[i].getAsFile();
|
||||
var blob = items[i].getAsFile();
|
||||
|
||||
// Get the image as base64 data
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
createImage(event.target.result);
|
||||
};
|
||||
// Get the image as base64 data
|
||||
var reader = new FileReader();
|
||||
var self = this;
|
||||
reader.onload = function(event) {
|
||||
self.createImage(event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
}
|
||||
reader.readAsDataURL(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
|
||||
// Handle Firefox
|
||||
setTimeout(checkInput, 100);
|
||||
// Handle Firefox
|
||||
setTimeout(this.checkInput.bind(this), 100);
|
||||
}
|
||||
};
|
||||
|
||||
// Parse the input in the paste catcher element
|
||||
Screenshot.prototype.checkInput = function() {
|
||||
var child = this.pasteCatcher.childNodes[0];
|
||||
|
||||
if (child) {
|
||||
// If the user pastes an image, the src attribute
|
||||
// will represent the image as a base64 encoded string.
|
||||
if (child.tagName === "IMG") {
|
||||
this.createImage(child.src);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the input in the paste catcher element
|
||||
function checkInput()
|
||||
{
|
||||
var child = pasteCatcher.childNodes[0];
|
||||
pasteCatcher.innerHTML = "";
|
||||
};
|
||||
|
||||
if (child) {
|
||||
// If the user pastes an image, the src attribute
|
||||
// will represent the image as a base64 encoded string.
|
||||
if (child.tagName === "IMG") {
|
||||
createImage(child.src);
|
||||
}
|
||||
}
|
||||
// Creates a new image from a given source
|
||||
Screenshot.prototype.createImage = function(blob) {
|
||||
var pastedImage = new Image();
|
||||
pastedImage.src = blob;
|
||||
|
||||
pasteCatcher.innerHTML = "";
|
||||
}
|
||||
|
||||
// Creates a new image from a given source
|
||||
function createImage(blob)
|
||||
{
|
||||
var pastedImage = new Image();
|
||||
pastedImage.src = blob;
|
||||
|
||||
// Send the image content to the form variable
|
||||
pastedImage.onload = function() {
|
||||
var sourceSplit = blob.split("base64,");
|
||||
var sourceString = sourceSplit[1];
|
||||
$("input[name=screenshot]").val(sourceString);
|
||||
};
|
||||
|
||||
var zone = document.getElementById("screenshot-zone");
|
||||
zone.innerHTML = "";
|
||||
zone.className = "screenshot-pasted";
|
||||
zone.appendChild(pastedImage);
|
||||
|
||||
destroy();
|
||||
init();
|
||||
}
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
|
||||
if (Kanboard.Exists("screenshot-zone")) {
|
||||
init();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
Init: init,
|
||||
Destroy: destroy
|
||||
// Send the image content to the form variable
|
||||
pastedImage.onload = function() {
|
||||
var sourceSplit = blob.split("base64,");
|
||||
var sourceString = sourceSplit[1];
|
||||
$("input[name=screenshot]").val(sourceString);
|
||||
};
|
||||
})();
|
||||
|
||||
var zone = document.getElementById("screenshot-zone");
|
||||
zone.innerHTML = "";
|
||||
zone.className = "screenshot-pasted";
|
||||
zone.appendChild(pastedImage);
|
||||
|
||||
this.destroy();
|
||||
this.initialize();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,90 +1,67 @@
|
|||
(function() {
|
||||
function Swimlane() {
|
||||
}
|
||||
|
||||
// Expand a Swimlane via display attributes
|
||||
function expand(swimlaneId)
|
||||
{
|
||||
$('.swimlane-row-' + swimlaneId).css('display', 'table-row');
|
||||
$('.show-icon-swimlane-' + swimlaneId).css('display', 'none');
|
||||
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'inline');
|
||||
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);
|
||||
}
|
||||
|
||||
// Collapse a Swimlane via display attributes
|
||||
function collapse(swimlaneId)
|
||||
{
|
||||
$('.swimlane-row-' + swimlaneId).css('display', 'none');
|
||||
$('.show-icon-swimlane-' + swimlaneId).css('display', 'inline');
|
||||
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'none');
|
||||
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
|
||||
|
||||
$('.swimlane-row-' + swimlaneId).css('display', 'table-row');
|
||||
$('.show-icon-swimlane-' + swimlaneId).css('display', 'none');
|
||||
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'inline');
|
||||
};
|
||||
|
||||
Swimlane.prototype.collapse = function(swimlaneId) {
|
||||
var swimlaneIds = this.getAllCollapsed();
|
||||
|
||||
if (swimlaneIds.indexOf(swimlaneId) < 0) {
|
||||
swimlaneIds.push(swimlaneId);
|
||||
localStorage.setItem(this.getStorageKey(), JSON.stringify(swimlaneIds));
|
||||
}
|
||||
|
||||
// Add swimlane Id to the hidden list and stores the list to localStorage
|
||||
function hide(id)
|
||||
{
|
||||
var storageKey = "hidden_swimlanes_" + $("#board").data("project-id");
|
||||
var hiddenSwimlaneIds = JSON.parse(Kanboard.GetStorageItem(storageKey)) || [];
|
||||
$('.swimlane-row-' + swimlaneId).css('display', 'none');
|
||||
$('.show-icon-swimlane-' + swimlaneId).css('display', 'inline');
|
||||
$('.hide-icon-swimlane-' + swimlaneId).css('display', 'none');
|
||||
};
|
||||
|
||||
hiddenSwimlaneIds.push(id);
|
||||
Swimlane.prototype.isCollapsed = function(swimlaneId) {
|
||||
return this.getAllCollapsed().indexOf(swimlaneId) > -1;
|
||||
};
|
||||
|
||||
Kanboard.SetStorageItem(storageKey, JSON.stringify(hiddenSwimlaneIds));
|
||||
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]);
|
||||
}
|
||||
};
|
||||
|
||||
// Remove swimlane Id from the hidden list and stores the list to
|
||||
// localStorage
|
||||
function unhide(id)
|
||||
{
|
||||
var storageKey = "hidden_swimlanes_" + $("#board").data("project-id");
|
||||
var hiddenSwimlaneIds = JSON.parse(Kanboard.GetStorageItem(storageKey)) || [];
|
||||
var index = hiddenSwimlaneIds.indexOf(id);
|
||||
Swimlane.prototype.listen = function() {
|
||||
var self = this;
|
||||
|
||||
if (index > -1) {
|
||||
hiddenSwimlaneIds.splice(index, 1);
|
||||
}
|
||||
|
||||
Kanboard.SetStorageItem(storageKey, JSON.stringify(hiddenSwimlaneIds));
|
||||
}
|
||||
|
||||
// Check if swimlane Id is hidden. Anything > -1 means hidden.
|
||||
function isHidden(id)
|
||||
{
|
||||
return getAllHidden().indexOf(id) > -1;
|
||||
}
|
||||
|
||||
// Gets all swimlane Ids that are hidden
|
||||
function getAllHidden()
|
||||
{
|
||||
var storageKey = "hidden_swimlanes_" + $("#board").data("project-id");
|
||||
return JSON.parse(Kanboard.GetStorageItem(storageKey)) || [];
|
||||
}
|
||||
|
||||
// Reload the swimlane states (shown/hidden) after an ajax call
|
||||
jQuery(document).ajaxComplete(function() {
|
||||
|
||||
getAllHidden().map(function(swimlaneId) {
|
||||
collapse(swimlaneId);
|
||||
});
|
||||
});
|
||||
|
||||
// Reload the swimlane states (shown/hidden) after page refresh
|
||||
jQuery(document).ready(function() {
|
||||
|
||||
getAllHidden().map(function(swimlaneId) {
|
||||
collapse(swimlaneId);
|
||||
});
|
||||
});
|
||||
|
||||
// Clicking on Show/Hide icon fires this.
|
||||
jQuery(document).on('click', ".board-swimlane-toggle", function(e) {
|
||||
$(document).on('click', ".board-swimlane-toggle", function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var swimlaneId = $(this).data('swimlane-id');
|
||||
|
||||
if (isHidden(swimlaneId)) {
|
||||
unhide(swimlaneId);
|
||||
expand(swimlaneId);
|
||||
if (self.isCollapsed(swimlaneId)) {
|
||||
self.expand(swimlaneId);
|
||||
}
|
||||
else {
|
||||
hide(swimlaneId);
|
||||
collapse(swimlaneId);
|
||||
self.collapse(swimlaneId);
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ print_css="print links table board task comment subtask markdown"
|
|||
app_css="base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown screenshot filters"
|
||||
vendor_css="jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min"
|
||||
|
||||
app_js="base board calendar analytic swimlane screenshot"
|
||||
app_js="Popover Tooltip Markdown Sidebar Search App Screenshot Calendar Board Swimlane TaskRepartitionChart UserRepartitionChart CumulativeFlowDiagram BurndownChart BudgetChart AvgTimeColumnChart TaskTimeColumnChart LeadCycleTimeChart Router"
|
||||
vendor_js="jquery-1.11.1.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min dropit.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min app.min"
|
||||
lang_js="da de es fi fr hu it ja nl pl pt-br ru sv sr th tr zh-cn"
|
||||
|
||||
|
|
@ -34,7 +34,9 @@ function minify_js {
|
|||
|
||||
rm -f $dst_file $tmp_file 2>/dev/null
|
||||
|
||||
echo "(function() { 'use strict';" > $tmp_file;
|
||||
for file in $app_js; do cat "assets/js/src/${file}.js" >> $tmp_file; done
|
||||
echo "})();" >> $tmp_file;
|
||||
|
||||
curl -s \
|
||||
-d compilation_level=SIMPLE_OPTIMIZATIONS \
|
||||
|
|
|
|||
Loading…
Reference in New Issue