diff --git a/appinfo/info.xml b/appinfo/info.xml
index 72004d86d..2be03a6f4 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -14,7 +14,7 @@
- 🚀 Get your project organized
- 0.4.0-alpha1
+ 0.4.0-alpha3
agpl
Julius Härtl
Deck
diff --git a/css/style.scss b/css/style.scss
index 0469ebbb4..fc36e81c6 100644
--- a/css/style.scss
+++ b/css/style.scss
@@ -461,6 +461,20 @@ input.input-inline {
}
}
+ .card-tasks {
+ border-radius: 3px;
+ margin: 4px 4px 4px 0px;
+ padding: 0 2px;
+ font-size: 90%;
+ opacity: 0.5;
+ display: flex;
+ align-items: center;
+
+ .icon {
+ background-size: contain;
+ }
+ }
+
button {
padding: 22px;
margin: 0;
@@ -1219,6 +1233,17 @@ input.input-inline {
white-space: pre;
}
}
+
+ input[type=checkbox] {
+ margin: 0px 10px 0px 0px;
+ line-height: 10px;
+ font-size: 10px;
+ display: inline-block;
+ min-height: 12px;
+ }
+ li input[type=checkbox] {
+ margin: 0px 10px 0px -20px;
+ }
}
/**
diff --git a/js/app/Config.js b/js/app/Config.js
index 8f3c7fa3d..a4f7acd91 100644
--- a/js/app/Config.js
+++ b/js/app/Config.js
@@ -25,18 +25,20 @@
import app from './App.js';
import md from 'angular-markdown-it';
import markdownitLinkTarget from 'markdown-it-link-target';
+import markdownitCheckbox from 'legacy/markdown-it-checkbox.js';
app.config(function ($provide, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider, $compileProvider, markdownItConverterProvider) {
'use strict';
$httpProvider.defaults.headers.common.requesttoken = oc_requesttoken;
+
$compileProvider.debugInfoEnabled(true);
markdownItConverterProvider.use(markdownitLinkTarget, {
breaks: true,
linkify: true,
xhtmlOut: true
- });
+ }).use(markdownitCheckbox);
$urlRouterProvider.otherwise('/');
diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js
index 2d2d1e374..6d4d7e615 100644
--- a/js/controller/BoardController.js
+++ b/js/controller/BoardController.js
@@ -49,6 +49,22 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
}, true);
$scope.params = $state;
+ /**
+ * Check for markdown checkboxes in description to render the counter
+ *
+ * This should probably be moved to the backend at some point
+ *
+ * @param text
+ * @returns array of [finished, total] checkboxes
+ */
+ $scope.getCheckboxes = function(text) {
+ const regTotal = /\[(X|\s|\_|\-)\]\s(.*)/ig;
+ const regFinished = /\[(X|\_|\-)\]\s(.*)/ig;
+ return [
+ ((text || '').match(regFinished) || []).length,
+ ((text || '').match(regTotal) || []).length
+ ];
+ };
$scope.search = function (searchText) {
$scope.searchText = searchText;
diff --git a/js/controller/CardController.js b/js/controller/CardController.js
index 49f60d5ca..f35a38817 100644
--- a/js/controller/CardController.js
+++ b/js/controller/CardController.js
@@ -23,7 +23,7 @@
/* global app moment */
import app from '../app/App.js';
-app.controller('CardController', function ($scope, $rootScope, $location, $stateParams, $interval, $timeout, $filter, BoardService, CardService, StackService, StatusService) {
+app.controller('CardController', function ($scope, $rootScope, $sce, $location, $stateParams, $interval, $timeout, $filter, BoardService, CardService, StackService, StatusService, markdownItConverter) {
$scope.sidebar = $rootScope.sidebar;
$scope.status = {
lastEdit: 0,
@@ -38,9 +38,19 @@ app.controller('CardController', function ($scope, $rootScope, $location, $state
$scope.statusservice.retainWaiting();
+ $scope.description = function() {
+ return $scope.rendered;
+ };
+
+ $scope.updateMarkdown = function(content) {
+ // only trust the html from markdown-it-checkbox
+ $scope.rendered = $sce.trustAsHtml(markdownItConverter.render(content || ''));
+ };
+
CardService.fetchOne($scope.cardId).then(function (data) {
$scope.statusservice.releaseWaiting();
$scope.archived = CardService.getCurrent().archived;
+ $scope.updateMarkdown(CardService.getCurrent().description);
}, function (error) {
});
@@ -51,7 +61,44 @@ app.controller('CardController', function ($scope, $rootScope, $location, $state
$scope.status.cardRename = true;
}
};
- $scope.cardEditDescriptionShow = function ($event) {
+
+ $scope.toggleCheckbox = function (id) {
+ $('#markdown input[type=checkbox]').attr('disabled', true);
+ $scope.status.edit = angular.copy(CardService.getCurrent());
+ var reg = /\[(X|\s|\_|\-)\]\s(.*)/ig;
+ var nth = 0;
+ $scope.status.edit.description = $scope.status.edit.description.replace(reg, function (match, i, original) {
+ if (nth++ === id) {
+ var result;
+ if (match.match(/^\[\s\]/i)) {
+ result = match.replace(/\[\s\]/i, '[x]');
+ }
+ if (match.match(/^\[x\]/i)) {
+ result = match.replace(/\[x\]/i, '[ ]');
+ }
+ return result;
+ }
+ return match;
+ });
+ CardService.update($scope.status.edit).then(function (data) {
+ var header = $('.section-header.card-description');
+ header.find('.save-indicator.unsaved').hide();
+ header.find('.save-indicator.saved').fadeIn(250).fadeOut(1000);
+ StackService.updateCard($scope.status.edit);
+ });
+ $('#markdown input[type=checkbox]').removeAttr('disabled');
+
+ };
+ $scope.clickCardDescription = function ($event) {
+ var checkboxId = $($event.target).data('id');
+ if ($event.target.tagName === 'LABEL') {
+ $scope.toggleCheckbox(checkboxId);
+ return;
+ }
+ if ($event.target.tagName === 'INPUT') {
+ $scope.toggleCheckbox(checkboxId);
+ return;
+ }
if (BoardService.isArchived() || CardService.getCurrent().archived) {
return false;
}
@@ -71,8 +118,9 @@ app.controller('CardController', function ($scope, $rootScope, $location, $state
$interval(function() {
var currentTime = Date.now();
var timeSinceEdit = currentTime-$scope.status.lastEdit;
- if (timeSinceEdit > 1000 && $scope.status.lastEdit > $scope.status.lastSave) {
+ if (timeSinceEdit > 1000 && $scope.status.lastEdit > $scope.status.lastSave && !$scope.status.saving) {
$scope.status.lastSave = currentTime;
+ $scope.status.saving = true;
var header = $('.section-header.card-description');
header.find('.save-indicator.unsaved').fadeIn(500);
CardService.update($scope.status.edit).then(function (data) {
@@ -80,6 +128,7 @@ app.controller('CardController', function ($scope, $rootScope, $location, $state
header.find('.save-indicator.unsaved').hide();
header.find('.save-indicator.saved').fadeIn(250).fadeOut(1000);
StackService.updateCard($scope.status.edit);
+ $scope.status.saving = false;
});
}
}, 500, 0, false);
diff --git a/js/legacy/markdown-it-checkbox.js b/js/legacy/markdown-it-checkbox.js
new file mode 100644
index 000000000..1aa1ecf95
--- /dev/null
+++ b/js/legacy/markdown-it-checkbox.js
@@ -0,0 +1,114 @@
+/**
+ * Original source code from https://github.com/mcecot/markdown-it-checkbox
+ * © 2015 Markus Cecot
+ * licenced under MIT
+ * https://github.com/mcecot/markdown-it-checkbox/blob/master/LICENSE
+ */
+var checkboxReplace;
+
+checkboxReplace = function(md, options, Token) {
+ "use strict";
+ var arrayReplaceAt, createTokens, defaults, lastId, pattern, splitTextToken;
+ arrayReplaceAt = md.utils.arrayReplaceAt;
+ lastId = 0;
+ defaults = {
+ divWrap: false,
+ divClass: 'checkbox',
+ idPrefix: 'checkbox'
+ };
+ options = Object.assign(defaults, options);
+ pattern = /\[(X|\s|\_|\-)\]\s(.*)/i;
+ createTokens = function(checked, label, Token) {
+ var id, idNumeric, nodes, token;
+ nodes = [];
+
+ /**
+ *
+ */
+ if (options.divWrap) {
+ token = new Token("checkbox_open", "div", 1);
+ token.attrs = [["class", options.divClass]];
+ nodes.push(token);
+ }
+
+ /**
+ *
+ */
+ id = options.idPrefix + lastId;
+ idNumeric = lastId;
+ lastId += 1;
+ token = new Token("checkbox_input", "input", 0);
+ token.attrs = [["type", "checkbox"], ["id", id], ["data-id", idNumeric]];
+ if (checked === true) {
+ token.attrs.push(["checked", "true"]);
+ }
+ nodes.push(token);
+
+ /**
+ *