Rewrite task move position component and remove Vuejs
This commit is contained in:
parent
e64faae69a
commit
04ff67e26b
|
|
@ -2,45 +2,22 @@
|
|||
<h2><?= t('Move task to another position on the board') ?></h2>
|
||||
</div>
|
||||
|
||||
<script type="x/template" id="template-task-move-position">
|
||||
<?= $this->form->label(t('Swimlane'), 'swimlane') ?>
|
||||
<select v-model="swimlaneId" @change="onChangeSwimlane()" id="form-swimlane">
|
||||
<option v-for="swimlane in board" v-bind:value="swimlane.id">
|
||||
{{ swimlane.name }}
|
||||
</option>
|
||||
</select>
|
||||
<form>
|
||||
|
||||
<div v-if="columns.length > 0">
|
||||
<?= $this->form->label(t('Column'), 'column') ?>
|
||||
<select v-model="columnId" @change="onChangeColumn()" id="form-column">
|
||||
<option v-for="column in columns" v-bind:value="column.id">
|
||||
{{ column.title }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<?= $this->app->component('task-move-position', array(
|
||||
'saveUrl' => $this->url->href('TaskMovePositionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
|
||||
'board' => $board,
|
||||
'swimlaneLabel' => t('Swimlane'),
|
||||
'columnLabel' => t('Column'),
|
||||
'positionLabel' => t('Position'),
|
||||
'beforeLabel' => t('Insert before this task'),
|
||||
'afterLabel' => t('Insert after this task'),
|
||||
)) ?>
|
||||
|
||||
<div v-if="tasks.length > 0">
|
||||
<?= $this->form->label(t('Position'), 'position') ?>
|
||||
<select v-model="position" id="form-position">
|
||||
<option v-for="task in tasks" v-bind:value="task.position">#{{ task.id }} - {{ task.title }}</option>
|
||||
</select>
|
||||
<label><input type="radio" value="before" v-model="positionChoice"><?= t('Insert before this task') ?></label>
|
||||
<label><input type="radio" value="after" v-model="positionChoice"><?= t('Insert after this task') ?></label>
|
||||
</div>
|
||||
<?= $this->app->component('submit-cancel', array(
|
||||
'submitLabel' => t('Save'),
|
||||
'orLabel' => t('or'),
|
||||
'cancelLabel' => t('cancel'),
|
||||
)) ?>
|
||||
|
||||
<div v-if="errorMessage">
|
||||
<div class="alert alert-error">{{ errorMessage }}</div>
|
||||
</div>
|
||||
|
||||
<submit-cancel
|
||||
label-button="<?= t('Save') ?>"
|
||||
label-or="<?= t('or') ?>"
|
||||
label-cancel="<?= t('cancel') ?>"
|
||||
:callback="onSubmit">
|
||||
</submit-cancel>
|
||||
</script>
|
||||
|
||||
<task-move-position
|
||||
save-url="<?= $this->url->href('TaskMovePositionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"
|
||||
:board='<?= json_encode($board, JSON_HEX_APOS) ?>'
|
||||
></task-move-position>
|
||||
</form>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3,6 +3,6 @@ KB.onClick('.accordion-toggle', function(e) {
|
|||
|
||||
if (section) {
|
||||
KB.dom(section).toggleClass('accordion-collapsed');
|
||||
KB.dom(KB.dom(section).child('.accordion-content')).toggle();
|
||||
KB.dom(KB.dom(section).find('.accordion-content')).toggle();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,35 +1,52 @@
|
|||
Vue.component('submit-cancel', {
|
||||
props: ['labelButton', 'labelOr', 'labelCancel', 'callback'],
|
||||
template: '<div class="form-actions">' +
|
||||
'<button type="button" class="btn btn-blue" @click="onSubmit" :disabled="isLoading">' +
|
||||
'<span v-show="isLoading"><i class="fa fa-spinner fa-pulse"></i> </span>' +
|
||||
'{{ labelButton }}' +
|
||||
'</button> ' +
|
||||
'{{ labelOr }} <a href="#" v-on:click.prevent="onCancel">{{ labelCancel }}</a>' +
|
||||
'</div>'
|
||||
,
|
||||
data: function () {
|
||||
return {
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isLoading: function () {
|
||||
return this.loading;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSubmit: function () {
|
||||
this.loading = true;
|
||||
this.callback();
|
||||
},
|
||||
onCancel: function () {
|
||||
_KB.get('Popover').close();
|
||||
}
|
||||
},
|
||||
events: {
|
||||
'submitCancelled': function() {
|
||||
this.loading = false;
|
||||
}
|
||||
KB.component('submit-cancel', function (containerElement, options) {
|
||||
var isLoading = false;
|
||||
|
||||
function onSubmit() {
|
||||
isLoading = true;
|
||||
KB.find('#modal-submit-button').replace(buildButton());
|
||||
KB.trigger('modal.submit');
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
KB.trigger('modal.cancel');
|
||||
_KB.get('Popover').close();
|
||||
}
|
||||
|
||||
function onStop() {
|
||||
isLoading = false;
|
||||
KB.find('#modal-submit-button').replace(buildButton());
|
||||
}
|
||||
|
||||
function buildButton() {
|
||||
var button = KB.dom('button')
|
||||
.click(onSubmit)
|
||||
.attr('id', 'modal-submit-button')
|
||||
.attr('type', 'submit')
|
||||
.attr('class', 'btn btn-blue');
|
||||
|
||||
if (isLoading) {
|
||||
button
|
||||
.disable()
|
||||
.add(KB.dom('i').attr('class', 'fa fa-spinner fa-pulse').build())
|
||||
.text(' ')
|
||||
;
|
||||
}
|
||||
|
||||
return button
|
||||
.text(options.submitLabel)
|
||||
.build();
|
||||
}
|
||||
|
||||
this.render = function () {
|
||||
KB.on('modal.stop', onStop);
|
||||
|
||||
var element = KB.dom('div')
|
||||
.attr('class', 'form-actions')
|
||||
.add(buildButton())
|
||||
.text(' ' + options.orLabel + ' ')
|
||||
.add(KB.dom('a').attr('href', '#').click(onCancel).text(options.cancelLabel).build())
|
||||
.build();
|
||||
|
||||
containerElement.appendChild(element);
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,86 +1,164 @@
|
|||
Vue.component('task-move-position', {
|
||||
props: ['board', 'saveUrl'],
|
||||
template: '#template-task-move-position',
|
||||
data: function () {
|
||||
return {
|
||||
swimlaneId: 0,
|
||||
columnId: 0,
|
||||
position: 1,
|
||||
columns: [],
|
||||
tasks: [],
|
||||
positionChoice: 'before',
|
||||
errorMessage: ''
|
||||
KB.component('task-move-position', function (containerElement, options) {
|
||||
|
||||
function getSelectedValue(id) {
|
||||
var element = KB.dom(document).find('#' + id);
|
||||
|
||||
if (element) {
|
||||
return parseInt(element.options[element.selectedIndex].value);
|
||||
}
|
||||
},
|
||||
ready: function () {
|
||||
this.columns = this.board[0].columns;
|
||||
this.columnId = this.columns[0].id;
|
||||
this.tasks = this.columns[0].tasks;
|
||||
this.errorMessage = '';
|
||||
},
|
||||
methods: {
|
||||
onChangeSwimlane: function () {
|
||||
var self = this;
|
||||
this.columnId = 0;
|
||||
this.position = 1;
|
||||
this.columns = [];
|
||||
this.tasks = [];
|
||||
this.positionChoice = 'before';
|
||||
|
||||
this.board.forEach(function(swimlane) {
|
||||
if (swimlane.id === self.swimlaneId) {
|
||||
self.columns = swimlane.columns;
|
||||
self.tasks = self.columns[0].tasks;
|
||||
self.columnId = self.columns[0].id;
|
||||
}
|
||||
});
|
||||
},
|
||||
onChangeColumn: function () {
|
||||
var self = this;
|
||||
this.position = 1;
|
||||
this.tasks = [];
|
||||
this.positionChoice = 'before';
|
||||
|
||||
this.columns.forEach(function(column) {
|
||||
if (column.id == self.columnId) {
|
||||
self.tasks = column.tasks;
|
||||
|
||||
if (self.tasks.length > 0) {
|
||||
self.position = parseInt(self.tasks[0]['position']);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
onSubmit: function () {
|
||||
var self = this;
|
||||
|
||||
if (this.positionChoice == 'after') {
|
||||
this.position++;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
cache: false,
|
||||
url: this.saveUrl,
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
processData: false,
|
||||
data: JSON.stringify({
|
||||
"column_id": this.columnId,
|
||||
"swimlane_id": this.swimlaneId,
|
||||
"position": this.position
|
||||
}),
|
||||
statusCode: {
|
||||
200: function() {
|
||||
window.location.reload(true);
|
||||
},
|
||||
403: function(jqXHR) {
|
||||
var response = JSON.parse(jqXHR.responseText);
|
||||
self.errorMessage = response.message;
|
||||
|
||||
self.$broadcast('submitCancelled');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSwimlaneId() {
|
||||
var swimlaneId = getSelectedValue('form-swimlanes');
|
||||
return swimlaneId === null ? options.board[0].id : swimlaneId;
|
||||
}
|
||||
|
||||
function getColumnId() {
|
||||
var columnId = getSelectedValue('form-columns');
|
||||
return columnId === null ? options.board[0].columns[0].id : columnId;
|
||||
}
|
||||
|
||||
function getPosition() {
|
||||
var position = getSelectedValue('form-position');
|
||||
return position === null ? 1 : position;
|
||||
}
|
||||
|
||||
function getPositionChoice() {
|
||||
var element = KB.find('input[name=positionChoice]:checked');
|
||||
|
||||
if (element) {
|
||||
return element.value;
|
||||
}
|
||||
|
||||
return 'before';
|
||||
}
|
||||
|
||||
function onSwimlaneChanged() {
|
||||
var columnSelect = KB.dom(document).find('#form-columns');
|
||||
KB.dom(columnSelect).replace(buildColumnSelect());
|
||||
|
||||
var taskSection = KB.dom(document).find('#form-tasks');
|
||||
KB.dom(taskSection).replace(buildTasks());
|
||||
}
|
||||
|
||||
function onColumnChanged() {
|
||||
var taskSection = KB.dom(document).find('#form-tasks');
|
||||
KB.dom(taskSection).replace(buildTasks());
|
||||
}
|
||||
|
||||
function onError(message) {
|
||||
KB.trigger('modal.stop');
|
||||
|
||||
KB.find('#message-container')
|
||||
.replace(KB.dom('div')
|
||||
.attr('id', 'message-container')
|
||||
.attr('class', 'alert alert-error')
|
||||
.text(message)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
var position = getPosition();
|
||||
var positionChoice = getPositionChoice();
|
||||
|
||||
if (positionChoice === 'after') {
|
||||
position++;
|
||||
}
|
||||
|
||||
KB.find('#message-container').replace(KB.dom('div').attr('id', 'message-container').build());
|
||||
|
||||
KB.http.postJson(options.saveUrl, {
|
||||
"column_id": getColumnId(),
|
||||
"swimlane_id": getSwimlaneId(),
|
||||
"position": position
|
||||
}).success(function () {
|
||||
window.location.reload(true);
|
||||
}).error(function (response) {
|
||||
if (response) {
|
||||
onError(response.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildSwimlaneSelect() {
|
||||
var swimlanes = [];
|
||||
|
||||
options.board.forEach(function(swimlane) {
|
||||
swimlanes.push({'value': swimlane.id, 'text': swimlane.name});
|
||||
});
|
||||
|
||||
return KB.dom('select')
|
||||
.attr('id', 'form-swimlanes')
|
||||
.change(onSwimlaneChanged)
|
||||
.for('option', swimlanes)
|
||||
.build();
|
||||
}
|
||||
|
||||
function buildColumnSelect() {
|
||||
var columns = [];
|
||||
var swimlaneId = getSwimlaneId();
|
||||
|
||||
options.board.forEach(function(swimlane) {
|
||||
if (swimlaneId === swimlane.id) {
|
||||
swimlane.columns.forEach(function(column) {
|
||||
columns.push({'value': column.id, 'text': column.title});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return KB.dom('select')
|
||||
.attr('id', 'form-columns')
|
||||
.change(onColumnChanged)
|
||||
.for('option', columns)
|
||||
.build();
|
||||
}
|
||||
|
||||
function buildTasks() {
|
||||
var tasks = [];
|
||||
var swimlaneId = getSwimlaneId();
|
||||
var columnId = getColumnId();
|
||||
var container = KB.dom('div').attr('id', 'form-tasks');
|
||||
|
||||
options.board.forEach(function(swimlane) {
|
||||
if (swimlaneId === swimlane.id) {
|
||||
swimlane.columns.forEach(function(column) {
|
||||
if (columnId === column.id) {
|
||||
column.tasks.forEach(function(task) {
|
||||
tasks.push({'value': task.position, 'text': '#' + task.id + ' - ' + task.title});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (tasks.length > 0) {
|
||||
container
|
||||
.add(KB.html.label(options.positionLabel, 'form-position'))
|
||||
.add(KB.dom('select').attr('id', 'form-position').for('option', tasks).build())
|
||||
.add(KB.html.radio(options.beforeLabel, 'positionChoice', 'before'))
|
||||
.add(KB.html.radio(options.afterLabel, 'positionChoice', 'after'))
|
||||
;
|
||||
}
|
||||
|
||||
return container.build();
|
||||
}
|
||||
|
||||
this.render = function () {
|
||||
KB.on('modal.submit', onSubmit);
|
||||
|
||||
var form = KB.dom('div')
|
||||
.on('submit', onSubmit)
|
||||
.add(KB.dom('div').attr('id', 'message-container').build())
|
||||
.add(KB.html.label(options.swimlaneLabel, 'form-swimlanes'))
|
||||
.add(buildSwimlaneSelect())
|
||||
.add(KB.html.label(options.columnLabel, 'form-columns'))
|
||||
.add(buildColumnSelect())
|
||||
.add(buildTasks())
|
||||
.build();
|
||||
|
||||
containerElement.appendChild(form);
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ KB.component('text-editor', function (containerElement, options) {
|
|||
.attr('tabindex', options.tabindex || '-1')
|
||||
.attr('required', options.required || false)
|
||||
.attr('autofocus', options.autofocus || null)
|
||||
.attr('placeholder', options.placeholder || '')
|
||||
.text(options.text)
|
||||
.text(options.text) // Order is important for IE11
|
||||
.attr('placeholder', options.placeholder || null)
|
||||
.build();
|
||||
|
||||
return KB.dom('div')
|
||||
|
|
@ -124,7 +124,7 @@ KB.component('text-editor', function (containerElement, options) {
|
|||
document.execCommand('ms-beginUndoUnit');
|
||||
} catch (error) {}
|
||||
|
||||
textarea.value = replaceTextRange(text, textarea.selectionStart, textarea.selectionEnd, replacedText);
|
||||
textarea.value = replaceTextRange(textarea.value, textarea.selectionStart, textarea.selectionEnd, replacedText);
|
||||
|
||||
try {
|
||||
document.execCommand('ms-endUndoUnit');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
var KB = {
|
||||
components: {},
|
||||
utils: {},
|
||||
html: {},
|
||||
http: {},
|
||||
listeners: {
|
||||
clicks: {},
|
||||
internals: {}
|
||||
}
|
||||
};
|
||||
|
||||
KB.on = function (eventType, callback) {
|
||||
if (! this.listeners.internals.hasOwnProperty(eventType)) {
|
||||
this.listeners.internals[eventType] = [];
|
||||
}
|
||||
|
||||
this.listeners.internals[eventType].push(callback);
|
||||
};
|
||||
|
||||
KB.trigger = function (eventType, eventData) {
|
||||
if (this.listeners.internals.hasOwnProperty(eventType)) {
|
||||
for (var i = 0; i < this.listeners.internals[eventType].length; i++) {
|
||||
if (! this.listeners.internals[eventType][i](eventData)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
KB.onClick = function (selector, callback) {
|
||||
this.listeners.clicks[selector] = callback;
|
||||
};
|
||||
|
||||
KB.listen = function () {
|
||||
var self = this;
|
||||
|
||||
function onClick(e) {
|
||||
for (var selector in self.listeners.clicks) {
|
||||
if (self.listeners.clicks.hasOwnProperty(selector) && e.target.matches(selector)) {
|
||||
e.preventDefault();
|
||||
self.listeners.clicks[selector](e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onClick, false);
|
||||
};
|
||||
|
||||
KB.component = function (name, object) {
|
||||
this.components[name] = object;
|
||||
};
|
||||
|
||||
KB.getComponent = function (name, containerElement, options) {
|
||||
var object = this.components[name];
|
||||
return new object(containerElement, options);
|
||||
};
|
||||
|
||||
KB.render = function () {
|
||||
for (var name in this.components) {
|
||||
var elementList = document.querySelectorAll('.js-' + name);
|
||||
|
||||
for (var i = 0; i < elementList.length; i++) {
|
||||
if (this.components.hasOwnProperty(name)) {
|
||||
var component = KB.getComponent(name, elementList[i], JSON.parse(elementList[i].dataset.params));
|
||||
component.render();
|
||||
elementList[i].className = elementList[i].className + '-rendered';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
KB.dom = function (tag) {
|
||||
|
||||
function DomManipulation(tag) {
|
||||
|
|
@ -31,19 +30,33 @@ KB.dom = function (tag) {
|
|||
return this;
|
||||
};
|
||||
|
||||
this.click = function (callback) {
|
||||
element.onclick = function (e) {
|
||||
this.on = function (eventName, callback) {
|
||||
element.addEventListener(eventName, function (e) {
|
||||
e.preventDefault();
|
||||
callback();
|
||||
};
|
||||
callback(e.target);
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.click = function (callback) {
|
||||
return this.on('click', callback);
|
||||
};
|
||||
|
||||
this.change = function (callback) {
|
||||
return this.on('change', callback);
|
||||
};
|
||||
|
||||
this.add = function (node) {
|
||||
element.appendChild(node);
|
||||
return this;
|
||||
};
|
||||
|
||||
this.replace = function (node) {
|
||||
element.parentNode.replaceChild(node, element);
|
||||
return this;
|
||||
};
|
||||
|
||||
this.html = function (html) {
|
||||
element.innerHTML = html;
|
||||
return this;
|
||||
|
|
@ -73,6 +86,16 @@ KB.dom = function (tag) {
|
|||
return element.classList.contains(className);
|
||||
};
|
||||
|
||||
this.disable = function () {
|
||||
element.disabled = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
this.enable = function () {
|
||||
element.disabled = false;
|
||||
return this;
|
||||
};
|
||||
|
||||
this.parent = function (selector) {
|
||||
for (; element && element !== document; element = element.parentNode) {
|
||||
if (element.matches(selector)) {
|
||||
|
|
@ -83,7 +106,7 @@ KB.dom = function (tag) {
|
|||
return null;
|
||||
};
|
||||
|
||||
this.child = function (selector) {
|
||||
this.find = function (selector) {
|
||||
return element.querySelector(selector);
|
||||
};
|
||||
|
||||
|
|
@ -118,3 +141,13 @@ KB.dom = function (tag) {
|
|||
|
||||
return new DomManipulation(tag);
|
||||
};
|
||||
|
||||
KB.find = function (selector) {
|
||||
var element = document.querySelector(selector);
|
||||
|
||||
if (element) {
|
||||
return KB.dom(element);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
KB.html.label = function (label, id) {
|
||||
return KB.dom('label').attr('for', id).text(label).build();
|
||||
};
|
||||
|
||||
KB.html.radio = function (label, name, value) {
|
||||
return KB.dom('label')
|
||||
.add(KB.dom('input')
|
||||
.attr('type', 'radio')
|
||||
.attr('name', name)
|
||||
.attr('value', value)
|
||||
.build()
|
||||
)
|
||||
.text(label)
|
||||
.build();
|
||||
};
|
||||
|
||||
KB.html.radios = function (items) {
|
||||
var html = KB.dom('div');
|
||||
|
||||
for (var item in items) {
|
||||
if (items.hasOwnProperty(item)) {
|
||||
html.add(KB.html.radio(item.label, item.name, item.value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
KB.http.request = function (method, url, headers, body) {
|
||||
var successCallback = function() {};
|
||||
var errorCallback = function() {};
|
||||
|
||||
function parseResponse(request) {
|
||||
try {
|
||||
return JSON.parse(request.responseText);
|
||||
} catch (e) {
|
||||
return request.responseText;
|
||||
}
|
||||
}
|
||||
|
||||
this.execute = function () {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open(method, url, true);
|
||||
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
|
||||
for (var header in headers) {
|
||||
if (headers.hasOwnProperty(header)) {
|
||||
request.setRequestHeader(header, headers[header]);
|
||||
}
|
||||
}
|
||||
|
||||
request.onerror = function() {
|
||||
errorCallback();
|
||||
};
|
||||
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState === XMLHttpRequest.DONE) {
|
||||
var response = parseResponse(request);
|
||||
|
||||
if (request.status === 200) {
|
||||
successCallback(response);
|
||||
} else {
|
||||
errorCallback(response);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.send(body);
|
||||
return this;
|
||||
};
|
||||
|
||||
this.success = function (callback) {
|
||||
successCallback = callback;
|
||||
return this;
|
||||
};
|
||||
|
||||
this.error = function (callback) {
|
||||
errorCallback = callback;
|
||||
return this;
|
||||
};
|
||||
};
|
||||
|
||||
KB.http.get = function (url) {
|
||||
return (new KB.http.request('GET', url)).execute();
|
||||
};
|
||||
|
||||
KB.http.postJson = function (url, body) {
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
|
||||
return (new KB.http.request('POST', url, headers, JSON.stringify(body))).execute();
|
||||
};
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
var KB = {
|
||||
components: {},
|
||||
utils: {},
|
||||
clickEvents: {}
|
||||
};
|
||||
|
||||
KB.onClick = function (selector, callback) {
|
||||
this.clickEvents[selector] = callback;
|
||||
};
|
||||
|
||||
KB.listen = function () {
|
||||
var self = this;
|
||||
|
||||
function onClick(e) {
|
||||
for (var selector in self.clickEvents) {
|
||||
if (self.clickEvents.hasOwnProperty(selector) && e.target.matches(selector)) {
|
||||
e.preventDefault();
|
||||
self.clickEvents[selector](e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onClick, false);
|
||||
};
|
||||
|
||||
KB.component = function (name, object) {
|
||||
this.components[name] = object;
|
||||
};
|
||||
|
||||
KB.render = function () {
|
||||
for (var name in this.components) {
|
||||
var elementList = document.querySelectorAll('.js-' + name);
|
||||
|
||||
for (var i = 0; i < elementList.length; i++) {
|
||||
if (this.components.hasOwnProperty(name)) {
|
||||
var object = this.components[name];
|
||||
var component = new object(elementList[i], JSON.parse(elementList[i].dataset.params));
|
||||
|
||||
component.render();
|
||||
elementList[i].className = elementList[i].className + '-rendered';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
KB.utils.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,13 @@
|
|||
KB.utils.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,14 @@
|
|||
if (!Element.prototype.matches) {
|
||||
Element.prototype.matches =
|
||||
Element.prototype.matchesSelector ||
|
||||
Element.prototype.mozMatchesSelector ||
|
||||
Element.prototype.msMatchesSelector ||
|
||||
Element.prototype.oMatchesSelector ||
|
||||
Element.prototype.webkitMatchesSelector ||
|
||||
function(s) {
|
||||
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
|
||||
i = matches.length;
|
||||
while (--i >= 0 && matches.item(i) !== this) {}
|
||||
return i > -1;
|
||||
};
|
||||
}
|
||||
|
|
@ -157,9 +157,5 @@ Kanboard.Popover.prototype.afterOpen = function() {
|
|||
this.app.autoComplete();
|
||||
this.app.tagAutoComplete();
|
||||
|
||||
new Vue({
|
||||
el: '#popover-container'
|
||||
});
|
||||
|
||||
KB.render();
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
12
gulpfile.js
12
gulpfile.js
|
|
@ -7,8 +7,9 @@ var strip = require('gulp-strip-comments');
|
|||
|
||||
var src = {
|
||||
js: [
|
||||
'assets/js/core/kb.js',
|
||||
'assets/js/core/dom.js',
|
||||
'assets/js/polyfills/*.js',
|
||||
'assets/js/core/base.js',
|
||||
'assets/js/core/!(base|bootstrap)*.js',
|
||||
'assets/js/components/*.js',
|
||||
'assets/js/core/bootstrap.js',
|
||||
'assets/js/src/Namespace.js',
|
||||
|
|
@ -69,13 +70,6 @@ gulp.task('bower', function() {
|
|||
});
|
||||
|
||||
gulp.task('vendor', function() {
|
||||
gulp.src('node_modules/vue/dist/vue.min.js')
|
||||
.pipe(strip({trim: true}))
|
||||
.pipe(gulp.dest('node_modules/vue/dist/'))
|
||||
;
|
||||
|
||||
vendor.js.push('node_modules/vue/dist/vue.min.js');
|
||||
|
||||
gulp.src(vendor.js)
|
||||
.pipe(concat('vendor.min.js'))
|
||||
.pipe(gulp.dest(dist.js))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "kanboard",
|
||||
"dependencies": {
|
||||
"devDependencies": {
|
||||
"bower": "^1.7.9",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-bower": "0.0.13",
|
||||
|
|
@ -9,9 +9,6 @@
|
|||
"gulp-sass": "^2.3.2",
|
||||
"gulp-strip-comments": "^2.4.3",
|
||||
"gulp-uglify": "^1.5.3",
|
||||
"vue": "1.0.26-csp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jshint": "^2.9.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue