joplock/public/tinymce/plugins/quickbars/plugin.min.js
igor 9fe3409b1c
Some checks are pending
Build and push Joplock image / build-and-push (push) Waiting to run
feat(editor): dual-mode editor — CodeMirror 6 markdown + TinyMCE 8 rendered
Squash-merge of the `tinymce` branch: replaces the previous editor with a
dual-mode setup backed by the hidden #note-body textarea.

- Rendered mode = TinyMCE 8 (persistent singleton over #tinymce-slot),
  markdown round-trip via Turndown (tinymceToMarkdown).
- Markdown mode = CodeMirror 6 mounted in #cm-host (initCM/getCM/
  cmSyncToTA/cmSetVal/mountMarkdownEditor); codemirror.min.js loaded
  before app.js. Full-screen CM6 code modal + language picker.
- Code highlighting: hljs in preview/markdown, Prism (codesample) in
  rendered mode.

Text expander + AI prose completion wired for both modes:
- Text triggers expand in CM6 and in TinyMCE.
- AI-action triggers and Ctrl/Cmd-Space run prose completion; in rendered
  mode the completion is offered in the same accept/dismiss popup as
  markdown mode (Enter/Tab insert, Esc discard), positioned at the iframe
  caret, inserted as DOM text nodes and synced to #note-body.

Uploads: upload modal + direct drag/paste into TinyMCE and CM6, admin
maxUploadMb limit with fast 413 pre-check, dropped images get a trailing
blank line, upload-reload sync.

Also included: per-user spellcheck toggle, runtime-toggleable debug
logging, settings-page Esc dismiss, separate render/markdown font sizes,
persisted editor mode, blank-line/image-spacing fixes across mode
switches.

Tests: cm6MarkdownMode, expanderRuntime, appRuntime, markdownToolbarClicks
unit suites (558 total, all passing) + playwright specs (desktop,
ai-rendered live provider E2E, upload-reload, resource-lifecycle).
2026-07-06 17:00:57 +12:00

1 line
No EOL
5.1 KiB
JavaScript

!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>typeof t===e,o=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=r=e,(n=String).prototype.isPrototypeOf(o)||r.constructor?.name===n.name)?"string":t;var o,r,n})(e);const r=t("boolean"),n=t("function"),i=()=>false;class s{tag;value;static singletonNone=new s(!1);constructor(e,t){this.tag=e,this.value=t}static some(e){return new s(!0,e)}static none(){return s.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?s.some(e(this.value)):s.none()}bind(e){return this.tag?e(this.value):s.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:s.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(e??"Called getOrDie on None")}static from(e){return null==e?s.none():s.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}let a=0;var l=tinymce.util.Tools.resolve("tinymce.util.Delay");const c=e=>{e.on("PreInit",()=>{e.queryCommandSupported("QuickbarInsertImage")||e.addCommand("QuickbarInsertImage",()=>{(e=>new Promise(t=>{let o=!1;const r=document.createElement("input");r.type="file",r.accept="image/*",r.style.position="fixed",r.style.left="0",r.style.top="0",r.style.opacity="0.001",document.body.appendChild(r);const n=e=>{o||(r.parentNode?.removeChild(r),o=!0,t(e))},i=e=>{n(Array.prototype.slice.call(e.target.files))};r.addEventListener("input",i),r.addEventListener("change",i);const s=t=>{const r=()=>{n([])};o||("focusin"===t.type?l.setEditorTimeout(e,r,1e3):r()),e.off("focusin remove",s)};e.on("focusin remove",s),r.click()}))(e).then(t=>{if(t.length>0){const o=t[0];(e=>new Promise(t=>{const o=new FileReader;o.onloadend=()=>{t(o.result.split(",")[1])},o.readAsDataURL(e)}))(o).then(t=>{((e,t,o)=>{const r=e.editorUpload.blobCache,n=r.create((e=>{const t=(new Date).getTime(),o=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return a++,e+"_"+o+a+String(t)})("mceu"),o,t);r.add(n),e.insertContent(e.dom.createHTML("img",{src:n.blobUri()}))})(e,t,o)})}})})})},u=e=>t=>t.options.get(e),d=u("quickbars_selection_toolbar"),m=u("quickbars_insert_toolbar"),g=u("quickbars_image_toolbar"),h=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},b=h,p=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}};var v=(e,t,o,r,i)=>e(o,r)?s.some(o):n(i)&&i(o)?s.none():t(o,r,i);const f=(e,t,o)=>{let r=e.dom;const a=n(o)?o:i;for(;r.parentNode;){r=r.parentNode;const e=b(r);if(t(e))return s.some(e);if(a(e))break}return s.none()},y=(e,t,o)=>f(e,e=>p(e,t),o),k=e=>{const t=m(e);t.length>0&&e.ui.registry.addContextToolbar("quickblock",{predicate:t=>{const o=b(t),r=e.schema.getTextBlockElements(),n=t=>t.dom===e.getBody();return!(e=>{const t=e.dom;return!(!t||!t.hasAttribute)&&t.hasAttribute("data-mce-bogus")})(o)&&((e,t,o)=>v((e,t)=>p(e,t),y,e,'table,[data-mce-bogus="all"]',o))(o,0,n).fold(()=>((e,t,o)=>((e,t,o)=>v((e,t)=>t(e),f,e,t,o))(e,t,o).isSome())(o,t=>t.dom.nodeName.toLowerCase()in r&&e.dom.isEmpty(t.dom),n),i)},items:t,position:"line",scope:"editor"})};e.add("quickbars",e=>{(e=>{const t=e.options.register,n=e=>t=>{const n=r(t)||o(t);return n?r(t)?{value:t?e:"",valid:n}:{value:t.trim(),valid:n}:{valid:!1,message:"Must be a boolean or string."}},i="bold italic | quicklink h2 h3 blockquote";t("quickbars_selection_toolbar",{processor:n(i),default:i});const s="quickimage quicktable";t("quickbars_insert_toolbar",{processor:n(s),default:s});const a="alignleft aligncenter alignright";t("quickbars_image_toolbar",{processor:n(a),default:a})})(e),c(e),(e=>{e.ui.registry.addButton("quickimage",{icon:"image",tooltip:"Insert image",onAction:()=>e.execCommand("QuickbarInsertImage")}),e.ui.registry.addButton("quicktable",{icon:"table",tooltip:"Insert table",onAction:()=>{(e=>{e.execCommand("mceInsertTable",!1,{rows:2,columns:2})})(e)}})})(e),k(e),(e=>{const t=t=>e.dom.isEditable(t),o=e=>{const o="FIGURE"===e.nodeName&&/image/i.test(e.className),r="IMG"===e.nodeName||o,n=(e=>void 0!==e.dom.classList)(i=b(e))&&i.dom.classList.contains("mce-pagebreak");var i;return r&&t(e.parentElement)&&!n},r=g(e);r.length>0&&e.ui.registry.addContextToolbar("imageselection",{predicate:o,items:r,position:"node"});const n=d(e);n.length>0&&e.ui.registry.addContextToolbar("textselection",{predicate:r=>!o(r)&&!e.selection.isCollapsed()&&t(r),items:n,position:"selection",scope:"editor"})})(e)})}();