Simple text editor based on tiptap. HTML format.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

439 lines
13 KiB

  1. <template>
  2. <div class="editor">
  3. <div id="file_actions">
  4. <button id="input_button" onclick="document.getElementById('input').click()"></button>
  5. <button id="output_button" v-on:click="saveFile"></button>
  6. <input type="file" style="display:none;" id="input" v-on:change="loadFile()">
  7. </div>
  8. <div class="editor-main">
  9. <editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
  10. <div>
  11. <div class="menubar char-menubar">
  12. <ul>
  13. <li>
  14. Mot
  15. <ul>
  16. <li>
  17. <button
  18. class="menubar__button"
  19. :class="{ 'is-active': isActive.customstyle({ type: 'acronym' }) }"
  20. @click="commands.customstyle({ type: 'acronym' })">
  21. Acronyme
  22. </button>
  23. </li>
  24. <li>
  25. <button
  26. class="menubar__button"
  27. :class="{ 'is-active': isActive.customstyle({ type: 'foreign' }) }"
  28. @click="commands.customstyle({ type: 'foreign' })">
  29. Étranger
  30. </button>
  31. </li>
  32. </ul>
  33. </li>
  34. <li>
  35. Nom
  36. <ul>
  37. <li>
  38. <button
  39. class="menubar__button"
  40. :class="{ 'is-active': isActive.customstyle({ type: 'author-quotation' }) }"
  41. @click="commands.customstyle({ type: 'author-quotation' })">
  42. Auteur - Citation
  43. </button>
  44. </li>
  45. <li>
  46. <button
  47. class="menubar__button"
  48. :class="{ 'is-active': isActive.customstyle({ type: 'author-work' }) }"
  49. @click="commands.customstyle({ type: 'author-work' })">
  50. Auteur - Œuvre
  51. </button>
  52. </li>
  53. <li>
  54. <button
  55. class="menubar__button"
  56. :class="{ 'is-active': isActive.customstyle({ type: 'brand' }) }"
  57. @click="commands.customstyle({ type: 'brand' })">
  58. Marque
  59. </button>
  60. </li>
  61. <li>
  62. <button
  63. class="menubar__button"
  64. :class="{ 'is-active': isActive.customstyle({ type: 'proper-noun' }) }"
  65. @click="commands.customstyle({ type: 'proper-noun' })">
  66. Nom propre
  67. </button>
  68. </li>
  69. </ul>
  70. </li>
  71. <li>
  72. Numéral
  73. <ul>
  74. <li>
  75. <button
  76. class="menubar__button"
  77. :class="{ 'is-active': isActive.customstyle({ type: 'century' }) }"
  78. @click="commands.customstyle({ type: 'century' })">
  79. Siècle
  80. </button>
  81. </li>
  82. <li>
  83. <button
  84. class="menubar__button"
  85. :class="{ 'is-active': isActive.customstyle({ type: 'date' }) }"
  86. @click="commands.customstyle({ type: 'date' })">
  87. Date
  88. </button>
  89. </li>
  90. <li>
  91. <button
  92. class="menubar__button"
  93. :class="{ 'is-active': isActive.customstyle({ type: 'chapter' }) }"
  94. @click="commands.customstyle({ type: 'chapter' })">
  95. Chapitre
  96. </button>
  97. </li>
  98. </ul>
  99. </li>
  100. <li>
  101. Typo
  102. <ul>
  103. <li>
  104. <button
  105. class="menubar__button"
  106. :class="{ 'is-active': isActive.subscriptstyle() }"
  107. @click="commands.subscriptstyle()">
  108. Indice
  109. </button>
  110. </li>
  111. <li>
  112. <button
  113. class="menubar__button"
  114. :class="{ 'is-active': isActive.superscriptstyle() }"
  115. @click="commands.superscriptstyle()">
  116. Exposant
  117. </button>
  118. </li>
  119. </ul>
  120. </li>
  121. </ul>
  122. </div>
  123. <div class="menubar paragraph-menubar">
  124. <button
  125. class="menubar__button"
  126. :class="{ 'is-active': isActive.paragraph() }"
  127. @click="commands.paragraph">
  128. </button>
  129. <button
  130. class="menubar__button"
  131. :class="{ 'is-active': isActive.heading({ level: 1 }) }"
  132. @click="commands.heading({ level: 1 })">
  133. T1
  134. </button>
  135. <button
  136. class="menubar__button"
  137. :class="{ 'is-active': isActive.heading({ level: 2 }) }"
  138. @click="commands.heading({ level: 2 })">
  139. T2
  140. </button>
  141. <button
  142. class="menubar__button"
  143. :class="{ 'is-active': isActive.heading({ level: 3 }) }"
  144. @click="commands.heading({ level: 3 })">
  145. T3
  146. </button>
  147. <button
  148. class="menubar__button"
  149. :class="{ 'is-active': isActive.heading({ level: 3 }) }"
  150. @click="commands.heading({ level: 3 })">
  151. T4
  152. </button>
  153. <button
  154. class="menubar__button"
  155. :class="{ 'is-active': isActive.blockquote() }"
  156. @click="commands.blockquote">
  157. « »
  158. </button>
  159. </div>
  160. </div>
  161. </editor-menu-bar>
  162. <!--
  163. <editor-menu-bubble class="menububble" :editor="editor" @hide="hideLinkMenu" v-slot="{ commands, isActive, getMarkAttrs, menu }">
  164. <div
  165. class="menububble"
  166. :class="{ 'is-active': menu.isActive }"
  167. :style="`left: ${menu.left}px; bottom: ${menu.bottom}px;`"
  168. >
  169. <form class="menububble__form" v-if="linkMenuIsActive" @submit.prevent="setLinkUrl(commands.link, linkUrl)">
  170. <input class="menububble__input" type="text" v-model="linkUrl" placeholder="https://" ref="linkInput" @keydown.esc="hideLinkMenu"/>
  171. <button class="menububble__button" @click="setLinkUrl(commands.link, null)" type="button">
  172. DEL
  173. </button>
  174. </form>
  175. <template v-else>
  176. <button
  177. class="menububble__button"
  178. @click="showLinkMenu(getMarkAttrs('link'))"
  179. :class="{ 'is-active': isActive.link() }"
  180. >
  181. <span>{{ isActive.link() ? 'Update Link' : 'Add Link'}}</span>
  182. LINK
  183. </button>
  184. </template>
  185. <button
  186. class="menubar__button"
  187. :class="{ 'is-active': isActive.paragraph() }"
  188. @click="commands.paragraph"
  189. >
  190. </button>
  191. <button
  192. class="menubar__button"
  193. :class="{ 'is-active': isActive.heading({ level: 1 }) }"
  194. @click="commands.heading({ level: 1 })"
  195. >
  196. H1
  197. </button>
  198. <button
  199. class="menubar__button"
  200. :class="{ 'is-active': isActive.heading({ level: 2 }) }"
  201. @click="commands.heading({ level: 2 })"
  202. >
  203. H2
  204. </button>
  205. <button
  206. class="menubar__button"
  207. :class="{ 'is-active': isActive.heading({ level: 3 }) }"
  208. @click="commands.heading({ level: 3 })"
  209. >
  210. H3
  211. </button>
  212. <button
  213. class="menubar__button"
  214. :class="{ 'is-active': isActive.bullet_list() }"
  215. @click="commands.bullet_list"
  216. >
  217. ul
  218. </button>
  219. <button
  220. class="menubar__button"
  221. :class="{ 'is-active': isActive.ordered_list() }"
  222. @click="commands.ordered_list"
  223. >
  224. ol
  225. </button>
  226. <button
  227. class="menubar__button"
  228. :class="{ 'is-active': isActive.blockquote() }"
  229. @click="commands.blockquote"
  230. >
  231. ""
  232. </button>
  233. <button
  234. class="menubar__button"
  235. :class="{ 'is-active': isActive.customstyle({ type: 'dede' }) }"
  236. @click="commands.customstyle({ type: 'dede' })">DeDe</button>
  237. </div>
  238. </editor-menu-bubble>
  239. -->
  240. <!--
  241. <editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
  242. <div class="menubar">
  243. </div>
  244. </editor-menu-bar>-->
  245. <editor-content class="editor__content" :editor="editor" />
  246. </div>
  247. </div>
  248. </template>
  249. <script>
  250. import { Editor, EditorContent, EditorMenuBar } from 'tiptap'
  251. import {
  252. Blockquote,
  253. Heading,
  254. OrderedList,
  255. BulletList,
  256. ListItem,
  257. Link
  258. } from 'tiptap-extensions'
  259. import CustomStyle from "./extensions/CustomStyle";
  260. import SubscriptStyle from "./extensions/SubscriptStyle";
  261. import SuperscriptStyle from "./extensions/SuperscriptStyle";
  262. export default {
  263. components: {
  264. EditorContent,
  265. EditorMenuBar
  266. },
  267. data() {
  268. return {
  269. keepInBounds: true,
  270. editor: new Editor({
  271. extensions: [
  272. new Blockquote(),
  273. new BulletList(),
  274. new Heading({ levels: [1, 2, 3] }),
  275. new ListItem(),
  276. new OrderedList(),
  277. new Link(),
  278. new CustomStyle(),
  279. new SuperscriptStyle(),
  280. new SubscriptStyle()
  281. ],
  282. content: `
  283. Soit un <a href="https://fr.wiktionary.org/wiki/moment">moment</a> de <a href="https://fr.wikipedia.org/wiki/Perception">perception</a> &amp; son ouverture <a href="https://fr.wikipedia.org/wiki/Philosophie_de_la_perception">philosophique</a>. Pour cela, avoir accès à une connexion <a href="https://fr.wikipedia.org/wiki/Internet">internet</a> &amp; installer, sur l’ordinateur exploité pour s’y connecter, un <a href="https://fr.wikipedia.org/wiki/Navigateur_web">navigateur</a> pour consulter le [web](<a href="https://fr.wikipedia.org/wiki/World_Wide_Web">World Wide Web — Wikipédia</a>). Cette consultation se concrétise par la surface d’un écran où nous sont perceptibles des pages d’informations de diverses natures (iconographique, vidéo ou <a href="https://fr.wiktionary.org/wiki/textuel">textuelle</a>) dédiées à notre <a href="https://fr.wiktionary.org/wiki/aspectus#la"><em>aspectus</em></a>. Ces informations nous sont disponibles dans l’espace de l’écran sous différents <a href="https://fr.wiktionary.org/wiki/aspect">aspects</a>, résultats de la <a href="https://fr.wiktionary.org/wiki/mani%C3%A8re">manière</a> dont elles ont été <a href="https://fr.wiktionary.org/wiki/former">formées</a>.
  284. `,
  285. }),
  286. linkUrl: null,
  287. linkMenuIsActive: false,
  288. }
  289. },
  290. beforeDestroy() {
  291. this.editor.destroy()
  292. },
  293. methods: {
  294. loadFile: function () {
  295. let ed = this.editor;
  296. let fr = new FileReader();
  297. fr.onload = function() {
  298. console.log(fr.result);
  299. ed.setContent(fr.result)
  300. };
  301. fr.readAsText(document.getElementById('input').files[0]);
  302. },
  303. saveFile: function(){
  304. console.log(this.editor.getHTML())
  305. },
  306. showLinkMenu(attrs) {
  307. this.linkUrl = attrs.href
  308. this.linkMenuIsActive = true
  309. this.$nextTick(() => {
  310. this.$refs.linkInput.focus()
  311. })
  312. },
  313. hideLinkMenu() {
  314. this.linkUrl = null
  315. this.linkMenuIsActive = false
  316. },
  317. setLinkUrl(command, url) {
  318. command({ href: url })
  319. this.hideLinkMenu()
  320. }
  321. }
  322. }
  323. </script>
  324. <style lang="scss">
  325. @import '../assets/menubar.scss';
  326. @import '../assets/dedediteur.css';
  327. .menubar{
  328. text-align: center;
  329. margin-top: 12px;
  330. }
  331. #file_actions{
  332. /*border-bottom : 1px solid #2c3e50;*/
  333. padding : 12px;
  334. position: fixed;
  335. top: 10px;
  336. left: 10px;
  337. }
  338. #output_button, #input_button{
  339. border : 1px solid black;
  340. width: 24px;
  341. height: 24px;
  342. }
  343. #input_button{
  344. background-color: white;
  345. }
  346. #output_button{
  347. background-color: black;
  348. margin-left: 12px;
  349. }
  350. /* editor*/
  351. .editor{
  352. position: relative;
  353. }
  354. .ProseMirror:read-write:focus {
  355. outline: none;
  356. }
  357. /*menububble */
  358. .menububble{
  359. /*visibility: hidden;*/
  360. background-color: black;
  361. border-radius: 5px;
  362. z-index: 100;
  363. padding: 5px;
  364. position: absolute;
  365. bottom: 25px;
  366. }
  367. .menububble.is-active{
  368. visibility: visible;
  369. }
  370. .menububble button{
  371. background-color: black;
  372. border: none;
  373. color : white;
  374. border-radius: 5px;
  375. }
  376. </style>