From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- src/fossil.wikiedit-wysiwyg.js | 490 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 src/fossil.wikiedit-wysiwyg.js (limited to 'src/fossil.wikiedit-wysiwyg.js') diff --git a/src/fossil.wikiedit-wysiwyg.js b/src/fossil.wikiedit-wysiwyg.js new file mode 100644 index 0000000..757cd2e --- /dev/null +++ b/src/fossil.wikiedit-wysiwyg.js @@ -0,0 +1,490 @@ +/** + A slight adaptation of fossil's legacy wysiwyg wiki editor which + makes it usable with the newer editor's edit widget replacement + API. + + Requires: window.fossil, fossil.dom, and that the current page is + /wikiedit. If called from another page it returns without effect. + + Caveat: this is an all-or-nothing solution. That is, once plugged + in to /wikiedit, it cannot be removed without reloading the page. + That is a limitation of the current editor-widget-swapping API. +*/ +(function(F/*fossil object*/){ + 'use strict'; + if(!F || !F.page || F.page.name!=='wikiedit') return; + + const D = F.dom; + + //////////////////////////////////////////////////////////////////////// + // Install an app-specific stylesheet... + (function(){ + const head = document.head || document.querySelector('head'), + styleTag = document.createElement('style'), + styleCSS = ` +.intLink { cursor: pointer; } +img.intLink { border: 0; } +#wysiwyg-container { + display: flex; + flex-direction: column; + max-width: 100% /* w/o this, toolbars don't wrap properly! */ +} +#wysiwygBox { + border: 1px solid rgba(127,127,127,0.3); + border-radius: 0.25em; + padding: 0.25em 1em; + margin: 0; + overflow: auto; + min-height: 20em; + resize: vertical; +} +#wysiwygEditMode { /* wrapper for radio buttons */ + border: 1px solid rgba(127,127,127,0.3); + border-radius: 0.25em; + padding: 0 0.35em 0 0.35em +} +#wysiwygEditMode > * { + vertical-align: text-top; +} +#wysiwygEditMode label { cursor: pointer; } +#wysiwyg-toolbars { + margin: 0 0 0.25em 0; + display: flex; + flex-wrap: wrap; + flex-direction: column; + align-items: flex-start; +} +#wysiwyg-toolbars > * { + margin: 0 0.5em 0.25em 0; +} +#wysiwyg-toolBar1, #wysiwyg-toolBar2 { + margin: 0 0.2em 0.2em 0; + display: flex; + flex-flow: row wrap; +} +#wysiwyg-toolBar1 > * { /* formatting buttons */ + vertical-align: middle; + margin: 0 0.25em 0.25em 0; +} +#wysiwyg-toolBar2 > * { /* icons */ + border: 1px solid rgba(127,127,127,0.3); + vertical-align: baseline; + margin: 0.1em; +} +`; + head.appendChild(styleTag); + styleTag.type = 'text/css'; + D.append(styleTag, styleCSS); + })(); + + const outerContainer = D.attr(D.div(), 'id', 'wysiwyg-container'), + toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'), + toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'), + // ^^^ formatting options + toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2') + // ^^^^ action icon buttons + ; + D.append(outerContainer, D.append(toolbars, toolbar1, toolbar2)); + + /** Returns a function which simplifies adding a list of options + to the given select element. See below for example usage. */ + const addOptions = function(select){ + return function ff(value, label){ + D.option(select, value, label || value); + return ff; + }; + }; + + //////////////////////////////////////////////////////////////////////// + // Edit mode selection (radio buttons). + const radio0 = + D.attr( + D.input('radio'), + 'name','wysiwyg-mode', + 'id', 'wysiwyg-mode-0', + 'value',0, + 'checked',true), + radio1 = D.attr( + D.input('radio'), + 'id','wysiwyg-mode-1', + 'name','wysiwyg-mode', + 'value',1), + radios = D.append( + D.attr(D.span(), 'id', 'wysiwygEditMode'), + radio0, D.append( + D.attr(D.label(), 'for', 'wysiwyg-mode-0'), + "WYSIWYG" + ), + radio1, D.append( + D.attr(D.label(), 'for', 'wysiwyg-mode-1'), + "Raw HTML" + ) + ); + D.append(toolbar1, radios); + const radioHandler = function(){setDocMode(+this.value)}; + radio0.addEventListener('change',radioHandler, false); + radio1.addEventListener('change',radioHandler, false); + + + //////////////////////////////////////////////////////////////////////// + // Text formatting options... + var select; + select = D.addClass(D.select(), 'format'); + select.dataset.format = "formatblock"; + D.append(toolbar1, select); + addOptions(select)( + '', '- formatting -')( + "h1", "Title 1

")( + "h2", "Title 2

")( + "h3", "Title 3

")( + "h4", "Title 4

")( + "h5", "Title 5

")( + "h6", "Subtitle
")( + "p", "Paragraph

")( + "pre", "Preformatted

");
+
+  select = D.addClass(D.select(), 'format');
+  select.dataset.format = "fontname";
+  D.append(toolbar1, select);
+  D.addClass(
+    D.option(select, '', '- font -'),
+    "heading"
+  );
+  addOptions(select)(
+    'Arial')(
+    'Arial Black')(
+    'Courier New')(
+    'Times New Roman');
+
+  select = D.addClass(D.select(), 'format');
+  D.append(toolbar1, select);
+  select.dataset.format = "fontsize";
+  D.addClass(
+    D.option(select, '', '- size -'),
+    "heading"
+  );
+  addOptions(select)(
+    "1", "Very small")(
+    "2", "A bit small")(
+    "3", "Normal")(
+    "4", "Medium-large")(
+    "5", "Big")(
+    "6", "Very big")(
+    "7", "Maximum");
+
+  select = D.addClass(D.select(), 'format');
+  D.append(toolbar1, select);
+  select.dataset.format = 'forecolor';
+  D.addClass(
+    D.option(select, '', '- color -'),
+    "heading"
+  );
+  addOptions(select)(
+    "red", "Red")(
+    "blue", "Blue")(
+    "green", "Green")(
+    "black", "Black")(
+    "grey", "Grey")(
+    "yellow", "Yellow")(
+    "cyan", "Cyan")(
+    "magenta", "Magenta");
+
+
+  ////////////////////////////////////////////////////////////////////////
+  // Icon-based toolbar...
+  /**
+     Inject the icons...
+
+     mkbuiltins strips anything which looks like a C++-style comment,
+     even if it's in a string literal, and thus the runs of "/"
+     characters in the DOM element data attributes have been mangled
+     to work around that: we simply use \x2f for every 2nd slash.
+  */
+  (function f(title,format,src){
+    const img = D.img();
+    D.append(toolbar2, img);
+    D.addClass(img, 'intLink');
+    D.attr(img, 'title', title);
+    img.dataset.format = format;
+    D.attr(img, 'src', 'string'===typeof src ? src : src.join(''));
+    return f;
+  })(
+    'Undo', 'undo',
+    ["data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7",
+     "/I19DV3NHa7P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/\x2f/\x2f/\x2f/yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq704680",
+     "7TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfE",
+     "whdRIH4fh/DZMICe3/C4nBQBADs="]
+  )(
+    'Redo','redo',
+    ["data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1/",
+     "/\x2f/yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9Na",
+     "EDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw=="]
+  )(
+    "Remove formatting",
+    "removeFormat",
+    ["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AA",
+     "AABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwA",
+     "AAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB5",
+     "01ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqG",
+     "Xz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMz",
+     "deiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3/\x2fsf37/1/c02cCG1lB8f/\x2ff95",
+     "DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af/\x2f/2ckaHBp7+7wmavP5n76+P2C",
+     "lrLIYl8H9W36auJCbCxM4szMTJac7Kza/\x2f/\x2fR3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tA",
+     "wMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n",
+     "7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1",
+     "lsXc4Db7z8C3r8p7Qjf/\x2f/2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj",
+     "5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwf",
+     "fj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv/\x2fvPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrj",
+     "b/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0/\x2f/\x2ffv77/\x2f8nLy+7MCc",
+     "XmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc66",
+     "6s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7/\x2f8/4/\x2f9/pgOnH",
+     "6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg=="]
+  )(
+    "Bold",
+    "bold",
+    ["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB",
+     "YAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs="]
+  )(
+    "Italic",
+    "italic",
+    ["data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf/\x2f/yH5BAEAAAMALA",
+     "AAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw=="]
+  )(
+    "Underline",
+    "underline",
+    ["data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj/\x2f/\x2f/\x2f/\x2fyH5BAEAAAIALA",
+     "AAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA",
+     "7"]
+  )(
+    "Left align",
+    "justifyleft",
+    ["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB",
+     "YAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw=="]
+  )(
+    "Center align",
+    "justifycenter",
+    ["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB",
+     "YAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7"]
+  )(
+    "Right align",
+    "justifyright",
+    ["data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWAB",
+     "YAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw=="]
+  )(
+    "Numbered list",
+    "insertorderedlist",
+    ["data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P/\x2f/\x2f",
+     "/\x2f/yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEO",
+     "zyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs="]
+  )(
+    "Dotted list",
+    "insertunorderedlist",
+    ["data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv/\x2f/\x2f",
+     "/\x2f/yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud6",
+     "4UwiuKnigGQliQuWOyKQykgAAOw=="]
+  )(
+    "Quote",
+    "formatblock",
+    ["data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2",
+     "R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P",
+     "/\x2f/\x2f/\x2f/\x2f/",
+     "/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/\x2f/\x2f/\x2fyH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2Cekk",
+     "ErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrT",
+     "q/b7/i8fp8PAQA7"]
+  )(
+    "Delete indentation",
+    "outdent",
+    ["data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P",
+     "/\x2f/yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMcz",
+     "sYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs="]
+  )(
+    "Add indentation",
+    "indent",
+    ["data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3N",
+     "Ha7P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/\x2f/\x2f/yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650",
+     "B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw=="
+    ]
+  )(
+    "Hyperlink",
+    "createlink",
+    ["data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb",
+     "/I19Ha7Pv8/f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq704682",
+     "7/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghG",
+     "i9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7"]
+  )(
+    "Cut",
+    "cut",
+    ["data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1",
+     "dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/",
+     "/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnE",
+     "bGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9",
+     "ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw=="]
+  )(
+    "Copy",
+    "copy",
+    ["data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31",
+     "iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OP",
+     "s++bx/Pv8/f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "/yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/",
+     "kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ",
+     "ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA",
+     "Grpy+wsbKzIiEAOw=="]
+  )(
+    /* Paste, when activated via JS, has no effect in some (maybe all)
+       environments. Activated externally, e.g. keyboard, it works. */
+    "Paste (does not work in all environments)",
+    "paste",
+    ["data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp",
+     "qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/\x2f/\x2f/\x2f",
+     "/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/",
+     "/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f/\x2f",
+     "yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB",
+     "SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ",
+     "o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA",
+     "MOaK+bLAOrtLUyt7i5uiUhADs="]
+  );
+
+  ////////////////////////////////////////////////////////////////////////
+  // The main editor area...
+  const oDoc = D.attr(D.div(), 'id', "wysiwygBox");
+  D.attr(oDoc, 'contenteditable', 'true');
+  D.append(outerContainer, oDoc);
+  
+  /* Initialize the document editor */
+  function initDoc() {
+    initEventHandlers();
+    if (!isWysiwyg()) { setDocMode(true); }
+  }
+
+  function initEventHandlers() {
+    //console.debug("initEventHandlers()");
+    const handleDropDown = function() {
+      formatDoc(this.dataset.format,this[this.selectedIndex].value);
+      this.selectedIndex = 0;
+    };
+    
+    const handleFormatButton = function() {
+      var extra;
+      switch (this.dataset.format) {
+      case 'createlink':
+        const sLnk = prompt('Target URL:','');
+        if(sLnk) extra = sLnk;
+        break;
+      case 'formatblock':
+        extra = 'blockquote';
+        break;
+      }
+      formatDoc(this.dataset.format, extra);
+    };
+
+    var i, controls = outerContainer.querySelectorAll('select.format');
+    for(i = 0; i < controls.length; i++) {
+      controls[i].addEventListener('change', handleDropDown, false);;
+    }
+    controls = outerContainer.querySelectorAll('.intLink');
+    for(i = 0; i < controls.length; i++) {
+      controls[i].addEventListener('click', handleFormatButton, false);
+    }
+  }
+
+  /* Return true if the document editor is in WYSIWYG mode.  Return
+  ** false if it is in Markup mode */
+  function isWysiwyg() {
+    return radio0.checked;
+  }
+
+  /* Run the editing command if in WYSIWYG mode */
+  function formatDoc(sCmd, sValue) {
+    if (isWysiwyg()){
+      try {
+        // First, try the W3C draft standard way, which has
+        // been working on all non-IE browsers for a while.
+        // It is also supported by IE11 and higher.
+        document.execCommand("styleWithCSS", false, false);
+      } catch (e) {
+        try {
+          // For IE9 or IE10, this should work.
+          document.execCommand("useCSS", 0, true);
+        } catch (e) {
+          // OK, that apparently did not work, do nothing.
+        }
+      }
+      document.execCommand(sCmd, false, sValue);
+      oDoc.focus();
+    }
+  }
+
+  /* Change the editing mode.  Convert to markup if the argument
+  ** is true and wysiwyg if the argument is false. */
+  function setDocMode(bToMarkup, content) {
+    if(undefined===content){
+      content = bToMarkup ? oDoc.innerHTML : oDoc.innerText;
+    }
+    if(!setDocMode.linebreak){
+      setDocMode.linebreak = new RegExp("

","ig"); + } + if(!setDocMode.toHide){ + setDocMode.toHide = toolbars.querySelectorAll( + '#wysiwyg-toolBar1 > *:not(#wysiwygEditMode), ' + +'#wysiwyg-toolBar2'); + } + if (bToMarkup) { + /* WYSIWYG -> Markup */ + // Legacy did this: content=content.replace(setDocMode.linebreak,"

\n\n

") + D.append(D.clearElement(oDoc), content) + oDoc.style.whiteSpace = "pre-wrap"; + D.addClass(setDocMode.toHide, 'hidden'); + } else { + /* Markup -> WYSIWYG */ + D.parseHtml(D.clearElement(oDoc), content); + oDoc.style.whiteSpace = "normal"; + D.removeClass(setDocMode.toHide, 'hidden'); + } + oDoc.focus(); + } + + //////////////////////////////////////////////////////////////////////// + // A hook which can be activated via a site skin to plug this editor + // into the wikiedit page. + F.page.wysiwyg = { + // only for debugging: oDoc: oDoc, + /* + Replaces wikiedit's default editor widget with this wysiwyg + editor. + + Must either be called via an onPageLoad handler via the site + skin's footer or else it can be called manually from the dev + tools console. Calling it too early (e.g. in the page footer + outside of an onPageLoad handler) will crash because wikiedit + has not been initialized. + */ + init: function(){ + initDoc(); + const content = F.page.wikiContent() || ''; + var isDirty = false /* keep from stashing too often */; + F.page.setContentMethods( + function(){ + const rc = isWysiwyg() ? oDoc.innerHTML : oDoc.innerText; + return rc; + }, + function(content){ + isDirty = false; + setDocMode(radio0.checked ? 0 : 1, content); + } + ); + oDoc.addEventListener('blur', function(){ + if(isDirty) F.page.notifyOfChange(); + }, false); + oDoc.addEventListener('input', function(){isDirty = true}, false); + F.page.wikiContent(content)/*feed it back in to our widget*/; + F.page.replaceEditorElement(outerContainer); + F.message("Replaced wiki editor widget with legacy wysiwyg editor."); + } + }; +})(window.fossil); -- cgit v1.3.1