checkpoint

This commit is contained in:
evilchili 2026-04-28 16:18:22 -07:00
parent d28b31ed14
commit ce8042759e
3 changed files with 386 additions and 101 deletions

View File

@ -7,21 +7,38 @@
--toolbar-height: 32px !important;
--toolbar-spacing: 5px !important;
--toolbar-button-size: 24px;
--toolbar-icon-size: 16px;
--toolbar-button-size: 32px;
--toolbar-button-enabled-background: rgba(128, 192, 128);
--toolbar-button-active-background: rgba(192, 255, 192);
--toolbar-button-enabled-border: 1px solid #000;
/* Icons by Flaticon: https://www.flaticon.com/uicons */
--toolbar-icon-bold: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M17.954,10.663A6.986,6.986,0,0,0,12,0H5A2,2,0,0,0,3,2V22a2,2,0,0,0,2,2H15a6.994,6.994,0,0,0,2.954-13.337ZM7,4h5a3,3,0,0,1,0,6H7Zm8,16H7V14h8a3,3,0,0,1,0,6Z"/></svg>');
--toolbar-icon-italic: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M20,0H7A1,1,0,0,0,7,2h5.354L9.627,22H4a1,1,0,0,0,0,2H17a1,1,0,0,0,0-2H11.646L14.373,2H20a1,1,0,0,0,0-2Z"/></svg>');
--toolbar-icon-underline: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M12,20a8.009,8.009,0,0,0,8-8V1a1,1,0,0,0-2,0V12A6,6,0,0,1,6,12V1A1,1,0,0,0,4,1V12A8.009,8.009,0,0,0,12,20Z"/><path d="M23,22H1a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/></svg>');
--toolbar-icon-bullet_list: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M7,6H23a1,1,0,0,0,0-2H7A1,1,0,0,0,7,6Z"/><path d="M23,11H7a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/><path d="M23,18H7a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/><circle cx="2" cy="5" r="2"/><circle cx="2" cy="12" r="2"/><circle cx="2" cy="19" r="2"/></svg>');
--toolbar-icon-center: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M1,6H23a1,1,0,0,0,0-2H1A1,1,0,0,0,1,6Z"/><path d="M5,9a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z"/><path d="M19,19H5a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z"/><path d="M23,14H1a1,1,0,0,0,0,2H23a1,1,0,0,0,0-2Z"/></svg>');
--toolbar-icon-bold: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M8.21 13c2.106 0 3.412-1.087 3.412-2.823 0-1.306-.984-2.283-2.324-2.386v-.055a2.176 2.176 0 0 0 1.852-2.14c0-1.51-1.162-2.46-3.014-2.46H3.843V13zM5.908 4.674h1.696c.963 0 1.517.451 1.517 1.244 0 .834-.629 1.32-1.73 1.32H5.908V4.673zm0 6.788V8.598h1.73c1.217 0 1.88.492 1.88 1.415 0 .943-.643 1.449-1.832 1.449H5.907z"/></svg>');
--toolbar-icon-italic: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M7.991 11.674 9.53 4.455c.123-.595.246-.71 1.347-.807l.11-.52H7.211l-.11.52c1.06.096 1.128.212 1.005.807L6.57 11.674c-.123.595-.246.71-1.346.806l-.11.52h3.774l.11-.52c-1.06-.095-1.129-.211-1.006-.806z"/></svg>');
/*
--toolbar-icon-underline: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M5.313 3.136h-1.23V9.54c0 2.105 1.47 3.623 3.917 3.623s3.917-1.518 3.917-3.623V3.136h-1.23v6.323c0 1.49-.978 2.57-2.687 2.57s-2.687-1.08-2.687-2.57zM12.5 15h-9v-1h9z"/></svg>');
*/
--toolbar-icon-h1: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M7.648 13V3H6.3v4.234H1.348V3H0v10h1.348V8.421H6.3V13zM14 13V3h-1.333l-2.381 1.766V6.12L12.6 4.443h.066V13z"/></svg>');
--toolbar-icon-h2: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M7.495 13V3.201H6.174v4.15H1.32V3.2H0V13h1.32V8.513h4.854V13zm3.174-7.071v-.05c0-.934.66-1.752 1.801-1.752 1.005 0 1.76.639 1.76 1.651 0 .898-.582 1.58-1.12 2.19l-3.69 4.2V13h6.331v-1.149h-4.458v-.079L13.9 8.786c.919-1.048 1.666-1.874 1.666-3.101C15.565 4.149 14.35 3 12.499 3 10.46 3 9.384 4.393 9.384 5.879v.05z"/></svg>');
--toolbar-icon-h3: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M11.07 8.4h1.049c1.174 0 1.99.69 2.004 1.724s-.802 1.786-2.068 1.779c-1.11-.007-1.905-.605-1.99-1.357h-1.21C8.926 11.91 10.116 13 12.028 13c1.99 0 3.439-1.188 3.404-2.87-.028-1.553-1.287-2.221-2.096-2.313v-.07c.724-.127 1.814-.935 1.772-2.293-.035-1.392-1.21-2.468-3.038-2.454-1.927.007-2.94 1.196-2.981 2.426h1.23c.064-.71.732-1.336 1.744-1.336 1.027 0 1.744.64 1.744 1.568.007.95-.738 1.639-1.744 1.639h-.991V8.4ZM7.495 13V3.201H6.174v4.15H1.32V3.2H0V13h1.32V8.513h4.854V13z"/></svg>');
--toolbar-icon-h4: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M13.007 3H15v10h-1.29v-2.051H8.854v-1.18C10.1 7.513 11.586 5.256 13.007 3m-2.82 6.777h3.524v-5.62h-.074a95 95 0 0 0-3.45 5.554zM7.495 13V3.201H6.174v4.15H1.32V3.2H0V13h1.32V8.513h4.854V13z"/></svg>');
--toolbar-icon-h5: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M9 10.516h1.264c.193.976 1.112 1.364 2.01 1.364 1.005 0 2.067-.782 2.067-2.247 0-1.292-.983-2.082-2.089-2.082-1.012 0-1.658.596-1.924 1.077h-1.12L9.646 3h5.535v1.141h-4.415L10.5 7.28h.072c.201-.316.883-.84 1.967-.84 1.709 0 3.13 1.177 3.13 3.158 0 2.025-1.407 3.403-3.475 3.403-1.809 0-3.1-1.048-3.194-2.484ZM7.495 13V3.201H6.174v4.15H1.32V3.2H0V13h1.32V8.512h4.854V13z"/></svg>');
--toolbar-icon-h6: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M15.596 5.178H14.3c-.106-.444-.62-1.072-1.706-1.072-1.332 0-2.325 1.269-2.325 3.947h.07c.268-.67 1.043-1.445 2.445-1.445 1.494 0 3.017 1.064 3.017 3.073C15.8 11.795 14.37 13 12.48 13c-1.036 0-2.093-.36-2.77-1.452C9.276 10.836 9 9.808 9 8.37 9 4.656 10.494 3 12.636 3c1.812 0 2.883 1.113 2.96 2.178m-5.151 4.566c0 1.367.944 2.15 2.043 2.15 1.128 0 2.037-.684 2.037-2.136 0-1.41-1-2.065-2.03-2.065-1.19 0-2.05.853-2.05 2.051M7.495 13V3.201H6.174v4.15H1.32V3.2H0V13h1.32V8.513h4.854V13z"/></svg>');
--toolbar-icon-unordered_list: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg>');
--toolbar-icon-ordered_list: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5"/><path d="M1.713 11.865v-.474H2c.217 0 .363-.137.363-.317 0-.185-.158-.31-.361-.31-.223 0-.367.152-.373.31h-.59c.016-.467.373-.787.986-.787.588-.002.954.291.957.703a.595.595 0 0 1-.492.594v.033a.615.615 0 0 1 .569.631c.003.533-.502.8-1.051.8-.656 0-1-.37-1.008-.794h.582c.008.178.186.306.422.309.254 0 .424-.145.422-.35-.002-.195-.155-.348-.414-.348h-.3zm-.004-4.699h-.604v-.035c0-.408.295-.844.958-.844.583 0 .96.326.96.756 0 .389-.257.617-.476.848l-.537.572v.03h1.054V9H1.143v-.395l.957-.99c.138-.142.293-.304.293-.508 0-.18-.147-.32-.342-.32a.33.33 0 0 0-.342.338zM2.564 5h-.635V2.924h-.031l-.598.42v-.567l.629-.443h.635z"/></svg>');
--toolbar-icon-line: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M2 8a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11A.5.5 0 0 1 2 8"/></svg>');
--toolbar-icon-quote: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M2.5 3a.5.5 0 0 0 0 1h11a.5.5 0 0 0 0-1zm5 3a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1zm0 3a.5.5 0 0 0 0 1h6a.5.5 0 0 0 0-1zm-5 3a.5.5 0 0 0 0 1h11a.5.5 0 0 0 0-1zm.79-5.373q.168-.117.444-.275L3.524 6q-.183.111-.452.287-.27.176-.51.428a2.4 2.4 0 0 0-.398.562Q2 7.587 2 7.969q0 .54.217.873.217.328.72.328.322 0 .504-.211a.7.7 0 0 0 .188-.463q0-.345-.211-.521-.205-.182-.568-.182h-.282q.036-.305.123-.498a1.4 1.4 0 0 1 .252-.37 2 2 0 0 1 .346-.298zm2.167 0q.17-.117.445-.275L5.692 6q-.183.111-.452.287-.27.176-.51.428a2.4 2.4 0 0 0-.398.562q-.165.31-.164.692 0 .54.217.873.217.328.72.328.322 0 .504-.211a.7.7 0 0 0 .188-.463q0-.345-.211-.521-.205-.182-.568-.182h-.282a1.8 1.8 0 0 1 .118-.492q.087-.194.257-.375a2 2 0 0 1 .346-.3z"/></svg>');
--toolbar-icon-link: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1 1 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4 4 0 0 1-.128-1.287z"/><path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243z"/></svg>');
--toolbar-icon-table: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 2h-4v3h4zm0 4h-4v3h4zm0 4h-4v3h3a1 1 0 0 0 1-1zm-5 3v-3H6v3zm-5 0v-3H1v2a1 1 0 0 0 1 1zm-4-4h4V8H1zm0-4h4V4H1zm5-3v3h4V4zm4 4H6v3h4z"/></svg>');
--toolbar-icon-macro: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M2.114 8.063V7.9c1.005-.102 1.497-.615 1.497-1.6V4.503c0-1.094.39-1.538 1.354-1.538h.273V2h-.376C3.25 2 2.49 2.759 2.49 4.352v1.524c0 1.094-.376 1.456-1.49 1.456v1.299c1.114 0 1.49.362 1.49 1.456v1.524c0 1.593.759 2.352 2.372 2.352h.376v-.964h-.273c-.964 0-1.354-.444-1.354-1.538V9.663c0-.984-.492-1.497-1.497-1.6M13.886 7.9v.163c-1.005.103-1.497.616-1.497 1.6v1.798c0 1.094-.39 1.538-1.354 1.538h-.273v.964h.376c1.613 0 2.372-.759 2.372-2.352v-1.524c0-1.094.376-1.456 1.49-1.456V7.332c-1.114 0-1.49-.362-1.49-1.456V4.352C13.51 2.759 12.75 2 11.138 2h-.376v.964h.273c.964 0 1.354.444 1.354 1.538V6.3c0 .984.492 1.497 1.497 1.6"/></svg>');
--toolbar-icon-macro_user: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/><path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"/></svg>');
--toolbar-icon-macro_toc: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2z"/><path d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8m0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m-1-5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0M4 8a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0m0 2.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0"/></svg>');
--toolbar-icon-macro_style: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16 16"><path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3m4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"/><path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8m-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7"/></svg>');
--toolbar-icon-markdown: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 16 16"><path d="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0m6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0"/></svg>');
--toolbar-icon-save: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.406 1.342A5.53 5.53 0 0 1 8 0c2.69 0 4.923 2 5.166 4.579C14.758 4.804 16 6.137 16 7.773 16 9.569 14.502 11 12.687 11H10a.5.5 0 0 1 0-1h2.688C13.979 10 15 8.988 15 7.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 2.825 10.328 1 8 1a4.53 4.53 0 0 0-2.941 1.1c-.757.652-1.153 1.438-1.153 2.055v.448l-.445.049C2.064 4.805 1 5.952 1 7.318 1 8.785 2.23 10 3.781 10H6a.5.5 0 0 1 0 1H3.781C1.708 11 0 9.366 0 7.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383"/><path fill-rule="evenodd" d="M7.646 4.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V14.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708z"/></svg>');
--toolbar-icon-toggle: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="m22.81,9.08c.807-.642,1.25-1.642,1.183-2.676-.067-1.05-.646-2.001-1.547-2.546-.772-.466-1.946-.892-3.574-1.297-.411-1.476-1.767-2.562-3.372-2.562-1.493,0-2.77.94-3.272,2.259C3.12,6.628.56,12.888.025,17.398c-.195,1.646.332,3.311,1.448,4.567,1.149,1.293,2.799,2.035,4.527,2.035h9c.552,0,1-.448,1-1s-.448-1-1-1h-2v-3c0-1.428.193-3.121.398-4.513l5.464,8.587c.369.579,1,.925,1.687.925h1.451c.552,0,1-.448,1-1s-.448-1-1-1h-1.451s-6.342-9.966-6.342-9.966c.116-.058.245-.095.383-.108,3.276-.294,6.349-1.358,8.22-2.846Zm-7.31-7.08c.827,0,1.5.673,1.5,1.5s-.673,1.5-1.5,1.5-1.5-.673-1.5-1.5.673-1.5,1.5-1.5Zm-3.783,10.367c-.143.797-.297,1.747-.426,2.745-1.189-1.297-2.897-2.112-4.791-2.112h-.5c-.552,0-1,.448-1,1s.448,1,1,1h.5c2.481,0,4.5,2.019,4.5,4.5v2.5h-5c-1.157,0-2.263-.497-3.032-1.363-.747-.841-1.087-1.908-.957-3.003.647-5.452,4.145-9.959,10.144-13.101.442,1.427,1.774,2.467,3.344,2.467,1.541,0,2.853-1.001,3.319-2.387,1.191.315,2.061.636,2.594.958.346.209.56.56.585.962.025.386-.133.744-.433.982-1.857,1.477-4.913,2.218-7.154,2.419-1.351.122-2.459,1.123-2.694,2.433Z" /></svg>');
--toolbar-icon-wysiwyg: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="m18 9.064a3.049 3.049 0 0 0 -.9-2.164 3.139 3.139 0 0 0 -4.334 0l-11.866 11.869a3.064 3.064 0 0 0 4.33 4.331l11.87-11.869a3.047 3.047 0 0 0 .9-2.167zm-14.184 12.624a1.087 1.087 0 0 1 -1.5 0 1.062 1.062 0 0 1 0-1.5l7.769-7.77 1.505 1.505zm11.872-11.872-2.688 2.689-1.5-1.505 2.689-2.688a1.063 1.063 0 1 1 1.5 1.5zm-10.825-6.961 1.55-.442.442-1.55a1.191 1.191 0 0 1 2.29 0l.442 1.55 1.55.442a1.191 1.191 0 0 1 0 2.29l-1.55.442-.442 1.55a1.191 1.191 0 0 1 -2.29 0l-.442-1.55-1.55-.442a1.191 1.191 0 0 1 0-2.29zm18.274 14.29-1.55.442-.442 1.55a1.191 1.191 0 0 1 -2.29 0l-.442-1.55-1.55-.442a1.191 1.191 0 0 1 0-2.29l1.55-.442.442-1.55a1.191 1.191 0 0 1 2.29 0l.442 1.55 1.55.442a1.191 1.191 0 0 1 0 2.29zm-5.382-14.645 1.356-.387.389-1.358a1.042 1.042 0 0 1 2 0l.387 1.356 1.356.387a1.042 1.042 0 0 1 0 2l-1.356.387-.387 1.359a1.042 1.042 0 0 1 -2 0l-.387-1.355-1.358-.389a1.042 1.042 0 0 1 0-2z"/></svg>');
--toolbar-icon-save: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill-rule="evenodd" clip-rule="evenodd" d="M18.1716 1C18.702 1 19.2107 1.21071 19.5858 1.58579L22.4142 4.41421C22.7893 4.78929 23 5.29799 23 5.82843V20C23 21.6569 21.6569 23 20 23H4C2.34315 23 1 21.6569 1 20V4C1 2.34315 2.34315 1 4 1H18.1716ZM4 3C3.44772 3 3 3.44772 3 4V20C3 20.5523 3.44772 21 4 21L5 21L5 15C5 13.3431 6.34315 12 8 12L16 12C17.6569 12 19 13.3431 19 15V21H20C20.5523 21 21 20.5523 21 20V6.82843C21 6.29799 20.7893 5.78929 20.4142 5.41421L18.5858 3.58579C18.2107 3.21071 17.702 3 17.1716 3H17V5C17 6.65685 15.6569 8 14 8H10C8.34315 8 7 6.65685 7 5V3H4ZM17 21V15C17 14.4477 16.5523 14 16 14L8 14C7.44772 14 7 14.4477 7 15L7 21L17 21ZM9 3H15V5C15 5.55228 14.5523 6 14 6H10C9.44772 6 9 5.55228 9 5V3Z" /></svg>');
}
#froghat[contenteditable] {
@ -39,6 +56,10 @@
}
#froghat.wysiwyg {
span {
display: inline;
border-bottom: 1px solid green;
}
}
main.editing {
@ -64,31 +85,77 @@ main.editing {
li {
padding: 0px;
padding-right: 5px;
margin: 0px;
margin: 2px;
text-align: center;
line-height: var(--toolbar-button-size);
width: var(--toolbar-button-size);
height: var(--toolbar-button-size);
a {
padding: var(--toolbar-spacing);
button {
opacity: 0.3;
display: block;
width: var(--toolbar-icon-size);
height: var(--toolbar-icon-size);
background-repeat: no-repeat;
background-attachment: local;
background-position: center;
background-size: 1.5rem 1.5rem;
border-radius: 5px;
border: 1px solid transparent;
width: var(--toolbar-button-size);
height: var(--toolbar-button-size);
}
#wysiwyg { background-image: var(--toolbar-icon-wysiwyg); }
#bold { background-image: var(--toolbar-icon-bold); }
#italic { background-image: var(--toolbar-icon-italic); }
#underline { background-image: var(--toolbar-icon-underline); }
#bullet_list { background-image: var(--toolbar-icon-bullet_list); }
#center { background-image: var(--toolbar-icon-center); }
button.enabled {
opacity: 1.0;
cursor: pointer;
}
button.on {
border: var(--toolbar-button-enabled-border);
background-color: var(--toolbar-button-enabled-background);
}
button:hover {
border: var(--toolbar-button-enabled-border);
background-color: var(--toolbar-button-active-background);
}
.dropdown-menu {
position-area: bottom;
margin: 0;
border: 0;
width: var(--toolbar-button-size);
min-height: var(--toolbar-button-size);
}
#bold { background-image: var(--toolbar-icon-bold); }
#italic { background-image: var(--toolbar-icon-italic); }
#underline { background-image: var(--toolbar-icon-underline); }
#header { background-image: var(--toolbar-icon-h1); anchor-name: "header"; }
#h1 { background-image: var(--toolbar-icon-h1); }
#h2 { background-image: var(--toolbar-icon-h2); }
#h3 { background-image: var(--toolbar-icon-h3); }
#h4 { background-image: var(--toolbar-icon-h4); }
#h5 { background-image: var(--toolbar-icon-h5); }
#h6 { background-image: var(--toolbar-icon-h6); }
#list { background-image: var(--toolbar-icon-unordered_list); anchor-name: "list"; }
#unordered_list { background-image: var(--toolbar-icon-unordered_list); }
#ordered_list { background-image: var(--toolbar-icon-ordered_list); }
#line { background-image: var(--toolbar-icon-line); }
#quote { background-image: var(--toolbar-icon-quote); }
#link { background-image: var(--toolbar-icon-link); }
#table { background-image: var(--toolbar-icon-table); }
#macro { background-image: var(--toolbar-icon-macro); anchor-name: "macro"}
#macro_user { background-image: var(--toolbar-icon-macro_user); }
#macro_toc { background-image: var(--toolbar-icon-macro_toc); }
#macro_style { background-image: var(--toolbar-icon-macro_style); }
#markdown { background-image: var(--toolbar-icon-markdown); }
#save { background-image: var(--toolbar-icon-save); }
#toggle {
background-color: var(--toolbar-button-enabled-background);
background-image: var(--toolbar-icon-toggle);
@ -105,7 +172,9 @@ main.editing {
border: var(--toolbar-button-enabled-border);
background-color: var(--toolbar-button-active-background);
}
#save { background-image: var(--toolbar-icon-save); }
#header-menu { position-anchor: "header"; }
#list-menu { position-anchor: "list"; }
}
li:last-child {
@ -120,20 +189,4 @@ main.editing {
border-radius: 0px;
border: 1px solid green;
border-bottom: 1px solid transparent;
ul {
li {
a {
opacity: 1.0;
cursor: pointer;
}
a.on {
border: var(--toolbar-button-enabled-border);
background-color: var(--toolbar-button-enabled-background);
}
a:hover {
border: var(--toolbar-button-enabled-border);
background-color: var(--toolbar-button-active-background);
}
}
}
}

View File

@ -1,27 +1,109 @@
function reEscape(string) {
return string.replaceAll('*', '\\*');
}
class ToolbarButton {
constructor(settings) {
this.id = settings.id;
this.element = settings.element || document.getElementById(this.id);
this.toolbar = settings.toolbar;
this.isMenu = settings.isMenu || false;
this.open = settings.open || '';
this.close = settings.close || '';
this.tag = settings.tag || null;
this.onclick = settings.onclick;
this.element.addEventListener('click', (e) => {
if (this.element.enabled) {
this.onclick({clickEvent: e, button: this });
if (!this.isMenu) {
if (this.open) {
var open = reEscape(this.open);
var close = this.close ? reEscape(this.close) : '';
var leading = '(?<leading>^(?:(?!' + open + ').)*)';
var middle = '(?<middle>(?:(?!' + open;
if (this.close && this.close != this.open) {
middle += '|' + close + ').)+)';
} else {
middle += ').)*)';
}
this.pattern = RegExp(
leading +
'(?<open>' + open + ')' +
middle +
(close ? '(?<closed>(?:' + close + ')(\\s.*?|$))' : '') +
'$'
);
console.log(this.id, this.pattern);
}
});
this.element.addEventListener('click', (e) => {
if (this.element.enabled) {
if (this.onclick) {
this.onclick({clickEvent: e, button: this });
} else if (this.toolbar.editor.isWysiwyg()) {
this.#applyHTMLFormatting();
} else if (this.toolbar.editor.isMarkdown()) {
this.#applyMarkdownFormatting();
}
}
document.querySelectorAll(".dropdown-menu:popover-open").forEach(el => {
el.hidePopover();
});
this.toolbar.editor.element.focus();
});
}
if (settings.enabled) {
this.enable();
}
}
#applyHTMLFormatting() {
if (!this.tag) {
return;
}
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var node = document.createElement(this.tag);
try {
range.surroundContents(node);
range.setStartAfter(node);
} catch(e) {
console.log(e);
}
selection.removeAllRanges();
selection.addRange(range);
this.toolbar.editor.moveCursorAfter(node);
}
#applyMarkdownFormatting() {
if (!this.open) {
return;
}
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var node = document.createTextNode(this.open + range.toString() + this.close);
range.deleteContents();
range.insertNode(node);
range.setStartAfter(node);
this.toolbar.editor.moveCursorAfter(node);
}
click() {
if (this.element.enabled) {
this.element.click();
}
}
enable() {
this.element.enabled = true;
this.element.classList.add('enabled');
}
disable() {
this.element.enabled = false;
this.element.classList.remove('enabled');
}
on() {
@ -37,42 +119,85 @@ class ToolbarButton {
}
}
class FroghatToolbar {
constructor(settings) {
this.editor = settings.editor;
this.element = settings.toolbar || document.getElementById('toolbar');
this.currentContext = null;
this.buttons = {
'bold': new ToolbarButton({ toolbar: this, id: 'bold', onclick: this.#click_bold }),
'italic': new ToolbarButton({ toolbar: this, id: 'italic', onclick: this.#click_italic }),
'underline': new ToolbarButton({ toolbar: this, id: 'underline', onclick: this.#click_underline }),
'bullet_list': new ToolbarButton({ toolbar: this, id: 'bullet_list', onclick: this.#click_bullet_list }),
'center': new ToolbarButton({ toolbar: this, id: 'center', onclick: this.#click_center }),
'save': new ToolbarButton({ toolbar: this, id: 'save', onclick: this.#click_save }),
'wysiwyg': new ToolbarButton({ toolbar: this, id: 'wysiwyg', onclick: this.#click_wysiwyg, enabled: true }),
'toggle': new ToolbarButton({ toolbar: this, id: 'toggle', onclick: this.#click_toggle, enabled: true })
'line': new ToolbarButton({ toolbar: this, id: 'line', open: '***', close: '', tag: 'HR'}),
'bold': new ToolbarButton({ toolbar: this, id: 'bold', open: '**', close: '**', tag: 'STRONG'}),
'italic': new ToolbarButton({ toolbar: this, id: 'italic', open: '*', close: '*', tag: 'EM'}),
'header': new ToolbarButton({ toolbar: this, id: 'header', isMenu: true}),
'h1': new ToolbarButton({ toolbar: this, id: 'h1', markdown: '# ', close: "", tag: 'H1' }),
'h2': new ToolbarButton({ toolbar: this, id: 'h2', markdown: '## ', close: "", tag: 'H2' }),
'h3': new ToolbarButton({ toolbar: this, id: 'h3', markdown: '### ', close: "", tag: 'H3' }),
'h4': new ToolbarButton({ toolbar: this, id: 'h4', markdown: '#### ', close: "", tag: 'H4' }),
'h5': new ToolbarButton({ toolbar: this, id: 'h5', markdown: '##### ', close: "", tag: 'H5' }),
'h6': new ToolbarButton({ toolbar: this, id: 'h6', markdown: '###### ', close: "", tag: 'H6' }),
'list': new ToolbarButton({ toolbar: this, id: 'list', isMenu: true}),
'unordered_list': new ToolbarButton({ toolbar: this, id: 'unordered_list', }),
'ordered_list': new ToolbarButton({ toolbar: this, id: 'ordered_list', }),
'link': new ToolbarButton({ toolbar: this, id: 'link', }),
'quote': new ToolbarButton({ toolbar: this, id: 'quote', }),
'table': new ToolbarButton({ toolbar: this, id: 'table', }),
'macro': new ToolbarButton({ toolbar: this, id: 'macro', isMenu: true}),
'macro_user': new ToolbarButton({ toolbar: this, id: 'macro_user', }),
'macro_toc': new ToolbarButton({ toolbar: this, id: 'macro_toc', }),
'macro_style': new ToolbarButton({ toolbar: this, id: 'macro_style', }),
'save': new ToolbarButton({ toolbar: this, id: 'save', onclick: this.#click_save }),
'markdown': new ToolbarButton({ toolbar: this, id: 'markdown', onclick: this.#click_markdown }),
'toggle': new ToolbarButton({ toolbar: this, id: 'toggle', onclick: this.#click_toggle, enabled: true })
}
}
#click_bold({clickEvent, button}) {
getContext() {
var context = null;
var node = window.getSelection().baseNode;
console.log({node});
Object.values(this.buttons).forEach(button => {
if (button.pattern) {
var closed = false;
var leading = "";
var matched = false;
matched = node.textContent.match(button.pattern);
if (matched && matched.groups) {
closed = matched.groups.closed;
leading = matched.groups.leading;
}
if (closed && matched.groups.middle) {
context = {
button: button,
closed: closed,
leading: leading,
node: node,
element: null
}
}
if (node.parentElement && node.parentElement.nodeName == button.tag) {
if (!context) {
context = {
button: button,
element: null
};
}
context.element = node.parentElement
}
if (context) {
return;
}
}
});
return context;
}
#click_italic({clickEvent, button}) {
}
#click_underline({clickEvent, button}) {
}
#click_bullet_list({clickEvent, button}) {
}
#click_center({clickEvent, button}) {
}
#click_save({clickEvent, button}) {
}
#click_wysiwyg({clickEvent, button}) {
button.toolbar.editor.toggleWysiwyg();
#click_markdown({clickEvent, button}) {
button.toolbar.editor.toggleMarkdown();
}
#click_toggle({clickEvent, button}) {
@ -80,14 +205,14 @@ class FroghatToolbar {
}
enable() {
button.toolbar.element.classList.add("enabled");
button.toolbar.buttons.forEach(button => { button.enable() });
this.element.classList.add("enabled");
Object.values(this.buttons).forEach(button => { button.enable() });
}
disable() {
button.toolbar.element.classList.remove("enabled");
button.toolbar.buttons.forEach(button => { button.disable() });
button.toolbar.buttons.toggle.enable();
this.element.classList.remove("enabled");
Object.values(this.buttons).forEach(button => { button.disable() });
this.buttons.toggle.enable();
}
}
@ -105,6 +230,8 @@ class FroghatEditor extends Froghat {
this.turndown = new TurndownService({
headingStyle: 'atx',
codeBlockStyle: 'fenced',
emDelimiter: '*',
strongDelimiter: '**',
});
this.turndown.use([turndownPluginGfm.gfm, turndownPluginGfm.tables]);
this.turndown.keep(['pre']);
@ -114,20 +241,71 @@ class FroghatEditor extends Froghat {
this.element.classList.add("loaded");
this.view();
}
#replaceWysiwygNode(context) {
var offset = context.leading.length || 0;
var slice = context.node.textContent.slice(offset);
var html = this.markdownToHTML(slice);
html = html.replace("<p>", "").replace("</p>", "");
var el = document.createElement("span");
el.innerHTML = context.leading + html;
console.log(el.innerHTML);
if (el.innerHTML != context.node.innerHTML) {
context.node.replaceWith(el);
}
return el;
}
#refreshMarkdownCache() {
if (this.cachedMarkdown != this.element.textContent) {
this.changed = true;
this.toolbar.buttons.save.enable();
this.cachedMarkdown = this.element.textContent;
}
}
#handleEditorChanges(evt) {
var context = this.toolbar.getContext();
if (!context) {
if (this.toolbar.currentContext) {
this.toolbar.currentContext.button.off();
this.toolbar.currentContext = null;
}
return;
}
if (this.toolbar.currentContext) {
this.toolbar.currentContext.button.off();
}
context.button.on();
this.toolbar.currentContext = context;
if (this.isWysiwyg()) {
if (context.closed) {
context.node = this.#replaceWysiwygNode(context);
context.button.off();
this.toolbar.currentContext = null;
this.toolbar.editor.moveCursorAfter(context.node);
}
} else if (context.button) {
context.button.on();
}
}
#bindEvents() {
this.element.addEventListener('keydown', (evt) => {
if (this.state === this.states.VIEW) {
if (! this.isEditing()) {
return;
}
if (this.cachedMarkdown != this.element.textContent) {
this.changed = true;
this.cachedMarkdown = this.element.textContent;
}
this.#refreshMarkdownCache();
this.#handleEditorChanges(evt);
});
};
toggleWysiwyg() {
toggleMarkdown() {
if (this.getState() === this.states.EDIT) {
this.wysiwyg();
} else {
@ -136,11 +314,12 @@ class FroghatEditor extends Froghat {
}
toggleView() {
this.toolbar.element.classList.toggle("enabled");
if (this.getState() === this.states.VIEW) {
this.toolbar.enable();
this.wysiwyg();
this.element.focus();
} else {
this.toolbar.disable();
this.view();
}
}
@ -183,7 +362,8 @@ class FroghatEditor extends Froghat {
}
});
this.setState(this.states.WYSIWYG);
this.toolbar.buttons.wysiwyg.on();
this.toolbar.buttons.markdown.off();
this.toolbar.buttons.markdown.enable();
document.getElementById("main").classList.add("editing");
}
@ -197,19 +377,45 @@ class FroghatEditor extends Froghat {
this.element.contentEditable = true;
this.element.innerHTML = encodeHtmlEntities(this.getMarkdown());
this.setState(this.states.EDIT);
this.toolbar.buttons.wysiwyg.off();
this.toolbar.buttons.markdown.on();
document.getElementById("main").classList.add("editing");
}
insertAtCursor(node) {
var sel, range, html;
sel = window.getSelection();
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode(node);
range.setStartAfter(node);
this.element.focus();
sel.removeAllRanges();
sel.addRange(range);
moveCursorAfter(node) {
var dummyElement = null;
if (!node.nextElementSibling) {
// workaround for https://issues.chromium.org/issues/41239578
var dummyElement = document.createElement('a');
dummyElement.innerHTML="&#x200B;";
dummyElement.className = 'bugfix';
node.parentNode.appendChild(dummyElement);
}
var nextElement = node.nextElementSibling;
nextElement.tabIndex=0;
nextElement.focus();
var range = document.createRange();
range.setStart(nextElement.childNodes[0], 1);
range.setEnd(nextElement.childNodes[0], 1);
var selection = window.getSelection();
console.log(range);
console.log(selection);
selection.removeAllRanges();
selection.addRange(range);
}
isWysiwyg() {
return this.state === this.states.WYSIWYG;
}
isMarkdown() {
return this.state === this.states.EDIT;
}
isEditing() {
return this.isWysiwyg() || this.isMarkdown();
}
}

View File

@ -1,17 +1,43 @@
<div class='main-aligned'>
<nav id='toolbar'>
<ul>
<li><a class='button' id='bold'></a></li>
<li><a class='button' id='italic'></a></li>
<li><a class='button' id='underline'></a></li>
<li>&nbsp;</li>
<li><a class='button' id='bullet_list'></a></li>
<li>&nbsp;</li>
<li><a class='button' id='center'></a></li>
<li>&nbsp;</li>
<li><a class='button' id='wysiwyg' alt='toggle WYSIWYG mode'></a></li>
<li><a class='button' id='save' alt='save'></a></li>
<li><a class='button' id='toggle' alt='toggle edit mode'></a></li>
<li><button id='bold'></button></li>
<li><button id='italic'></button></li>
<li>
<button id='header' popovertarget='header-menu'></button>
<div id='header-menu' class='dropdown-menu' popover>
<button id='h1'></button>
<button id='h2'></button>
<button id='h3'></button>
<button id='h4'></button>
<button id='h5'></button>
<button id='h6'></button>
</div>
</li>
<li><button id='link'></button></li>
<li class='spacer'></li>
<li><button id='line'></button></li>
<li>
<button id='list' popovertarget='list-menu'></button>
<div id='list-menu' class='dropdown-menu' popover>
<button id='unordered_list'></button>
<button id='ordered_list'></button>
</div>
</li>
<li><button id='quote'></button></li>
<li><button id='table'></button></li>
<li>
<button id='macro' popovertarget='macro-menu'></button>
<div id='macro-menu' class='dropdown-menu' popover>
<button id='macro_user'></button>
<button id='macro_toc'></button>
<button id='macro_style'></button>
</div>
</li>
<li class='spacer'></li>
<li><button id='markdown' alt='toggle markdown editor'></button></li>
<li><button id='save' alt='save'></button></li>
<li><button id='toggle' alt='toggle edit mode'></button></li>
</ul>
</nav>
</div>