Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix checkboxhandling with nested checkboxes #22

Merged
merged 7 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Assets/js/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ KB.on('dom.ready', function () {
else {
link = '?controller=CheckboxController&action=toggle&plugin=MarkdownPlus';
}

KB.http.postJson(link, {
'task_id': task_id,
'number': e.target.getAttribute('number')
'number': e.target.dataset.number
});
}
}
Expand Down
118 changes: 72 additions & 46 deletions Controller/CheckboxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,29 @@

class CheckboxController extends BaseController
{
private const regexCheckbox = '/\[[x, ]\]/m';
/*
# must match
+ [x] 2
* [ ] 3
> - [ ] 1
+ [x] 2
* [ ] 3
> > * * [ ] 3
> * > * * [ ] 3
[ ] test 8

# must not match:

- [x]1
+ [ ]
test [x]
test [x]
[] test 3
[a] test
[x](www.google.de) test4
*/

private const regexCheckbox = '/^([+,\-,*,>, ] )*(\[[x, ]\] )/m';

private function findCheckBox($text, $number, &$offset)
{
Expand All @@ -17,7 +39,9 @@ private function findCheckBox($text, $number, &$offset)
if ($offset >= $number) {
return array(
'success' => true,
'offset' => $matches[0][$count - $offset + $number - 1][1] + 1
'offset' => end($matches) // the actual box [ ]/[x]
[$count - $offset + $number - 1] // the requested checkbox
[1] + 1 // the offset to the checkbox content
);
}
return array('success' => false);
Expand All @@ -35,69 +59,71 @@ private function togglechar(&$string, $offset)
public function toggle()
{
$values = $this->request->getJson();

$foundCheckboxes = 0;
$number = intval($values['number']);
$taskId = $values['task_id'];

if (isset($taskId)) {
$task = $this->taskFinderModel->getById($taskId);

$text = $task['description'];
$result = $this->findCheckBox($text, $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($text, $result['offset']);
$task['description'] = $text;
$this->taskModificationModel->update($task);
return;
}
if ($task) {
$foundCheckboxes = 0;
$number = intval($values['number']);

if (isset($this->container["definitionOfDoneModel"])) {
foreach ($this->definitionOfDoneModel->getAll($taskId) as $subtask) {
$dod = $this->definitionOfDoneModel->getById($subtask['id']);
$text = $task['description'];
$result = $this->findCheckBox($text, $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($text, $result['offset']);
$task['description'] = $text;
$this->taskModificationModel->update($task);
return;
}

$result = $this->findCheckBox($dod['title'], $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($dod['title'], $result['offset']);
$this->definitionOfDoneModel->save($dod);
return;
if (isset($this->container["definitionOfDoneModel"])) {
foreach ($this->definitionOfDoneModel->getAll($taskId) as $subtask) {
$dod = $this->definitionOfDoneModel->getById($subtask['id']);

$result = $this->findCheckBox($dod['title'], $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($dod['title'], $result['offset']);
$this->definitionOfDoneModel->save($dod);
return;
}

$result = $this->findCheckBox($dod['text'], $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($dod['text'], $result['offset']);
$this->definitionOfDoneModel->save($dod);
return;
}
}
}

$result = $this->findCheckBox($dod['text'], $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($dod['text'], $result['offset']);
$this->definitionOfDoneModel->save($dod);
return;
if (isset($this->container["subtaskResultModel"])) {
foreach ($this->subtaskModel->getAll($taskId) as $subtask) {
$text = $this->subtaskResultModel->getById($subtask['id']);
$result = $this->findCheckBox($text, $number, $foundCheckboxes);
if ($result['success']) {
$this->togglechar($text, $result['offset']);
$this->subtaskResultModel->Save($subtask['id'], $text);
return;
}
}
}
}

if (isset($this->container["subtaskResultModel"])) {
foreach ($this->subtaskModel->getAll($taskId) as $subtask) {
$text = $this->subtaskResultModel->getById($subtask['id']);
$commentSortingDirection = $this->userMetadataCacheDecorator->get(UserMetadataModel::KEY_COMMENT_SORTING_DIRECTION, 'ASC');

foreach ($this->commentModel->getAll($taskId, $commentSortingDirection) as $comment) {
$text = $comment['comment'];

$result = $this->findCheckBox($text, $number, $foundCheckboxes);

if ($result['success']) {
$this->togglechar($text, $result['offset']);
$this->subtaskResultModel->Save($subtask['id'], $text);
$comment['comment'] = $text;
$this->commentModel->update($comment);
return;
}
}
}

$commentSortingDirection = $this->userMetadataCacheDecorator->get(UserMetadataModel::KEY_COMMENT_SORTING_DIRECTION, 'ASC');

foreach ($this->commentModel->getAll($taskId, $commentSortingDirection) as $comment) {
$text = $comment['comment'];

$result = $this->findCheckBox($text, $number, $foundCheckboxes);

if ($result['success']) {
$this->togglechar($text, $result['offset']);
$comment['comment'] = $text;
$this->commentModel->update($comment);
return;
}
}
}
}
}
37 changes: 32 additions & 5 deletions Helper/CoreMarkdown.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected function inlineTaskLink(array $Excerpt)
if (preg_match('!#(\d+)!i', $Excerpt['text'], $matches)) {
$link = $this->buildTaskLink($matches[1]);

if (! empty($link)) {
if (!empty($link)) {
return array(
'extent' => strlen($matches[0]),
'element' => array(
Expand All @@ -89,11 +89,11 @@ protected function inlineTaskLink(array $Excerpt)
*/
protected function inlineUserLink(array $Excerpt)
{
if (! $this->isPublicLink && preg_match('/^@([^\s,!:?]+)/', $Excerpt['text'], $matches)) {
if (!$this->isPublicLink && preg_match('/^@([^\s,!:?]+)/', $Excerpt['text'], $matches)) {
$username = rtrim($matches[1], '.');
$user = $this->container['userCacheDecorator']->getByUsername($username);

if (! empty($user)) {
if (!empty($user)) {
$url = $this->container['helper']->url->to('UserViewController', 'profile', array('user_id' => $user['id']));
$name = $user['name'] ?: $user['username'];

Expand Down Expand Up @@ -128,7 +128,7 @@ private function buildTaskLink($task_id)
if ($this->isPublicLink) {
$token = $this->container['memoryCache']->proxy($this->container['taskFinderModel'], 'getProjectToken', $task_id);

if (! empty($token)) {
if (!empty($token)) {
return $this->container['helper']->url->to(
'TaskViewController',
'readonly',
Expand Down Expand Up @@ -165,4 +165,31 @@ protected function inlineLink($Excerpt)
}
return $Inline;
}
}

function text($text)
{
$markup = parent::text($text);

$this->nummerizeCheckboxes($markup);

return $markup;
}

private function nummerizeCheckboxes(&$markup)
{
$counter = new Counter;
$count = 0;

$markup = preg_replace_callback("/activecheckbox\"/m", array($counter, 'count'), $markup, -1, $count, PREG_OFFSET_CAPTURE);
}
}

class Counter
{
private static $count = 0;

public function count($matches) {
$this::$count++;
return $matches[0][0] . " data-number=". $this::$count . " ";
}
};
25 changes: 18 additions & 7 deletions vendor/erusev/parsedown-extra/ParsedownExtra.php
Original file line number Diff line number Diff line change
Expand Up @@ -628,19 +628,30 @@ protected function processTag($elementMarkup) # recursive
$elementMarkup = mb_convert_encoding($elementMarkup, 'HTML-ENTITIES', 'UTF-8');

# http://stackoverflow.com/q/4879946/200145
$DOMDocument->loadHTML($elementMarkup);

if (!$DOMDocument->validate()) {
$errormessage = 'could not parse html<br>';
$errors = libxml_get_errors();
$success = $DOMDocument->loadHTML($elementMarkup);
$DOMDocument->removeChild($DOMDocument->doctype);

$errors = libxml_get_errors();
if ($errors)
{
$errormessage = "<h1>HTML-parser error:</h1><br>";
$errormessage .= "The input was interpret as HTML - did you miss the <code>markdown=1</code> attribute?<br>";
foreach ($errors as $error) {
$errormessage .= $error->message;
$errormessage .= "Line: " . $error->line . " - " . $error->message;
$errormessage .= '<br>';
}
return $errormessage;
}

$DOMDocument->removeChild($DOMDocument->doctype);
if (!isset($DOMDocument->firstChild->firstChild->firstChild))
{
$errormessage = "<h1>General HTML-parser error:</h1><br>";
$errormessage .= "The input was interpret as HTML - did you miss the <code>markdown=1</code> attribute?<br>";
$errormessage .= "Input:<pre><code>" . htmlspecialchars($elementMarkup) . "</code></pre>";
$errormessage .= "Output:<pre><code>" . htmlspecialchars($DOMDocument->saveHTML()) . "</code></pre>";
return $errormessage;
}

$DOMDocument->replaceChild($DOMDocument->firstChild->firstChild->firstChild, $DOMDocument->firstChild);

$elementText = '';
Expand Down
2 changes: 1 addition & 1 deletion vendor/erusev/parsedown/Parsedown.php
Original file line number Diff line number Diff line change
Expand Up @@ -1977,7 +1977,7 @@ static function instance($name = 'default')
protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+';

protected $voidElements = array(
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source'
);

protected $textLevelElements = array(
Expand Down
4 changes: 2 additions & 2 deletions vendor/leblanc-simon/parsedown-checkbox/ParsedownCheckbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected function checkboxUnchecked($text)
$text = self::escape($text);
}

return '<input type="checkbox" class="activecheckbox" number="'. ParsedownCheckbox::$count++ .'"/> ' . $this->format($text);
return '<input type="checkbox" class="activecheckbox"> ' . $this->format($text);
}

protected function checkboxChecked($text)
Expand All @@ -83,7 +83,7 @@ protected function checkboxChecked($text)
$text = self::escape($text);
}

return '<input type="checkbox" class="activecheckbox" number="'. ParsedownCheckbox::$count++ .'" checked/> ' . $this->format($text);
return '<input type="checkbox" class="activecheckbox" checked/> ' . $this->format($text);
}

/**
Expand Down