diff --git a/docs/PREFERENCES.md b/docs/PREFERENCES.md
index e4838a1c..4a2a72a0 100644
--- a/docs/PREFERENCES.md
+++ b/docs/PREFERENCES.md
@@ -40,6 +40,7 @@ Preferences can be controlled and modified in the settings window or via the `pr
| autoGuessEncoding | Boolean | true | Try to automatically guess the file encoding when opening files |
| trimTrailingNewline | Enum | `2` | Ensure a single trailing newline or whether trailing newlines should be removed: `0`: trim all trailing newlines, `1`: ensure single newline, `2`: auto detect, `3`: disabled. |
| hideLinkPopup | Boolean | false | It will not show the link popup when hover over the link if set `hideLinkPopup` to true |
+| autoCheck | Boolean | false | Whether to automatically check related task. Optional value: true, false |
#### Markdown
diff --git a/src/main/preferences/schema.json b/src/main/preferences/schema.json
index 35f40727..ffa7c22e 100644
--- a/src/main/preferences/schema.json
+++ b/src/main/preferences/schema.json
@@ -200,6 +200,11 @@
"type": "boolean",
"default": false
},
+ "autoCheck": {
+ "description": "Editor--Whether to automatically check related task.",
+ "type": "boolean",
+ "default": false
+ },
"preferLooseListItem": {
"description": "Markdown--The preferred list type",
"type": "boolean"
diff --git a/src/muya/lib/config/index.js b/src/muya/lib/config/index.js
index 88c7f210..f24358c5 100644
--- a/src/muya/lib/config/index.js
+++ b/src/muya/lib/config/index.js
@@ -264,6 +264,7 @@ export const MUYA_DEFAULT_OPTION = {
vegaTheme: 'latimes', // excel / ggplot2 / quartz / vox / fivethirtyeight / dark / latimes
hideQuickInsertHint: false,
hideLinkPopup: false,
+ autoCheck: false,
// Whether we should set spellcheck attribute on our container to highlight misspelled words.
// NOTE: The browser is not able to correct misspelled words words without a custom
// implementation like in Mark Text.
diff --git a/src/muya/lib/contentState/clickCtrl.js b/src/muya/lib/contentState/clickCtrl.js
index feb630d1..b670563e 100644
--- a/src/muya/lib/contentState/clickCtrl.js
+++ b/src/muya/lib/contentState/clickCtrl.js
@@ -1,6 +1,8 @@
import selection from '../selection'
import { isMuyaEditorElement } from '../selection/dom'
import { HAS_TEXT_BLOCK_REG, CLASS_OR_ID } from '../config'
+import { getParentCheckBox } from '../utils/getParentCheckBox'
+import { cumputeCheckboxStatus } from '../utils/cumputeCheckBoxStatus'
const clickCtrl = ContentState => {
ContentState.prototype.clickHandler = function (event) {
@@ -193,6 +195,50 @@ const clickCtrl = ContentState => {
this.cursor = { start, end }
}
}
+
+ ContentState.prototype.setCheckBoxState = function (checkbox, checked) {
+ checkbox.checked = checked
+ const block = this.getBlock(checkbox.id)
+ block.checked = checked
+ checkbox.classList.toggle(CLASS_OR_ID.AG_CHECKBOX_CHECKED)
+ }
+
+ ContentState.prototype.updateParentsCheckBoxState = function (checkbox) {
+ let parent = getParentCheckBox(checkbox)
+ while (parent !== null) {
+ const checked = cumputeCheckboxStatus(parent)
+ if (parent.checked !== checked) {
+ this.setCheckBoxState(parent, checked)
+ parent = getParentCheckBox(parent)
+ } else {
+ break
+ }
+ }
+ }
+
+ ContentState.prototype.updateChildrenCheckBoxState = function (checkbox, checked) {
+ const checkboxes = checkbox.parentElement.querySelectorAll(`input ~ ul .${CLASS_OR_ID.AG_TASK_LIST_ITEM_CHECKBOX}`)
+ const len = checkboxes.length
+ for (let i = 0; i < len; i++) {
+ const checkbox = checkboxes[i]
+ if (checkbox.checked !== checked) {
+ this.setCheckBoxState(checkbox, checked)
+ }
+ }
+ }
+
+ // handle task list item checkbox click
+ ContentState.prototype.listItemCheckBoxClick = function (checkbox) {
+ const { checked } = checkbox
+ this.setCheckBoxState(checkbox, checked)
+
+ // A task checked, then related task should be update
+ const { autoCheck } = this.muya.options
+ if (autoCheck) {
+ this.updateChildrenCheckBoxState(checkbox, checked)
+ this.updateParentsCheckBoxState(checkbox)
+ }
+ }
}
export default clickCtrl
diff --git a/src/muya/lib/contentState/updateCtrl.js b/src/muya/lib/contentState/updateCtrl.js
index baedb065..6a7b45c1 100644
--- a/src/muya/lib/contentState/updateCtrl.js
+++ b/src/muya/lib/contentState/updateCtrl.js
@@ -1,6 +1,5 @@
import { tokenizer } from '../parser/'
import { conflict } from '../utils'
-import { CLASS_OR_ID } from '../config'
const INLINE_UPDATE_FRAGMENTS = [
'(?:^|\n) {0,3}([*+-] {1,4})', // Bullet list
@@ -17,14 +16,6 @@ const INLINE_UPDATE_FRAGMENTS = [
const INLINE_UPDATE_REG = new RegExp(INLINE_UPDATE_FRAGMENTS.join('|'), 'i')
const updateCtrl = ContentState => {
- // handle task list item checkbox click
- ContentState.prototype.listItemCheckBoxClick = function (checkbox) {
- const { checked, id } = checkbox
- const block = this.getBlock(id)
- block.checked = checked
- checkbox.classList.toggle(CLASS_OR_ID.AG_CHECKBOX_CHECKED)
- }
-
ContentState.prototype.checkSameMarkerOrDelimiter = function (list, markerOrDelimiter) {
if (!/ol|ul/.test(list.type)) return false
return list.children[0].bulletMarkerOrDelimiter === markerOrDelimiter
@@ -142,7 +133,7 @@ const updateCtrl = ContentState => {
for (const l of lines) {
/* eslint-disable no-useless-escape */
if (/ {0,3}(?:\* *\* *\*|- *- *-|_ *_ *_)[ \*\-\_]*$/.test(l) && !thematicLineHasPushed) {
- /* eslint-enable no-useless-escape */
+ /* eslint-enable no-useless-escape */
thematicLine = l
thematicLineHasPushed = true
} else if (!thematicLineHasPushed) {
@@ -303,7 +294,7 @@ const updateCtrl = ContentState => {
}
}
if (TASK_LIST_REG.test(listItemText)) {
- const [,, tasklist,,,,] = listItemText.match(INLINE_UPDATE_REG) || [] // eslint-disable-line comma-spacing
+ const [, , tasklist, , , ,] = listItemText.match(INLINE_UPDATE_REG) || [] // eslint-disable-line comma-spacing
return this.updateTaskListItem(block, 'tasklist', tasklist)
} else {
return block
diff --git a/src/muya/lib/utils/cumputeCheckBoxStatus.js b/src/muya/lib/utils/cumputeCheckBoxStatus.js
new file mode 100644
index 00000000..2678baf1
--- /dev/null
+++ b/src/muya/lib/utils/cumputeCheckBoxStatus.js
@@ -0,0 +1,11 @@
+export const cumputeCheckboxStatus = function (parentCheckbox) {
+ const children = parentCheckbox.parentElement.lastElementChild.children
+ const len = children.length
+ for (let i = 0; i < len; i++) {
+ const checkbox = children[i].firstElementChild
+ if (checkbox.checked === false) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/muya/lib/utils/getParentCheckBox.js b/src/muya/lib/utils/getParentCheckBox.js
new file mode 100644
index 00000000..bde97241
--- /dev/null
+++ b/src/muya/lib/utils/getParentCheckBox.js
@@ -0,0 +1,10 @@
+import { CLASS_OR_ID } from '../config'
+
+export const getParentCheckBox = function (checkbox) {
+ const parent = checkbox.parentElement.parentElement.parentElement
+ if (parent.id !== CLASS_OR_ID.AG_EDITOR_ID) {
+ return parent.firstElementChild
+ } else {
+ return null
+ }
+}
diff --git a/src/renderer/components/editorWithTabs/editor.vue b/src/renderer/components/editorWithTabs/editor.vue
index 91fe316e..139f435d 100644
--- a/src/renderer/components/editorWithTabs/editor.vue
+++ b/src/renderer/components/editorWithTabs/editor.vue
@@ -147,6 +147,7 @@ export default {
editorFontFamily: state => state.preferences.editorFontFamily,
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
hideLinkPopup: state => state.preferences.hideLinkPopup,
+ autoCheck: state => state.preferences.autoCheck,
editorLineWidth: state => state.preferences.editorLineWidth,
imageInsertAction: state => state.preferences.imageInsertAction,
imageFolderPath: state => state.preferences.imageFolderPath,
@@ -319,6 +320,12 @@ export default {
editor.setOptions({ hideLinkPopup: value })
}
},
+ autoCheck: function (value, oldValue) {
+ const { editor } = this
+ if (value !== oldValue && editor) {
+ editor.setOptions({ autoCheck: value })
+ }
+ },
codeFontSize: function (value, oldValue) {
if (value !== oldValue) {
addCommonStyle({
@@ -477,7 +484,8 @@ export default {
theme,
sequenceTheme,
spellcheckerEnabled,
- hideLinkPopup
+ hideLinkPopup,
+ autoCheck
} = this
// use muya UI plugins
@@ -520,6 +528,7 @@ export default {
footnote,
hideQuickInsertHint,
hideLinkPopup,
+ autoCheck,
sequenceTheme,
spellcheckEnabled: spellcheckerEnabled,
imageAction: this.imageAction.bind(this),
diff --git a/src/renderer/prefComponents/editor/index.vue b/src/renderer/prefComponents/editor/index.vue
index 7ad78612..0207e4f5 100644
--- a/src/renderer/prefComponents/editor/index.vue
+++ b/src/renderer/prefComponents/editor/index.vue
@@ -109,6 +109,11 @@
:bool="hideLinkPopup"
:onChange="value => onSelectChange('hideLinkPopup', value)"
>
+
state.preferences.trimUnnecessaryCodeBlockEmptyLines,
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
hideLinkPopup: state => state.preferences.hideLinkPopup,
+ autoCheck: state => state.preferences.autoCheck,
editorLineWidth: state => state.preferences.editorLineWidth,
defaultEncoding: state => state.preferences.defaultEncoding,
autoGuessEncoding: state => state.preferences.autoGuessEncoding,
diff --git a/src/renderer/store/preferences.js b/src/renderer/store/preferences.js
index bdf6b551..c2b23e17 100644
--- a/src/renderer/store/preferences.js
+++ b/src/renderer/store/preferences.js
@@ -36,6 +36,7 @@ const state = {
hideQuickInsertHint: false,
imageInsertAction: 'folder',
hideLinkPopup: false,
+ autoCheck: false,
preferLooseListItem: true,
bulletListMarker: '-',
diff --git a/static/preference.json b/static/preference.json
index a068583a..019de891 100644
--- a/static/preference.json
+++ b/static/preference.json
@@ -32,6 +32,7 @@
"hideQuickInsertHint": false,
"imageInsertAction": "path",
"hideLinkPopup": false,
+ "autoCheck": false,
"preferLooseListItem": true,
"bulletListMarker": "-",