1/******************************************************************************* 2 * $URL: $ 3 * $Id: $ 4 * ********************************************************************************** 5 * 6 * Copyright (c) 2010 The Sakai Foundation 7 * 8 * Licensed under the Educational Community License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.opensource.org/licenses/ECL-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 ******************************************************************************/ 21var sakai = sakai || {}; 22sakai.editor = sakai.editor || {}; 23sakai.editor.editors = sakai.editor.editors || {}; 24// Temporarily disable enableResourceSearch till citations plugin is ported (SAK-22862) 25sakai.editor.enableResourceSearch = false; 26 27sakai.editor.editors.ckeditor = sakai.editor.editors.ckeditor || {} ; 28 29//get path of directory ckeditor 30var basePath = "/library/editor/ckextraplugins/"; 31var webJars = "/library/webjars/" 32 33// Update properties in one object from another: https://stackoverflow.com/a/12534361/3708872 34// I believe this is available as lodash.merge but don't see that available here yet and this looked like the simplest version of that 35function objectMerge(obj/*, ...*/) { 36 for (var i=1; i<arguments.length; i++) { 37 for (var prop in arguments[i]) { 38 var val = arguments[i][prop]; 39 if (typeof val == "object") // this also applies to arrays or null! 40 objectMerge(obj[prop], val); 41 else 42 obj[prop] = val; 43 } 44 } 45 return obj; 46} 47 48// Please note that no more parameters should be added to this signature. 49// The config object allows for name-based config options to be passed. 50// The w and h parameters should be removed as soon as their uses can be migrated. 51sakai.editor.editors.ckeditor.launch = function(targetId, config, w, h) { 52 //http://www.quirksmode.org/js/findpos.html 53 function findPos(obj) { 54 var curleft = curtop = 0; 55 if (obj.offsetParent) { 56 do { 57 curleft += obj.offsetLeft; 58 curtop += obj.offsetTop; 59 } while (obj = obj.offsetParent); 60 return [curleft,curtop]; 61 } 62 } 63 64 //http://stackoverflow.com/a/1038781/3708872 65 function getWidth() { 66 if (self.innerHeight) { 67 return self.innerWidth; 68 } 69 70 if (document.documentElement && document.documentElement.clientWidth) { 71 return document.documentElement.clientWidth; 72 } 73 74 if (document.body) { 75 return document.body.clientWidth; 76 } 77 } 78 79 function addClassOnLoad(){ 80 try { 81 if (typeof this.instances !== 'undefined'){ 82 //Run on all ckeditor instances on the page 83 for (const instance in this.instances) { 84 //check for the instance to be an object not a function 85 if (Object.hasOwnProperty.call(this.instances, instance)) { 86 const instanceDoc = this.instances[instance]; 87 //Add sakai-dark-theme class to ckeditor iframe 88 instanceDoc.document.$.documentElement.classList.add('sakaiUserTheme-dark'); 89 } 90 } 91 } 92 } catch (error) { 93 console.error(error); 94 } 95 } 96 97 function addClassOnModeChange(){ 98 try { 99 //Only run when switching out of source mode into mysiwyg mode 100 if (this.mode === 'wysiwyg') { 101 //Check for the editor to be an object not a function 102 if (Object.prototype.hasOwnProperty.call(this, 'document')) { 103 const instanceDoc = this.document.$; 104 //Add sakai-dark-theme class to ckeditor iframe 105 instanceDoc.documentElement.classList.add('sakaiUserTheme-dark'); 106 } 107 } 108 } catch (error) { 109 console.error(error); 110 } 111 } 112 113 var folder = ""; 114 115 var collectionId = ""; 116 if (config != null && config.collectionId) { 117 collectionId=config.collectionId; 118 } 119 else if (sakai.editor.collectionId) { 120 collectionId=sakai.editor.collectionId 121 } 122 123 if (collectionId) { 124 folder = "CurrentFolder=" + collectionId 125 } 126 127 var language = sakai.locale && sakai.locale.userLanguage || ''; 128 var country = sakai.locale && sakai.locale.userCountry || null; 129 130 if (sakai.editor.editors.ckeditor.browser === "elfinder") { 131 var elfinderUrl = '/library/editor/elfinder/sakai/elfinder.html?connector=elfinder-connector/elfinder-servlet/connector'; 132 133 // Add tilde to userId in order to avoid permission error while getting resources from user workspace 134 collectionId = collectionId.replace('/user/','/user/~'); 135 136 var filebrowser = { 137 browseUrl : elfinderUrl + '&startdir=' + collectionId, 138 imageBrowseUrl : elfinderUrl + '&startdir=' + collectionId + '&type=images', 139 flashBrowseUrl : elfinderUrl + '&startdir=' + collectionId + '&type=flash' 140 }; 141 142 } else { 143 var fckeditorUrl = '/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html' + 144 '?Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector'; 145 146 var filebrowser = { 147 browseUrl : fckeditorUrl + collectionId + '&' + folder, 148 imageBrowseUrl : fckeditorUrl + collectionId + '&' + folder + "&Type=Image", 149 flashBrowseUrl : fckeditorUrl + collectionId + '&' + folder + "&Type=Flash" 150 }; 151 } 152 153 var ckconfig = { 154 //Some defaults for audio recorder 155 audiorecorder : { 156 "maxSeconds" : 180, 157 "attemptAllowed" : Number.MAX_VALUE, 158 "attemptsRemaining": Number.MAX_VALUE 159 }, 160 skin: 'moono-lisa', 161 uiColor: 'themeswitcher', 162 defaultLanguage: 'en', 163 // SAK-31829, SAK-33279 Disable functionality in table plugin 164 //https://docs.ckeditor.com/#!/guide/dev_disallowed_content-section-how-to-allow-everything-except... 165 allowedContent: { 166 $1: { 167 // Use the ability to specify elements as an object. 168 elements: CKEDITOR.dtd, 169 attributes: true, 170 styles: true, 171 classes: true 172 } 173 }, 174 disallowedContent: 'table[cellspacing,cellpadding,border,summary]', 175 176 contentsCss: [(webJars+'bootstrap/3.3.7/css/bootstrap.min.css')], 177 178 language: language + (country ? '-' + country.toLowerCase() : ''), 179 // This is used for uploading by the autorecorder plugin. 180 // TODO Get this to work with elfinder. 181 fileConnectorUrl : '/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '?' + folder, 182 183 // These are the general URLs for browsing generally and specifically for images/flash object. 184 filebrowserBrowseUrl : filebrowser.browseUrl, 185 filebrowserImageBrowseUrl : filebrowser.imageBrowseUrl, 186 filebrowserFlashBrowseUrl : filebrowser.flashBrowseUrl, 187 188 extraPlugins: (sakai.editor.enableResourceSearch ? 'resourcesearch,' : '')+'', 189 190 191 // These two settings enable the browser's native spell checking and context menus. 192 // Control-Right-Click (Windows/Linux) or Command-Right-Click (Mac) on highlighted
192words 193 // will cause the CKEditor menu to be suppressed and display the browser's standard context 194 // menu. In some cases (Firefox and Safari, at least), this supplies corrections, suggestions, etc. 195 disableNativeSpellChecker: false, 196 browserContextMenuOnCtrl: true, 197 198 // Fix the smileys to a single location 199 smiley_path: "/library/editor/ckeditor/plugins/smiley/images/", 200 201 toolbar_Basic: 202 [ 203 ['Source', '-', 'Bold', 'Italic', 'Underline', '-', 'Link', 'Unlink', '-', 'NumberedList','BulletedList', 'Blockquote'] 204 ], 205 toolbar_Full: 206 [ 207 ['About'], 208 ['Source','-','Templates'], 209 // Uncomment the next line and comment the following to enable the default spell checker. 210 // Note that it uses spellchecker.net, displays ads and sends content to remote servers without additional setup. 211 //['Cut','Copy','Paste','PasteText','-','Print', 'SpellChecker', 'Scayt'], 212 ['Cut','Copy','Paste','PasteText','-','Print', 'SakaiPreview'], 213 ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'], 214 ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'], 215 '/', 216 ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'], 217 ['atd-ckeditor'], 218 ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'], 219 ['BidiLtr', 'BidiRtl' ], 220 ['Link','Unlink','Anchor'], 221 (sakai.editor.enableResourceSearch 222 ? ( sakai.editor.contentItemUrl 223 ? ['ContentItem', 'AudioRecorder','ResourceSearch', 'Image','Html5video','Table','HorizontalRule','Smiley','SpecialChar'] 224 : ['AudioRecorder','ResourceSearch', 'Image','Html5video','Table','HorizontalRule','Smiley','SpecialChar'] 225 ) 226 : ( sakai.editor.contentItemUrl 227 ? ['ContentItem', 'AudioRecorder', 'Image','Html5video','Table','HorizontalRule','Smiley','SpecialChar'] 228 : ['AudioRecorder', 'Image','Html5video','Table','HorizontalRule','Smiley','SpecialChar'] 229 ) 230 ), 231 '/', 232 ['Styles','Format','Font','FontSize'], 233 ['TextColor','BGColor'], 234 ['Maximize', 'ShowBlocks'] 235 ,['A11ychecker'] 236 ], 237 toolbar: 'Full', 238 resize_dir: 'both', 239 //SAK-23418 240 pasteFromWordRemoveFontStyles : false, 241 pasteFromWordRemoveStyles : false, 242 autosave : { 243 saveDetectionSelectors : "form input[type='button'],form input[type='submit']", 244 //Delay for autosave 245 delay: 120, 246 //autosave_messageType can be "no" or "notification" 247 messageType : "statusbar" 248 }, 249 250 //wordcount Plugin see https://github.com/w8tcha/CKEditor-WordCount-Plugin for more config options 251 //This value should match the one in antisamy (kernel/kernel-impl/src/main/resources/antisamy/low-security-policy.xml) 252 wordcount : { 253 "maxCharCount" : 1000000, 254 //Previous behavior 255 "countSpacesAsCharsHTML" : true, 256 "countHTML" : true, 257 "showParagraphs" : false, 258 "showWordCount" : true, 259 "showCharCount" : true, 260 }, 261 262 //SAK-29598 - Add more templates to CK Editor 263 templates_files: [basePath+"templates/default.js"], 264 templates: 'customtemplates', 265 templates_replaceContent: false, 266 }; 267 268 // Merge config values into ckconfig 269 ckconfig = objectMerge(ckconfig, config); 270 271 if (config && config.toolbarSet && ckconfig['toolbar_' + config.toolbarSet]) { 272 ckconfig.toolbar = config.toolbarSet; 273 } 274 275 //To add extra plugins outside the plugins directory, add them here! (And in the variable) 276 (function() { 277 // SAK-30370 present a nice and simple editor without plugins to the user on a tiny screen. 278 // 279 //Check for the portal variable (Should be defined) 280 //These are defined in user/user-tool-prefs/tool/src/webapp/prefs/editor.jsp 281 282 var detectWidth = true; 283 if (typeof portal != 'undefined' && typeof portal.editor != 'undefined' && typeof portal.editor.type == 'string') { 284 if (portal.editor.type == "basic") { 285 ckconfig.toolbar = "Basic"; 286 detectWidth = false;
287 } 288 else if (portal.editor.type == "full") { 289 ckconfig.toolbar = "Full"; 290 detectWidth = false; 291 } 292 } 293 294 if (detectWidth == true && getWidth() < 800) { 295 ckconfig.toolbar = 'Basic'; 296 } 297 //These could be applicable to the basic toolbar 298 CKEDITOR.plugins.addExternal('lineutils',basePath+'lineutils/', 'plugin.js'); 299 CKEDITOR.plugins.addExternal('widget',basePath+'widget/', 'plugin.js'); 300 CKEDITOR.plugins.addExternal('iframedialog',basePath+'iframedialog/', 'plugin.js'); 301 CKEDITOR.plugins.addExternal('html5video',webJars+'github-com-bahriddin-ckeditor-html5-video/1.2.1/html5video/', 'plugin.js'); 302 CKEDITOR.plugins.addExternal('audiorecorder',basePath+'audiorecorder/', 'plugin.js'); 303 CKEDITOR.plugins.addExternal('contentitem',basePath+'contentitem/', 'plugin.js'); 304 CKEDITOR.plugins.addExternal('sakaipreview',basePath+'sakaipreview/', 'plugin.js'); 305 CKEDITOR.plugins.addExternal('bt_table',basePath+'bt_table/', 'plugin.js'); 306 CKEDITOR.plugins.addExternal('image2',webJars+'ckeditor-image2/4.14.0/', 'plugin.js'); 307 308 //Autosave has a dependency on notification 309 CKEDITOR.plugins.addExternal('autosave',webJars+'ckeditor-autosave/0.18.4/', 'plugin.js'); 310 CKEDITOR.plugins.addExternal('wordcount',webJars+'wordcount/1.17.6/', 'plugin.js'); 311 CKEDITOR.plugins.addExternal('notification',basePath+'notification/', 'plugin.js'); 312 // Accessibility checker has a dependency on balloonpanel 313 CKEDITOR.plugins.addExternal('balloonpanel',webJars+'balloonpanel/4.9.2/', 'plugin.js'); 314 CKEDITOR.plugins.addExternal('a11ychecker',webJars+'a11ychecker/1.1.1/', 'plugin.js'); 315 /* 316 To enable after the deadline uncomment these two lines and add atd-ckeditor to toolbar 317 and to extraPlugins. This also needs extra stylesheets. 318 See readme for more info http://www.polishmywriting.com/atd-ckeditor/readme.html 319 You have to actually setup a server or get an API key 320 Hopefully this will get easier to configure soon. 321 */ 322 CKEDITOR.plugins.addExternal('atd-ckeditor',basePath+'atd-ckeditor/', 'plugin.js'); 323 /* 324 Replace this with your own server if you download it from http://openatd.wordpress.com/ 325 Or you can proxy to the public one, see the page for more information. 326 */ 327 //ckconfig.atd_rpc='//localhost/proxy/spellcheck'; 328 //ckconfig.extraPlugins+="atd-ckeditor,"; 329 //ckconfig.contentsCss = [basePath+'atd-ckeditor/atd.css']; 330 331 ckconfig.extraPlugins+="sakaipreview,image2,audiorecorder,contentitem,html5video,wordcount,notification,autosave,bt_table"; 332 333 // Load FontAwesome CSS in case a user wants to manually add FA markup 334 ckconfig.contentsCss.push(webJars+'fontawesome/4.7.0/css/font-awesome.min.css'); 335 //If the siteskin is defined, add the print.css 336 if (sakai.editor.sitePrintSkin) { 337 ckconfig.contentsCss.push(sakai.editor.sitePrintSkin); 338 } 339 CKEDITOR.dtd.$removeEmpty.span = false; 340 CKEDITOR.dtd.$removeEmpty['i'] = false; 341 //Add greek special characters to set 342 ckconfig.specialChars = CKEDITOR.config.specialChars.concat([ ["α","alpha"],["β","beta"],["γ","gamma"],["δ","delta"],["ε","epsilon"],["ζ","zeta"],["η","eta"],["θ","theta"], ["ι","iota"],["κ","kappa"],["λ","lambda"],["μ","mu"],["ν","nu"],["ξ","xi"],["ο","omnicron"],["π","pi"],["ρ","rho"],["σ","sigma"],["τ","tau"],["υ","upsilon"], ["φ","phi"],["χ","chi"],["ψ","psi"],["ω","omega"],["Α","Alpha"],["Β","Beta"],["Γ","Gamma"],["Δ","Delta"],["Ε","Epsilon"],["Ζ","Zeta"],["Η","Eta"],["Θ","Theta"], ["Ι","Iota"],["Κ","Kappa"],["Λ","Lambda"],["Μ","Mu"],["Ν","Nu"],["Ξ","Xi"],["Ο","Omnicron"],["Π","Pi"],["Ρ","Rho"],["Σ","Sigma"],["Τ","Tau"],["Υ","Upsilon"], ["Φ","Phi"],["Χ","Chi"],["Ψ","Psi"],["Ω","Omega"] ]); 343 344 //SAK-44562 Dark Mode 345 //Add styles to the content in CKeditor 346 if (sakai.editor.sitePropertiesSkin) { 347 ckconfig.contentsCss.push(sakai.editor.sitePropertiesSkin); 348 ckconfig.contentsCss.push('/library/editor/ckeditor.css'); 349 } 350 351 //CKEditor doesn't have a method to add classes to the HTML element 352 //so we manually add the class on load 353 //should be refactored when ckeditor5 is implemented 354 if (document.firstElementChild.classList.contains('sakaiUserTheme-dark')){ 355 356 CKEDITOR.once('instanceReady', addClassOnLoad); 357 // //and we watch for switching out or source mode 358 CKEDITOR.once('instanceReady', function(editor){ 359 editor.editor.on('mode', addClassOnModeChange); 360 }); 361 } 362 363 //Enable ckeditor to reflect themeswitcher changes. Overrides: 364 //https://github.com/ckeditor/ckeditor4/blob/a786d6f43c17ef90c13b1cf001dbd00204a622b1/skins/moono-lisa/skin.js 365 CKEDITOR.skin.chameleon = ( function() { 366 367 templates = { 368 editor: new CKEDITOR.template( 369 `.cke_reset_all, .cke_reset_all *, .cke_reset_all a, .cke_reset_all textarea [ 370 color:{defaultTextColor}; 371 ] 372 {id}.cke_chrome [ 373 color:{defaultTextColor}; 374 border-color:{defaultBorder}; 375 ] 376 {id} .cke_top [
377 background-color:{defaultBackground}; 378 border-bottom-color:{defaultBorder}; 379 ] 380 {id} .cke_bottom [ 381 background-color:{defaultBackground}; 382 border-top-color:{defaultBorder}; 383 ] 384 {id} .cke_resizer [ 385 border-right-color:{ckeResizer} 386 ] 387 {id} .cke_wysiwyg_frame, 388 {id} .cke_wysiwyg_div [ 389 background:{defaultBackground} 390 ] 391 {id} textarea.cke_source [ 392 background-color: {lightBackground}; 393 color: {defaultTextColor}; 394 ]` + 395 // Dialogs. 396 `{id} .cke_dialog_title [ 397 color:{defaultTextColor}; 398 background-color:{defaultBackground}; 399 border-bottom-color:{defaultBorder}; 400 ] 401 {id} .cke_dialog_footer [ 402 color:{defaultTextColor}; 403 background-color:{defaultBackground}; 404 outline-color:{defaultBorder}; 405 ] 406 {id} .cke_dialog_tab [ 407 color:{defaultTextColor}; 408 background-color:{dialogTab}; 409 border-color:{defaultBorder}; 410 ] 411 {id} .cke_dialog_tab:hover, {id} .cke_dialog_tab_selected:hover [ 412 color:{menubuttonTextHover};
413 background-color:{lightBackground}; 414 ] 415 {id} .cke_dialog_contents [ 416 color:{defaultTextColor}; 417 background-color:{lightBackground}; 418 border-top-color:{defaultBorder}; 419 ] 420 {id} .cke_dialog_tab_selected [ 421 color:{defaultTextColor}; 422 background:{dialogTabSelected}; 423 border-bottom-color:{dialogTabSelectedBorder}; 424 ] 425 {id} .cke_dialog_body [ 426 color:{defaultTextColor}; 427 background:{dialogBody}; 428 border-color:{defaultBorder}; 429 ] 430 .cke_dialog a.cke_dialog_ui_button [ 431 background:{menubutton}; 432 color: {menubuttonIcon}; 433 ] 434 .cke_dialog a.cke_dialog_ui_button:hover [ 435 background:{menubuttonHover}; 436 color:{menubuttonTextHover}; 437 ] 438 .cke_dialog a.cke_dialog_ui_button.cke_dialog_ui_button_ok [ 439 background:{okBackground}; 440 border-color:{okBorderColor}; 441 color: {okColor}; 442 ] 443 {id} input.cke_dialog_ui_input_text, {id} input.cke_dialog_ui_input_password, {id} input.cke_dialog_ui_input_tel, {id} textarea.cke_dialog_ui_input_textarea, {id} select.cke_dialog_ui_input_select [ 444 background:{dialogBody}; 445 border-color:{defaultBorder}; 446 color:{defaultTextColor}; 447 ]` + 448 // Toolbars, buttons. 449 `{id} a.cke_button .cke_button_icon [ 450 filter: {invertIfDarkMode} 451 ] 452 {id} a.cke_button_off:hover, 453 {id} a.cke_button_off:focus, 454 {id} a.cke_button_off:active [ 455 background-color:{darkBackground}; 456 border-color:{toolbarElementsBorder}; 457 color:{defaultTextColor}; 458 ] 459 {id} .cke_button_label, 460 {id} a.cke_button_off:hover .cke_button_label, 461 {id} a.cke_button_off:focus .cke_button_label, 462 {id} a.cke_button_off:active .cke_button_label [ 463 color:{defaultTextColor}; 464 ] 465 {id} .cke_button_on [ 466 color: {ckeButtonOnForeColor}; 467 background-color:{ckeButtonOnBackColor}; 468 border-color:{toolbarElementsBorder}; 469 ] 470 {id} .cke_toolbar_separator, 471 {id} .cke_toolgroup a.cke_button:last-child:after, 472 {id} .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after [ 473 background-color: {toolbarElementsBorder}; 474 border-color: {toolbarElementsBorder}; 475 ] 476 {id} .cke_button_arrow [ 477 border--top-color: {toolbarElementsBorder}; 478 ]` + 479 // Combo buttons. 480 `{id} a.cke_combo_button:hover, 481 {id} a.cke_combo_button:focus, 482 {id} .cke_combo_on a.cke_combo_button [ 483 border-color:{toolbarElementsBorder}; 484 color:{menubuttonTextHover}; 485 background-color:{darkBackground}; 486 ] 487 {id} .cke_combo_arrow, 488 {id} .cke_combo:after [ 489 border-top-color:{defaultTextColor}; 490 ] 491 {id} .cke_combo_text [ 492 color:{defaultTextColor}; 493 ]`+ 494 // Elementspath. 495 `{id} .cke_path_item [ 496 color:{elementsPathColor}; 497 ] 498 {id} a.cke_path_item:hover, 499 {id} a.cke_path_item:focus, 500 {id} a.cke_path_item:active [ 501 color:{menubuttonTextHover};
502 background-color:{darkBackground}; 503 ] 504 {id}.cke_panel [ 505 border-color:{defaultBorder}; 506 ]` 507 ), 508 panel: new CKEDITOR.template( 509 // Context menus. 510 `.cke_menubutton_icon [ 511 background-color:{menubuttonIcon}; 512 ] 513 .cke_menubutton:hover, 514 .cke_menubutton:focus, 515 .cke_menubutton:active [ 516 color:{menubuttonTextHover}; 517 background-color:{menubuttonHover}; 518 ] 519 .cke_menubutton:hover .cke_menubutton_icon, 520 .cke_menubutton:focus .cke_menubutton_icon, 521 .cke_menubutton:active .cke_menubutton_icon [ 522 color:{menubuttonTextHover}; 523 background-color:{menubuttonIconHover}; 524 ] 525 .cke_menubutton_disabled:hover .cke_menubutton_icon, 526 .cke_menubutton_disabled:focus .cke_menubutton_icon, 527 .cke_menubutton_disabled:active .cke_menubutton_icon [ 528 background-color:{menubuttonIcon}; 529 ] 530 .cke_menuseparator [ 531 background-color:{menubuttonIcon}; 532 ] ` + 533 // Color boxes. 534 `a:hover.cke_colorbox, 535 a:active.cke_colorbox [ 536 border-color:{defaultBorder}; 537 ] 538 a:hover.cke_colorauto, 539 a:hover.cke_colormore, 540 a:active.cke_colorauto, 541 a:active.cke_colormore [ 542 background-color:{ckeColorauto}; 543 border-color:{defaultBorder}; 544 ] ` 545 ) 546 }; 547 return function( editor, part ) { 548 // CKEditor instances have a unique ID, which is used as class name into 549 // the outer container of the editor UI (e.g. ".cke_1"). 550 // 551 // The Chameleon feature is available for each CKEditor instance, 552 // independently. Because of this, we need to prefix all CSS selectors with 553 // the unique class name of the instance. 554 uiColor = getComputedStyle(document.firstElementChild); 555 templateStyles = { 556 id: '.' + editor.id, 557 invertIfDarkMode: (document.firstElementChild.classList.contains('sakaiUserTheme-dark')) ? uiColor.getPropertyValue("--sakai-image-invert") : '', 558 // These styles are used by various UI elements. 559 defaultBorder: uiColor.getPropertyValue("--sakai-border-color"), 560 toolbarElementsBorder: uiColor.getPropertyValue("--sakai-border-color"), 561 defaultBackground: uiColor.getPropertyValue("--sakai-background-color-2"),
562 lightBackground: uiColor.getPropertyValue("--sakai-background-color-1"), 563 darkBackground: uiColor.getPropertyValue("--sakai-background-color-3"), 564 defaultTextColor: uiColor.getPropertyValue("--sakai-text-color-1"), 565 566 // These are for specific UI elements. 567 ckeButtonColor: uiColor.getPropertyValue("--sakai-text-color-1"), 568 ckeButtonOnBackColor: uiColor.getPropertyValue("--sakai-passive-color-4"), 569 ckeButtonOnForeColor: uiColor.getPropertyValue("--sakai-text-color-inverted"), 570 ckeResizer: uiColor.getPropertyValue("--sakai-text-color-1"), 571 ckeColorauto: uiColor.getPropertyValue("--sakai-background-color-3"), 572 dialogBody: uiColor.getPropertyValue("--sakai-background-color-2"), 573 dialogTab: uiColor.getPropertyValue("--sakai-background-color-2"), 574 dialogTabSelected: uiColor.getPropertyValue("--sakai-passive-color-3"), 575 dialogTabSelectedBorder: uiColor.getPropertyValue("--sakai-border-color"), 576 elementsPathColor: uiColor.getPropertyValue("--sakai-text-color-1"), 577 menubutton: uiColor.getPropertyValue("--button-background"), 578 menubuttonHover: uiColor.getPropertyValue("--button-hover-background"), 579 menubuttonTextHover: uiColor.getPropertyValue("--button-hover-text-color"), 580 menubuttonIcon: uiColor.getPropertyValue("--button-text-color"), 581 menubuttonIconHover: uiColor.getPropertyValue("--button-hover-background"), 582 okBackground: uiColor.getPropertyValue("--sakai-color-green--darker-3"), 583 okBorderColor: uiColor.getPropertyValue("--sakai-color-green--darker-4"), 584 okColor: uiColor.getPropertyValue("--sakai-color-green--lighter-7"), 585 } 586 return templates[ part ] 587 .output(templateStyles) 588 .replace( /\[/g, '{' )// Replace brackets with braces. 589 .replace( /\]/g, '}' ); 590 }; 591 } )(); 592 })(); 593 594 let instance = CKEDITOR.replace(targetId, ckconfig); 595 //SAK-22505 596 CKEDITOR.on('dialogDefinition', function(e) { 597 // Take the dialog name and its definition from the event 598 // data. 599 var dialogName = e.data.name; 600 var dialogDefinition = e.data.definition; 601 602 var onShow = dialogDefinition.onShow; 603 dialogDefinition.onShow = function() { 604 var result; 605 if (typeof onShow !== 'undefined' && typeof onShow.call === 'function') { 606 result = onShow.call(this); 607 } 608 return result; 609 } 610 611 if ( dialogName == 'link' ) 612 { 613 var targetTab = dialogDefinition.getContents('target'); 614 var linkTypeItems = targetTab.elements[0].children[0].items; 615 var itemsNoPopup = []; 616 for (i=0;i<linkTypeItems.length;i++) { 617 if (linkTypeItems[i][1] != "popup") { 618 itemsNoPopup.push(linkTypeItems[i]); 619 } 620 } 621 targetTab.elements[0].children[0].items = itemsNoPopup; 622 623 } 624 625 }); 626 627 return instance; 628} 629 630sakai.editor.launch = sakai.editor.editors.ckeditor.launch;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.