WaniKani Markdown Editor Notes (2023)

Write Markdown and HTML in the notes

目前为 2023-06-18 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name WaniKani Markdown Editor Notes (2023)
  3. // @namespace wanikani
  4. // @description Write Markdown and HTML in the notes
  5. // @version 2.0.1
  6. // @require https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js
  7. // @require https://unpkg.com/dexie@3/dist/dexie.js
  8. // @require https://gf.qytechs.cn/scripts/430565-wanikani-item-info-injector/code/WaniKani%20Item%20Info%20Injector.user.js?version=1207013
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=markdownguide.org
  10. // @match *://www.wanikani.com/*
  11. // @match *://preview.wanikani.com/*
  12. // @license MIT
  13. // @homepage https://gf.qytechs.cn/en/scripts/468764-wanikani-markdown-editor-notes-2023
  14. // @source https://github.com/patarapolw/wanikani-userscript/blob/master/userscripts/markdown-notes.user.js
  15. // @supportURL https://community.wanikani.com/t/userscript-markdown-editor-notes-2023/62246
  16. // @grant none
  17. // ==/UserScript==
  18.  
  19. // @ts-check
  20. /// <reference path="./types/item-info.d.ts" />
  21. (function () {
  22. 'use strict';
  23.  
  24. const entryClazz = 'wk-markdown-notes';
  25.  
  26. // @ts-ignore
  27. const _Dexie = /** @type {typeof import('dexie').default} */ (Dexie);
  28. /**
  29. * @typedef {{ id: number; state: any; markdown: string }} EntryMarkdown
  30. */
  31.  
  32. class Database extends _Dexie {
  33. /** @type {import('dexie').Table<EntryMarkdown, number>} */
  34. markdown;
  35.  
  36. constructor() {
  37. super(entryClazz);
  38. this.version(1).stores({
  39. markdown: 'id',
  40. });
  41. }
  42. }
  43.  
  44. const db = new Database();
  45.  
  46. /** @type {HTMLElement} */
  47. let elEditor;
  48. /** @type {import('@toast-ui/editor').Editor} */
  49. let editor;
  50. /** @type {WKItemInfoState} */
  51. let state;
  52.  
  53. const injector = wkItemInfo
  54. .under('meaning,reading')
  55. .spoiling('nothing')
  56. .append('Markdown Notes', (o) => {
  57. if (editor) {
  58. save();
  59. }
  60.  
  61. state = o;
  62.  
  63. const onElLoaded = () => {
  64. db.markdown.get(state.id).then((entry) => {
  65. if (editor) {
  66. editor.setMarkdown(entry?.markdown || '');
  67. setTimeout(() => {
  68. editor.blur();
  69. });
  70. } else {
  71. /** @type {import('@toast-ui/editor').EditorOptions} */
  72. const opts = {
  73. el: elEditor,
  74. initialEditType: 'markdown',
  75. previewStyle: 'vertical',
  76. hideModeSwitch: true,
  77. linkAttributes: {
  78. target: '_blank',
  79. },
  80. previewHighlight: false,
  81. customHTMLSanitizer: (s) => {
  82. return s;
  83. },
  84. autofocus: false,
  85. initialValue: entry?.markdown,
  86. };
  87.  
  88. // @ts-ignore
  89. editor = new toastui.Editor(opts);
  90.  
  91. const elSave = document.createElement('button');
  92. elSave.type = 'button';
  93. elSave.className = 'fa fa-save save-button';
  94.  
  95. elSave.onclick = () => {
  96. elSave.classList.add(isClickedClass);
  97. save();
  98. setTimeout(() => {
  99. elSave.classList.remove(isClickedClass);
  100. }, 100);
  101. };
  102.  
  103. editor.insertToolbarItem(
  104. { groupIndex: -1, itemIndex: -1 },
  105. {
  106. name: 'Save',
  107. el: elSave,
  108. },
  109. );
  110.  
  111. editor.on('blur', () => {
  112. save();
  113. });
  114. }
  115. });
  116. };
  117.  
  118. if (!elEditor) {
  119. elEditor = document.createElement('div');
  120. elEditor.id = 'wk-markdown-editor';
  121. elEditor.lang = 'ja';
  122. elEditor.onkeydown = (ev) => {
  123. ev.stopImmediatePropagation();
  124. ev.stopPropagation();
  125. };
  126. }
  127.  
  128. onElLoaded();
  129.  
  130. return elEditor;
  131. });
  132.  
  133. window.addEventListener('willShowNextQuestion', () => {
  134. injector.renew();
  135. });
  136.  
  137. function save() {
  138. if (editor) {
  139. db.markdown.put(
  140. { id: state.id, state, markdown: editor.getMarkdown() },
  141. state.id,
  142. );
  143.  
  144. if (!elEditor) {
  145. editor.destroy();
  146. }
  147. }
  148. }
  149.  
  150. const isClickedClass = 'is-clicked';
  151.  
  152. add_css(/* css */ `
  153. @import url("https://uicdn.toast.com/editor/latest/toastui-editor.min.css");
  154.  
  155. .toastui-editor-defaultUI {
  156. background-color: #fff;
  157. }
  158.  
  159. .toastui-editor-defaultUI button.save-button {
  160. position: relative;
  161. background: transparent;
  162. font-size: 1em;
  163. bottom: 0.5em;
  164. }
  165.  
  166. .toastui-editor-defaultUI button.save-button.${isClickedClass} {
  167. background-color: gray;
  168. }
  169. `);
  170.  
  171. function add_css(css) {
  172. const style = document.createElement('style');
  173. style.append(document.createTextNode(css));
  174. document.head.append(style);
  175. }
  176. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址