Fossil SCM
Some wysiwyg code reduction, balanced out by more docs ;).
Commit
79cb2df73ca12e314cb6079c6d71d87cd2aa07caf64cd0cd4386f83bc0bf2e38
Parent
b8297d34bd3e009…
1 file changed
+85
-54
| --- src/fossil.page.wikiedit-wysiwyg-legacy.js | ||
| +++ src/fossil.page.wikiedit-wysiwyg-legacy.js | ||
| @@ -1,11 +1,12 @@ | ||
| 1 | 1 | /** |
| 2 | 2 | A slight adaptation of fossil's legacy wysiwyg wiki editor which |
| 3 | 3 | makes it usable with the newer editor's edit widget replacement |
| 4 | 4 | API. |
| 5 | 5 | |
| 6 | - Requires: window.fossil, fossil.dom. | |
| 6 | + Requires: window.fossil, fossil.dom, and that the current page is | |
| 7 | + /wikiedit. If called from another page it returns without effect. | |
| 7 | 8 | */ |
| 8 | 9 | (function(F/*fossil object*/){ |
| 9 | 10 | 'use strict'; |
| 10 | 11 | if(!F || !F.page || F.page.name!=='wikiedit') return; |
| 11 | 12 | |
| @@ -57,88 +58,105 @@ | ||
| 57 | 58 | D.append(styleTag, styleCSS); |
| 58 | 59 | })(); |
| 59 | 60 | |
| 60 | 61 | const outerContainer = D.attr(D.div(), 'id', 'wysiwyg-container'); |
| 61 | 62 | |
| 62 | - const toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'); | |
| 63 | - D.append(outerContainer, toolbars); | |
| 63 | + const toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'), | |
| 64 | + toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'), | |
| 65 | + toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2'); | |
| 66 | + D.append(outerContainer, | |
| 67 | + D.append(toolbars, toolbar1, toolbar2)); | |
| 64 | 68 | |
| 65 | - var select, div; | |
| 69 | + /** Returns a function which simplifies adding a list of options | |
| 70 | + to the given select element. See below for example usage. */ | |
| 71 | + const addOptions = function(select){ | |
| 72 | + return function ff(value, label){ | |
| 73 | + D.option(select, value, label || value); | |
| 74 | + return ff; | |
| 75 | + }; | |
| 76 | + }; | |
| 66 | 77 | |
| 67 | - const toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'); | |
| 68 | - | |
| 78 | + //////////////////////////////////////////////////////////////////////// | |
| 79 | + // Edit mode selection button | |
| 80 | + var select; | |
| 69 | 81 | const selectEditMode = select = D.attr( |
| 70 | 82 | D.attr(D.select(), 'id', 'wysiwygEditMode'), |
| 71 | 83 | 'size', |
| 72 | 84 | 1 |
| 73 | 85 | ); |
| 74 | 86 | D.append(toolbar1, select); |
| 75 | - D.option(select, "0", "WYSIWYG"); | |
| 76 | - D.option(select, "1", "Raw HTML"); | |
| 87 | + addOptions(select)( | |
| 88 | + 0, "WYSIWYG")( | |
| 89 | + 1, "Raw HTML"); | |
| 77 | 90 | select.selectedIndex = 0; |
| 78 | 91 | |
| 79 | - | |
| 80 | - div = toolbar1; | |
| 81 | - D.append(toolbars, ' ', toolbar1); | |
| 92 | + | |
| 93 | + //////////////////////////////////////////////////////////////////////// | |
| 94 | + // Text formatting options... | |
| 82 | 95 | select = D.addClass(D.select(), 'format'); |
| 83 | 96 | select.dataset.format = "formatblock"; |
| 84 | - D.append(div, select); | |
| 85 | - D.option(select, '', '- formatting -'); | |
| 86 | - D.option(select, "h1", "Title 1 <h1>"); | |
| 87 | - D.option(select, "h2", "Title 2 <h2>"); | |
| 88 | - D.option(select, "h3", "Title 3 <h3>"); | |
| 89 | - D.option(select, "h4", "Title 4 <h4>"); | |
| 90 | - D.option(select, "h5", "Title 5 <h5>"); | |
| 91 | - D.option(select, "h6", "Subtitle <h6>"); | |
| 92 | - D.option(select, "p", "Paragraph <p>"); | |
| 93 | - D.option(select, "pre", "Preformatted <pre>"); | |
| 97 | + D.append(toolbar1, select); | |
| 98 | + addOptions(select)( | |
| 99 | + '', '- formatting -')( | |
| 100 | + "h1", "Title 1 <h1>")( | |
| 101 | + "h2", "Title 2 <h2>")( | |
| 102 | + "h3", "Title 3 <h3>")( | |
| 103 | + "h4", "Title 4 <h4>")( | |
| 104 | + "h5", "Title 5 <h5>")( | |
| 105 | + "h6", "Subtitle <h6>")( | |
| 106 | + "p", "Paragraph <p>")( | |
| 107 | + "pre", "Preformatted <pre>"); | |
| 94 | 108 | |
| 95 | 109 | select = D.addClass(D.select(), 'format'); |
| 96 | 110 | select.dataset.format = "fontname"; |
| 97 | - D.append(div, select); | |
| 111 | + D.append(toolbar1, select); | |
| 98 | 112 | D.addClass( |
| 99 | 113 | D.option(select, '', '- font -'), |
| 100 | 114 | "heading" |
| 101 | 115 | ); |
| 102 | - D.option(select, 'Arial'); | |
| 103 | - D.option(select, 'Arial Black'); | |
| 104 | - D.option(select, 'Courier New'); | |
| 105 | - D.option(select, 'Times New Roman'); | |
| 116 | + addOptions(select)( | |
| 117 | + 'Arial')( | |
| 118 | + 'Arial Black')( | |
| 119 | + 'Courier New')( | |
| 120 | + 'Times New Roman'); | |
| 106 | 121 | |
| 107 | 122 | select = D.addClass(D.select(), 'format'); |
| 108 | - D.append(div, select); | |
| 123 | + D.append(toolbar1, select); | |
| 109 | 124 | select.dataset.format = "fontsize"; |
| 110 | 125 | D.addClass( |
| 111 | 126 | D.option(select, '', '- size -'), |
| 112 | 127 | "heading" |
| 113 | 128 | ); |
| 114 | - D.option(select, "1", "Very small"); | |
| 115 | - D.option(select, "2", "A bit small"); | |
| 116 | - D.option(select, "3", "Normal"); | |
| 117 | - D.option(select, "4", "Medium-large"); | |
| 118 | - D.option(select, "5", "Big"); | |
| 119 | - D.option(select, "6", "Very big"); | |
| 120 | - D.option(select, "7", "Maximum"); | |
| 129 | + addOptions(select)( | |
| 130 | + "1", "Very small")( | |
| 131 | + "2", "A bit small")( | |
| 132 | + "3", "Normal")( | |
| 133 | + "4", "Medium-large")( | |
| 134 | + "5", "Big")( | |
| 135 | + "6", "Very big")( | |
| 136 | + "7", "Maximum"); | |
| 121 | 137 | |
| 122 | 138 | select = D.addClass(D.select(), 'format'); |
| 123 | - D.append(div, select); | |
| 139 | + D.append(toolbar1, select); | |
| 124 | 140 | select.dataset.format = 'forecolor'; |
| 125 | 141 | D.addClass( |
| 126 | 142 | D.option(select, '', '- color -'), |
| 127 | 143 | "heading" |
| 128 | 144 | ); |
| 129 | - D.option(select, "red", "Red"); | |
| 130 | - D.option(select, "blue", "Blue"); | |
| 131 | - D.option(select, "green", "Green"); | |
| 132 | - D.option(select, "black", "Black"); | |
| 133 | - D.option(select, "yellow", "Yellow"); | |
| 134 | - D.option(select, "cyan", "Cyan"); | |
| 135 | - D.option(select, "magenta", "Magenta"); | |
| 136 | - | |
| 137 | - const toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2'); | |
| 138 | - D.append(toolbars, toolbar2); | |
| 139 | - | |
| 145 | + addOptions(select)( | |
| 146 | + "red", "Red")( | |
| 147 | + "blue", "Blue")( | |
| 148 | + "green", "Green")( | |
| 149 | + "black", "Black")( | |
| 150 | + "grey", "Grey")( | |
| 151 | + "yellow", "Yellow")( | |
| 152 | + "cyan", "Cyan")( | |
| 153 | + "magenta", "Magenta"); | |
| 154 | + | |
| 155 | + | |
| 156 | + //////////////////////////////////////////////////////////////////////// | |
| 157 | + // Icon-based toolbar... | |
| 140 | 158 | /** |
| 141 | 159 | Inject the icons... |
| 142 | 160 | |
| 143 | 161 | mkbuiltins strips anything which looks like a C++-style comment, |
| 144 | 162 | even if it's in a string literal, and thus the runs of "/" |
| @@ -274,23 +292,27 @@ | ||
| 274 | 292 | "s++bx/Pv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/", |
| 275 | 293 | "kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ", |
| 276 | 294 | "ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA", |
| 277 | 295 | "Grpy+wsbKzIiEAOw=="] |
| 278 | 296 | )( |
| 279 | - "Paste", | |
| 297 | + /* Paste, when activated via JS, has no effect in some (maybe all) | |
| 298 | + environments. Activated externally, e.g. keyboard, it works. */ | |
| 299 | + "Paste (does not work in all environments)", | |
| 280 | 300 | "paste", |
| 281 | 301 | ["data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp", |
| 282 | 302 | "qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/", |
| 283 | 303 | "/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002fyH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB", |
| 284 | 304 | "SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ", |
| 285 | 305 | "o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA", |
| 286 | 306 | "MOaK+bLAOrtLUyt7i5uiUhADs="] |
| 287 | 307 | ); |
| 288 | 308 | |
| 289 | - const oDoc = div = D.attr(D.div(), 'id', "wysiwygBox"); | |
| 290 | - D.attr(div, 'contenteditable', 'true'); | |
| 291 | - D.append(outerContainer, div); | |
| 309 | + //////////////////////////////////////////////////////////////////////// | |
| 310 | + // The main editor area... | |
| 311 | + const oDoc = D.attr(D.div(), 'id', "wysiwygBox"); | |
| 312 | + D.attr(oDoc, 'contenteditable', 'true'); | |
| 313 | + D.append(outerContainer, oDoc); | |
| 292 | 314 | |
| 293 | 315 | /* Initialize the document editor */ |
| 294 | 316 | function initDoc() { |
| 295 | 317 | initEventHandlers(); |
| 296 | 318 | if (!isWysiwyg()) { setDocMode(true); } |
| @@ -320,16 +342,14 @@ | ||
| 320 | 342 | selectEditMode.addEventListener('change',function() { |
| 321 | 343 | setDocMode(this.selectedIndex) |
| 322 | 344 | },false); |
| 323 | 345 | var i, controls = outerContainer.querySelectorAll('select.format'); |
| 324 | 346 | for(i = 0; i < controls.length; i++) { |
| 325 | - //console.debug("select.format",controls[i]); | |
| 326 | 347 | controls[i].addEventListener('change', handleDropDown, false);; |
| 327 | 348 | } |
| 328 | 349 | controls = outerContainer.querySelectorAll('.intLink'); |
| 329 | 350 | for(i = 0; i < controls.length; i++) { |
| 330 | - //console.debug("intLink",controls[i]); | |
| 331 | 351 | controls[i].addEventListener('click', handleFormatButton, false); |
| 332 | 352 | } |
| 333 | 353 | } |
| 334 | 354 | |
| 335 | 355 | /* Return true if the document editor is in WYSIWYG mode. Return |
| @@ -393,16 +413,27 @@ | ||
| 393 | 413 | D.removeClass(setDocMode.toHide, 'hidden'); |
| 394 | 414 | } |
| 395 | 415 | oDoc.focus(); |
| 396 | 416 | } |
| 397 | 417 | |
| 418 | + //////////////////////////////////////////////////////////////////////// | |
| 419 | + // A hook which can be activated via a site skin to plug this editor | |
| 420 | + // in to the wikiedit page. | |
| 398 | 421 | F.page.wysiwyg = { |
| 399 | 422 | // only for debugging: oDoc: oDoc, |
| 423 | + /* | |
| 424 | + Replaces wikiedit's default editor widget with this wysiwyg | |
| 425 | + editor. | |
| 426 | + | |
| 427 | + Must either be called via an onPageLoad handler instead via the | |
| 428 | + site skin's footer or else it can be called manually from the | |
| 429 | + dev tools console. Calling it too early (e.g. in the page | |
| 430 | + footer *without* outside of an an onPageLoad handler) will | |
| 431 | + crash because wikiedit has not been initialized. | |
| 432 | + */ | |
| 400 | 433 | init: function(){ |
| 401 | 434 | initDoc(); |
| 402 | - /* Must not be called outside of an onPageLoad handler, else it | |
| 403 | - can run before to the wikiedit app has been initialized. */ | |
| 404 | 435 | const content = F.page.wikiContent() || ''; |
| 405 | 436 | var isDirty = false /* keep from stashing too often */; |
| 406 | 437 | F.page.setContentMethods( |
| 407 | 438 | function(){ |
| 408 | 439 | //selectEditMode.selectedIndex = 1; |
| 409 | 440 |
| --- src/fossil.page.wikiedit-wysiwyg-legacy.js | |
| +++ src/fossil.page.wikiedit-wysiwyg-legacy.js | |
| @@ -1,11 +1,12 @@ | |
| 1 | /** |
| 2 | A slight adaptation of fossil's legacy wysiwyg wiki editor which |
| 3 | makes it usable with the newer editor's edit widget replacement |
| 4 | API. |
| 5 | |
| 6 | Requires: window.fossil, fossil.dom. |
| 7 | */ |
| 8 | (function(F/*fossil object*/){ |
| 9 | 'use strict'; |
| 10 | if(!F || !F.page || F.page.name!=='wikiedit') return; |
| 11 | |
| @@ -57,88 +58,105 @@ | |
| 57 | D.append(styleTag, styleCSS); |
| 58 | })(); |
| 59 | |
| 60 | const outerContainer = D.attr(D.div(), 'id', 'wysiwyg-container'); |
| 61 | |
| 62 | const toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'); |
| 63 | D.append(outerContainer, toolbars); |
| 64 | |
| 65 | var select, div; |
| 66 | |
| 67 | const toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'); |
| 68 | |
| 69 | const selectEditMode = select = D.attr( |
| 70 | D.attr(D.select(), 'id', 'wysiwygEditMode'), |
| 71 | 'size', |
| 72 | 1 |
| 73 | ); |
| 74 | D.append(toolbar1, select); |
| 75 | D.option(select, "0", "WYSIWYG"); |
| 76 | D.option(select, "1", "Raw HTML"); |
| 77 | select.selectedIndex = 0; |
| 78 | |
| 79 | |
| 80 | div = toolbar1; |
| 81 | D.append(toolbars, ' ', toolbar1); |
| 82 | select = D.addClass(D.select(), 'format'); |
| 83 | select.dataset.format = "formatblock"; |
| 84 | D.append(div, select); |
| 85 | D.option(select, '', '- formatting -'); |
| 86 | D.option(select, "h1", "Title 1 <h1>"); |
| 87 | D.option(select, "h2", "Title 2 <h2>"); |
| 88 | D.option(select, "h3", "Title 3 <h3>"); |
| 89 | D.option(select, "h4", "Title 4 <h4>"); |
| 90 | D.option(select, "h5", "Title 5 <h5>"); |
| 91 | D.option(select, "h6", "Subtitle <h6>"); |
| 92 | D.option(select, "p", "Paragraph <p>"); |
| 93 | D.option(select, "pre", "Preformatted <pre>"); |
| 94 | |
| 95 | select = D.addClass(D.select(), 'format'); |
| 96 | select.dataset.format = "fontname"; |
| 97 | D.append(div, select); |
| 98 | D.addClass( |
| 99 | D.option(select, '', '- font -'), |
| 100 | "heading" |
| 101 | ); |
| 102 | D.option(select, 'Arial'); |
| 103 | D.option(select, 'Arial Black'); |
| 104 | D.option(select, 'Courier New'); |
| 105 | D.option(select, 'Times New Roman'); |
| 106 | |
| 107 | select = D.addClass(D.select(), 'format'); |
| 108 | D.append(div, select); |
| 109 | select.dataset.format = "fontsize"; |
| 110 | D.addClass( |
| 111 | D.option(select, '', '- size -'), |
| 112 | "heading" |
| 113 | ); |
| 114 | D.option(select, "1", "Very small"); |
| 115 | D.option(select, "2", "A bit small"); |
| 116 | D.option(select, "3", "Normal"); |
| 117 | D.option(select, "4", "Medium-large"); |
| 118 | D.option(select, "5", "Big"); |
| 119 | D.option(select, "6", "Very big"); |
| 120 | D.option(select, "7", "Maximum"); |
| 121 | |
| 122 | select = D.addClass(D.select(), 'format'); |
| 123 | D.append(div, select); |
| 124 | select.dataset.format = 'forecolor'; |
| 125 | D.addClass( |
| 126 | D.option(select, '', '- color -'), |
| 127 | "heading" |
| 128 | ); |
| 129 | D.option(select, "red", "Red"); |
| 130 | D.option(select, "blue", "Blue"); |
| 131 | D.option(select, "green", "Green"); |
| 132 | D.option(select, "black", "Black"); |
| 133 | D.option(select, "yellow", "Yellow"); |
| 134 | D.option(select, "cyan", "Cyan"); |
| 135 | D.option(select, "magenta", "Magenta"); |
| 136 | |
| 137 | const toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2'); |
| 138 | D.append(toolbars, toolbar2); |
| 139 | |
| 140 | /** |
| 141 | Inject the icons... |
| 142 | |
| 143 | mkbuiltins strips anything which looks like a C++-style comment, |
| 144 | even if it's in a string literal, and thus the runs of "/" |
| @@ -274,23 +292,27 @@ | |
| 274 | "s++bx/Pv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/", |
| 275 | "kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ", |
| 276 | "ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA", |
| 277 | "Grpy+wsbKzIiEAOw=="] |
| 278 | )( |
| 279 | "Paste", |
| 280 | "paste", |
| 281 | ["data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp", |
| 282 | "qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/", |
| 283 | "/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002fyH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB", |
| 284 | "SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ", |
| 285 | "o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA", |
| 286 | "MOaK+bLAOrtLUyt7i5uiUhADs="] |
| 287 | ); |
| 288 | |
| 289 | const oDoc = div = D.attr(D.div(), 'id', "wysiwygBox"); |
| 290 | D.attr(div, 'contenteditable', 'true'); |
| 291 | D.append(outerContainer, div); |
| 292 | |
| 293 | /* Initialize the document editor */ |
| 294 | function initDoc() { |
| 295 | initEventHandlers(); |
| 296 | if (!isWysiwyg()) { setDocMode(true); } |
| @@ -320,16 +342,14 @@ | |
| 320 | selectEditMode.addEventListener('change',function() { |
| 321 | setDocMode(this.selectedIndex) |
| 322 | },false); |
| 323 | var i, controls = outerContainer.querySelectorAll('select.format'); |
| 324 | for(i = 0; i < controls.length; i++) { |
| 325 | //console.debug("select.format",controls[i]); |
| 326 | controls[i].addEventListener('change', handleDropDown, false);; |
| 327 | } |
| 328 | controls = outerContainer.querySelectorAll('.intLink'); |
| 329 | for(i = 0; i < controls.length; i++) { |
| 330 | //console.debug("intLink",controls[i]); |
| 331 | controls[i].addEventListener('click', handleFormatButton, false); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /* Return true if the document editor is in WYSIWYG mode. Return |
| @@ -393,16 +413,27 @@ | |
| 393 | D.removeClass(setDocMode.toHide, 'hidden'); |
| 394 | } |
| 395 | oDoc.focus(); |
| 396 | } |
| 397 | |
| 398 | F.page.wysiwyg = { |
| 399 | // only for debugging: oDoc: oDoc, |
| 400 | init: function(){ |
| 401 | initDoc(); |
| 402 | /* Must not be called outside of an onPageLoad handler, else it |
| 403 | can run before to the wikiedit app has been initialized. */ |
| 404 | const content = F.page.wikiContent() || ''; |
| 405 | var isDirty = false /* keep from stashing too often */; |
| 406 | F.page.setContentMethods( |
| 407 | function(){ |
| 408 | //selectEditMode.selectedIndex = 1; |
| 409 |
| --- src/fossil.page.wikiedit-wysiwyg-legacy.js | |
| +++ src/fossil.page.wikiedit-wysiwyg-legacy.js | |
| @@ -1,11 +1,12 @@ | |
| 1 | /** |
| 2 | A slight adaptation of fossil's legacy wysiwyg wiki editor which |
| 3 | makes it usable with the newer editor's edit widget replacement |
| 4 | API. |
| 5 | |
| 6 | Requires: window.fossil, fossil.dom, and that the current page is |
| 7 | /wikiedit. If called from another page it returns without effect. |
| 8 | */ |
| 9 | (function(F/*fossil object*/){ |
| 10 | 'use strict'; |
| 11 | if(!F || !F.page || F.page.name!=='wikiedit') return; |
| 12 | |
| @@ -57,88 +58,105 @@ | |
| 58 | D.append(styleTag, styleCSS); |
| 59 | })(); |
| 60 | |
| 61 | const outerContainer = D.attr(D.div(), 'id', 'wysiwyg-container'); |
| 62 | |
| 63 | const toolbars = D.attr(D.div(), 'id', 'wysiwyg-toolbars'), |
| 64 | toolbar1 = D.attr(D.div(), 'id', 'wysiwyg-toolBar1'), |
| 65 | toolbar2 = D.attr(D.div(), 'id', 'wysiwyg-toolBar2'); |
| 66 | D.append(outerContainer, |
| 67 | D.append(toolbars, toolbar1, toolbar2)); |
| 68 | |
| 69 | /** Returns a function which simplifies adding a list of options |
| 70 | to the given select element. See below for example usage. */ |
| 71 | const addOptions = function(select){ |
| 72 | return function ff(value, label){ |
| 73 | D.option(select, value, label || value); |
| 74 | return ff; |
| 75 | }; |
| 76 | }; |
| 77 | |
| 78 | //////////////////////////////////////////////////////////////////////// |
| 79 | // Edit mode selection button |
| 80 | var select; |
| 81 | const selectEditMode = select = D.attr( |
| 82 | D.attr(D.select(), 'id', 'wysiwygEditMode'), |
| 83 | 'size', |
| 84 | 1 |
| 85 | ); |
| 86 | D.append(toolbar1, select); |
| 87 | addOptions(select)( |
| 88 | 0, "WYSIWYG")( |
| 89 | 1, "Raw HTML"); |
| 90 | select.selectedIndex = 0; |
| 91 | |
| 92 | |
| 93 | //////////////////////////////////////////////////////////////////////// |
| 94 | // Text formatting options... |
| 95 | select = D.addClass(D.select(), 'format'); |
| 96 | select.dataset.format = "formatblock"; |
| 97 | D.append(toolbar1, select); |
| 98 | addOptions(select)( |
| 99 | '', '- formatting -')( |
| 100 | "h1", "Title 1 <h1>")( |
| 101 | "h2", "Title 2 <h2>")( |
| 102 | "h3", "Title 3 <h3>")( |
| 103 | "h4", "Title 4 <h4>")( |
| 104 | "h5", "Title 5 <h5>")( |
| 105 | "h6", "Subtitle <h6>")( |
| 106 | "p", "Paragraph <p>")( |
| 107 | "pre", "Preformatted <pre>"); |
| 108 | |
| 109 | select = D.addClass(D.select(), 'format'); |
| 110 | select.dataset.format = "fontname"; |
| 111 | D.append(toolbar1, select); |
| 112 | D.addClass( |
| 113 | D.option(select, '', '- font -'), |
| 114 | "heading" |
| 115 | ); |
| 116 | addOptions(select)( |
| 117 | 'Arial')( |
| 118 | 'Arial Black')( |
| 119 | 'Courier New')( |
| 120 | 'Times New Roman'); |
| 121 | |
| 122 | select = D.addClass(D.select(), 'format'); |
| 123 | D.append(toolbar1, select); |
| 124 | select.dataset.format = "fontsize"; |
| 125 | D.addClass( |
| 126 | D.option(select, '', '- size -'), |
| 127 | "heading" |
| 128 | ); |
| 129 | addOptions(select)( |
| 130 | "1", "Very small")( |
| 131 | "2", "A bit small")( |
| 132 | "3", "Normal")( |
| 133 | "4", "Medium-large")( |
| 134 | "5", "Big")( |
| 135 | "6", "Very big")( |
| 136 | "7", "Maximum"); |
| 137 | |
| 138 | select = D.addClass(D.select(), 'format'); |
| 139 | D.append(toolbar1, select); |
| 140 | select.dataset.format = 'forecolor'; |
| 141 | D.addClass( |
| 142 | D.option(select, '', '- color -'), |
| 143 | "heading" |
| 144 | ); |
| 145 | addOptions(select)( |
| 146 | "red", "Red")( |
| 147 | "blue", "Blue")( |
| 148 | "green", "Green")( |
| 149 | "black", "Black")( |
| 150 | "grey", "Grey")( |
| 151 | "yellow", "Yellow")( |
| 152 | "cyan", "Cyan")( |
| 153 | "magenta", "Magenta"); |
| 154 | |
| 155 | |
| 156 | //////////////////////////////////////////////////////////////////////// |
| 157 | // Icon-based toolbar... |
| 158 | /** |
| 159 | Inject the icons... |
| 160 | |
| 161 | mkbuiltins strips anything which looks like a C++-style comment, |
| 162 | even if it's in a string literal, and thus the runs of "/" |
| @@ -274,23 +292,27 @@ | |
| 292 | "s++bx/Pv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/", |
| 293 | "kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQ", |
| 294 | "ACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAA", |
| 295 | "Grpy+wsbKzIiEAOw=="] |
| 296 | )( |
| 297 | /* Paste, when activated via JS, has no effect in some (maybe all) |
| 298 | environments. Activated externally, e.g. keyboard, it works. */ |
| 299 | "Paste (does not work in all environments)", |
| 300 | "paste", |
| 301 | ["data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrp", |
| 302 | "qbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/", |
| 303 | "/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002f/\u002fyH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvB", |
| 304 | "SyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQ", |
| 305 | "o9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAA", |
| 306 | "MOaK+bLAOrtLUyt7i5uiUhADs="] |
| 307 | ); |
| 308 | |
| 309 | //////////////////////////////////////////////////////////////////////// |
| 310 | // The main editor area... |
| 311 | const oDoc = D.attr(D.div(), 'id', "wysiwygBox"); |
| 312 | D.attr(oDoc, 'contenteditable', 'true'); |
| 313 | D.append(outerContainer, oDoc); |
| 314 | |
| 315 | /* Initialize the document editor */ |
| 316 | function initDoc() { |
| 317 | initEventHandlers(); |
| 318 | if (!isWysiwyg()) { setDocMode(true); } |
| @@ -320,16 +342,14 @@ | |
| 342 | selectEditMode.addEventListener('change',function() { |
| 343 | setDocMode(this.selectedIndex) |
| 344 | },false); |
| 345 | var i, controls = outerContainer.querySelectorAll('select.format'); |
| 346 | for(i = 0; i < controls.length; i++) { |
| 347 | controls[i].addEventListener('change', handleDropDown, false);; |
| 348 | } |
| 349 | controls = outerContainer.querySelectorAll('.intLink'); |
| 350 | for(i = 0; i < controls.length; i++) { |
| 351 | controls[i].addEventListener('click', handleFormatButton, false); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | /* Return true if the document editor is in WYSIWYG mode. Return |
| @@ -393,16 +413,27 @@ | |
| 413 | D.removeClass(setDocMode.toHide, 'hidden'); |
| 414 | } |
| 415 | oDoc.focus(); |
| 416 | } |
| 417 | |
| 418 | //////////////////////////////////////////////////////////////////////// |
| 419 | // A hook which can be activated via a site skin to plug this editor |
| 420 | // in to the wikiedit page. |
| 421 | F.page.wysiwyg = { |
| 422 | // only for debugging: oDoc: oDoc, |
| 423 | /* |
| 424 | Replaces wikiedit's default editor widget with this wysiwyg |
| 425 | editor. |
| 426 | |
| 427 | Must either be called via an onPageLoad handler instead via the |
| 428 | site skin's footer or else it can be called manually from the |
| 429 | dev tools console. Calling it too early (e.g. in the page |
| 430 | footer *without* outside of an an onPageLoad handler) will |
| 431 | crash because wikiedit has not been initialized. |
| 432 | */ |
| 433 | init: function(){ |
| 434 | initDoc(); |
| 435 | const content = F.page.wikiContent() || ''; |
| 436 | var isDirty = false /* keep from stashing too often */; |
| 437 | F.page.setContentMethods( |
| 438 | function(){ |
| 439 | //selectEditMode.selectedIndex = 1; |
| 440 |