Simple text editor based on tiptap. HTML format.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

439 lignes
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>