[{"title":"$:/plugins/codecogs/eqneditor","description":"Insert CodeCogs equations into tiddlers from the editor toolbar","author":"CodeCogs","version":"1.1.0","core-version":">=5.4.0","list":"readme","plugin-type":"plugin","dependents":"","type":"application/json","text":"{\"tiddlers\":{\"$:/plugins/codecogs/eqneditor/dropdown\":{\"title\":\"$:/plugins/codecogs/eqneditor/dropdown\",\"text\":\"<div class=\\\"cc-eqneditor-dropdown\\\">\\n\\n<$eqneditor/>\\n\\n</div>\\n\"},\"$:/plugins/codecogs/eqneditor/eqneditor-widget.js\":{\"title\":\"$:/plugins/codecogs/eqneditor/eqneditor-widget.js\",\"text\":\"/*\\\\\\ntitle: $:/plugins/codecogs/eqneditor/eqneditor-widget.js\\ntype: application/javascript\\nmodule-type: widget\\n\\nRenders the CodeCogs equation editor inside the toolbar dropdown (see dropdown.tid/\\ntoolbar-button.tid) - the same maths-view-only layout as CodeCogs' other editor plugins, with the\\nLaTeX and Inline toggles bottom-left and \\\"Insert as\\\", Cancel and OK bottom-right - and on OK\\ndispatches a plain tm-edit-text-operation - the same message <$action-sendmessage> would send -\\ncarrying the equation as MathML or an <img>. Built as a widget rather than a plain wikitext dropdown (the\\nway most core toolbar buttons work, e.g. core/ui/EditorToolbar/picture-dropdown.tid) because the\\nCodeCogs UI is only ever the current state of a third-party script's live DOM, not something\\nTiddlyWiki's own reactive tiddler/transclusion model has any state for. Insert/Cancel are part of\\nthis widget's own DOM instead of separate wikitext <$button>s so the click handler can read that\\nstate - eqTextArea.getTextArea().textContent, eqOutput.exportAs() - synchronously, the same\\nway every other adapter in fxPlugins does it (see tinymce/v6/eqneditor.js), rather\\nthan needing a bridge tiddler kept in sync by polling.\\n\\nThe shared EqEditor API (TextArea/Toolbar/Output/History/MathView) is loaded at runtime from\\nfxtex.codecogs.com, same host and API surface as every other adapter here - override with\\n$:/config/codecogs/eqneditor/Server (a host, or a full origin such as \\\"http://localhost:8010\\\" for local development against\\neqneditor-v5-www) and $:/config/codecogs/eqneditor/RenderUrl.\\n\\n\\\\*/\\n\\\"use strict\\\";\\n\\nvar Widget = require( \\\"$:/core/modules/widgets/widget.js\\\" ).widget;\\n\\nvar DEFAULT_SERVER = \\\"fxtex.codecogs.com\\\";\\nvar DEFAULT_RENDER_URL = \\\"https://latex.codecogs.com\\\";\\n\\nvar scriptPromises = {};\\n\\nfunction loadScriptOnce( url ) {\\n\\tif ( scriptPromises[ url ] ) return scriptPromises[ url ];\\n\\n\\tscriptPromises[ url ] = new Promise( function ( resolve, reject ) {\\n\\t\\tif ( typeof window.EqEditor !== \\\"undefined\\\" ) {\\n\\t\\t\\tresolve();\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\n\\t\\tvar existing = document.querySelector( 'script[src=\\\"' + url + '\\\"]' );\\n\\t\\tvar script = existing || document.createElement( \\\"script\\\" );\\n\\n\\t\\tscript.addEventListener( \\\"load\\\", function () { resolve(); } );\\n\\t\\tscript.addEventListener( \\\"error\\\", function () {\\n\\t\\t\\treject( new Error( \\\"CodeCogs Equation Editor: could not load \\\" + url ) );\\n\\t\\t} );\\n\\n\\t\\tif ( !existing ) {\\n\\t\\t\\tscript.src = url;\\n\\t\\t\\tdocument.head.appendChild( script );\\n\\t\\t}\\n\\t} );\\n\\n\\treturn scriptPromises[ url ];\\n}\\n\\n// EqEditor.init() switches the converter every TextArea/MathView/Toolbar construction takes on\\n// to fxTeX Pro - skip it and they keep the placeholder converter for their whole lifetime, even\\n// once fxeditor.api.min.js itself has loaded. Called once per page; an empty licence is the\\n// normal, expected state until a real one is configured.\\nvar initPromise = null;\\n\\nfunction ensureInit( licence ) {\\n\\tif ( initPromise ) return initPromise;\\n\\tinitPromise = ( typeof EqEditor.init === \\\"function\\\" )\\n\\t\\t? EqEditor.init( { licence: licence || \\\"\\\" } ).catch( function ( err ) {\\n\\t\\t\\twindow.console && console.warn( \\\"fxTeX Pro: \\\" + ( err && err.message || err ) );\\n\\t\\t} )\\n\\t\\t: Promise.resolve();\\n\\treturn initPromise;\\n}\\n\\nfunction loadCssOnce( url ) {\\n\\tif ( document.querySelector( 'link[href=\\\"' + url + '\\\"]' ) ) return;\\n\\tvar link = document.createElement( \\\"link\\\" );\\n\\tlink.rel = \\\"stylesheet\\\";\\n\\tlink.href = url;\\n\\tdocument.head.appendChild( link );\\n}\\n\\n// The API's own @font-face for \\\"Latin Modern Math\\\" only carries local(), so it falls back to a\\n// generic serif unless the font happens to be installed; redeclaring it here adds a real url().\\n// The rest lays the editor out to fill the dropdown and gives it the same bottom bar as the\\n// other plugins, !important where TiddlyWiki's own dropdown/button styles would otherwise win.\\nfunction injectStyleOverridesOnce( fontUrl ) {\\n\\tif ( document.getElementById( \\\"cc-eqneditor-style-overrides\\\" ) ) return;\\n\\tvar style = document.createElement( \\\"style\\\" );\\n\\tstyle.id = \\\"cc-eqneditor-style-overrides\\\";\\n\\tstyle.textContent = '@font-face { font-family: \\\"Latin Modern Math\\\"; font-display: swap; ' +\\n\\t\\t'src: local(\\\"Latin Modern Math\\\"), url(\\\"' + fontUrl.replace( /prototypes\\\\/latinmodern-math\\\\.otf$/, 'fonts/LatinModernMath-Regular.woff2' ) + '\\\") format(\\\"woff2\\\"), url(\\\"' + fontUrl + '\\\") format(\\\"opentype\\\"); }' +\\n\\t\\t// Undo host resets (e.g. .cke_reset_all *) inside the toolbar icons and the maths view's MathML.\\n\\t\\t'.CCToolbar svg:has(g[font-family]), .CCToolbar svg:has(g[font-family]) * { font: revert-layer !important; }' +\\n\\t\\t// Icons drawn as <text>: the svg gets the API's own .cc_panel font (fxTeX Toolbar, 16px) back over host resets, and each <text> its own font-size attribute (revert-layer lets attributes win).\\n\\t\\t'.CCToolbar svg:not(:has(g[font-family])) { font: normal normal 16px \\\"fxTeX Toolbar\\\" !important; }' +\\n\\t\\t'.CCToolbar svg:not(:has(g[font-family])) * { font: revert-layer !important; }' +\\n\\t\\t'.CCToolbar svg, .CCToolbar svg * { width: revert-layer !important; height: revert-layer !important; max-width: revert-layer !important; }' +\\n\\t\\t'.CCToolbar svg g[font-family=\\\"fxTeX Toolbar\\\"] { color: #000 !important; }' +\\n\\t\\t'.CCMathView math, .CCMathView math * { font: revert-layer !important; ' +\\n\\t\\t\\t'width: revert-layer !important; height: revert-layer !important; padding: revert-layer !important; ' +\\n\\t\\t\\t'margin: revert-layer !important; text-transform: revert-layer !important; text-align: revert-layer !important; ' +\\n\\t\\t\\t'box-sizing: revert-layer !important; white-space: revert-layer !important; }' +\\n\\t\\tapiMathRules() +\\n\\t\\t'.CCEqnEditor { display: flex !important; flex-direction: column !important; height: 480px !important; }' +\\n\\t\\t'.CCEqnEditor .CCEditorBar, .CCEqnEditor .CCToolbarHost { flex: 0 0 auto; }' +\\n\\t\\t// The toolbar as wide as the dialog, no wider: sized to its own content instead (width: auto)\\n\\t\\t// it kept the toolbar's whole row and ran past a narrow dialog (`design.width`); at 100% the\\n\\t\\t// toolbar scrolls.\\n\\t\\t'.CCEqnEditor .CCToolbarHost { align-self: flex-start; width: 100%; }' +\\n\\t\\t'.CCEqnEditor .CCMathViewHost { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; ' +\\n\\t\\t\\t'justify-content: center; overflow: auto; }' +\\n\\t\\t'.CCEqnEditor[data-inline=\\\"on\\\"] .CCMathViewHost { justify-content: flex-start; }' +\\n\\t\\t'.CCEqnEditor[data-latex=\\\"on\\\"] .CCMathViewHost { display: none !important; }' +\\n\\t\\t'.CCEqnEditor .CCLatexInput { flex: 1 1 auto; min-height: 0; overflow: auto; }' +\\n\\t\\t'.CCEqnEditor[data-latex=\\\"off\\\"] .CCLatexInput { display: none !important; }' +\\n\\t\\t'.CCEqnEditor .CCEqnOutput-hidden { display: none !important; }' +\\n\\t\\t// TiddlyWiki styles every button in a dropdown as a full-width block, which stacked the history buttons.\\n\\t\\t'.tc-drop-down .CCEqnEditor .CCHistory button { display: inline-block !important; width: auto !important; padding: revert-layer !important; margin: revert-layer !important; ' +\\n\\t\\t\\t'text-align: center !important; line-height: normal !important; vertical-align: middle !important; }' +\\n\\t\\t// The bottom bar: toggles left, Insert-as and the dialog's buttons right, one type size. All !important - host dialog resets otherwise restyle it.\\n\\t\\t'.cc-eqn-bar { display: flex !important; flex-wrap: wrap !important; align-items: center !important; gap: 16px !important; flex: 0 0 auto !important; ' +\\n\\t\\t\\t'margin: 8px 0 0 !important; padding: 10px 0 0 !important; border: 0 !important; border-top: 1px solid #e2e8f0 !important; ' +\\n\\t\\t\\t'background: none !important; font: 13px/1.3 system-ui, -apple-system, \\\"Segoe UI\\\", Arial, sans-serif !important; color: #1c2530 !important; }' +\\n\\t\\t'.cc-eqn-bar-right { display: flex !important; align-items: center !important; gap: 8px !important; margin: 0 0 0 auto !important; padding: 0 !important; font: inherit !important; color: inherit !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch { display: inline-flex !important; align-items: center !important; gap: 6px !important; margin: 0 !important; ' +\\n\\t\\t\\t'padding: 0 !important; font: inherit !important; color: #54647c !important; cursor: pointer !important; user-select: none !important; white-space: nowrap !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input { position: absolute !important; width: 1px !important; height: 1px !important; margin: -1px !important; ' +\\n\\t\\t\\t'padding: 0 !important; border: 0 !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; opacity: 0 !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch-track { position: relative !important; display: inline-block !important; flex: 0 0 auto !important; width: 28px !important; ' +\\n\\t\\t\\t'height: 16px !important; margin: 0 !important; padding: 0 !important; border: 0 !important; border-radius: 8px !important; ' +\\n\\t\\t\\t'background: #ccc !important; transition: background .2s !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch-knob { position: absolute !important; display: block !important; top: 2px !important; left: 2px !important; ' +\\n\\t\\t\\t'width: 12px !important; height: 12px !important; margin: 0 !important; border-radius: 50% !important; background: #fff !important; transition: left .2s !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input:checked + .cc-switch-track { background: #4caf50 !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input:checked + .cc-switch-track .cc-switch-knob { left: 14px !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input:focus-visible + .cc-switch-track { outline: 2px solid #003794 !important; outline-offset: 2px !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input:disabled ~ * { opacity: .5 !important; cursor: default !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch-label { font: inherit !important; color: inherit !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-switch input:checked ~ .cc-switch-label { color: #003794 !important; font-weight: 600 !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-eqn-select { width: auto !important; height: 30px !important; margin: 0 !important; padding: 0 8px !important; ' +\\n\\t\\t\\t'border: 1px solid #cbd5e0 !important; border-radius: 4px !important; background: #fff !important; font: inherit !important; color: #1c2530 !important; cursor: pointer !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-eqn-btn { display: inline-flex !important; align-items: center !important; height: 30px !important; margin: 0 !important; ' +\\n\\t\\t\\t'padding: 0 16px !important; border: 1px solid #cbd5e0 !important; border-radius: 4px !important; background: #fff !important; ' +\\n\\t\\t\\t'font: inherit !important; color: #1c2530 !important; cursor: pointer !important; box-shadow: none !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-eqn-btn * { font: inherit !important; color: inherit !important; }' +\\n\\t\\t'.cc-eqn-bar .cc-eqn-btn.cc-eqn-primary { background: #2c7a4b !important; border-color: #2c7a4b !important; color: #fff !important; }';\\n\\tdocument.head.appendChild( style );\\n}\\n\\n// Re-asserts the API's own .CCMathView/.fxtex rules, which host resets and revert-layer override.\\n// The `design` option (see the README): how the editor looks, set by the site rather than the\\n// author. The toolbar\\\"s rows and scale go to Toolbar.link() itself; everything else is applied\\n// here, once the editor is mounted - CSS scoped to this editor\\\"s root, then the starting state of\\n// the LaTeX toggle and the \\\"Insert as\\\" menu.\\n// The dialog's size when the design does not set one: about 700 by 450 pixels.\\nvar DEFAULT_WIDTH = 700, DEFAULT_HEIGHT = 450;\\nfunction designWidth( design ) { return Number( design && design.width ) > 0 ? Number( design.width ) : DEFAULT_WIDTH; }\\nfunction designHeight( design ) { return Number( design && design.height ) > 0 ? Number( design.height ) : DEFAULT_HEIGHT; }\\nvar designCount = 0;\\nfunction applyDesign( root, design, latexToggle, insertSelect ) {\\n\\tif ( !root || !design ) return;\\n\\tif ( !root.id ) root.id = \\\"cc-eqn-design-\\\" + ( ++designCount );\\n\\tvar sel = \\\"#\\\" + root.id, css = \\\"\\\";\\n\\tvar colour = String( design.colour || \\\"\\\" );\\n\\tif ( /^(#[0-9a-f]{3,8}|[a-z]+)$/i.test( colour ) ) {\\n\\t\\tcss += sel + \\\" { --cc-accent: \\\" + colour + \\\";\\\" +\\n\\t\\t\\t\\\" --cc-accent-soft: color-mix(in srgb, \\\" + colour + \\\" 11%, #fff);\\\" +\\n\\t\\t\\t\\\" --cc-accent-soft-ring: color-mix(in srgb, \\\" + colour + \\\" 28%, #fff);\\\" +\\n\\t\\t\\t\\\" --cc-accent-mid: color-mix(in srgb, \\\" + colour + \\\" 22%, #fff);\\\" +\\n\\t\\t\\t\\\" --cc-accent-mid-ring: color-mix(in srgb, \\\" + colour + \\\" 43%, #fff); }\\\";\\n\\t}\\n\\tif ( Number( design.mathSize ) > 0 ) css += sel + \\\" .CCMathView { font-size: \\\" + Number( design.mathSize ) + \\\"px !important; }\\\";\\n\\tif ( Number( design.latexSize ) > 0 ) css += sel + \\\" .CCLatexInput { font-size: \\\" + Number( design.latexSize ) + \\\"px !important; }\\\";\\n\\tif ( design.toolbar === false ) css += sel + \\\" .CCToolbar { display: none !important; }\\\";\\n\\tif ( design.history === false ) css += sel + \\\" .CCEditorBar { display: none !important; }\\\";\\n\\tif ( css ) {\\n\\t\\tvar style = document.createElement( \\\"style\\\" );\\n\\t\\tstyle.textContent = css;\\n\\t\\troot.appendChild( style );\\n\\t}\\n\\t// The dialog's width and height (`width`, `height`), before any scaling: the box takes the width,\\n\\t// and the editing area whatever height makes the whole dialog the height asked for - measured,\\n\\t// since everything else in it (toolbar rows, the bottom bar) varies with the design. Hosts that\\n\\t// size their dialogs themselves (TinyMCE 4, CKEditor 4) are given both when they open it instead.\\n\\tvar sizedBox = root.closest( '.tox-dialog, .mce-window, .cke_dialog, .ck-balloon-panel, .cc-eqneditor-modal, .tc-drop-down' ) || root;\\n\\tif ( !sizedBox.matches( '.mce-window, .cke_dialog' ) ) {\\n\\t\\tsizedBox.style.setProperty( 'width', designWidth( design ) + 'px', 'important' );\\n\\t\\tvar area = root.querySelector( '.CCMathViewHost' );\\n\\t\\tif ( area ) {\\n\\t\\t\\t// Measured, then measured again as the dialog settles - the toolbar fits itself to its row\\n\\t\\t\\t// after the dialog first lays out, and the fonts arrive - correcting by the difference each time.\\n\\t\\t\\t// A box with a height of its own (Froala's and Tiptap's modals) sizes to its contents instead.\\n\\t\\t\\tsizedBox.style.setProperty( 'height', 'auto', 'important' );\\n\\t\\t\\tvar sizing = document.createElement( 'style' );\\n\\t\\t\\troot.appendChild( sizing );\\n\\t\\t\\tvar h = 0;\\n\\t\\t\\tvar fit = function () {\\n\\t\\t\\t\\tvar shown = root.querySelector( '.CCLatexInput' ) && getComputedStyle( area ).display === 'none'\\n\\t\\t\\t\\t\\t? root.querySelector( '.CCLatexInput' ) : area;\\n\\t\\t\\t\\t// Scale may already be applied (see below), and on-screen sizes include it.\\n\\t\\t\\t\\tvar applied = parseFloat( sizedBox.style.zoom ) || parseFloat( ( sizedBox.style.transform.match( /scale\\\\(([\\\\d.]+)\\\\)/ ) || [] )[ 1 ] ) || 1;\\n\\t\\t\\t\\tvar now = h || shown.getBoundingClientRect().height / applied;\\n\\t\\t\\t\\th = Math.max( 120, Math.round( now + designHeight( design ) - sizedBox.getBoundingClientRect().height / applied ) );\\n\\t\\t\\t\\t// Never taller than the whole dialog asked for: a host that caps its dialog (and scrolls the\\n\\t\\t\\t\\t// rest) would otherwise be chased upwards on every pass.\\n\\t\\t\\t\\th = Math.min( h, designHeight( design ) );\\n\\t\\t\\t\\tsizing.textContent = '#' + root.id + ' { height: auto !important; } #' + root.id + ' .CCMathViewHost, #' + root.id + ' .CCLatexInput { height: ' + h + 'px !important; min-height: ' + h + 'px !important; }';\\n\\t\\t\\t};\\n\\t\\t\\tfit();\\n\\t\\t\\t[ 150, 500, 1200 ].forEach( function ( t ) { setTimeout( fit, t ); } );\\n\\t\\t}\\n\\t}\\n\\t// The whole dialog, box and contents together - see `dialogSize` in the README. Zoomed where\\n\\t// the host lays the dialog out (it grows in place); scaled where the host positions it itself\\n\\t// (CKEditor, TinyMCE 4, a TiddlyWiki drop-down), so that placement still holds.\\n\\tvar size = Number( design.dialogSize );\\n\\tif ( size > 0 && size !== 1 ) {\\n\\t\\tvar box = root.closest( '.tox-dialog, .mce-window, .cke_dialog, .ck-balloon-panel, .cc-eqneditor-modal, .tc-drop-down' ) || root;\\n\\t\\tvar position = getComputedStyle( box ).position;\\n\\t\\tif ( position === 'absolute' || position === 'fixed' ) {\\n\\t\\t\\tbox.style.transform = 'scale(' + size + ')';\\n\\t\\t\\tbox.style.transformOrigin = box.matches( '.ck-balloon-panel' ) ? 'top center'\\n\\t\\t\\t\\t: box.matches( '.tc-drop-down' ) ? 'top left' : 'center center';\\n\\t\\t\\t// A cap on the box's width (CKEditor 5's balloon: 96vw) holds before the scale - divided by it,\\n\\t\\t\\t// as for zoom below, or a scaled-down box is squeezed narrower than its own contents.\\n\\t\\t\\tbox.style.removeProperty( 'max-width' );   // a host that reuses the box (CKEditor 5) would otherwise divide it again\\n\\t\\t\\tvar cap = getComputedStyle( box ).maxWidth;\\n\\t\\t\\tif ( cap !== 'none' ) box.style.setProperty( 'max-width', 'calc(' + cap + ' / ' + size + ')', 'important' );\\n\\t\\t} else {\\n\\t\\t\\tbox.style.zoom = String( size );\\n\\t\\t\\tbox.style.setProperty( 'max-width', 'calc(96vw / ' + size + ')', 'important' );   // still no wider than the window\\n\\t\\t}\\n\\t}\\n\\tif ( insertSelect && design.insertAs && insertSelect.querySelector( 'option[value=\\\"' + design.insertAs + '\\\"]' ) ) {\\n\\t\\tinsertSelect.value = design.insertAs;\\n\\t}\\n\\tif ( latexToggle && design.latex && !latexToggle.checked && !latexToggle.disabled ) {\\n\\t\\tlatexToggle.checked = true;\\n\\t\\tlatexToggle.dispatchEvent( new Event( \\\"change\\\", { bubbles: true } ) );\\n\\t}\\n}\\n\\n// Ready to type into, with its cursor showing: the MathView (or the LaTeX pane, when that is the\\n// one showing) takes focus as the dialog opens - otherwise focus stays on whatever opened it.\\n// The API draws the MathView's caret where the cursor is at that moment and only redraws it on an\\n// edit or on focus, but a dialog goes on settling after it opens (fonts arrive, the toolbar fits\\n// itself to its row) and moves the equation out from under it. Its focus handler only redraws\\n// (the cursor stays where it is), so it is fired again whenever the editing area changes size.\\n// The predictor (design.predictor): whole equations that start the way this one does - the API's\\n// PredictorView - in a panel on the right of the editing area. The maths view and the markup pane\\n// share one row with it, so it sits beside whichever is showing. The bar between them drags to\\n// resize the panel, and its button (or Enter on the bar) folds it away; arrow keys resize it from\\n// the keyboard. The width and whether it is folded are remembered in this browser.\\nvar PREDICTOR_WIDTH = 220, PREDICTOR_MIN = 140, PREDICTOR_KEY = \\\"cc-eqn-predictor\\\";\\nfunction addPredictor( root, design, textArea, mathView ) {\\n\\tif ( !root || !design || !design.predictor || typeof EqEditor === \\\"undefined\\\" || !EqEditor.PredictorView ) return;\\n\\tvar host = root.querySelector( \\\".CCMathViewHost\\\" ), markup = root.querySelector( \\\".CCLatexInput\\\" );\\n\\tvar first = host || markup;\\n\\tif ( !first || root.querySelector( \\\".cc-eqn-work\\\" ) ) return;\\n\\tinjectPredictorStylesOnce();\\n\\n\\tvar saved = {};\\n\\ttry { saved = JSON.parse( localStorage.getItem( PREDICTOR_KEY ) ) || {}; } catch ( e ) {}\\n\\tvar width = Number( saved.width ) >= PREDICTOR_MIN ? Number( saved.width ) : PREDICTOR_WIDTH;\\n\\n\\tvar work = document.createElement( \\\"div\\\" );\\n\\twork.className = \\\"cc-eqn-work\\\";\\n\\tfirst.parentNode.insertBefore( work, first );\\n\\tvar panes = document.createElement( \\\"div\\\" );\\n\\tpanes.className = \\\"cc-eqn-panes\\\";\\n\\tif ( host ) panes.appendChild( host );\\n\\tif ( markup ) panes.appendChild( markup );\\n\\n\\tvar bar = document.createElement( \\\"div\\\" );\\n\\tbar.className = \\\"cc-eqn-split\\\";\\n\\tbar.tabIndex = 0;\\n\\tbar.setAttribute( \\\"role\\\", \\\"separator\\\" );\\n\\tbar.setAttribute( \\\"aria-orientation\\\", \\\"vertical\\\" );\\n\\tbar.setAttribute( \\\"aria-label\\\", \\\"Resize the suggested equations\\\" );\\n\\tvar fold = document.createElement( \\\"button\\\" );\\n\\tfold.type = \\\"button\\\";\\n\\tfold.className = \\\"cc-eqn-split-fold\\\";\\n\\tbar.appendChild( fold );\\n\\n\\tvar side = document.createElement( \\\"aside\\\" );\\n\\tside.className = \\\"cc-eqn-predictor\\\";\\n\\tside.id = root.id + \\\"-predictor\\\";\\n\\tside.setAttribute( \\\"aria-label\\\", \\\"Suggested equations\\\" );\\n\\n\\twork.appendChild( panes );\\n\\twork.appendChild( bar );\\n\\twork.appendChild( side );\\n\\n\\tfunction remember() {\\n\\t\\ttry { localStorage.setItem( PREDICTOR_KEY, JSON.stringify( { width: width, folded: work.classList.contains( \\\"cc-eqn-folded\\\" ) } ) ); } catch ( e ) {}\\n\\t}\\n\\tfunction setWidth( w ) {\\n\\t\\t// Never so wide that the editing area beside it has nothing left.\\n\\t\\tvar room = work.clientWidth - bar.offsetWidth - 160;\\n\\t\\twidth = Math.round( Math.max( PREDICTOR_MIN, room > PREDICTOR_MIN ? Math.min( w, room ) : w ) );\\n\\t\\tside.style.width = width + \\\"px\\\";\\n\\t}\\n\\tfunction setFolded( folded ) {\\n\\t\\twork.classList.toggle( \\\"cc-eqn-folded\\\", folded );\\n\\t\\tfold.textContent = folded ? \\\"‹\\\" : \\\"›\\\";\\n\\t\\tfold.title = folded ? \\\"Show suggested equations\\\" : \\\"Hide suggested equations\\\";\\n\\t\\tbar.setAttribute( \\\"aria-expanded\\\", folded ? \\\"false\\\" : \\\"true\\\" );\\n\\t}\\n\\tside.style.width = width + \\\"px\\\";\\n\\tsetFolded( !!saved.folded );\\n\\n\\tfold.addEventListener( \\\"click\\\", function () { setFolded( !work.classList.contains( \\\"cc-eqn-folded\\\" ) ); remember(); } );\\n\\tbar.addEventListener( \\\"keydown\\\", function ( e ) {\\n\\t\\tif ( e.target !== bar ) return;\\n\\t\\tif ( e.key === \\\"Enter\\\" || e.key === \\\" \\\" ) {\\n\\t\\t\\te.preventDefault(); setFolded( !work.classList.contains( \\\"cc-eqn-folded\\\" ) ); remember();\\n\\t\\t} else if ( ( e.key === \\\"ArrowLeft\\\" || e.key === \\\"ArrowRight\\\" ) && !work.classList.contains( \\\"cc-eqn-folded\\\" ) ) {\\n\\t\\t\\te.preventDefault(); setWidth( width + ( e.key === \\\"ArrowLeft\\\" ? 20 : -20 ) ); remember();\\n\\t\\t}\\n\\t} );\\n\\t// Dragged from anywhere on the bar but its button. Pointer movement is in screen pixels, which a\\n\\t// scaled dialog (design.dialogSize) does not share with the panel's own width - hence the ratio.\\n\\tbar.addEventListener( \\\"pointerdown\\\", function ( e ) {\\n\\t\\tif ( e.target === fold || e.button !== 0 ) return;\\n\\t\\te.preventDefault();\\n\\t\\tvar scale = work.getBoundingClientRect().width / ( work.offsetWidth || 1 ) || 1;\\n\\t\\tvar startX = e.clientX, startW = work.classList.contains( \\\"cc-eqn-folded\\\" ) ? 0 : width;\\n\\t\\tif ( startW === 0 ) { setFolded( false ); startW = PREDICTOR_MIN; setWidth( startW ); }\\n\\t\\tbar.setPointerCapture( e.pointerId );\\n\\t\\twork.classList.add( \\\"cc-eqn-dragging\\\" );\\n\\t\\tfunction move( ev ) { setWidth( startW + ( startX - ev.clientX ) / scale ); }\\n\\t\\tfunction up() {\\n\\t\\t\\tbar.removeEventListener( \\\"pointermove\\\", move );\\n\\t\\t\\tbar.removeEventListener( \\\"pointerup\\\", up );\\n\\t\\t\\tbar.removeEventListener( \\\"pointercancel\\\", up );\\n\\t\\t\\twork.classList.remove( \\\"cc-eqn-dragging\\\" );\\n\\t\\t\\tremember();\\n\\t\\t}\\n\\t\\tbar.addEventListener( \\\"pointermove\\\", move );\\n\\t\\tbar.addEventListener( \\\"pointerup\\\", up );\\n\\t\\tbar.addEventListener( \\\"pointercancel\\\", up );\\n\\t} );\\n\\n\\tvar show = design.predictorShow === \\\"latex\\\" || design.predictorShow === \\\"both\\\" ? design.predictorShow : \\\"mathml\\\";\\n\\tvar view = EqEditor.PredictorView.link( side.id, { limit: 6, show: show } ).addTextArea( textArea );\\n\\tif ( mathView ) view.addMathView( mathView );\\n}\\n\\n// !important throughout: hosts reset their dialogs\\\" contents (TinyMCE\\\"s .tox, CKEditor's\\n// .ck-reset_all) more specifically than a plain class rule reaches.\\nfunction injectPredictorStylesOnce() {\\n\\tif ( document.getElementById( \\\"cc-eqn-predictor-css\\\" ) ) return;\\n\\tvar style = document.createElement( \\\"style\\\" );\\n\\tstyle.id = \\\"cc-eqn-predictor-css\\\";\\n\\tstyle.textContent =\\n\\t\\t\\\".cc-eqn-work { display: flex !important; flex: 1 1 auto !important; min-height: 0 !important; min-width: 0 !important; align-items: stretch !important; }\\\" +\\n\\t\\t\\\".cc-eqn-panes { display: flex !important; flex-direction: column !important; flex: 1 1 auto !important; min-width: 0 !important; min-height: 0 !important; }\\\" +\\n\\t\\t\\\".cc-eqn-split { flex: 0 0 auto !important; width: 9px !important; margin: 0 2px !important; cursor: col-resize !important; \\\" +\\n\\t\\t\\t\\\"display: flex !important; align-items: center !important; justify-content: center !important; position: relative !important; \\\" +\\n\\t\\t\\t\\\"background: transparent !important; touch-action: none !important; user-select: none !important; outline: none !important; }\\\" +\\n\\t\\t\\\".cc-eqn-split::before { content: \\\\\\\"\\\\\\\" !important; position: absolute !important; top: 0 !important; bottom: 0 !important; left: 4px !important; \\\" +\\n\\t\\t\\t\\\"width: 1px !important; background: #d5dbe3 !important; }\\\" +\\n\\t\\t\\\".cc-eqn-split:hover::before, .cc-eqn-split:focus-visible::before, .cc-eqn-dragging .cc-eqn-split::before { left: 3px !important; width: 3px !important; background: var(--cc-accent, #003794) !important; }\\\" +\\n\\t\\t\\\".cc-eqn-split-fold { flex: 0 0 auto !important; position: relative !important; z-index: 1 !important; width: 16px !important; height: 34px !important; margin: 0 !important; padding: 0 !important; \\\" +\\n\\t\\t\\t\\\"border: 1px solid #cbd5e0 !important; border-radius: 8px !important; background: #fff !important; color: #52606d !important; \\\" +\\n\\t\\t\\t\\\"font: 14px/1 sans-serif !important; cursor: pointer !important; box-shadow: none !important; display: flex !important; align-items: center !important; justify-content: center !important; }\\\" +\\n\\t\\t\\\".cc-eqn-split-fold:hover { color: var(--cc-accent, #003794) !important; border-color: var(--cc-accent, #003794) !important; }\\\" +\\n\\t\\t// contain: size - the list's length is no reason for the dialog to grow; the panel takes the\\n\\t\\t// editing area's height (stretched, as a flex item) and scrolls within it. layout, as the API\\n\\t\\t// has it, keeps its search box anchored to the panel.\\n\\t\\t\\\".cc-eqn-predictor { flex: 0 0 auto !important; min-width: 0 !important; min-height: 0 !important; overflow: auto !important; box-sizing: border-box !important; contain: size layout !important; }\\\" +\\n\\t\\t\\\".cc-eqn-folded .cc-eqn-predictor { display: none !important; }\\\" +\\n\\t\\t\\\".cc-eqn-dragging, .cc-eqn-dragging * { cursor: col-resize !important; user-select: none !important; }\\\" +\\n\\t\\t// The suggestions\\\" maths set as the maths view\\\"s is: a host\\\"s reset (TinyMCE\\\"s .tox\\n\\t\\t// :not(svg) { font-family: inherit; font-style: inherit }) outranks the API's .fxtex rules,\\n\\t\\t// which left it in the dialog's sans-serif with its letters upright (the browser italicises\\n\\t\\t// them through text-transform, which the reset takes too). Reverted to the browser's own\\n\\t\\t// maths styling, as the maths view is, then the API's .fxtex rules re-asserted for the panel.\\n\\t\\t\\\".cc-eqn-predictor math, .cc-eqn-predictor math * { font: revert-layer !important; text-transform: revert-layer !important; \\\" +\\n\\t\\t\\t\\\"width: revert-layer !important; height: revert-layer !important; padding: revert-layer !important; margin: revert-layer !important; \\\" +\\n\\t\\t\\t\\\"text-align: revert-layer !important; box-sizing: revert-layer !important; white-space: revert-layer !important; }\\\";\\n\\tfor ( var i = 0; i < document.styleSheets.length; i++ ) {\\n\\t\\tvar rules;\\n\\t\\ttry { rules = document.styleSheets[ i ].cssRules; } catch ( e ) { continue; }\\n\\t\\tfor ( var j = 0; j < rules.length; j++ ) {\\n\\t\\t\\tvar r = rules[ j ], decls = \\\"\\\";\\n\\t\\t\\tvar sel = r.selectorText && r.selectorText.replace( /:where\\\\(\\\\.fxEditor\\\\)\\\\s*/g, \\\"\\\" ).trim();\\n\\t\\t\\tif ( !sel || !/^\\\\.fxtex\\\\b/.test( sel ) || sel.indexOf( \\\",\\\" ) > -1 ) continue;\\n\\t\\t\\tfor ( var k = 0; k < r.style.length; k++ ) {\\n\\t\\t\\t\\tdecls += r.style[ k ] + \\\":\\\" + r.style.getPropertyValue( r.style[ k ] ) + \\\" !important;\\\";\\n\\t\\t\\t}\\n\\t\\t\\tif ( decls ) style.textContent += \\\".cc-eqn-predictor \\\" + sel + \\\"{\\\" + decls + \\\"}\\\";\\n\\t\\t}\\n\\t}\\n\\tdocument.head.appendChild( style );\\n}\\n\\nfunction focusEditor( root ) {\\n\\tif ( !root ) return;\\n\\tvar pane = root.querySelector( root.getAttribute( \\\"data-latex\\\" ) === \\\"on\\\" ? \\\".CCLatexInput\\\" : \\\".CCMathView\\\" );\\n\\tif ( pane ) pane.focus( { preventScroll: true } );\\n\\tvar view = root.querySelector( \\\".CCMathView\\\" ), host = view && view.parentElement;\\n\\tif ( host && !host.ccCaretWatch && typeof ResizeObserver !== \\\"undefined\\\" ) {\\n\\t\\thost.ccCaretWatch = new ResizeObserver( function () {\\n\\t\\t\\tvar mv = host.querySelector( \\\".CCMathView\\\" );\\n\\t\\t\\tif ( mv && document.activeElement === mv ) mv.dispatchEvent( new FocusEvent( \\\"focus\\\" ) );\\n\\t\\t} );\\n\\t\\thost.ccCaretWatch.observe( host );\\n\\t}\\n}\\n\\nfunction apiMathRules() {\\n\\tvar out = '';\\n\\tfor ( var i = 0; i < document.styleSheets.length; i++ ) {\\n\\t\\tvar rules;\\n\\t\\ttry { rules = document.styleSheets[ i ].cssRules; } catch ( e ) { continue; }\\n\\t\\tfor ( var j = 0; j < rules.length; j++ ) {\\n\\t\\t\\tvar r = rules[ j ], decls = '';\\n\\t\\t\\tif ( !r.selectorText || !/(^|,)\\\\s*(:where\\\\(\\\\.fxEditor\\\\)\\\\s*)?\\\\.(fxtex|CCMathView)\\\\b/.test( r.selectorText ) ) continue;\\n\\t\\t\\tfor ( var k = 0; k < r.style.length; k++ ) {\\n\\t\\t\\t\\tdecls += r.style[ k ] + ':' + r.style.getPropertyValue( r.style[ k ] ) + ' !important;';\\n\\t\\t\\t}\\n\\t\\t\\tif ( decls ) {\\n\\t\\t\\t\\tout += r.selectorText.replace( /:where\\\\(\\\\.fxEditor\\\\)\\\\s*/g, '' ).split( ',' ).map( function ( s ) {\\n\\t\\t\\t\\t\\ts = s.trim();\\n\\t\\t\\t\\t\\treturn /^\\\\.CCMathView\\\\b/.test( s ) ? s : '.CCMathView ' + s;\\n\\t\\t\\t\\t} ).join( ',' ) + '{' + decls + '}';\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn out;\\n}\\n\\n// A wikitext attribute value, quoted with whichever of TiddlyWiki's quote forms the value\\n// doesn't itself contain.\\nfunction wikitextAttr( value ) {\\n\\tif ( value.indexOf( '\\\"' ) === -1 ) return '\\\"' + value + '\\\"';\\n\\tif ( value.indexOf( \\\"'\\\" ) === -1 ) return \\\"'\\\" + value + \\\"'\\\";\\n\\treturn '\\\"\\\"\\\"' + value.replace( /\\\"\\\"\\\"/g, '\\\"\\\"' ) + '\\\"\\\"\\\"';\\n}\\n\\nfunction switchHtml( id, label, title ) {\\n\\treturn '<label class=\\\"cc-switch\\\" title=\\\"' + title + '\\\">' +\\n\\t\\t'<input type=\\\"checkbox\\\" id=\\\"' + id + '\\\">' +\\n\\t\\t'<span class=\\\"cc-switch-track\\\"><span class=\\\"cc-switch-knob\\\"></span></span>' +\\n\\t\\t'<span class=\\\"cc-switch-label\\\">' + label + '</span>' +\\n\\t'</label>';\\n}\\n\\n// TiddlyWiki parses the text inside HTML elements as wikitext, so the LaTeX source the\\n// converter keeps in <annotation> (where \\\"--\\\", \\\"''\\\" or \\\"^^\\\" would become formatting) is dropped.\\n// The <math> element's title still carries it, and attribute values aren't parsed.\\nfunction mathmlForWikitext( mathml ) {\\n\\treturn mathml\\n\\t\\t.replace( /<annotation(-xml)?\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/annotation(-xml)?>/g, \\\"\\\" )\\n\\t\\t.replace( />\\\\s+</g, \\\"><\\\" );\\n}\\n\\nvar instanceCount = 0;\\n\\nvar EqNEditorWidget = function ( parseTreeNode, options ) {\\n\\tthis.initialise( parseTreeNode, options );\\n};\\n\\nEqNEditorWidget.prototype = new Widget();\\n\\nEqNEditorWidget.prototype.render = function ( parent, nextSibling ) {\\n\\tvar self = this;\\n\\tthis.parentDomNode = parent;\\n\\tthis.computeAttributes();\\n\\tthis.execute();\\n\\n\\tinstanceCount++;\\n\\tvar n = instanceCount;\\n\\tvar ids = {\\n\\t\\troot: \\\"cc-eqn-tw-\\\" + n,\\n\\t\\thistory: \\\"cc-eqn-tw-history-\\\" + n,\\n\\t\\ttoolbar: \\\"cc-eqn-tw-toolbar-\\\" + n,\\n\\t\\tmathview: \\\"cc-eqn-tw-mathview-\\\" + n,\\n\\t\\tlatexInput: \\\"cc-eqn-tw-latex-\\\" + n,\\n\\t\\toutput: \\\"cc-eqn-tw-output-\\\" + n,\\n\\t\\ttoggleInline: \\\"cc-eqn-tw-toggle-inline-\\\" + n,\\n\\t\\ttoggleLatex: \\\"cc-eqn-tw-toggle-latex-\\\" + n,\\n\\t\\tinsertMode: \\\"cc-eqn-tw-insert-mode-\\\" + n\\n\\t};\\n\\n\\t// .trim() because a config tiddler's text commonly carries a trailing newline (any .tid\\n\\t// file with a body written the ordinary way does) - left in, that newline lands inside the\\n\\t// script src/CSS href built below and inside the querySelector() dedupe check in\\n\\t// loadScriptOnce/loadCssOnce, breaking both silently for the URL and throwing for the\\n\\t// selector.\\n\\tvar host = this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/Server\\\", DEFAULT_SERVER ).trim();\\n\\t// A bare host means https; a full origin (e.g. http://localhost:8010 for local development) is used as it is.\\n\\tvar origin = /^https?:\\\\/\\\\//.test( host ) ? host.replace( /\\\\/+$/, \\\"\\\" ) : \\\"https://\\\" + host;\\n\\tvar renderUrl = this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/RenderUrl\\\", DEFAULT_RENDER_URL ).trim();\\n\\tvar licence = this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/Licence\\\", \\\"\\\" ).trim();\\n\\t// The look of the editor, as JSON - see the `design` option in the README.\\n\\tvar design = {};\\n\\ttry { design = JSON.parse( this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/Design\\\", \\\"{}\\\" ) || \\\"{}\\\" ) || {}; } catch ( e ) { design = {}; }\\n\\t// Full-URL overrides, not just the host - the default assumes https, which a local dev\\n\\t// server (see other/tiddlywiki/test-wiki's config tiddlers) generally isn't.\\n\\tvar scriptUrl = this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/ScriptUrl\\\",\\n\\t\\torigin + \\\"/fxeditor.api.min.js\\\" ).trim();\\n\\tvar cssUrl = this.wiki.getTiddlerText( \\\"$:/config/codecogs/eqneditor/CssUrl\\\",\\n\\t\\torigin + \\\"/fxeditor.css\\\" ).trim();\\n\\n\\tvar domNode = this.document.createElement( \\\"div\\\" );\\n\\tdomNode.id = ids.root;\\n\\tdomNode.className = \\\"CCEqnEditor\\\";\\n\\tdomNode.setAttribute( \\\"data-latex\\\", \\\"off\\\" );\\n\\tdomNode.setAttribute( \\\"data-inline\\\", \\\"off\\\" );\\n\\tdomNode.innerHTML =\\n\\t\\t'<div class=\\\"CCEditorBar\\\"><div id=\\\"' + ids.history + '\\\" class=\\\"CCHistory\\\"></div></div>' +\\n\\t\\t'<div id=\\\"' + ids.toolbar + '\\\" class=\\\"CCToolbarHost\\\"></div>' +\\n\\t\\t'<div id=\\\"' + ids.mathview + '\\\" class=\\\"CCMathViewHost\\\"></div>' +\\n\\t\\t'<div id=\\\"' + ids.latexInput + '\\\" class=\\\"CCLatexInput\\\" autocorrect=\\\"off\\\" ' +\\n\\t\\t\\t'placeholder=\\\"Write LaTeX here...\\\"></div>' +\\n\\t\\t// Not shown: eqOutput needs an element to bind to, to build the SVG URL.\\n\\t\\t'<img id=\\\"' + ids.output + '\\\" class=\\\"CCEqnOutput-hidden\\\" alt=\\\"\\\">' +\\n\\t\\t'<div class=\\\"cc-eqn-bar\\\">' +\\n\\t\\t\\tswitchHtml( ids.toggleInline, \\\"Inline\\\", \\\"Left-align the equation instead of centring it\\\" ) +\\n\\t\\t\\tswitchHtml( ids.toggleLatex, \\\"LaTeX markup\\\", \\\"Show or hide the LaTeX markup\\\" ) +\\n\\t\\t\\t'<div class=\\\"cc-eqn-bar-right\\\">' +\\n\\t\\t\\t\\t'<select class=\\\"cc-eqn-select\\\" id=\\\"' + ids.insertMode + '\\\" title=\\\"How to insert the equation\\\">' +\\n\\t\\t\\t\\t\\t'<option value=\\\"mathml\\\" selected>Insert MathML</option>' +\\n\\t\\t\\t\\t\\t'<option value=\\\"svg\\\">Insert SVG</option>' +\\n\\t\\t\\t\\t'</select>' +\\n\\t\\t\\t\\t'<button type=\\\"button\\\" class=\\\"cc-eqn-btn cc-cancel\\\">Cancel</button>' +\\n\\t\\t\\t\\t'<button type=\\\"button\\\" class=\\\"cc-eqn-btn cc-eqn-primary cc-ok\\\" disabled>OK</button>' +\\n\\t\\t\\t'</div>' +\\n\\t\\t'</div>';\\n\\n\\tparent.insertBefore( domNode, nextSibling );\\n\\tthis.domNodes.push( domNode );\\n\\n\\tfunction closeDropdown() {\\n\\t\\tvar stateTitle = self.getVariable( \\\"dropdown-state\\\" );\\n\\t\\tif ( stateTitle ) self.wiki.deleteTiddler( stateTitle );\\n\\t}\\n\\n\\tdomNode.querySelector( \\\".cc-cancel\\\" ).addEventListener( \\\"click\\\", closeDropdown );\\n\\n\\tloadCssOnce( cssUrl );\\n\\n\\tvar eqOutput = null, eqTextArea = null, eqMathView = null, eqToolbar = null;\\n\\n\\tloadScriptOnce( scriptUrl ).then( function () { return ensureInit( licence ); } ).then( function () {\\n\\t\\tinjectStyleOverridesOnce( cssUrl.slice( 0, cssUrl.lastIndexOf( \\\"/\\\" ) + 1 ) + \\\"prototypes/latinmodern-math.otf\\\" );\\n\\n\\t\\teqOutput = new window.EqEditor.Output( ids.output );\\n\\t\\teqOutput.setRenderURL( renderUrl );\\n\\n\\t\\teqTextArea = window.EqEditor.TextArea.link( ids.latexInput )\\n\\t\\t\\t.addOutput( eqOutput )\\n\\t\\t\\t.addHistoryMenu( new window.EqEditor.History( ids.history ) );\\n\\n\\t\\teqToolbar = window.EqEditor.Toolbar.link( ids.toolbar, design.toolbar || \\\"default\\\", design.toolbarScale || 1 ).addTextArea( eqTextArea );\\n\\n\\t\\tvar latexToggle = domNode.querySelector( \\\"#\\\" + ids.toggleLatex );\\n\\n\\t\\tif ( typeof window.EqEditor.MathView !== \\\"undefined\\\" ) {\\n\\t\\t\\teqMathView = window.EqEditor.MathView.link( ids.mathview ).addTextArea( eqTextArea );\\n\\t\\t\\teqToolbar.addMathView( eqMathView );\\n\\t\\t} else {\\n\\t\\t\\t// Without a maths view the markup is the only thing to edit in - force it visible\\n\\t\\t\\t// and lock the toggle so it cannot be switched to an empty pane.\\n\\t\\t\\tdomNode.setAttribute( \\\"data-latex\\\", \\\"on\\\" );\\n\\t\\t\\tlatexToggle.checked = true;\\n\\t\\t\\tlatexToggle.disabled = true;\\n\\t\\t}\\n\\n\\t\\tlatexToggle.addEventListener( \\\"change\\\", function ( e ) {\\n\\t\\t\\tvar visible = e.target.checked;\\n\\t\\t\\tdomNode.setAttribute( \\\"data-latex\\\", visible ? \\\"on\\\" : \\\"off\\\" );\\n\\t\\t\\t// Hiding a pane moves the toolbar's target to the other one, so a button pressed\\n\\t\\t\\t// straight afterwards doesn't insert into something the author can't see.\\n\\t\\t\\teqToolbar.setActiveTextArea( visible ? eqTextArea : ( eqMathView || eqTextArea ) );\\n\\t\\t} );\\n\\n\\t\\tdomNode.querySelector( \\\"#\\\" + ids.toggleInline ).addEventListener( \\\"change\\\", function ( e ) {\\n\\t\\t\\tvar inline = e.target.checked;\\n\\t\\t\\tdomNode.setAttribute( \\\"data-inline\\\", inline ? \\\"on\\\" : \\\"off\\\" );\\n\\t\\t\\tif ( eqMathView ) eqMathView.setInline( inline );\\n\\t\\t\\teqOutput.setInline( inline );\\n\\t\\t} );\\n\\n\\t\\taddPredictor( domNode, design, eqTextArea, eqMathView );\\n\\t\\tapplyDesign( domNode, design, latexToggle, domNode.querySelector( \\\"#\\\" + ids.insertMode ) );\\n\\t\\tfocusEditor( domNode );\\n\\n\\t\\tvar okBtn = domNode.querySelector( \\\".cc-ok\\\" );\\n\\t\\tokBtn.disabled = false;\\n\\t\\tokBtn.addEventListener( \\\"click\\\", function () {\\n\\t\\t\\tvar latex = eqTextArea.getTextArea().textContent.trim();\\n\\t\\t\\tif ( !latex ) return;\\n\\n\\t\\t\\tvar mode = domNode.querySelector( \\\"#\\\" + ids.insertMode ).value;\\n\\t\\t\\t// Wikitext attribute values are taken literally - no entity decoding - so they are\\n\\t\\t\\t// written raw rather than HTML-escaped: \\\"&amp;\\\" would reach latex.codecogs.com as-is.\\n\\t\\t\\t// referrerpolicy explicitly: latex.codecogs.com identifies the calling site by referer,\\n\\t\\t\\t// and a stricter page policy would otherwise send none.\\n\\t\\t\\tvar text = mode === \\\"svg\\\"\\n\\t\\t\\t\\t? '<img class=\\\"fxtex\\\" src=\\\"' + eqOutput.exportAs( \\\"url\\\" ) + '\\\" alt=' + wikitextAttr( latex ) +\\n\\t\\t\\t\\t\\t' referrerpolicy=\\\"origin\\\">'\\n\\t\\t\\t\\t: mathmlForWikitext( eqOutput.exportAs( \\\"mathml\\\" ) );\\n\\n\\t\\t\\t// The same message <$action-sendmessage $message=\\\"tm-edit-text-operation\\\"\\n\\t\\t\\t// $param=\\\"insert-text\\\" text=\\\"...\\\"/> would send - inserting at the cursor (replacing\\n\\t\\t\\t// any selection) in whichever text editor widget is an ancestor of this one, exactly\\n\\t\\t\\t// like core/ui/EditorToolbar/picture-dropdown.tid's image-picker insert action.\\n\\t\\t\\tself.dispatchEvent( {\\n\\t\\t\\t\\ttype: \\\"tm-edit-text-operation\\\",\\n\\t\\t\\t\\tparam: \\\"insert-text\\\",\\n\\t\\t\\t\\tparamObject: { text: text }\\n\\t\\t\\t} );\\n\\n\\t\\t\\teqTextArea.pushToHistory();\\n\\t\\t\\tcloseDropdown();\\n\\t\\t} );\\n\\t} ).catch( function ( err ) {\\n\\t\\tdomNode.textContent = err.message;\\n\\t} );\\n\\n\\tthis._eqTextArea = function () { return eqTextArea; };\\n};\\n\\nEqNEditorWidget.prototype.execute = function () {\\n};\\n\\nEqNEditorWidget.prototype.refresh = function ( changedTiddlers ) {\\n\\treturn false;\\n};\\n\\nEqNEditorWidget.prototype.destroy = function () {\\n\\tvar ta = this._eqTextArea && this._eqTextArea();\\n\\tif ( ta ) ta.close();\\n};\\n\\nexports.eqneditor = EqNEditorWidget;\\n\",\"type\":\"application/javascript\",\"module-type\":\"widget\"},\"$:/plugins/codecogs/eqneditor/icon\":{\"title\":\"$:/plugins/codecogs/eqneditor/icon\",\"type\":\"image/svg+xml\",\"text\":\"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"18\\\" height=\\\"20\\\" viewBox=\\\"0 0 18 20\\\"><path d=\\\"M4,9.5H2L2.3,7h2.1l0.3-1.8C4.7,4.6,4.9,4.1,5,3.6c0.2-0.5,0.4-0.9,0.7-1.3c0.3-0.4,0.8-0.7,1.3-0.9C7.7,1.1,8.4,1,9.2,1c0.3,0,0.6,0,0.9,0c0.3,0,0.6,0.1,0.9,0.1l-0.5,2.7c-0.2-0.1-0.3-0.1-0.5-0.2c-0.1,0-0.3-0.1-0.5-0.1C9,3.7,8.6,3.8,8.4,4C8.1,4.2,7.9,4.7,7.8,5.4L7.6,7h2.3L9.5,9.5H7.2l-1.1,7.7H3L4,9.5z\\\"/><path d=\\\"M11.1,15.3l-2.3-3.2h2.5l1.2,1.8l1.2-1.8H16l-2.2,3.2l2.6,3.6h-2.5l-1.5-2.3L10.8,19H8.4L11.1,15.3z\\\"/></svg>\\n\"},\"readme\":{\"title\":\"readme\",\"text\":\"Adds an ''Equation'' button to the tiddler editor toolbar that opens the CodeCogs Equation\\nEditor. It opens on the maths view; ''LaTeX markup'' and ''Inline'' are toggles in its bottom\\nbar, next to ''Insert as'', which writes the equation at the cursor either as MathML or as an\\n`<img>` rendered by latex.codecogs.com.\\n\\nPut your fxTeX Pro licence key in `$:/config/codecogs/eqneditor/Licence`. The editor loads from\\n`fxtex.codecogs.com` at runtime - override the host with `$:/config/codecogs/eqneditor/Server`\\n(a host, or a full origin such as `http://localhost:8010`) and the rendering host with\\n`$:/config/codecogs/eqneditor/RenderUrl` if needed.\\n\"},\"$:/plugins/codecogs/eqneditor/styles\":{\"title\":\"$:/plugins/codecogs/eqneditor/styles\",\"tags\":\"$:/tags/Stylesheet\",\"type\":\"text/css\",\"text\":\"/* Wide enough for the equation toolbar without it wrapping; narrower screens - or a narrower\\n   drop-down, from `design.width` - get what fits. */\\n.cc-eqneditor-dropdown {\\n\\tpadding: 10px 12px;\\n\\twidth: 850px;\\n\\tmax-width: min(100%, calc(100vw - 32px));\\n\\tbox-sizing: border-box;\\n}\\n\"},\"$:/plugins/codecogs/eqneditor/toolbar-button\":{\"title\":\"$:/plugins/codecogs/eqneditor/toolbar-button\",\"tags\":\"$:/tags/EditorToolbar\",\"icon\":\"$:/plugins/codecogs/eqneditor/icon\",\"caption\":\"Equation\",\"description\":\"Insert a CodeCogs equation\",\"condition\":\"[<targetTiddler>!has[type]] [<targetTiddler>get[type]prefix[text/vnd.tiddlywiki]]\",\"dropdown\":\"$:/plugins/codecogs/eqneditor/dropdown\"}}}"}]