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,16 @@
Version 1.0.27 (unreleased)
--------------
Improvements:
New features:
* Improve comments design
* Added Markdown editor
* Added letter avatar provider
* Added pluggable Avatar providers
Improvements:
* Refactoring of Javascript code
* Improve comments design
* Improve task summary sections
* Put back the action sidebar in task view
* Added support for multiple placeholders for LDAP_USER_FILTER

View File

@ -2,10 +2,10 @@ BUILD_DIR = /tmp
CSS_APP = $(addprefix assets/css/src/, $(addsuffix .css, base links title table form button alert tooltip header board task comment subtask tasklink markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown upload filters gantt project files views accordion avatar))
CSS_PRINT = $(addprefix assets/css/src/, $(addsuffix .css, print links table board task comment subtask tasklink markdown))
CSS_VENDOR = $(addprefix assets/css/vendor/, $(addsuffix .css, jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min))
CSS_VENDOR = $(addprefix assets/css/vendor/, $(addsuffix .css, jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min simplemde.min))
JS_APP = $(addprefix assets/js/src/, $(addsuffix .js, Popover Dropdown Tooltip Markdown Search App Screenshot FileUpload Calendar Board Column Swimlane Gantt Task Project Subtask TaskRepartitionChart UserRepartitionChart CumulativeFlowDiagram BurndownChart AvgTimeColumnChart TaskTimeColumnChart LeadCycleTimeChart CompareHoursColumnChart Accordion Router))
JS_VENDOR = $(addprefix assets/js/vendor/, $(addsuffix .js, jquery-1.11.3.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min jquery.textcomplete))
JS_APP = $(addprefix assets/js/src/, $(addsuffix .js, Namespace App Dropdown Popover Notification Accordion Session Calendar AvgTimeColumnChart BurndownChart CompareHoursColumnChart CumulativeFlowDiagram LeadCycleTimeChart UserRepartitionChart TaskTimeColumnChart TaskRepartitionChart Gantt Column Markdown ProjectPermission ProjectCreation Screenshot FileUpload Search Task Subtask Swimlane BoardColumnView BoardColumnScrolling BoardHorizontalScrolling BoardCollapsedMode BoardDragAndDrop BoardTask BoardPolling Tooltip Bootstrap))
JS_VENDOR = $(addprefix assets/js/vendor/, $(addsuffix .js, jquery-1.11.3.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min simplemde.min))
JS_LANG = $(addprefix assets/js/vendor/lang/, $(addsuffix .js, cs da de es el fi fr hu id it ja nl nb pl pt pt-br ru sv sr th tr zh-cn))
all: css js
@ -35,10 +35,9 @@ vendor.js:
@ cat ${JS_LANG} >> vendor.js
app.js:
@ rm -f tmp.js
@ rm -f assets/js/app.js
@ echo "(function() { 'use strict';" > tmp.js
@ cat ${JS_APP} >> tmp.js
@ echo "})();" >> tmp.js
@ yuicompressor --charset utf-8 --type js -o tmp.js tmp.js
@ cat vendor.js tmp.js >> assets/js/app.js
@ rm -f tmp.js

View File

@ -13,24 +13,7 @@
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -14,24 +14,7 @@
<?= $this->form->number('task_limit', $values, $errors) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -16,25 +16,7 @@
<?= $this->form->number('task_limit', $values, $errors) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -6,36 +6,21 @@
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
<div class="form-tabs">
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
<div class="write-area">
<?= $this->form->textarea(
'comment',
$values,
$errors,
array(
'autofocus',
'required',
'placeholder="'.t('Leave a comment').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
),
'comment-textarea'
) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<div class="markdown-editor-small">
<?= $this->form->textarea(
'comment',
$values,
$errors,
array(
'autofocus',
'required',
'placeholder="'.t('Leave a comment').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
),
'markdown-editor'
) ?>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>

View File

@ -9,25 +9,16 @@
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
<div class="form-tabs">
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
<div class="write-area">
<?= $this->form->textarea('comment', $values, $errors, array('autofocus', 'required', 'placeholder="'.t('Leave a comment').'"'), 'comment-textarea') ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<div class="markdown-editor-small">
<?= $this->form->textarea(
'comment',
$values,
$errors,
array('autofocus', 'required', 'placeholder="'.t('Leave a comment').'"'),
'markdown-editor'
) ?>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
<?= t('or') ?>

View File

@ -3,31 +3,19 @@
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
<div class="form-tabs">
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
<div class="write-area">
<?= $this->form->textarea(
'comment',
$values,
$errors,
array(
'required',
'placeholder="'.t('Leave a comment').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
),
'comment-textarea'
) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<div class="markdown-editor-small">
<?= $this->form->textarea(
'comment',
$values,
$errors,
array(
'data-markdown-editor-disable-toolbar="true"',
'required',
'placeholder="'.t('Leave a comment').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"',
),
'markdown-editor'
) ?>
</div>
<div class="form-actions">

View File

@ -12,22 +12,7 @@
<?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large') ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors, array('placeholder="'.t('Leave a description').'"', 'tabindex="2"')) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<?= $this->form->textarea('description', $values, $errors, array('placeholder="'.t('Leave a description').'"', 'tabindex="2"'), 'markdown-editor') ?>
<?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?>
</div>

View File

@ -11,25 +11,7 @@
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('name', $values) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -10,24 +10,7 @@
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -13,25 +13,7 @@
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea('description', $values, $errors) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea('description', $values, $errors, array(), 'markdown-editor') ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -11,32 +11,17 @@
<?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large') ?>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">
<div class="write-area">
<?= $this->form->textarea(
'description',
$values,
$errors,
array(
'placeholder="'.t('Leave a description').'"',
'tabindex="2"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $values['project_id'])).'"'
)
) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
</div>
<?= $this->form->textarea(
'description',
$values,
$errors,
array(
'placeholder="'.t('Leave a description').'"',
'tabindex="2"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $values['project_id'])).'"'
),
'markdown-editor'
) ?>
<?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?>

View File

@ -7,34 +7,17 @@
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<div class="form-tabs">
<ul class="form-tabs-nav">
<li class="form-tab form-tab-selected">
<i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
</li>
<li class="form-tab">
<a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
</li>
</ul>
<div class="write-area">
<?= $this->form->textarea(
'description',
$values,
$errors,
array(
'autofocus',
'placeholder="'.t('Leave a description').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"'
),
'task-show-description-textarea'
) ?>
</div>
<div class="preview-area">
<div class="markdown"></div>
</div>
</div>
<div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div>
<?= $this->form->textarea(
'description',
$values,
$errors,
array(
'autofocus',
'placeholder="'.t('Leave a description').'"',
'data-mention-search-url="'.$this->url->href('UserHelper', 'mention', array('project_id' => $task['project_id'])).'"'
),
'markdown-editor'
) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -68,15 +68,3 @@
.comment-content {
margin-left: 55px;
}
/* comment textarea */
.comment-textarea {
height: 200px;
width: 80%;
max-width: 800px;
}
#comments .comment-textarea {
height: 80px;
width: 500px;
}

View File

@ -149,7 +149,8 @@ input.form-input-large {
.form-column {
float: left;
margin-right: 3%;
max-width: 47%;
max-width: 50%;
min-width: 40%;
}
.form-column ul {
@ -184,55 +185,6 @@ input.form-input-large {
margin-bottom: 0;
}
/* preview tabs */
label + .form-tabs {
margin-top: 10px;
}
.form-tabs {
width: 100%;
max-width: 800px;
}
ul.form-tabs-nav {
margin-bottom: 8px;
margin-top: 0;
}
.form-tabs-nav li {
margin-left: 0;
display: inline;
}
.form-tab {
margin-right: 20px;
}
.form-tab a {
color: #ccc;
font-weight: bold;
text-decoration: none;
}
.form-tab a:focus,
.form-tab a:hover {
color: #000;
}
.form-tab-selected a {
color: #333;
}
.preview-area {
border: 1px dashed #000;
padding-top: 5px;
padding-left: 5px;
padding-right: 5px;
margin-bottom: 5px;
display: none;
overflow: auto;
}
.reset-password {
margin-top: 20px;
}

View File

@ -1,7 +1,23 @@
/* markdown editor */
div.CodeMirror,
div.CodeMirror-scroll {
max-height: 250px;
min-height: 200px;
}
.markdown-editor-small div.CodeMirror,
.markdown-editor-small div.CodeMirror-scroll {
min-height: 100px;
max-height: 180px;
}
.form-column div.CodeMirror {
margin-bottom: 10px;
}
/* markdown content */
.markdown {
line-height: 1.4em;
font-size: 1.0em;
}
.markdown h1 {

View File

@ -13,11 +13,10 @@
#popover-content {
position: absolute;
width: 70%;
margin: 0 0 0 -35%;
left: 50%;
left: 15%;
top: 1%;
padding: 15px;
background: #fff;
overflow: auto;
max-height: 85%;
max-height: 90%;
}

View File

@ -10,6 +10,15 @@
text-decoration: underline;
}
td.task-table a {
color: #000;
text-decoration: none;
}
td.task-table a:hover {
text-decoration: underline;
}
/* task inside the board */
.task-board {
position: relative;

7
assets/css/vendor/simplemde.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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();
});

File diff suppressed because it is too large Load Diff

14
assets/js/vendor/simplemde.min.js vendored Normal file

File diff suppressed because one or more lines are too long