#298 use jodit for rich-text editing

This commit is contained in:
Roland Gruber 2024-02-19 20:40:38 +01:00
parent e74eb5414e
commit 1db553e48d
3663 changed files with 41563 additions and 177469 deletions

View file

@ -1,3 +1,3 @@
#!/bin/bash
~/.local/bin/codespell --skip '*3rdParty*,*/ckeditor/*,*/po/*,*/locale/*,tmp,sess,config,graphics,*/style/images/*,*/style/*.gif,*/style/*.png,*/docs/manual-onePage/*,*/docs/manual-sources/images/*,*/templates/lib/*jquery*,*/templates/lib/*popper*,*/templates/lib/*tippy*,*/templates/lib/*flatpickr*,*/templates/lib/*Sortable*,*/templates/lib/*cropper*,*~,*/docs/phpdoc/*,*/docs/manual/*,*/docs/devel/images/*,*/docs/manual-pdf/*,*.sh,*/cropper.js,*/lib/extra/*,lam/.phpdoc,lam/composer.*' --ignore-words-list "tim,te,pres,files'" lam
~/.local/bin/codespell --skip '*3rdParty*,*/jodit/*,*/po/*,*/locale/*,tmp,sess,config,graphics,*/style/images/*,*/style/*.gif,*/style/*.png,*/docs/manual-onePage/*,*/docs/manual-sources/images/*,*/templates/lib/*jquery*,*/templates/lib/*popper*,*/templates/lib/*tippy*,*/templates/lib/*flatpickr*,*/templates/lib/*Sortable*,*/templates/lib/*cropper*,*~,*/docs/phpdoc/*,*/docs/manual/*,*/docs/devel/images/*,*/docs/manual-pdf/*,*.sh,*/cropper.js,*/lib/extra/*,lam/.phpdoc,lam/composer.*' --ignore-words-list "tim,te,pres,files'" lam

View file

@ -69,7 +69,6 @@ export VERSION=`./getVersion`
rm -r lam/po
rm -r lam/tests
rm -f lam/lib/3rdParty/tcpdf/fonts/*.ttf
rm -r lam/templates/lib/extra/ckeditor/plugins/*/dev
rm -r lam/lib/3rdParty/composer/nesbot/carbon/bin
chmod -R -x+X lam/lib/3rdParty
rm lam/composer*

View file

@ -16,7 +16,7 @@ Depends: php (>= 8.0.2), php-ldap,
libapache2-mod-php | libapache2-mod-fcgid | php-fpm,
apache2 (>= 2.4.0) | httpd,
gettext, fonts-dejavu,
ckeditor (>= 4.0), libjs-jquery-jstree (>= 3.3.0),
libjs-jquery-jstree (>= 3.3.0),
php-phpseclib3, php-psr-log (<< 2.0), php-monolog (<< 3.0),
php-voku-portable-ascii (<< 3.0), libphp-phpmailer (<< 7.0),
debconf (>= 0.2.26) | debconf-2.0, ${misc:Depends}

View file

@ -26,6 +26,7 @@ time.
* lib/modules/groupOfNames.inc
* lib/modules/groupOfNamesUser.inc
* lib/modules/groupOfUniqueNames.inc
* lib/modules/guacamole.inc
* lib/modules/heimdalKerberos.inc
* lib/modules/ipHost.inc
* lib/modules/kopanoAddressList.inc
@ -34,6 +35,7 @@ time.
* lib/modules/kopanoGroup.inc
* lib/modules/kopanoServer.inc
* lib/modules/kopanoUser.inc
* lib/modules/lastBind.inc
* lib/modules/locking389ds.inc
* lib/modules/mitKerberos.inc
* lib/modules/mitKerberosPolicy.inc
@ -45,10 +47,12 @@ time.
* lib/modules/oracleService.inc
* lib/modules/organizationalRole*.inc
* lib/modules/passwordSelfReset.inc
* lib/modules/powerDNS.inc
* lib/modules/ppolicy.inc
* lib/modules/ppolicyUser.inc
* lib/modules/qmailGroup.inc
* lib/modules/qmailUser.inc
* lib/modules/requestAccess.inc
* lib/modules/rfc2307bisAutomount.inc
* lib/modules/rfc2307bisPosixGroup.inc
* lib/modules/selfRegistration.inc
@ -57,12 +61,6 @@ time.
* lib/modules/webauthn.inc
* lib/modules/windowsLDSGroup.inc
* lib/modules/windowsLDSUser.inc
* lib/modules/zarafaAddressList.inc
* lib/modules/zarafaContact.inc
* lib/modules/zarafaDynamicGroup.inc
* lib/modules/zarafaGroup.inc
* lib/modules/zarafaServer.inc
* lib/modules/zarafaUser.inc
* lib/types/alias.inc
* lib/types/automountType.inc
* lib/types/bind.inc
@ -74,10 +72,9 @@ time.
* lib/types/nisObjectType.inc
* lib/types/nsview.inc
* lib/types/oracleContextType.inc
* lib/types/powerDNSType.inc
* lib/types/ppolicyType.inc
* lib/types/sudo.inc
* lib/types/zarafaAddressListType.inc
* lib/types/zarafaDynamicGroupType.inc
All other files are licensed under the conditions below.
@ -1139,6 +1136,7 @@ accepting any such warranty or additional liability.
Programs and licenses with other licenses and/or authors than the
main license and authors:
graphics/webauthn.svg F 2017 Duo Security, Inc.
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/brick B Benjamin Morel
lib/3rdParty/composer/carbonphp B 2023 Carbon
@ -1172,6 +1170,8 @@ lib/3rdParty/composer/webklex B 2016 We
lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
style/010_normalize.css B Nicolas Gallagher and Jonathan Neal
style/050_grid.css B
templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors
templates/lib/*popper*.js B
templates/lib/*tippy*.js B 2021 atomiks
@ -1179,12 +1179,10 @@ templates/lib/*flatpickr*.js B 2017 Gr
style/600_flatpickr.css B 2017 Gregory Petrosyan
templates/lib/*sweetalert2*.js B
style/*sweetalert2*.css B
templates/lib/extra/cropperjs B 2018 Chen Fengyuan
templates/lib/cropper*.js B 2018 Chen Fengyuan
style/600_cropper*.css B 2018 Chen Fengyuan
templates/lib/extra/jodit B Chupurnov
templates/lib/extra/friendlyCaptcha B
graphics/webauthn.svg F 2017 Duo Security, Inc.
templates/lib/400_Sortable*.js B RubaXa, owenm
style/010_normalize.css B Nicolas Gallagher and Jonathan Neal
style/050_grid.css B
templates/lib/extra/jstree/* B 2014 Ivan Bozhanov
style/jstree/* B 2014 Ivan Bozhanov

View file

@ -10,7 +10,7 @@ fi
db_version 2.0 || [ $? -lt 30 ]
# 3rd party libs
jsThirdPartyLibs='ckeditor jstree'
jsThirdPartyLibs='jstree'
for jsThirdPartyLib in $jsThirdPartyLibs; do
if [ ! -L /usr/share/ldap-account-manager/templates/lib/extra/${jsThirdPartyLib} ] ; then
ln -s /usr/share/javascript/${jsThirdPartyLib} /usr/share/ldap-account-manager/templates/lib/extra/${jsThirdPartyLib}

View file

@ -61,7 +61,6 @@ install:
install -D --mode=644 sess/.htaccess debian/ldap-account-manager/var/lib/ldap-account-manager/sess/.htaccess
cp -r style debian/ldap-account-manager/usr/share/ldap-account-manager/
cp -r templates debian/ldap-account-manager/usr/share/ldap-account-manager/
rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/templates/lib/extra/ckeditor
rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/templates/lib/extra/jstree
install -D --mode=755 lib/lamdaemon.pl debian/ldap-account-manager-lamdaemon/usr/share/ldap-account-manager/lib/lamdaemon.pl

View file

@ -85,7 +85,6 @@ RUN apt-get install --no-install-recommends -y \
wget \
libldap-common \
gettext \
ckeditor \
libjs-jquery-jstree \
php-phpseclib3 \
php-voku-portable-ascii \

View file

@ -26,6 +26,7 @@ time.
* lib/modules/groupOfNames.inc
* lib/modules/groupOfNamesUser.inc
* lib/modules/groupOfUniqueNames.inc
* lib/modules/guacamole.inc
* lib/modules/heimdalKerberos.inc
* lib/modules/ipHost.inc
* lib/modules/kopanoAddressList.inc
@ -34,6 +35,7 @@ time.
* lib/modules/kopanoGroup.inc
* lib/modules/kopanoServer.inc
* lib/modules/kopanoUser.inc
* lib/modules/lastBind.inc
* lib/modules/locking389ds.inc
* lib/modules/mitKerberos.inc
* lib/modules/mitKerberosPolicy.inc
@ -45,10 +47,12 @@ time.
* lib/modules/oracleService.inc
* lib/modules/organizationalRole*.inc
* lib/modules/passwordSelfReset.inc
* lib/modules/powerDNS.inc
* lib/modules/ppolicy.inc
* lib/modules/ppolicyUser.inc
* lib/modules/qmailGroup.inc
* lib/modules/qmailUser.inc
* lib/modules/requestAccess.inc
* lib/modules/rfc2307bisAutomount.inc
* lib/modules/rfc2307bisPosixGroup.inc
* lib/modules/selfRegistration.inc
@ -57,12 +61,6 @@ time.
* lib/modules/webauthn.inc
* lib/modules/windowsLDSGroup.inc
* lib/modules/windowsLDSUser.inc
* lib/modules/zarafaAddressList.inc
* lib/modules/zarafaContact.inc
* lib/modules/zarafaDynamicGroup.inc
* lib/modules/zarafaGroup.inc
* lib/modules/zarafaServer.inc
* lib/modules/zarafaUser.inc
* lib/types/alias.inc
* lib/types/automountType.inc
* lib/types/bind.inc
@ -74,10 +72,9 @@ time.
* lib/types/nisObjectType.inc
* lib/types/nsview.inc
* lib/types/oracleContextType.inc
* lib/types/powerDNSType.inc
* lib/types/ppolicyType.inc
* lib/types/sudo.inc
* lib/types/zarafaAddressListType.inc
* lib/types/zarafaDynamicGroupType.inc
All other files are licensed under the conditions below.
@ -1138,6 +1135,7 @@ accepting any such warranty or additional liability.
Programs and licenses with other licenses and/or authors than the
main license and authors:
graphics/webauthn.svg F 2017 Duo Security, Inc.
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/brick B Benjamin Morel
lib/3rdParty/composer/carbonphp B 2023 Carbon
@ -1171,6 +1169,8 @@ lib/3rdParty/composer/webklex B 2016 We
lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB
style/010_normalize.css B Nicolas Gallagher and Jonathan Neal
style/050_grid.css B
templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors
templates/lib/*popper*.js B
templates/lib/*tippy*.js B 2021 atomiks
@ -1178,12 +1178,10 @@ templates/lib/*flatpickr*.js B 2017 Gr
style/600_flatpickr.css B 2017 Gregory Petrosyan
templates/lib/*sweetalert2*.js B
style/*sweetalert2*.css B
templates/lib/extra/cropperjs B 2018 Chen Fengyuan
templates/lib/cropper*.js B 2018 Chen Fengyuan
style/600_cropper*.css B 2018 Chen Fengyuan
templates/lib/extra/jodit B Chupurnov
templates/lib/extra/friendlyCaptcha B
graphics/webauthn.svg F 2017 Duo Security, Inc.
templates/lib/400_Sortable*.js B RubaXa, owenm
style/010_normalize.css B Nicolas Gallagher and Jonathan Neal
style/050_grid.css B
templates/lib/extra/jstree/* B 2014 Ivan Bozhanov
style/jstree/* B 2014 Ivan Bozhanov

View file

@ -1110,3 +1110,8 @@ div.tippy-box {
padding: 0 var(--lam-regular-space) var(--lam-regular-space) var(--lam-regular-space);
max-width: 25rem;
}
div.jodit-container {
margin: var(--lam-small-space);
margin-bottom: var(--lam-regular-space);
}

View file

@ -165,6 +165,7 @@ if (isset($_POST['saveSettings']) || isset($_POST['editmodules'])
echo $_SESSION['header'];
printHeaderContents(_("LDAP Account Manager Configuration"), '../..');
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../templates/lib/extra/jodit/jodit.css\">\n";
echo "<body>\n";
// include all JavaScript files
printJsIncludes('../..');
@ -608,7 +609,7 @@ parseHtml(null, $buttonContainer, [], false, 'user');
?>
</form>
<script type="text/javascript" src="../lib/extra/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="../lib/extra/jodit/jodit.js"></script>
</body>
</html>
<?php

View file

@ -3374,35 +3374,14 @@ window.lam.richEdit = window.lam.richEdit || {};
* Inits the rich-text editors.
*/
window.lam.richEdit.init = function() {
const richEditorInputs = document.getElementsByClassName('lam-rich-edit');
Array.from(richEditorInputs).forEach(function (richInput) {
CKEDITOR.replace(richInput, {
plugins: 'dialogui,dialog,basicstyles,blockquote,notification,button,toolbar,clipboard,panel,floatpanel,menu,contextmenu,resize,elementspath'
+ ',enterkey,entities,popup,filetools,filebrowser,floatingspace,listblock,richcombo,format,horizontalrule,htmlwriter,wysiwygarea,image,indent'
+ ',indentlist,fakeobjects,link,list,magicline,maximize,pastetext,removeformat,showborders,sourcearea,specialchar,menubutton,stylescombo,tab'
+ ',table,tabletools,tableselection,undo,lineutils,widgetselection,widget,notificationaggregator,iframe,justify,font,panelbutton,colordialog,colorbutton',
toolbarGroups: [
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
{ name: 'forms', groups: [ 'forms' ] },
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
{ name: 'links', groups: [ 'links' ] },
{ name: 'insert', groups: [ 'insert' ] },
{ name: 'colors', groups: [ 'colors' ] },
{ name: 'tools', groups: [ 'tools' ] },
{ name: 'styles', groups: [ 'styles' ] },
{ name: 'others', groups: [ 'others' ] }
],
removeButtons: 'About,Templates,Preview,Save,NewPage,Print,PasteFromWord,PasteText,Find,Replace,SelectAll,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,CopyFormatting,RemoveFormat,BidiLtr,BidiRtl,Language,Flash,PageBreak,ShowBlocks',
// Set the most common block elements.
format_tags: 'p;h1;h2;h3;pre',
height: 200
document.querySelectorAll('.lam-rich-edit').forEach(textarea => {
Jodit.make(textarea, {
beautifyHTML: false,
sourceEditorCDNUrlsJS: [],
sourceEditor: 'area',
uploader: {
"insertImageAsBase64URI": true
}
});
});
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,39 +0,0 @@
CKEditor 4
==========
Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
https://ckeditor.com - See https://ckeditor.com/legal/ckeditor-oss-license for license information.
CKEditor 4 is a text editor to be used inside web pages. It's not a replacement
for desktop text editors like Word or OpenOffice, but a component to be used as
part of web applications and websites.
## Documentation
The full editor documentation is available online at the following address:
https://ckeditor.com/docs/
## Installation
Installing CKEditor is an easy task. Just follow these simple steps:
1. **Download** the latest version from the CKEditor website:
https://ckeditor.com. You should have already completed this step, but be
sure you have the very latest version.
2. **Extract** (decompress) the downloaded file into the root of your website.
**Note:** CKEditor is by default installed in the `ckeditor` folder. You can
place the files in whichever you want though.
## Checking Your Installation
The editor comes with a few sample pages that can be used to verify that
installation proceeded properly. Take a look at the `samples` directory.
To test your installation, just call the following page at your website:
http://<your site>/<CKEditor installation path>/samples/index.html
For example:
http://www.example.com/ckeditor/samples/index.html

View file

@ -1,47 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
// Compressed version of core/ckeditor_base.js. See original for instructions.
/* jshint ignore:start */
/* jscs:disable */
// replace_start
window.CKEDITOR||(window.CKEDITOR=function(){var o,d=/(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i,e={timestamp:"",version:"%VERSION%",revision:"%REV%",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:d},status:"unloaded",basePath:function(){var t=window.CKEDITOR_BASEPATH||"";if(!t)for(var e=document.getElementsByTagName("script"),n=0;n<e.length;n++){var a=e[n].src.match(d);if(a){t=a[1];break}}if(-1==t.indexOf(":/")&&"//"!=t.slice(0,2)&&(t=0===t.indexOf("/")?location.href.match(/^.*?:\/\/[^\/]*/)[0]+t:location.href.match(/^[^\?]*\/(?:)/)[0]+t),!t)throw'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';return t}(),getUrl:function(t){return-1==t.indexOf(":/")&&0!==t.indexOf("/")&&(t=this.basePath+t),t=this.appendTimestamp(t)},appendTimestamp:function(t){if(!this.timestamp||"/"===t.charAt(t.length-1)||/[&?]t=/.test(t))return t;var e=0<=t.indexOf("?")?"&":"?";return t+e+"t="+this.timestamp},domReady:(o=[],function(t){if(o.push(t),"complete"===document.readyState&&setTimeout(i,1),1==o.length)if(document.addEventListener)document.addEventListener("DOMContentLoaded",i,!1),window.addEventListener("load",i,!1);else if(document.attachEvent){document.attachEvent("onreadystatechange",i),window.attachEvent("onload",i);var e=!1;try{e=!window.frameElement}catch(n){}document.documentElement.doScroll&&e&&!function a(){try{document.documentElement.doScroll("left")}catch(n){return void setTimeout(a,1)}i()}()}})};function i(){try{document.addEventListener?(document.removeEventListener("DOMContentLoaded",i,!1),window.removeEventListener("load",i,!1),n()):document.attachEvent&&"complete"===document.readyState&&(document.detachEvent("onreadystatechange",i),window.detachEvent("onload",i),n())}catch(t){}}function n(){for(var t;t=o.shift();)t()}var a,r=window.CKEDITOR_GETURL;return r&&(a=e.getUrl,e.getUrl=function(t){return r.call(e,t)||a.call(e,t)}),e}());
// replace_end
/* jscs:enable */
/* jshint ignore:end */
if ( CKEDITOR.loader )
CKEDITOR.loader.load( 'ckeditor' );
else {
// Set the script name to be loaded by the loader.
CKEDITOR._autoLoad = 'ckeditor';
// Include the loader script.
if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) {
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = CKEDITOR.getUrl( 'core/loader.js' );
document.body.appendChild( script );
} else {
document.write( '<script type="text/javascript" src="' + CKEDITOR.getUrl( 'core/loader.js' ) + '"></script>' );
}
}
/**
* The skin to load for all created instances, it may be the name of the skin
* folder inside the editor installation path, or the name and the path separated
* by a comma.
*
* **Note:** This is a global configuration that applies to all instances.
*
* CKEDITOR.skinName = 'moono';
*
* CKEDITOR.skinName = 'myskin,/customstuff/myskin/';
*
* @cfg {String} [skinName='moono-lisa']
* @member CKEDITOR
*/
CKEDITOR.skinName = 'moono-lisa';

View file

@ -1,208 +0,0 @@
/*
Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
body
{
/* Font */
/* Emoji fonts are added to visualise them nicely in Internet Explorer. */
font-family: sans-serif, Arial, Verdana, "Trebuchet MS", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 12px;
/* Text color */
color: #333;
/* Remove the background color to make it transparent. */
background-color: #fff;
margin: 20px;
}
.cke_editable
{
font-size: 13px;
line-height: 1.6;
/* Fix for missing scrollbars with RTL texts. (#10488) */
word-wrap: break-word;
}
blockquote
{
font-style: italic;
font-family: Georgia, Times, "Times New Roman", serif;
padding: 2px 0;
border-style: solid;
border-color: #ccc;
border-width: 0;
}
.cke_contents_ltr blockquote
{
padding-left: 20px;
padding-right: 8px;
border-left-width: 5px;
}
.cke_contents_rtl blockquote
{
padding-left: 8px;
padding-right: 20px;
border-right-width: 5px;
}
a
{
color: #0782C1;
}
ol,ul,dl
{
/* IE7: reset rtl list margin. (#7334) */
*margin-right: 0px;
/* Preserved spaces for list items with text direction different than the list. (#6249,#8049)*/
padding: 0 40px;
}
h1,h2,h3,h4,h5,h6
{
font-weight: normal;
line-height: 1.2;
}
hr
{
border: 0px;
border-top: 1px solid #ccc;
}
img.right
{
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
img.left
{
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
pre
{
white-space: pre-wrap; /* CSS 2.1 */
word-wrap: break-word; /* IE7 */
-moz-tab-size: 4;
tab-size: 4;
}
.marker
{
background-color: Yellow;
}
span[lang]
{
font-style: italic;
}
figure
{
text-align: center;
outline: solid 1px #ccc;
background: rgba(0,0,0,0.05);
padding: 10px;
margin: 10px 20px;
display: inline-block;
}
figure > figcaption
{
text-align: center;
display: block; /* For IE8 */
}
a > img {
padding: 1px;
margin: 1px;
border: none;
outline: 1px solid #0782C1;
}
/* Widget Styles */
.code-featured
{
border: 5px solid red;
}
.math-featured
{
padding: 20px;
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.image-clean
{
border: 0;
background: none;
padding: 0;
}
.image-clean > figcaption
{
font-size: .9em;
text-align: right;
}
.image-grayscale
{
background-color: white;
color: #666;
}
.image-grayscale img, img.image-grayscale
{
filter: grayscale(100%);
}
.embed-240p
{
max-width: 426px;
max-height: 240px;
margin:0 auto;
}
.embed-360p
{
max-width: 640px;
max-height: 360px;
margin:0 auto;
}
.embed-480p
{
max-width: 854px;
max-height: 480px;
margin:0 auto;
}
.embed-720p
{
max-width: 1280px;
max-height: 720px;
margin:0 auto;
}
.embed-1080p
{
max-width: 1920px;
max-height: 1080px;
margin:0 auto;
}

View file

@ -1,69 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview API initialization code.
*/
( function() {
// Check whether high contrast is active by creating a colored border.
var hcDetect = CKEDITOR.dom.element.createFromHtml( '<div style="width:0;height:0;position:absolute;left:-10000px;' +
'border:1px solid;border-color:red blue"></div>', CKEDITOR.document );
hcDetect.appendTo( CKEDITOR.document.getHead() );
// Update CKEDITOR.env.
// Catch exception needed sometimes for FF. (https://dev.ckeditor.com/ticket/4230)
try {
var top = hcDetect.getComputedStyle( 'border-top-color' ),
right = hcDetect.getComputedStyle( 'border-right-color' );
// We need to check if getComputedStyle returned any value, because on FF
// it returnes empty string if CKEditor is loaded in hidden iframe. (https://dev.ckeditor.com/ticket/11121)
CKEDITOR.env.hc = !!( top && top == right );
} catch ( e ) {
CKEDITOR.env.hc = false;
}
hcDetect.remove();
if ( CKEDITOR.env.hc )
CKEDITOR.env.cssClass += ' cke_hc';
// Initially hide UI spaces when relevant skins are loading, later restored by skin css.
CKEDITOR.document.appendStyleText( '.cke{visibility:hidden;}' );
// Mark the editor as fully loaded.
CKEDITOR.status = 'loaded';
CKEDITOR.fireOnce( 'loaded' );
// Process all instances created by the "basic" implementation.
var pending = CKEDITOR._.pending;
if ( pending ) {
delete CKEDITOR._.pending;
for ( var i = 0; i < pending.length; i++ ) {
CKEDITOR.editor.prototype.constructor.apply( pending[ i ][ 0 ], pending[ i ][ 1 ] );
CKEDITOR.add( pending[ i ][ 0 ] );
}
}
} )();
/**
* Indicates that CKEditor is running on a High Contrast environment.
*
* if ( CKEDITOR.env.hc )
* alert( 'You\'re running on High Contrast mode. The editor interface will get adapted to provide you a better experience.' );
*
* @property {Boolean} hc
* @member CKEDITOR.env
*/
/**
* Fired when a CKEDITOR core object is fully loaded and ready for interaction.
*
* @event loaded
* @member CKEDITOR
*/

View file

@ -1,209 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Contains the third and last part of the {@link CKEDITOR} object
* definition.
*/
/** @class CKEDITOR */
// Remove the CKEDITOR.loadFullCore reference defined on ckeditor_basic.
delete CKEDITOR.loadFullCore;
/**
* Stores references to all editor instances created. The name of the properties
* in this object correspond to instance names, and their values contain the
* {@link CKEDITOR.editor} object representing them.
*
* alert( CKEDITOR.instances.editor1.name ); // 'editor1'
*
* @property {Object}
*/
CKEDITOR.instances = {};
/**
* The document of the window storing the CKEDITOR object.
*
* alert( CKEDITOR.document.getBody().getName() ); // 'body'
*
* @property {CKEDITOR.dom.document}
*/
CKEDITOR.document = new CKEDITOR.dom.document( document );
/**
* Adds an editor instance to the global {@link CKEDITOR} object. This function
* is available for internal use mainly.
*
* @param {CKEDITOR.editor} editor The editor instance to be added.
*/
CKEDITOR.add = function( editor ) {
CKEDITOR.instances[ editor.name ] = editor;
editor.on( 'focus', function() {
if ( CKEDITOR.currentInstance != editor ) {
CKEDITOR.currentInstance = editor;
CKEDITOR.fire( 'currentInstance' );
}
} );
editor.on( 'blur', removeInstance );
// Remove currentInstance if it's destroyed (#589).
editor.on( 'destroy', removeInstance );
CKEDITOR.fire( 'instance', null, editor );
function removeInstance() {
if ( CKEDITOR.currentInstance == editor ) {
CKEDITOR.currentInstance = null;
CKEDITOR.fire( 'currentInstance' );
}
}
};
/**
* Removes an editor instance from the global {@link CKEDITOR} object. This function
* is available for internal use only. External code must use {@link CKEDITOR.editor#method-destroy}.
*
* @private
* @param {CKEDITOR.editor} editor The editor instance to be removed.
*/
CKEDITOR.remove = function( editor ) {
delete CKEDITOR.instances[ editor.name ];
};
( function() {
var tpls = {};
/**
* Adds a named {@link CKEDITOR.template} instance to be reused among all editors.
* This will return the existing one if a template with same name is already
* defined. Additionally, it fires the "template" event to allow template source customization.
*
* @param {String} name The name which identifies a UI template.
* @param {String} source The source string for constructing this template.
* @returns {CKEDITOR.template} The created template instance.
*/
CKEDITOR.addTemplate = function( name, source ) {
var tpl = tpls[ name ];
if ( tpl )
return tpl;
// Make it possible to customize the template through event.
var params = { name: name, source: source };
CKEDITOR.fire( 'template', params );
return ( tpls[ name ] = new CKEDITOR.template( params.source ) );
};
/**
* Retrieves a defined template created with {@link CKEDITOR#addTemplate}.
*
* @param {String} name The template name.
*/
CKEDITOR.getTemplate = function( name ) {
return tpls[ name ];
};
} )();
( function() {
var styles = [];
/**
* Adds CSS rules to be appended to the editor document.
* This method is mostly used by plugins to add custom styles to the editor
* document. For basic content styling the `contents.css` file should be
* used instead.
*
* **Note:** This function should be called before the creation of editor instances.
*
* // Add styles for all headings inside editable contents.
* CKEDITOR.addCss( '.cke_editable h1,.cke_editable h2,.cke_editable h3 { border-bottom: 1px dotted red }' );
*
* @param {String} css The style rules to be appended.
* @see CKEDITOR.config#contentsCss
*/
CKEDITOR.addCss = function( css ) {
styles.push( css );
};
/**
* Returns a string with all CSS rules passed to the {@link CKEDITOR#addCss} method.
*
* @returns {String} A string containing CSS rules.
*/
CKEDITOR.getCss = function() {
return styles.join( '\n' );
};
} )();
// Perform global clean up to free as much memory as possible
// when there are no instances left
CKEDITOR.on( 'instanceDestroyed', function() {
if ( CKEDITOR.tools.isEmpty( this.instances ) )
CKEDITOR.fire( 'reset' );
} );
// Load the bootstrap script.
CKEDITOR.loader.load( '_bootstrap' ); // %REMOVE_LINE%
// Tri-state constants.
/**
* Used to indicate the ON or ACTIVE state.
*
* @readonly
* @property {Number} [=1]
*/
CKEDITOR.TRISTATE_ON = 1;
/**
* Used to indicate the OFF or INACTIVE state.
*
* @readonly
* @property {Number} [=2]
*/
CKEDITOR.TRISTATE_OFF = 2;
/**
* Used to indicate the DISABLED state.
*
* @readonly
* @property {Number} [=0]
*/
CKEDITOR.TRISTATE_DISABLED = 0;
/**
* The editor which is currently active (has user focus).
*
* function showCurrentEditorName() {
* if ( CKEDITOR.currentInstance )
* alert( CKEDITOR.currentInstance.name );
* else
* alert( 'Please focus an editor first.' );
* }
*
* @property {CKEDITOR.editor} currentInstance
* @see CKEDITOR#event-currentInstance
*/
/**
* Fired when the CKEDITOR.currentInstance object reference changes. This may
* happen when setting the focus on different editor instances in the page.
*
* var editor; // A variable to store a reference to the current editor.
* CKEDITOR.on( 'currentInstance', function() {
* editor = CKEDITOR.currentInstance;
* } );
*
* @event currentInstance
*/
/**
* Fired when the last instance has been destroyed. This event is used to perform
* global memory cleanup.
*
* @event reset
*/

View file

@ -1,340 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Contains the first and essential part of the {@link CKEDITOR}
* object definition.
*/
// #### Compressed Code
// Compressed code in ckeditor.js must be be updated on changes in the script.
// Simply run `grunt ckeditor-base-replace` after changing this file.
// #### Raw code
// ATTENTION: read the above "Compressed Code" notes when changing this code.
if ( !window.CKEDITOR ) {
/**
* This is the API entry point. The entire CKEditor code runs under this object.
* @class CKEDITOR
* @mixins CKEDITOR.event
* @singleton
*/
window.CKEDITOR = ( function() {
var basePathSrcPattern = /(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i;
var CKEDITOR = {
/**
* A constant string unique for each release of CKEditor. Its value
* is used, by default, to build the URL for all resources loaded
* by the editor code, guaranteeing clean cache results when
* upgrading.
*
* alert( CKEDITOR.timestamp ); // e.g. '87dm'
*/
timestamp: '', // %REMOVE_LINE%
/* // %REMOVE_LINE%
// The production implementation contains a fixed timestamp, unique
// for each release and generated by the releaser.
// (Base 36 value of each component of YYMMDDHH - 4 chars total - e.g. 87bm == 08071122)
timestamp: '%TIMESTAMP%',
// %REMOVE_LINE% */
/**
* Contains the CKEditor version number.
*
* alert( CKEDITOR.version ); // e.g. 'CKEditor 3.4.1'
*/
version: '%VERSION%',
/**
* Contains the CKEditor revision number.
* The revision number is incremented automatically, following each
* modification to the CKEditor source code.
*
* alert( CKEDITOR.revision ); // e.g. '3975'
*/
revision: '%REV%',
/**
* A 3-digit random integer, valid for the entire life of the CKEDITOR object.
*
* alert( CKEDITOR.rnd ); // e.g. 319
*
* Generated integer is not cryptographically secure. It has been deprecated to
* prevent using it in a security-sensitive context by accident.
* Use `window.crypto.getRandomValues()` native browser method instead.
*
* @deprecated 4.18.0
* @property {Number}
*/
rnd: Math.floor( Math.random() * ( 999 /*Max*/ - 100 /*Min*/ + 1 ) ) + 100 /*Min*/,
/**
* Private object used to hold core stuff. It should not be used outside of
* the API code as properties defined here may change at any time
* without notice.
*
* @private
*/
_: {
pending: [],
basePathSrcPattern: basePathSrcPattern
},
/**
* Indicates the API loading status. The following statuses are available:
*
* * **unloaded**: the API is not yet loaded.
* * **basic_loaded**: the basic API features are available.
* * **basic_ready**: the basic API is ready to load the full core code.
* * **loaded**: the API can be fully used.
*
* Example:
*
* if ( CKEDITOR.status == 'loaded' ) {
* // The API can now be fully used.
* doSomething();
* } else {
* // Wait for the full core to be loaded and fire its loading.
* CKEDITOR.on( 'load', doSomething );
* CKEDITOR.loadFullCore && CKEDITOR.loadFullCore();
* }
*/
status: 'unloaded',
/**
* The full URL for the CKEditor installation directory.
* It is possible to manually provide the base path by setting a
* global variable named `CKEDITOR_BASEPATH`. This global variable
* must be set **before** the editor script loading.
*
* alert( CKEDITOR.basePath ); // e.g. 'http://www.example.com/ckeditor/'
*
* @property {String}
*/
basePath: ( function() {
// Find out the editor directory path, based on its <script> tag.
var path = window.CKEDITOR_BASEPATH || '';
if ( !path ) {
var scripts = document.getElementsByTagName( 'script' );
for ( var i = 0; i < scripts.length; i++ ) {
var match = scripts[ i ].src.match( basePathSrcPattern );
if ( match ) {
path = match[ 1 ];
break;
}
}
}
// In IE (only) the script.src string is the raw value entered in the
// HTML source. Other browsers return the full resolved URL instead.
if ( path.indexOf( ':/' ) == -1 && path.slice( 0, 2 ) != '//' ) {
// Absolute path.
if ( path.indexOf( '/' ) === 0 )
path = location.href.match( /^.*?:\/\/[^\/]*/ )[ 0 ] + path;
// Relative path.
else
path = location.href.match( /^[^\?]*\/(?:)/ )[ 0 ] + path;
}
if ( !path )
throw 'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';
return path;
} )(),
/**
* Gets the full URL for CKEditor resources. By default, URLs
* returned by this function contain a querystring parameter ("t")
* set to the {@link CKEDITOR#timestamp} value.
*
* It is possible to provide a custom implementation of this
* function by setting a global variable named `CKEDITOR_GETURL`.
* This global variable must be set **before** the editor script
* loading. If the custom implementation returns nothing (`==null`), the
* default implementation is used.
*
* // e.g. 'http://www.example.com/ckeditor/skins/default/editor.css?t=87dm'
* alert( CKEDITOR.getUrl( 'skins/default/editor.css' ) );
*
* // e.g. 'http://www.example.com/skins/default/editor.css?t=87dm'
* alert( CKEDITOR.getUrl( '/skins/default/editor.css' ) );
*
* // e.g. 'http://www.somesite.com/skins/default/editor.css?t=87dm'
* alert( CKEDITOR.getUrl( 'http://www.somesite.com/skins/default/editor.css' ) );
*
* @param {String} resource The resource whose full URL we want to get.
* It may be a full, absolute, or relative URL.
* @returns {String} The full URL.
*/
getUrl: function( resource ) {
// If this is not a full or absolute path.
if ( resource.indexOf( ':/' ) == -1 && resource.indexOf( '/' ) !== 0 )
resource = this.basePath + resource;
resource = this.appendTimestamp( resource );
return resource;
},
/**
* Appends {@link CKEDITOR#timestamp} to the provided URL as querystring parameter ("t").
*
* Leaves the URL unchanged if it is a directory URL or it already contains querystring parameter.
*
* @since 4.17.2
* @param {String} resource The resource URL to which the timestamp should be appended.
* @returns {String} The resource URL with cache key appended whenever possible.
*/
appendTimestamp: function( resource ) {
if ( !this.timestamp ||
resource.charAt( resource.length - 1 ) === '/' ||
( /[&?]t=/ ).test( resource )
) {
return resource;
}
var concatenateSign = resource.indexOf( '?' ) >= 0 ? '&' : '?';
return resource + concatenateSign + 't=' + this.timestamp;
},
/**
* Specify a function to execute when the DOM is fully loaded.
*
* If called after the DOM has been initialized, the function passed in will
* be executed immediately.
*
* @method
* @todo
*/
domReady: ( function() {
// Based on the original jQuery code (available under the MIT license, see LICENSE.md).
var callbacks = [];
function onReady() {
try {
// Cleanup functions for the document ready method
if ( document.addEventListener ) {
document.removeEventListener( 'DOMContentLoaded', onReady, false );
window.removeEventListener( 'load', onReady, false );
executeCallbacks();
}
// Make sure body exists, at least, in case IE gets a little overzealous.
else if ( document.attachEvent && document.readyState === 'complete' ) {
document.detachEvent( 'onreadystatechange', onReady );
window.detachEvent( 'onload', onReady );
executeCallbacks();
}
} catch ( er ) {}
}
function executeCallbacks() {
var i;
while ( ( i = callbacks.shift() ) )
i();
}
return function( fn ) {
callbacks.push( fn );
// Catch cases where this is called after the
// browser event has already occurred.
if ( document.readyState === 'complete' )
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( onReady, 1 );
// Run below once on demand only.
if ( callbacks.length != 1 )
return;
// For IE>8, Firefox, Opera and Webkit.
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( 'DOMContentLoaded', onReady, false );
// A fallback to window.onload, that will always work
window.addEventListener( 'load', onReady, false );
}
// If old IE event model is used
else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent( 'onreadystatechange', onReady );
// A fallback to window.onload, that will always work
window.attachEvent( 'onload', onReady );
// If IE and not a frame
// continually check to see if the document is ready
// use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
var toplevel = false;
try {
toplevel = !window.frameElement;
} catch ( e ) {}
if ( document.documentElement.doScroll && toplevel ) {
scrollCheck();
}
}
function scrollCheck() {
try {
document.documentElement.doScroll( 'left' );
} catch ( e ) {
setTimeout( scrollCheck, 1 );
return;
}
onReady();
}
};
} )()
};
// Make it possible to override the "url" function with a custom
// implementation pointing to a global named CKEDITOR_GETURL.
var newGetUrl = window.CKEDITOR_GETURL;
if ( newGetUrl ) {
var originalGetUrl = CKEDITOR.getUrl;
CKEDITOR.getUrl = function( resource ) {
return newGetUrl.call( CKEDITOR, resource ) || originalGetUrl.call( CKEDITOR, resource );
};
}
return CKEDITOR;
} )();
}
/**
* Function called upon loading a custom configuration file that can
* modify the editor instance configuration ({@link CKEDITOR.editor#config}).
* It is usually defined inside the custom configuration files that can
* include developer defined settings.
*
* // This is supposed to be placed in the config.js file.
* CKEDITOR.editorConfig = function( config ) {
* // Define changes to default configuration here. For example:
* config.language = 'fr';
* config.uiColor = '#AADC6E';
* };
*
* @method editorConfig
* @param {CKEDITOR.config} config A configuration object containing the
* settings defined for a {@link CKEDITOR.editor} instance up to this
* function call. Note that not all settings may still be available. See
* [Configuration Loading Order](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_configuration.html)
* for details.
*/
// PACKAGER_RENAME( CKEDITOR )

View file

@ -1,94 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Contains the second part of the {@link CKEDITOR} object
* definition, which defines the basic editor features to be available in
* the root ckeditor_basic.js file.
*/
if ( CKEDITOR.status == 'unloaded' ) {
( function() {
CKEDITOR.event.implementOn( CKEDITOR );
/**
* Forces the full CKEditor core code, in the case only the basic code has been
* loaded (`ckeditor_basic.js`). This method self-destroys (becomes undefined) in
* the first call or as soon as the full code is available.
*
* // Check if the full core code has been loaded and load it.
* if ( CKEDITOR.loadFullCore )
* CKEDITOR.loadFullCore();
*
* @member CKEDITOR
*/
CKEDITOR.loadFullCore = function() {
// If the basic code is not ready, just mark it to be loaded.
if ( CKEDITOR.status != 'basic_ready' ) {
CKEDITOR.loadFullCore._load = 1;
return;
}
// Destroy this function.
delete CKEDITOR.loadFullCore;
// Append the script to the head.
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = CKEDITOR.basePath + 'ckeditor.js';
script.src = CKEDITOR.basePath + 'ckeditor_source.js'; // %REMOVE_LINE%
document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
};
/**
* The time to wait (in seconds) to load the full editor code after the
* page load, if the "ckeditor_basic" file is used. If set to zero, the
* editor is loaded on demand, as soon as an instance is created.
*
* This value must be set on the page before the page load completion.
*
* // Loads the full source after five seconds.
* CKEDITOR.loadFullCoreTimeout = 5;
*
* @property
* @member CKEDITOR
*/
CKEDITOR.loadFullCoreTimeout = 0;
// Documented at ckeditor.js.
CKEDITOR.add = function( editor ) {
// For now, just put the editor in the pending list. It will be
// processed as soon as the full code gets loaded.
var pending = this._.pending || ( this._.pending = [] );
pending.push( editor );
};
( function() {
var onload = function() {
var loadFullCore = CKEDITOR.loadFullCore,
loadFullCoreTimeout = CKEDITOR.loadFullCoreTimeout;
if ( !loadFullCore )
return;
CKEDITOR.status = 'basic_ready';
if ( loadFullCore && loadFullCore._load )
loadFullCore();
else if ( loadFullCoreTimeout ) {
setTimeout( function() {
if ( CKEDITOR.loadFullCore )
CKEDITOR.loadFullCore();
}, loadFullCoreTimeout * 1000 );
}
};
CKEDITOR.domReady( onload );
} )();
CKEDITOR.status = 'basic_loaded';
} )();
}

View file

@ -1,197 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* global console */
( function() {
var apiUrl = 'https://cke4.ckeditor.com/ckeditor4-secure-version/versions.json',
upgradeLink = 'https://ckeditor.com/ckeditor-4-support/',
versionRegex = /^4\.(\d+)\.(\d+)(-lts)?(?: \(?.+?\)?)?$/,
isDrupal = 'Drupal' in window,
consoleErrorDisplayed = false,
versionInfo = {
current: parseVersion( CKEDITOR.version )
};
if ( isDrupal || !versionInfo.current ) {
return;
}
CKEDITOR.config.versionCheck = versionInfo.current.isLts ? false : true;
CKEDITOR.on( 'instanceReady', function( evt ) {
var editor = evt.editor;
if ( !editor.config.versionCheck ) {
return;
}
editor.on( 'dialogShow', function( evt ) {
var dialog = evt.data;
if ( dialog._.name !== 'about' ) {
return;
}
performVersionCheck( function() {
addInfoToAboutDialog( editor, dialog );
} );
} );
performVersionCheck( function() {
notifyAboutInsecureVersion( editor );
} );
} );
function performVersionCheck( callback ) {
if ( versionInfo.secure && versionInfo.latest ) {
return callback();
}
try {
var request = new XMLHttpRequest(),
requestUrl = apiUrl + '?v=' + encodeURIComponent( versionInfo.current.original );
request.onreadystatechange = function() {
if ( request.readyState === 4 && request.status === 200 ) {
var response = JSON.parse( request.responseText );
versionInfo.latest = parseVersion( response.latestVersion );
versionInfo.secure = parseVersion( response.secureVersion );
versionInfo.isLatest = isLatestVersion();
versionInfo.isSecure = isSecureVersion();
callback();
}
};
request.open( 'GET', requestUrl );
request.responseType = 'text';
request.send();
} catch ( e ) {
}
}
function notifyAboutInsecureVersion( editor ) {
if ( versionInfo.isSecure ) {
return;
}
var notificationMessage = editor.lang.versionCheck.notificationMessage.replace( '%current', versionInfo.current.original ).
replace( '%latest', versionInfo.latest.original ).
replace( /%link/g, upgradeLink ),
isNotificationAvailable = 'notification' in editor.plugins;
showConsoleError( editor );
if ( isNotificationAvailable ) {
editor.showNotification( notificationMessage, 'warning' );
}
}
function showConsoleError( editor ) {
if ( !window.console || !window.console.error ) {
return;
}
if ( consoleErrorDisplayed ) {
return;
}
consoleErrorDisplayed = true;
var consoleMessage = editor.lang.versionCheck.consoleMessage.replace( '%current', versionInfo.current.original ).
replace( '%latest', versionInfo.latest.original ).
replace( /%link/g, upgradeLink );
console.error( consoleMessage );
}
function addInfoToAboutDialog( editor, dialog ) {
var container = dialog.getElement().findOne( '.cke_about_version-check' ),
message = getAboutMessage( editor );
container.setHtml( '' );
if ( editor.config.versionCheck ) {
container.setStyle( 'color', versionInfo.isSecure ? '' : '#C83939' );
container.setHtml( message );
}
}
function getAboutMessage( editor ) {
var lang = editor.lang.versionCheck,
msg = '';
if ( !versionInfo.isLatest ) {
msg = lang.aboutDialogUpgradeMessage;
}
if ( !versionInfo.isSecure ) {
msg = lang.aboutDialogInsecureMessage;
}
return msg.replace( '%current', versionInfo.current.original ).
replace( '%latest', versionInfo.latest.original ).
replace( /%link/g, upgradeLink );
}
function isLatestVersion() {
return versionInfo.current.minor === versionInfo.latest.minor &&
versionInfo.current.patch === versionInfo.latest.patch;
}
function isSecureVersion() {
if ( versionInfo.current.minor > versionInfo.secure.minor ) {
return true;
}
if ( versionInfo.current.minor === versionInfo.secure.minor &&
versionInfo.current.patch >= versionInfo.secure.patch ) {
return true;
}
return false;
}
function parseVersion( version ) {
var parts = version.match( versionRegex );
if ( !parts ) {
return null;
}
return {
original: version,
major: 4,
minor: Number( parts[ 1 ] ),
patch: Number( parts[ 2 ] ),
isLts: !!parts[ 3 ]
};
}
/**
* The version check feature adds a notification system to the editor that informs
* users if the editor version is secure. It is highly recommended to stay up to
* date with the editor version to ensure that the editor is secure and provides
* the best editing experience to users.
*
* If the current version is below the latest published secure version,
* a user will be prompted about the available update. This feature is integrated
* with the [Notification](https://ckeditor.com/cke4/addon/notification) plugin,
* the [About](https://ckeditor.com/cke4/addon/about) dialog,
* and developer console logs.
*
* You can manually disable this feature by setting the option to `false`,
* but we strongly recommend upgrading the editor instead.
*
* - For CKEditor 4.22.* and below, this option is enabled by default.
* - For CKEditor 4 LTS (4.23.0 and above), this option is disabled by default.
*
* @cfg {Boolean} [versionCheck]
* @since 4.22.0
* @member CKEDITOR.config
*/
} )();

View file

@ -1,275 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* Represents a command that can be executed on an editor instance.
*
* var command = new CKEDITOR.command( editor, {
* exec: function( editor ) {
* alert( editor.document.getBody().getHtml() );
* }
* } );
*
* @class
* @extends CKEDITOR.commandDefinition
* @mixins CKEDITOR.event
* @constructor Creates a command class instance.
* @param {CKEDITOR.editor} editor The editor instance this command will be
* related to.
* @param {CKEDITOR.commandDefinition} commandDefinition The command
* definition.
*/
CKEDITOR.command = function( editor, commandDefinition ) {
/**
* Lists UI items that are associated to this command. This list can be
* used to interact with the UI on command execution (by the execution code
* itself, for example).
*
* alert( 'Number of UI items associated to this command: ' + command.uiItems.length );
*/
this.uiItems = [];
/**
* Executes the command.
*
* command.exec(); // The command gets executed.
*
* **Note:** You should use the {@link CKEDITOR.editor#execCommand} method instead of calling
* `command.exec()` directly.
*
* @param {Object} [data] Any data to pass to the command. Depends on the
* command implementation and requirements.
* @returns {Boolean} A boolean indicating that the command has been successfully executed.
*/
this.exec = function( data ) {
if ( this.state == CKEDITOR.TRISTATE_DISABLED || !this.checkAllowed() )
return false;
if ( this.editorFocus ) // Give editor focus if necessary (https://dev.ckeditor.com/ticket/4355).
editor.focus();
if ( this.fire( 'exec' ) === false )
return true;
return ( commandDefinition.exec.call( this, editor, data ) !== false );
};
/**
* Explicitly update the status of the command, by firing the {@link CKEDITOR.command#event-refresh} event,
* as well as invoke the {@link CKEDITOR.commandDefinition#refresh} method if defined, this method
* is to allow different parts of the editor code to contribute in command status resolution.
*
* @param {CKEDITOR.editor} editor The editor instance.
* @param {CKEDITOR.dom.elementPath} path
*/
this.refresh = function( editor, path ) {
// Do nothing is we're on read-only and this command doesn't support it.
// We don't need to disabled the command explicitely here, because this
// is already done by the "readOnly" event listener.
if ( !this.readOnly && editor.readOnly )
return true;
// Disable commands that are not allowed in the current selection path context.
if ( this.context && !path.isContextFor( this.context ) ) {
this.disable();
return true;
}
// Disable commands that are not allowed by the active filter.
if ( !this.checkAllowed( true ) ) {
this.disable();
return true;
}
// Make the "enabled" state a default for commands enabled from start.
if ( !this.startDisabled )
this.enable();
// Disable commands which shouldn't be enabled in this mode.
if ( this.modes && !this.modes[ editor.mode ] )
this.disable();
if ( this.fire( 'refresh', { editor: editor, path: path } ) === false )
return true;
return ( commandDefinition.refresh && commandDefinition.refresh.apply( this, arguments ) !== false );
};
var allowed;
/**
* Checks whether this command is allowed by the active allowed
* content filter ({@link CKEDITOR.editor#activeFilter}). This means
* that if command implements {@link CKEDITOR.feature} interface it will be tested
* by the {@link CKEDITOR.filter#checkFeature} method.
*
* @since 4.1.0
* @param {Boolean} [noCache] Skip cache for example due to active filter change. Since CKEditor 4.2.0.
* @returns {Boolean} Whether this command is allowed.
*/
this.checkAllowed = function( noCache ) {
if ( !noCache && typeof allowed == 'boolean' )
return allowed;
return allowed = editor.activeFilter.checkFeature( this );
};
CKEDITOR.tools.extend( this, commandDefinition, {
/**
* The editor modes within which the command can be executed. The
* execution will have no action if the current mode is not listed
* in this property.
*
* // Enable the command in both WYSIWYG and Source modes.
* command.modes = { wysiwyg:1,source:1 };
*
* // Enable the command in Source mode only.
* command.modes = { source:1 };
*
* @see CKEDITOR.editor#mode
*/
modes: { wysiwyg: 1 },
/**
* Indicates that the editor will get the focus before executing
* the command.
*
* // Do not force the editor to have focus when executing the command.
* command.editorFocus = false;
*
* @property {Boolean} [=true]
*/
editorFocus: 1,
/**
* Indicates that this command is sensible to the selection context.
* If `true`, the {@link CKEDITOR.command#method-refresh} method will be
* called for this command on the {@link CKEDITOR.editor#event-selectionChange} event.
*
* @property {Boolean} [=false]
*/
contextSensitive: !!commandDefinition.context,
/**
* Indicates the editor state. Possible values are:
*
* * {@link CKEDITOR#TRISTATE_DISABLED}: the command is
* disabled. It's execution will have no effect. Same as {@link #disable}.
* * {@link CKEDITOR#TRISTATE_ON}: the command is enabled
* and currently active in the editor (for context sensitive commands, for example).
* * {@link CKEDITOR#TRISTATE_OFF}: the command is enabled
* and currently inactive in the editor (for context sensitive commands, for example).
*
* Do not set this property directly, using the {@link #setState} method instead.
*
* if ( command.state == CKEDITOR.TRISTATE_DISABLED )
* alert( 'This command is disabled' );
*
* @property {Number} [=CKEDITOR.TRISTATE_DISABLED]
*/
state: CKEDITOR.TRISTATE_DISABLED
} );
// Call the CKEDITOR.event constructor to initialize this instance.
CKEDITOR.event.call( this );
};
CKEDITOR.command.prototype = {
/**
* Enables the command for execution. The command state (see
* {@link CKEDITOR.command#property-state}) available before disabling it is restored.
*
* command.enable();
* command.exec(); // Execute the command.
*/
enable: function() {
if ( this.state == CKEDITOR.TRISTATE_DISABLED && this.checkAllowed() )
this.setState( ( !this.preserveState || ( typeof this.previousState == 'undefined' ) ) ? CKEDITOR.TRISTATE_OFF : this.previousState );
},
/**
* Disables the command for execution. The command state (see
* {@link CKEDITOR.command#property-state}) will be set to {@link CKEDITOR#TRISTATE_DISABLED}.
*
* command.disable();
* command.exec(); // "false" - Nothing happens.
*/
disable: function() {
this.setState( CKEDITOR.TRISTATE_DISABLED );
},
/**
* Sets the command state.
*
* command.setState( CKEDITOR.TRISTATE_ON );
* command.exec(); // Execute the command.
* command.setState( CKEDITOR.TRISTATE_DISABLED );
* command.exec(); // 'false' - Nothing happens.
* command.setState( CKEDITOR.TRISTATE_OFF );
* command.exec(); // Execute the command.
*
* @param {Number} newState The new state. See {@link #property-state}.
* @returns {Boolean} Returns `true` if the command state changed.
*/
setState: function( newState ) {
// Do nothing if there is no state change.
if ( this.state == newState )
return false;
if ( newState != CKEDITOR.TRISTATE_DISABLED && !this.checkAllowed() )
return false;
this.previousState = this.state;
// Set the new state.
this.state = newState;
// Fire the "state" event, so other parts of the code can react to the
// change.
this.fire( 'state' );
return true;
},
/**
* Toggles the on/off (active/inactive) state of the command. This is
* mainly used internally by context sensitive commands.
*
* command.toggleState();
*/
toggleState: function() {
if ( this.state == CKEDITOR.TRISTATE_OFF )
this.setState( CKEDITOR.TRISTATE_ON );
else if ( this.state == CKEDITOR.TRISTATE_ON )
this.setState( CKEDITOR.TRISTATE_OFF );
}
};
CKEDITOR.event.implementOn( CKEDITOR.command.prototype );
/**
* Indicates the previous command state.
*
* alert( command.previousState );
*
* @property {Number} previousState
* @see #state
*/
/**
* Fired when the command state changes.
*
* command.on( 'state', function() {
* // Alerts the new state.
* alert( this.state );
* } );
*
* @event state
*/
/**
* @event refresh
* @todo
*/

View file

@ -1,162 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.commandDefinition} class
* which contains the defintion of a command. This file is for
* documentation purposes only.
*/
/**
* Virtual class that illustrates the features of command objects to be
* passed to the {@link CKEDITOR.editor#addCommand} function.
*
* @class CKEDITOR.commandDefinition
* @abstract
*/
/**
* The function to be fired when the commend is executed.
*
* editorInstance.addCommand( 'sample', {
* exec: function( editor ) {
* alert( 'Executing a command for the editor name "' + editor.name + '"!' );
* }
* } );
*
* @method exec
* @param {CKEDITOR.editor} editor The editor within which to run the command.
* @param {Object} [data] Additional data to be used to execute the command.
* @returns {Boolean} Whether the command has been successfully executed.
* Defaults to `true` if nothing is returned.
*/
/**
* Whether the command needs to be hooked into the redo/undo system.
*
* editorInstance.addCommand( 'alertName', {
* exec: function( editor ) {
* alert( editor.name );
* },
* canUndo: false // No support for undo/redo.
* } );
*
* @property {Boolean} [canUndo=true]
*/
/**
* Whether the command is asynchronous, which means that the
* {@link CKEDITOR.editor#event-afterCommandExec} event will be fired by the
* command itself manually, and that the return value of this command is not to
* be returned by the {@link #exec} function.
*
* editorInstance.addCommand( 'loadoptions', {
* exec: function( editor ) {
* var cmd = this;
* // Asynchronous operation below.
* CKEDITOR.ajax.loadXml( 'data.xml', function() {
* editor.fire( 'afterCommandExec', {
* name: 'loadoptions',
* command: cmd
* } );
* } );
* },
* async: true // The command needs some time to complete after the exec function returns.
* } );
*
* @property {Boolean} [async=false]
*/
/**
* Whether the command should give focus to the editor before execution.
*
* editorInstance.addCommand( 'maximize', {
* exec: function( editor ) {
* // ...
* },
* editorFocus: false // The command does not require focusing the editing document.
* } );
*
* See also {@link CKEDITOR.command#editorFocus}.
*
* @property {Boolean} [editorFocus=true]
*/
/**
* Whether the command state should be set to {@link CKEDITOR#TRISTATE_DISABLED} on startup.
*
* editorInstance.addCommand( 'unlink', {
* exec: function( editor ) {
* // ...
* },
* startDisabled: true // The command is unavailable until the selection is inside a link.
* } );
*
* @property {Boolean} [startDisabled=false]
*/
/**
* Indicates that this command is sensitive to the selection context.
* If `true`, the {@link CKEDITOR.command#method-refresh} method will be
* called for this command on selection changes, with a single parameter
* representing the current elements path.
*
* @property {Boolean} [contextSensitive=true]
*/
/**
* Defined by the command definition, a function to determine the command state. It will be invoked
* when the editor has its `states` or `selection` changed.
*
* **Note:** The function provided must be calling {@link CKEDITOR.command#setState} in all circumstances
* if it is intended to update the command state.
*
* @method refresh
* @param {CKEDITOR.editor} editor
* @param {CKEDITOR.dom.elementPath} path
*/
/**
* Sets the element name used to reflect the command state on selection changes.
* If the selection is in a place where the element is not allowed, the command
* will be disabled.
* Setting this property overrides {@link #contextSensitive} to `true`.
*
* @property {Boolean} [context=true]
*/
/**
* The editor modes within which the command can be executed. The execution
* will have no action if the current mode is not listed in this property.
*
* editorInstance.addCommand( 'link', {
* exec: function( editor ) {
* // ...
* },
* modes: { wysiwyg:1 } // The command is available in wysiwyg mode only.
* } );
*
* See also {@link CKEDITOR.command#modes}.
*
* @property {Object} [modes={ wysiwyg:1 }]
*/
/**
* Whether the command should be enabled in the {@link CKEDITOR.editor#setReadOnly read-only mode}.
*
* @since 4.0.0
* @property {Boolean} [readOnly=false]
*/
/**
* A property that should be set when a command has no keystroke assigned by {@link CKEDITOR.editor#setKeystroke}, but
* the keystroke is still supported. For example: `cut`, `copy` and `paste` commands are handled that way.
* This property is used when displaying keystroke information in tooltips and context menus. It is used by
* {@link CKEDITOR.editor#getCommandKeystroke}.
*
* @since 4.6.0
* @property {Number} fakeKeystroke
*/

View file

@ -1,453 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.config} object that stores the
* default configuration settings.
*/
/**
* Used in conjunction with the {@link CKEDITOR.config#enterMode}
* and {@link CKEDITOR.config#shiftEnterMode} configuration
* settings to make the editor produce `<p>` tags when
* using the <kbd>Enter</kbd> key.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.ENTER_P = 1;
/**
* Used in conjunction with the {@link CKEDITOR.config#enterMode}
* and {@link CKEDITOR.config#shiftEnterMode} configuration
* settings to make the editor produce `<br>` tags when
* using the <kbd>Enter</kbd> key.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.ENTER_BR = 2;
/**
* Used in conjunction with the {@link CKEDITOR.config#enterMode}
* and {@link CKEDITOR.config#shiftEnterMode} configuration
* settings to make the editor produce `<div>` tags when
* using the <kbd>Enter</kbd> key.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* @readonly
* @property {Number} [=3]
* @member CKEDITOR
*/
CKEDITOR.ENTER_DIV = 3;
/**
* Stores default configuration settings. Changes to this object are
* reflected in all editor instances, if not specified otherwise for a particular
* instance.
*
* Read more about setting CKEditor configuration in the
* {@glink guide/dev_configuration documentation}.
*
* @class
* @singleton
*/
CKEDITOR.config = {
/**
* The URL path to the custom configuration file to be loaded. If not
* overwritten with inline configuration, it defaults to the `config.js`
* file present in the root of the CKEditor installation directory.
*
* CKEditor will recursively load custom configuration files defined inside
* other custom configuration files.
*
* Read more about setting CKEditor configuration in the
* {@glink guide/dev_configuration documentation}.
*
* // Load a specific configuration file.
* CKEDITOR.replace( 'myfield', { customConfig: '/myconfig.js' } );
*
* // Do not load any custom configuration file.
* CKEDITOR.replace( 'myfield', { customConfig: '' } );
*
* @cfg {String} [="<CKEditor folder>/config.js"]
*/
customConfig: 'config.js',
/**
* Whether the element replaced by the editor (usually a `<textarea>`)
* is to be updated automatically when posting the form containing the editor.
*
* @cfg
*/
autoUpdateElement: true,
/**
* The user interface language localization to use. If left empty, the editor
* will automatically be localized to the user language. If the user language is not supported,
* the language specified in the {@link CKEDITOR.config#defaultLanguage}
* configuration setting is used.
*
* Read more in the {@glink features/uilanguage documentation} and see the
* {@glink examples/uilanguages example}.
*
* // Load the German interface.
* config.language = 'de';
*
* @cfg
*/
language: '',
/**
* The language to be used if the {@link CKEDITOR.config#language}
* setting is left empty and it is not possible to localize the editor to the user language.
*
* Read more in the {@glink features/uilanguage documentation} and see the
* {@glink examples/uilanguages example}.
*
* config.defaultLanguage = 'it';
*
* @cfg
*/
defaultLanguage: 'en',
/**
* The writing direction of the language which is used to create editor content.
* Allowed values are:
*
* * `''` (an empty string) &ndash; Indicates that content direction will be the same as either
* the editor UI direction or the page element direction depending on the editor type:
* * {@glink guide/dev_framed Classic editor} &ndash; The same as the user interface language direction.
* * {@glink guide/dev_inline Inline editor}&ndash; The same as the editable element text direction.
* * `'ltr'` &ndash; Indicates a Left-To-Right text direction (like in English).
* * `'rtl'` &ndash; Indicates a Right-To-Left text direction (like in Arabic).
*
* See the {@glink examples/language example}.
*
* Example:
*
* config.contentsLangDirection = 'rtl';
*
* @cfg
*/
contentsLangDirection: '',
/**
* Sets the behavior of the <kbd>Enter</kbd> key. It also determines other behavior
* rules of the editor, like whether the `<br>` element is to be used
* as a paragraph separator when indenting text.
* The allowed values are the following constants that cause the behavior outlined below:
*
* * {@link CKEDITOR#ENTER_P} (1) &ndash; New `<p>` paragraphs are created.
* * {@link CKEDITOR#ENTER_BR} (2) &ndash; Lines are broken with `<br>` elements.
* * {@link CKEDITOR#ENTER_DIV} (3) &ndash; New `<div>` blocks are created.
*
* **Note**: It is recommended to use the {@link CKEDITOR#ENTER_P} setting because of
* its semantic value and correctness. The editor is optimized for this setting.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* // Not recommended.
* config.enterMode = CKEDITOR.ENTER_BR;
*
* @cfg {Number} [=CKEDITOR.ENTER_P]
*/
enterMode: CKEDITOR.ENTER_P,
/**
* Forces the use of {@link CKEDITOR.config#enterMode} as line break regardless
* of the context. If, for example, {@link CKEDITOR.config#enterMode} is set
* to {@link CKEDITOR#ENTER_P}, pressing the <kbd>Enter</kbd> key inside a
* `<div>` element will create a new paragraph with a `<p>`
* instead of a `<div>`.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* // Not recommended.
* config.forceEnterMode = true;
*
* @since 3.2.1
* @cfg
*/
forceEnterMode: false,
/**
* Similarly to the {@link CKEDITOR.config#enterMode} setting, it defines the behavior
* of the <kbd>Shift+Enter</kbd> key combination.
*
* The allowed values are the following constants that cause the behavior outlined below:
*
* * {@link CKEDITOR#ENTER_P} (1) &ndash; New `<p>` paragraphs are created.
* * {@link CKEDITOR#ENTER_BR} (2) &ndash; Lines are broken with `<br>` elements.
* * {@link CKEDITOR#ENTER_DIV} (3) &ndash; New `<div>` blocks are created.
*
* Read more in the {@glink features/enterkey documentation} and see the
* {@glink examples/enterkey example}.
*
* Example:
*
* config.shiftEnterMode = CKEDITOR.ENTER_P;
*
* @cfg {Number} [=CKEDITOR.ENTER_BR]
*/
shiftEnterMode: CKEDITOR.ENTER_BR,
/**
* Sets the `DOCTYPE` to be used when loading the editor content as HTML.
*
* // Set the DOCTYPE to the HTML 4 (Quirks) mode.
* config.docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
*
* @cfg
*/
docType: '<!DOCTYPE html>',
/**
* Sets the `id` attribute to be used on the `body` element
* of the editing area. This can be useful when you intend to reuse the original CSS
* file you are using on your live website and want to assign the editor the same ID
* as the section that will include the contents. In this way ID-specific CSS rules will
* be enabled.
*
* config.bodyId = 'contents_id';
*
* @since 3.1.0
* @cfg
*/
bodyId: '',
/**
* Sets the `class` attribute to be used on the `body` element
* of the editing area. This can be useful when you intend to reuse the original CSS
* file you are using on your live website and want to assign the editor the same class
* as the section that will include the contents. In this way class-specific CSS rules will
* be enabled.
*
* config.bodyClass = 'contents';
*
* **Note:** The editor needs to load stylesheets containing contents styles. You can either
* copy them to the `contents.css` file that the editor loads by default or set the {@link #contentsCss}
* option.
*
* **Note:** This setting only applies to {@glink guide/dev_framed classic editor} (the one that uses `iframe`).
*
* @since 3.1.0
* @cfg
*/
bodyClass: '',
/**
* Indicates whether the content to be edited is being input as a full HTML page.
* A full page includes the `<html>`, `<head>`, and `<body>` elements.
* The final output will also reflect this setting, including the
* `<body>` content only if this setting is disabled.
*
* Read more in the {@glink features/fullpage documentation} and see the
* {@glink examples/fullpage example}.
*
* config.fullPage = true;
*
* @since 3.1.0
* @cfg
*/
fullPage: false,
/**
* The height of the editing area that includes the editor content. This configuration
* option accepts an integer (to denote a value in pixels) or any CSS-defined length unit
* except percent (`%`) values which are not supported.
*
* **Note:** This configuration option is ignored by {@glink guide/dev_inline inline editor}.
*
* Read more in the {@glink features/size documentation} and see the
* {@glink examples/size example}.
*
* config.height = 500; // 500 pixels.
* config.height = '25em'; // CSS length.
* config.height = '300px'; // CSS length.
*
* @cfg {Number/String}
*/
height: 200,
/**
* The CSS file(s) to be used to apply style to editor content. It should
* reflect the CSS used in the target pages where the content is to be
* displayed.
*
* **Note:** This configuration value is used only in {@glink guide/dev_framed `<iframe>`-based editor }
* and ignored by {@glink guide/dev_inline inline editor}
* as it uses the styles that come directly from the page that CKEditor is
* rendered on. It is also ignored in the {@link #fullPage full page mode} in
* which the developer has full control over the page HTML code.
*
* Read more in the {@glink features/styles documentation} and see the
* {@glink examples/styles example}.
*
* config.contentsCss = '/css/mysitestyles.css';
* config.contentsCss = [ '/css/mysitestyles.css', '/css/anotherfile.css' ];
*
* @cfg {String/Array} [contentsCss=CKEDITOR.getUrl( 'contents.css' )]
*/
contentsCss: CKEDITOR.getUrl( 'contents.css' ),
/**
* Comma-separated list of plugins to be used in an editor instance. Note that
* the actual plugins that are to be loaded could still be affected by two other settings:
* {@link CKEDITOR.config#extraPlugins} and {@link CKEDITOR.config#removePlugins}.
*
* @cfg {String/String[]} [="<default list of plugins>"]
*/
plugins: '', // %REMOVE_LINE%
/**
* A list of additional plugins to be loaded. This setting makes it easier
* to add new plugins without having to touch the {@link CKEDITOR.config#plugins} setting.
*
* **Note:** The most recommended way to
* [add CKEditor plugins](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_plugins.html) is through
* [CKEditor Builder](https://ckeditor.com/cke4/builder). Read more in the
* {@glink guide/dev_plugins documentation}.
*
* config.extraPlugins = 'myplugin,anotherplugin';
*
* @cfg {String/String[]}
*/
extraPlugins: '',
/**
* A list of plugins that must not be loaded. This setting makes it possible
* to avoid loading some plugins defined in the {@link CKEDITOR.config#plugins}
* setting without having to touch it.
*
* **Note:** A plugin required by another plugin cannot be removed and will cause
* an error to be thrown. So for example if `contextmenu` is required by `tabletools`,
* it can only be removed if `tabletools` is not loaded.
*
* config.removePlugins = 'elementspath,save,font';
*
* @cfg {String/String[]}
*/
removePlugins: '',
/**
* A list of regular expressions to be executed on input HTML,
* indicating HTML source code that when matched, must **not** be available in the WYSIWYG
* mode for editing.
*
* config.protectedSource.push( /<\?[\s\S]*?\?>/g ); // PHP code
* config.protectedSource.push( /<%[\s\S]*?%>/g ); // ASP code
* config.protectedSource.push( /(<asp:[^\>]+>[\s|\S]*?<\/asp:[^\>]+>)|(<asp:[^\>]+\/>)/gi ); // ASP.NET code
*
* @cfg
*/
protectedSource: [],
/**
* The editor `tabindex` value.
*
* Read more in the {@glink features/tabindex documentation} and see the
* {@glink examples/tabindex example}.
*
* config.tabIndex = 1;
*
* @cfg
*/
tabIndex: 0,
/**
* Indicates that some of the editor features, like alignment and text
* direction, should use the "computed value" of the feature to indicate its
* on/off state instead of using the "real value".
*
* If enabled in a Left-To-Right written document, the "Left Justify"
* alignment button will be shown as active, even if the alignment style is not
* explicitly applied to the current paragraph in the editor.
*
* config.useComputedState = false;
*
* @since 3.4.0
* @cfg {Boolean} [useComputedState=true]
*/
useComputedState: true,
/**
* The editor UI outer width. This configuration option accepts an integer
* (to denote a value in pixels) or any CSS-defined length unit.
*
* Unlike the {@link CKEDITOR.config#height} setting, this
* one will set the outer width of the entire editor UI, not for the
* editing area only.
*
* **Note:** This configuration option is ignored by {@glink guide/dev_inline inline editor}.
*
* Read more in the {@glink features/size documentation} and see the
* {@glink examples/size example}.
*
* config.width = 850; // 850 pixels wide.
* config.width = '75%'; // CSS unit.
*
* @cfg {String/Number}
*/
width: '',
/**
* The base Z-index for floating dialog windows and popups.
*
* config.baseFloatZIndex = 2000;
*
* @cfg
*/
baseFloatZIndex: 10000,
/**
* The keystrokes that are blocked by default as the browser implementation
* is buggy. These default keystrokes are handled by the editor.
*
* // Default setting.
* config.blockedKeystrokes = [
* CKEDITOR.CTRL + 66, // Ctrl+B
* CKEDITOR.CTRL + 73, // Ctrl+I
* CKEDITOR.CTRL + 85 // Ctrl+U
* ];
*
* @cfg {Array} [blockedKeystrokes=see example]
*/
blockedKeystrokes: [
CKEDITOR.CTRL + 66, // Ctrl+B
CKEDITOR.CTRL + 73, // Ctrl+I
CKEDITOR.CTRL + 85 // Ctrl+U
]
};
/**
* The base user interface color to be used by the editor. Not all skins are
* {@glink guide/skin_sdk_chameleon compatible with this setting}.
*
* Read more in the {@glink features/uicolor documentation} and see the
* {@glink examples/uicolor example}.
*
* // Using a color code.
* config.uiColor = '#AADC6E';
*
* // Using an HTML color name.
* config.uiColor = 'Gold';
*
* @cfg {String} uiColor
*/
// PACKAGER_RENAME( CKEDITOR.config )

View file

@ -1,204 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
( function() {
/** @class CKEDITOR */
/**
* Turns a DOM element with the `contenteditable` attribute set to `true` into a
* CKEditor instance. Check {@link CKEDITOR.dtd#$editable} for a list of
* allowed element names.
*
* **Note:** If the DOM element for which inline editing is being enabled does not have
* the `contenteditable` attribute set to `true` or the {@link CKEDITOR.config#readOnly `config.readOnly`}
* configuration option is set to `true`, the editor will start in read-only mode.
*
* <div contenteditable="true" id="content">...</div>
* ...
* CKEDITOR.inline( 'content' );
*
* It is also possible to create an inline editor from the `<textarea>` element.
* If you do so, an additional `<div>` element with editable content will be created
* directly after the `<textarea>` element and the `<textarea>` element will be hidden.
*
* Since 4.17 this function also supports the {@glink features/delayed_creation Delayed Editor Creation} feature
* allowing to postpone the editor initialization.
*
* Since 4.19 if the editor has been configured to use the {@glink features/delayed_creation Delayed Editor Creation}
* feature and the editor has not been initialized yet, this function will return a handle allowing
* to cancel the interval set by the {@link CKEDITOR.config#delayIfDetached} and
* {@link CKEDITOR.config#delayIfDetached_interval} options.
*
* ```javascript
* var cancelInterval = CKEDITOR.inline( 'editor', {
* delayIfDetached: true,
* delayIfDetached_interval: 50 // Default value, you can skip that option.
* } );
*
* cancelInterval(); // Cancel editor initialization if needed.
* ```
*
* It is recommended to use this function to prevent potential memory leaks. Use it if you know
* that the editor host element will never be attached to the DOM. As an example, execute cancel handle
* in your component cleanup logic (e.g. `onDestroy` lifecycle methods in popular frontend frameworks).
*
* Read more about this feature in the {@glink features/delayed_creation documentation}.
*
* @param {Object/String} element The DOM element or its ID.
* @param {Object} [instanceConfig] The specific configurations to apply to this editor instance.
* See {@link CKEDITOR.config}.
* @returns {CKEDITOR.editor/Function/null} The editor instance or a cancellation function.
* If {@glink features/delayed_creation Delayed Editor Creation} feature has not been set and
* element is missing in DOM, this function will return `null`.
*/
CKEDITOR.inline = function( element, instanceConfig ) {
element = CKEDITOR.editor._getEditorElement( element );
if ( !element ) {
return null;
}
// (#4461)
if ( CKEDITOR.editor.shouldDelayEditorCreation( element, instanceConfig ) ) {
return CKEDITOR.editor.initializeDelayedEditorCreation( element, instanceConfig, 'inline' );
}
var textarea = element.is( 'textarea' ) ? element : null,
editorData = textarea ? textarea.getValue() : element.getHtml(),
editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE );
if ( textarea ) {
editor.setData( editorData, null, true );
//Change element from textarea to div
element = CKEDITOR.dom.element.createFromHtml(
'<div contenteditable="' + !!editor.readOnly + '" class="cke_textarea_inline">' +
textarea.getValue() +
'</div>',
CKEDITOR.document );
element.insertAfter( textarea );
textarea.hide();
// Attaching the concrete form.
if ( textarea.$.form )
editor._attachToForm();
} else {
// If editor element does not have contenteditable attribute, but config.readOnly
// is explicitly set to false, set the contentEditable property to true (#3866).
if ( instanceConfig && typeof instanceConfig.readOnly !== 'undefined' && !instanceConfig.readOnly ) {
element.setAttribute( 'contenteditable', 'true' );
}
// Initial editor data is simply loaded from the page element content to make
// data retrieval possible immediately after the editor creation.
editor.setData( editorData, null, true );
}
// Once the editor is loaded, start the UI.
editor.on( 'loaded', function() {
editor.fire( 'uiReady' );
// Enable editing on the element.
editor.editable( element );
// Editable itself is the outermost element.
editor.container = element;
editor.ui.contentsElement = element;
// Load and process editor data.
editor.setData( editor.getData( 1 ) );
// Clean on startup.
editor.resetDirty();
editor.fire( 'contentDom' );
// Inline editing defaults to "wysiwyg" mode, so plugins don't
// need to make special handling for this "mode-less" environment.
editor.mode = 'wysiwyg';
editor.fire( 'mode' );
// The editor is completely loaded for interaction.
editor.status = 'ready';
editor.fireOnce( 'instanceReady' );
CKEDITOR.fire( 'instanceReady', null, editor );
// give priority to plugins that relay on editor#loaded for bootstrapping.
}, null, null, 10000 );
// Handle editor destroying.
editor.on( 'destroy', function() {
var container = editor.container;
// Remove container from DOM if inline-textarea editor.
// Show <textarea> back again.
// Editor can be destroyed before container is created (#3115).
if ( textarea && container ) {
container.clearCustomData();
container.remove();
}
if ( textarea ) {
textarea.show();
}
editor.element.clearCustomData();
delete editor.element;
} );
return editor;
};
/**
* Calls the {@link CKEDITOR#inline `CKEDITOR.inline()`} method for all page elements with the `contenteditable` attribute set to
* `true` that are allowed in the {@link CKEDITOR.dtd#$editable} object.
*
* Since 4.17 this function also supports the {@glink features/delayed_creation Delayed Editor Creation} feature
* allowing to postpone the editor initialization.
* Read more about this feature in the {@glink features/delayed_creation documentation}.
*/
CKEDITOR.inlineAll = function() {
var el,
data;
for ( var name in CKEDITOR.dtd.$editable ) {
var elements = CKEDITOR.document.getElementsByTag( name );
for ( var i = 0, len = elements.count(); i < len; i++ ) {
el = elements.getItem( i );
// Check whether an element is editable and if an editor attached is not to it already (#4293).
if ( el.getAttribute( 'contenteditable' ) == 'true' && !el.getEditor() ) {
// Fire the "inline" event, making it possible to customize
// the instance settings and eventually cancel the creation.
data = {
element: el,
config: {}
};
if ( CKEDITOR.fire( 'inline', data ) !== false ) {
CKEDITOR.inline( el, data.config );
}
}
}
}
};
CKEDITOR.domReady( function() {
!CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
} );
} )();
/**
* Disables creating the inline editor automatically for elements with
* the `contenteditable` attribute set to `true`.
*
* CKEDITOR.disableAutoInline = true;
*
* @cfg {Boolean} [disableAutoInline=false]
*/

View file

@ -1,630 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/** @class CKEDITOR */
/**
* The class name used to identify `<textarea>` elements to be replaced
* by CKEditor instances. Set it to empty/`null` to disable this feature.
*
* CKEDITOR.replaceClass = 'rich_editor';
*
* @cfg {String} [replaceClass='ckeditor']
*/
CKEDITOR.replaceClass = 'ckeditor';
( function() {
/**
* Replaces a `<textarea>` or a DOM element (`<div>`) with a CKEditor
* instance. For textareas, the initial value in the editor will be the
* textarea value. For DOM elements, their `innerHTML` will be used
* instead. It is recommended to use `<textarea>` and `<div>` elements only.
*
* <textarea id="myfield" name="myfield"></textarea>
* ...
* CKEDITOR.replace( 'myfield' );
*
* var textarea = document.body.appendChild( document.createElement( 'textarea' ) );
* CKEDITOR.replace( textarea );
*
* Since 4.17 this function also supports the {@glink features/delayed_creation Delayed Editor Creation} feature
* allowing to postpone the editor initialization.
*
* Since 4.19 if the editor has been configured to use the {@glink features/delayed_creation Delayed Editor Creation}
* feature and the editor has not been initialized yet, this function will return a handle allowing
* to cancel the interval set by the {@link CKEDITOR.config#delayIfDetached} and
* {@link CKEDITOR.config#delayIfDetached_interval} options.
*
* ```javascript
* var cancelInterval = CKEDITOR.replace( 'editor', {
* delayIfDetached: true,
* delayIfDetached_interval: 50 // Default value, you can skip that option.
* } );
*
* cancelInterval(); // Cancel editor initialization if needed.
* ```
*
* It is recommended to use this function to prevent potential memory leaks. Use it if you know
* that the editor host element will never be attached to the DOM. As an example, execute cancel handle
* in your component cleanup logic (e.g. `onDestroy` lifecycle methods in popular frontend frameworks).
*
* Read more about this feature in the {@glink features/delayed_creation documentation}.
*
* @param {Object/String} element The DOM element (textarea), its ID, or name.
* @param {Object} [config] The specific configuration to apply to this
* editor instance. Configuration set here will override the global CKEditor settings
* (see {@link CKEDITOR.config}).
* @returns {CKEDITOR.editor/Function/null} The editor instance or a cancellation function.
* If {@glink features/delayed_creation Delayed Editor Creation} feature has not been set and
* element is missing in DOM, this function will return `null`.
*/
CKEDITOR.replace = function( element, config ) {
return createInstance( element, config, null, CKEDITOR.ELEMENT_MODE_REPLACE );
};
/**
* Creates a new editor instance at the end of a specific DOM element.
*
* <!DOCTYPE html>
* <html>
* <head>
* <meta charset="utf-8">
* <title>CKEditor</title>
* <!-- Make sure the path to CKEditor is correct. -->
* <script src="/ckeditor/ckeditor.js"></script>
* </head>
* <body>
* <div id="editorSpace"></div>
* <script>
* CKEDITOR.appendTo( 'editorSpace' );
* </script>
* </body>
* </html>
*
* Since 4.17 this function also supports the {@glink features/delayed_creation Delayed Editor Creation} feature
* allowing to postpone the editor initialization.
*
* Since 4.19 if the editor has been configured to use the {@glink features/delayed_creation Delayed Editor Creation}
* feature and the editor has not been initialized yet, this function will return a handle allowing
* to cancel the interval set by the {@link CKEDITOR.config#delayIfDetached} and
* {@link CKEDITOR.config#delayIfDetached_interval} options.
*
* ```javascript
* var cancelInterval = CKEDITOR.appendTo( 'editorSpace', {
* delayIfDetached: true,
* delayIfDetached_interval: 50 // Default value, you can skip that option.
* } );
*
* cancelInterval(); // Cancel editor initialization if needed.
* ```
*
* It is recommended to use this function to prevent potential memory leaks. Use it if you know
* that the editor host element will never be attached to the DOM. As an example, execute cancel handle
* in your component cleanup logic (e.g. `onDestroy` lifecycle methods in popular frontend frameworks).
*
* Read more about this feature in the {@glink features/delayed_creation documentation}.
*
* @param {Object/String} element The DOM element, its ID, or name.
* @param {Object} [config] The specific configuration to apply to this
* editor instance. Configuration set here will override the global CKEditor settings
* (see {@link CKEDITOR.config}).
* @param {String} [data] Since 3.3. Initial value for the instance.
* @returns {CKEDITOR.editor/Function/null} The editor instance or a cancelation function.
* If {@glink features/delayed_creation Delayed Editor Creation} feature has not been set and
* element is missing in DOM, this function will return `null`.
*/
CKEDITOR.appendTo = function( element, config, data ) {
return createInstance( element, config, data, CKEDITOR.ELEMENT_MODE_APPENDTO );
};
/**
* Replaces all `<textarea>` elements available in the document with
* editor instances.
*
* // Replace all <textarea> elements in the page.
* CKEDITOR.replaceAll();
*
* // Replace all <textarea class="myClassName"> elements in the page.
* CKEDITOR.replaceAll( 'myClassName' );
*
* // Selectively replace <textarea> elements, based on a custom evaluation function.
* CKEDITOR.replaceAll( function( textarea, config ) {
* // A function that needs to be evaluated for the <textarea>
* // to be replaced. It must explicitly return "false" to ignore a
* // specific <textarea>.
* // You can also customize the editor instance by having the function
* // modify the "config" parameter.
* } );
*
* // Full page example where three <textarea> elements are replaced.
* <!DOCTYPE html>
* <html>
* <head>
* <meta charset="utf-8">
* <title>CKEditor</title>
* <!-- Make sure the path to CKEditor is correct. -->
* <script src="/ckeditor/ckeditor.js"></script>
* </head>
* <body>
* <textarea name="editor1"></textarea>
* <textarea name="editor2"></textarea>
* <textarea name="editor3"></textarea>
* <script>
* // Replace all three <textarea> elements above with CKEditor instances.
* CKEDITOR.replaceAll();
* </script>
* </body>
* </html>
*
* Since 4.17 this function also supports the {@glink features/delayed_creation Delayed Editor Creation} feature
* allowing to postpone the editor initialization.
* Read more about this feature in the {@glink features/delayed_creation documentation}.
*
* @param {String} [className] The `<textarea>` class name.
* @param {Function} [evaluator] An evaluation function that must return `true` for a `<textarea>`
* to be replaced with the editor. If the function returns `false`, the `<textarea>` element
* will not be replaced.
*/
CKEDITOR.replaceAll = function() {
var textareas = document.getElementsByTagName( 'textarea' );
for ( var i = 0; i < textareas.length; i++ ) {
var config = null,
textarea = textareas[ i ];
// The "name" and/or "id" attribute must exist.
if ( !textarea.name && !textarea.id )
continue;
if ( typeof arguments[ 0 ] == 'string' ) {
// The textarea class name could be passed as the function
// parameter.
var classRegex = new RegExp( '(?:^|\\s)' + arguments[ 0 ] + '(?:$|\\s)' );
if ( !classRegex.test( textarea.className ) )
continue;
} else if ( typeof arguments[ 0 ] == 'function' ) {
// An evaluation function could be passed as the function parameter.
// It must explicitly return "false" to ignore a specific <textarea>.
config = {};
if ( arguments[ 0 ]( textarea, config ) === false )
continue;
}
this.replace( textarea, config );
}
};
/** @class CKEDITOR.editor */
/**
* Registers an editing mode. This function is to be used mainly by plugins.
*
* @param {String} mode The mode name.
* @param {Function} exec The function that performs the actual mode change.
*/
CKEDITOR.editor.prototype.addMode = function( mode, exec ) {
( this._.modes || ( this._.modes = {} ) )[ mode ] = exec;
};
/**
* Changes the editing mode of this editor instance.
*
* **Note:** The mode switch could be asynchronous depending on the mode provider.
* Use the `callback` to hook subsequent code.
*
* // Switch to "source" view.
* CKEDITOR.instances.editor1.setMode( 'source' );
* // Switch to "wysiwyg" view and be notified on completion.
* CKEDITOR.instances.editor1.setMode( 'wysiwyg', function() { alert( 'wysiwyg mode loaded!' ); } );
*
* @param {String} [newMode] If not specified, the {@link CKEDITOR.config#startupMode} will be used.
* @param {Function} [callback] Optional callback function which is invoked once the mode switch has succeeded.
*/
CKEDITOR.editor.prototype.setMode = function( newMode, callback ) {
var editor = this;
var modes = this._.modes;
// Mode loading quickly fails.
if ( newMode == editor.mode || !modes || !modes[ newMode ] )
return;
editor.fire( 'beforeSetMode', newMode );
if ( editor.mode ) {
var isDirty = editor.checkDirty(),
previousModeData = editor._.previousModeData,
currentData,
unlockSnapshot = 0;
editor.fire( 'beforeModeUnload' );
// Detach the current editable. While detaching editable will set
// cached editor's data (with internal setData call). We use this
// data below to avoid two getData() calls in a row.
editor.editable( 0 );
editor._.previousMode = editor.mode;
// Get cached data, which was set while detaching editable.
editor._.previousModeData = currentData = editor.getData( 1 );
// If data has not been modified in the mode which we are currently leaving,
// avoid making snapshot right after initializing new mode.
// https://dev.ckeditor.com/ticket/5217#comment:20
// Tested by:
// 'test switch mode with unrecoreded, inner HTML specific content (boguses)'
// 'test switch mode with unrecoreded, inner HTML specific content (boguses) plus changes in source mode'
if ( editor.mode == 'source' && previousModeData == currentData ) {
// We need to make sure that unlockSnapshot will update the last snapshot
// (will not create new one) if lockSnapshot is not called on outdated snapshots stack.
// Additionally, forceUpdate prevents from making content image now, which is useless
// (because it equals editor data not inner HTML).
editor.fire( 'lockSnapshot', { forceUpdate: true } );
unlockSnapshot = 1;
}
// Clear up the mode space.
editor.ui.space( 'contents' ).setHtml( '' );
editor.mode = '';
} else {
editor._.previousModeData = editor.getData( 1 );
}
// Fire the mode handler.
this._.modes[ newMode ]( function() {
// Set the current mode.
editor.mode = newMode;
if ( isDirty !== undefined )
!isDirty && editor.resetDirty();
if ( unlockSnapshot )
editor.fire( 'unlockSnapshot' );
// Since snapshot made on dataReady (which normally catches changes done by setData)
// won't work because editor.mode was not set yet (it's set in this function), we need
// to make special snapshot for changes done in source mode here.
else if ( newMode == 'wysiwyg' )
editor.fire( 'saveSnapshot' );
// Delay to avoid race conditions (setMode inside setMode).
setTimeout( function() {
if ( editor.isDestroyed() || editor.isDetached() ) {
return;
}
editor.fire( 'mode' );
callback && callback.call( editor );
}, 0 );
} );
};
/**
* Resizes the editor interface.
*
* **Note:** Since 4.14.1 this method accepts numeric or absolute CSS length units.
*
* ```javascript
* editor.resize( 900, 300 );
*
* editor.resize( '5in', 450, true );
* ```
*
* @param {Number/String} width The new width. It can be an integer denoting a value
* in pixels or a CSS size value with unit. When null is passed, the value will not be set.
* @param {Number/String} height The new height. It can be an integer denoting a value
* in pixels or a CSS size value with unit.
* @param {Boolean} [isContentHeight] Indicates that the provided height is to
* be applied to the editor content area, and not to the entire editor
* interface. Defaults to `false`.
* @param {Boolean} [resizeInner] Indicates that it is the inner interface
* element that must be resized, not the outer element. The default theme
* defines the editor interface inside a pair of `<span>` elements
* (`<span><span>...</span></span>`). By default the first,
* outer `<span>` element receives the sizes. If this parameter is set to
* `true`, the second, inner `<span>` is resized instead.
*/
CKEDITOR.editor.prototype.resize = function( width, height, isContentHeight, resizeInner ) {
var container = this.container,
contents = this.ui.space( 'contents' ),
contentsFrame = CKEDITOR.env.webkit && this.document && this.document.getWindow().$.frameElement,
outer;
if ( resizeInner ) {
outer = this.container.getFirst( function( node ) {
return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_inner' );
} );
} else {
outer = container;
}
if ( width || width === 0 ) {
width = convertCssUnitToPx( width );
}
// Set as border box width. (https://dev.ckeditor.com/ticket/5353)
outer.setSize( 'width', width, true );
// WebKit needs to refresh the iframe size to avoid rendering issues. (1/2) (https://dev.ckeditor.com/ticket/8348)
contentsFrame && ( contentsFrame.style.width = '1%' );
height = convertCssUnitToPx( height );
// Get the height delta between the outer table and the content area.
var contentsOuterDelta = ( outer.$.offsetHeight || 0 ) - ( contents.$.clientHeight || 0 ),
// If we're setting the content area's height, then we don't need the delta.
resultContentsHeight = Math.max( height - ( isContentHeight ? 0 : contentsOuterDelta ), 0 ),
resultOuterHeight = ( isContentHeight ? height + contentsOuterDelta : height );
contents.setStyle( 'height', CKEDITOR.tools.cssLength( resultContentsHeight ) );
// WebKit needs to refresh the iframe size to avoid rendering issues. (2/2) (https://dev.ckeditor.com/ticket/8348)
contentsFrame && ( contentsFrame.style.width = '100%' );
// Emit a resize event.
this.fire( 'resize', {
outerHeight: resultOuterHeight,
contentsHeight: resultContentsHeight,
// Sometimes width is not provided.
outerWidth: width || outer.getSize( 'width' )
} );
};
/**
* Gets the element that can be used to check the editor size. This method
* is mainly used by the [Editor Resize](https://ckeditor.com/cke4/addon/resize) plugin, which adds
* a UI handle that can be used to resize the editor.
*
* @param {Boolean} forContents Whether to return the "contents" part of the theme instead of the container.
* @returns {CKEDITOR.dom.element} The resizable element.
*/
CKEDITOR.editor.prototype.getResizable = function( forContents ) {
return forContents ? this.ui.space( 'contents' ) : this.container;
};
function convertCssUnitToPx( unit ) {
return CKEDITOR.tools.convertToPx( CKEDITOR.tools.cssLength( unit ) );
}
function createInstance( element, config, data, mode ) {
element = CKEDITOR.editor._getEditorElement( element );
if ( !element ) {
return null;
}
// (#4461)
if ( CKEDITOR.editor.shouldDelayEditorCreation( element, config ) ) {
return CKEDITOR.editor.initializeDelayedEditorCreation( element, config, 'replace' );
}
// Create the editor instance.
var editor = new CKEDITOR.editor( config, element, mode );
if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
// Do not replace the textarea right now, just hide it. The effective
// replacement will be done later in the editor creation lifecycle.
element.setStyle( 'visibility', 'hidden' );
// https://dev.ckeditor.com/ticket/8031 Remember if textarea was required and remove the attribute.
editor._.required = element.hasAttribute( 'required' );
element.removeAttribute( 'required' );
}
data && editor.setData( data, null, true );
// Once the editor is loaded, start the UI.
editor.on( 'loaded', function() {
if ( editor.isDestroyed() || editor.isDetached() ) {
return;
}
loadTheme( editor );
if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE && editor.config.autoUpdateElement && element.$.form )
editor._attachToForm();
editor.setMode( editor.config.startupMode, function() {
// Clean on startup.
editor.resetDirty();
// Editor is completely loaded for interaction.
editor.status = 'ready';
editor.fireOnce( 'instanceReady' );
CKEDITOR.fire( 'instanceReady', null, editor );
} );
} );
editor.on( 'destroy', destroy );
return editor;
}
function destroy() {
var editor = this,
container = editor.container,
element = editor.element;
if ( container ) {
container.clearCustomData();
container.remove();
}
if ( element ) {
element.clearCustomData();
if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
element.show();
if ( editor._.required )
element.setAttribute( 'required', 'required' );
}
delete editor.element;
}
}
function loadTheme( editor ) {
var name = editor.name,
element = editor.element,
elementMode = editor.elementMode;
// Get the HTML for the predefined spaces.
var topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html;
var bottomHtml = editor.fire( 'uiSpace', { space: 'bottom', html: '' } ).html;
var themedTpl = new CKEDITOR.template(
'<{outerEl}' +
' id="cke_{name}"' +
' class="{id} cke cke_reset cke_chrome cke_editor_{name} cke_{langDir} ' + CKEDITOR.env.cssClass + '" ' +
' dir="{langDir}"' +
' lang="{langCode}"' +
' role="application"' +
( editor.applicationTitle ? ' aria-labelledby="cke_{name}_arialbl"' : '' ) +
'>' +
( editor.applicationTitle ? '<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' : '' ) +
'<{outerEl} class="cke_inner cke_reset" role="presentation">' +
'{topHtml}' +
'<{outerEl} id="{contentId}" class="cke_contents cke_reset" role="presentation"></{outerEl}>' +
'{bottomHtml}' +
'</{outerEl}>' +
'</{outerEl}>' );
var container = CKEDITOR.dom.element.createFromHtml( themedTpl.output( {
id: editor.id,
name: name,
langDir: editor.lang.dir,
langCode: editor.langCode,
voiceLabel: editor.applicationTitle,
topHtml: topHtml ? '<span id="' + editor.ui.spaceId( 'top' ) + '" class="cke_top cke_reset_all" role="presentation" style="height:auto">' + topHtml + '</span>' : '',
contentId: editor.ui.spaceId( 'contents' ),
bottomHtml: bottomHtml ? '<span id="' + editor.ui.spaceId( 'bottom' ) + '" class="cke_bottom cke_reset_all" role="presentation">' + bottomHtml + '</span>' : '',
outerEl: CKEDITOR.env.ie ? 'span' : 'div' // https://dev.ckeditor.com/ticket/9571
} ) );
if ( elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
element.hide();
container.insertAfter( element );
} else {
element.append( container );
}
editor.container = container;
editor.ui.contentsElement = editor.ui.space( 'contents' );
// Make top and bottom spaces unelectable, but not content space,
// otherwise the editable area would be affected.
topHtml && editor.ui.space( 'top' ).unselectable();
bottomHtml && editor.ui.space( 'bottom' ).unselectable();
var width = editor.config.width, height = editor.config.height;
if ( width )
container.setStyle( 'width', CKEDITOR.tools.cssLength( width ) );
// The editor height is applied to the contents space.
if ( height )
editor.ui.space( 'contents' ).setStyle( 'height', CKEDITOR.tools.cssLength( height ) );
// Disable browser context menu for editor's chrome.
container.disableContextMenu();
// Redirect the focus into editor for webkit. (https://dev.ckeditor.com/ticket/5713)
CKEDITOR.env.webkit && container.on( 'focus', function() {
editor.focus();
} );
editor.fireOnce( 'uiReady' );
}
// Replace all textareas with the default class name.
CKEDITOR.domReady( function() {
CKEDITOR.replaceClass && CKEDITOR.replaceAll( CKEDITOR.replaceClass );
} );
} )();
/**
* The current editing mode. An editing mode basically provides
* different ways of editing or viewing the editor content.
*
* alert( CKEDITOR.instances.editor1.mode ); // (e.g.) 'wysiwyg'
*
* @readonly
* @property {String} mode
*/
/**
* The mode to load at the editor startup. It depends on the plugins
* loaded. By default, the `wysiwyg` and `source` modes are available.
*
* config.startupMode = 'source';
*
* @cfg {String} [startupMode='wysiwyg']
* @member CKEDITOR.config
*/
CKEDITOR.config.startupMode = 'wysiwyg';
/**
* Fired after the editor instance is resized through
* the {@link CKEDITOR.editor#method-resize CKEDITOR.resize} method.
*
* @event resize
* @param {CKEDITOR.editor} editor This editor instance.
* @param {Object} data Available since CKEditor 4.5.0.
* @param {Number} data.outerHeight The height of the entire area that the editor covers.
* @param {Number} data.contentsHeight Editable area height in pixels.
* @param {Number} data.outerWidth The width of the entire area that the editor covers.
*/
/**
* Fired before changing the editing mode. See also
* {@link #beforeSetMode} and {@link #event-mode}.
*
* @event beforeModeUnload
* @param {CKEDITOR.editor} editor This editor instance.
*/
/**
* Fired before the editor mode is set. See also
* {@link #event-mode} and {@link #beforeModeUnload}.
*
* @since 3.5.3
* @event beforeSetMode
* @param {CKEDITOR.editor} editor This editor instance.
* @param {String} data The name of the mode which is about to be set.
*/
/**
* Fired after setting the editing mode. See also {@link #beforeSetMode} and {@link #beforeModeUnload}
*
* @event mode
* @param {CKEDITOR.editor} editor This editor instance.
*/
/**
* Fired when the editor (replacing a `<textarea>` which has a `required` attribute) is empty during form submission.
*
* This event replaces native required fields validation that the browsers cannot
* perform when CKEditor replaces `<textarea>` elements.
*
* You can cancel this event to prevent the page from submitting data.
*
* editor.on( 'required', function( evt ) {
* alert( 'Article content is required.' );
* evt.cancel();
* } );
*
* @event required
* @param {CKEDITOR.editor} editor This editor instance.
*/
/**
* Fired when the UI space is created. This event allows to modify the top bar or the bottom bar with additional HTML.
*
* For example, it is used in the [Editor Resize](https://ckeditor.com/cke4/addon/resize) plugin
* to add the HTML element used to resize the editor.
*
* @event uiSpace
* @param {Object} data
* @param {String} data.space The name of the {@link CKEDITOR.ui#space space} for which the event is fired.
* @param {String} data.html HTML string which will be included in the given space.
*/

View file

@ -1,70 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.dataProcessor} class, which
* defines the basic structure of data processor objects to be
* set to {@link CKEDITOR.editor.dataProcessor}.
*/
/**
* If defined, points to the data processor which is responsible for translating
* and transforming the editor data on input and output.
* Generally it will point to an instance of {@link CKEDITOR.htmlDataProcessor},
* which handles HTML data. The editor may also handle other data formats by
* using different data processors provided by specific plugins.
*
* @property {CKEDITOR.dataProcessor} dataProcessor
* @member CKEDITOR.editor
*/
/**
* Represents a data processor which is responsible for translating and
* transforming the editor data on input and output.
*
* This class is here for documentation purposes only and is not really part of
* the API. It serves as the base ("interface") for data processor implementations.
*
* @class CKEDITOR.dataProcessor
* @abstract
*/
/**
* Transforms input data into HTML to be loaded into the editor.
* While the editor is able to handle non-HTML data (like BBCode), it can only
* handle HTML data at runtime. The role of the data processor is to transform
* the input data into HTML through this function.
*
* // Tranforming BBCode data, with a custom BBCode data processor available.
* var data = 'This is [b]an example[/b].';
* var html = editor.dataProcessor.toHtml( data ); // '<p>This is <b>an example</b>.</p>'
*
* @method toHtml
* @param {String} data The input data to be transformed.
* @param {String} [fixForBody] The tag name to be used if the data must be
* fixed because it is supposed to be loaded direcly into the `<body>`
* tag. This is generally not used by non-HTML data processors.
* @todo fixForBody type - compare to htmlDataProcessor.
*/
/**
* Transforms HTML into data to be output by the editor, in the format
* expected by the data processor.
*
* While the editor is able to handle non-HTML data (like BBCode), it can only
* handle HTML data at runtime. The role of the data processor is to transform
* the HTML data contained by the editor into a specific data format through
* this function.
*
* // Tranforming into BBCode data, with a custom BBCode data processor available.
* var html = '<p>This is <b>an example</b>.</p>';
* var data = editor.dataProcessor.toDataFormat( html ); // 'This is [b]an example[/b].'
*
* @method toDataFormat
* @param {String} html The HTML to be transformed.
* @param {String} fixForBody The tag name to be used if the output data is
* coming from the `<body>` element and may be eventually fixed for it. This is
* generally not used by non-HTML data processors.
*/

View file

@ -1,13 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom} object, which contains DOM
* manipulation objects and function.
*/
CKEDITOR.dom = {};
// PACKAGER_RENAME( CKEDITOR.dom )

View file

@ -1,53 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents
* a DOM comment node.
*/
/**
* Represents a DOM comment node.
*
* var nativeNode = document.createComment( 'Example' );
* var comment = new CKEDITOR.dom.comment( nativeNode );
*
* var comment = new CKEDITOR.dom.comment( 'Example' );
*
* @class
* @extends CKEDITOR.dom.node
* @constructor Creates a comment class instance.
* @param {Object/String} comment A native DOM comment node or a string containing
* the text to use to create a new comment node.
* @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
* the node in case of new node creation. Defaults to the current document.
*/
CKEDITOR.dom.comment = function( comment, ownerDocument ) {
if ( typeof comment == 'string' )
comment = ( ownerDocument ? ownerDocument.$ : document ).createComment( comment );
CKEDITOR.dom.domObject.call( this, comment );
};
CKEDITOR.dom.comment.prototype = new CKEDITOR.dom.node();
CKEDITOR.tools.extend( CKEDITOR.dom.comment.prototype, {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_COMMENT]
*/
type: CKEDITOR.NODE_COMMENT,
/**
* Gets the outer HTML of this comment.
*
* @returns {String} The HTML `<!-- comment value -->`.
*/
getOuterHtml: function() {
return '<!--' + this.$.nodeValue + '-->';
}
} );

View file

@ -1,328 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.document} class which
* represents a DOM document.
*/
/**
* Represents a DOM document.
*
* var document = new CKEDITOR.dom.document( document );
*
* @class
* @extends CKEDITOR.dom.domObject
* @constructor Creates a document class instance.
* @param {Object} domDocument A native DOM document.
*/
CKEDITOR.dom.document = function( domDocument ) {
CKEDITOR.dom.domObject.call( this, domDocument );
};
// PACKAGER_RENAME( CKEDITOR.dom.document )
CKEDITOR.dom.document.prototype = new CKEDITOR.dom.domObject();
CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_DOCUMENT]
*/
type: CKEDITOR.NODE_DOCUMENT,
/**
* Appends a CSS file to the document.
*
* CKEDITOR.document.appendStyleSheet( '/mystyles.css' );
*
* @param {String} cssFileUrl The CSS file URL.
*/
appendStyleSheet: function( cssFileUrl ) {
cssFileUrl = CKEDITOR.appendTimestamp( cssFileUrl );
if ( this.$.createStyleSheet )
this.$.createStyleSheet( cssFileUrl );
else {
var link = new CKEDITOR.dom.element( 'link' );
link.setAttributes( {
rel: 'stylesheet',
type: 'text/css',
href: cssFileUrl
} );
this.getHead().append( link );
}
},
/**
* Creates a CSS stylesheet and inserts it into the document.
*
* @param cssStyleText {String} CSS style text.
* @returns {Object} The created DOM native stylesheet object.
*/
appendStyleText: function( cssStyleText ) {
if ( this.$.createStyleSheet ) {
var styleSheet = this.$.createStyleSheet( '' );
styleSheet.cssText = cssStyleText;
} else {
var style = new CKEDITOR.dom.element( 'style', this );
style.append( new CKEDITOR.dom.text( cssStyleText, this ) );
this.getHead().append( style );
}
return styleSheet || style.$.sheet;
},
/**
* Creates a {@link CKEDITOR.dom.element} instance in this document.
*
* @param {String} name The name of the element.
* @param {Object} [attributesAndStyles]
* @param {Object} [attributesAndStyles.attributes] Attributes that will be set.
* @param {Object} [attributesAndStyles.styles] Styles that will be set.
* @returns {CKEDITOR.dom.element}
*/
createElement: function( name, attribsAndStyles ) {
var element = new CKEDITOR.dom.element( name, this );
if ( attribsAndStyles ) {
if ( attribsAndStyles.attributes )
element.setAttributes( attribsAndStyles.attributes );
if ( attribsAndStyles.styles )
element.setStyles( attribsAndStyles.styles );
}
return element;
},
/**
* Creates a {@link CKEDITOR.dom.text} instance in this document.
*
* @param {String} text Value of the text node.
* @returns {CKEDITOR.dom.element}
*/
createText: function( text ) {
return new CKEDITOR.dom.text( text, this );
},
/**
* Moves the selection focus to this document's window.
*/
focus: function() {
this.getWindow().focus();
},
/**
* Returns the element that is currently designated as the active element in the document.
*
* **Note:** Only one element can be active at a time in a document.
* An active element does not necessarily have focus,
* but an element with focus is always the active element in a document.
*
* @returns {CKEDITOR.dom.element} Active element or `null` if an IE8-9 bug is encountered.
* See [#10030](https://dev.ckeditor.com/ticket/10030).
*/
getActive: function() {
var $active;
try {
$active = this.$.activeElement;
} catch ( e ) {
return null;
}
return new CKEDITOR.dom.element( $active );
},
/**
* Gets an element based on its ID.
*
* var element = CKEDITOR.document.getById( 'myElement' );
* alert( element.getId() ); // 'myElement'
*
* @param {String} elementId The element ID.
* @returns {CKEDITOR.dom.element} The element instance, or `null` if not found.
*/
getById: function( elementId ) {
var $ = this.$.getElementById( elementId );
return $ ? new CKEDITOR.dom.element( $ ) : null;
},
/**
* Gets a node based on its address. See {@link CKEDITOR.dom.node#getAddress}.
*
* @param {Array} address
* @param {Boolean} [normalized=false]
*/
getByAddress: function( address, normalized ) {
var $ = this.$.documentElement;
for ( var i = 0; $ && i < address.length; i++ ) {
var target = address[ i ];
if ( !normalized ) {
$ = $.childNodes[ target ];
continue;
}
var currentIndex = -1;
for ( var j = 0; j < $.childNodes.length; j++ ) {
var candidate = $.childNodes[ j ];
if ( normalized === true && candidate.nodeType == 3 && candidate.previousSibling && candidate.previousSibling.nodeType == 3 )
continue;
currentIndex++;
if ( currentIndex == target ) {
$ = candidate;
break;
}
}
}
return $ ? new CKEDITOR.dom.node( $ ) : null;
},
/**
* Gets elements list based on a given tag name.
*
* @param {String} tagName The element tag name.
* @returns {CKEDITOR.dom.nodeList} The nodes list.
*/
getElementsByTag: function( tagName, namespace ) {
if ( !( CKEDITOR.env.ie && ( document.documentMode <= 8 ) ) && namespace )
tagName = namespace + ':' + tagName;
return new CKEDITOR.dom.nodeList( this.$.getElementsByTagName( tagName ) );
},
/**
* Gets the `<head>` element for this document.
*
* var element = CKEDITOR.document.getHead();
* alert( element.getName() ); // 'head'
*
* @returns {CKEDITOR.dom.element} The `<head>` element.
*/
getHead: function() {
var head = this.$.getElementsByTagName( 'head' )[ 0 ];
if ( !head )
head = this.getDocumentElement().append( new CKEDITOR.dom.element( 'head' ), true );
else
head = new CKEDITOR.dom.element( head );
return head;
},
/**
* Gets the `<body>` element for this document.
*
* var element = CKEDITOR.document.getBody();
* alert( element.getName() ); // 'body'
*
* @returns {CKEDITOR.dom.element} The `<body>` element.
*/
getBody: function() {
return new CKEDITOR.dom.element( this.$.body );
},
/**
* Gets the DOM document element for this document.
*
* @returns {CKEDITOR.dom.element} The DOM document element.
*/
getDocumentElement: function() {
return new CKEDITOR.dom.element( this.$.documentElement );
},
/**
* Gets the window object that stores this document.
*
* @returns {CKEDITOR.dom.window} The window object.
*/
getWindow: function() {
return new CKEDITOR.dom.window( this.$.parentWindow || this.$.defaultView );
},
/**
* Defines the document content through `document.write`. Note that the
* previous document content will be lost (cleaned).
*
* document.write(
* '<html>' +
* '<head><title>Sample Document</title></head>' +
* '<body>Document content created by code.</body>' +
* '</html>'
* );
*
* @since 3.5.0
* @param {String} html The HTML defining the document content.
*/
write: function( html ) {
// Don't leave any history log in IE. (https://dev.ckeditor.com/ticket/5657)
this.$.open( 'text/html', 'replace' );
// Support for custom document.domain in IE.
//
// The script must be appended because if placed before the
// doctype, IE will go into quirks mode and mess with
// the editable, e.g. by changing its default height.
if ( CKEDITOR.env.ie )
html = html.replace( /(?:^\s*<!DOCTYPE[^>]*?>)|^/i, '$&\n<script data-cke-temp="1">(' + CKEDITOR.tools.fixDomain + ')();</script>' );
this.$.write( html );
this.$.close();
},
/**
* Wrapper for `querySelectorAll`. Returns a list of elements within this document that match
* the specified `selector`.
*
* **Note:** The returned list is not a live collection (like the result of native `querySelectorAll`).
*
* @since 4.3.0
* @param {String} selector A valid [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors).
* @returns {CKEDITOR.dom.nodeList}
*/
find: function( selector ) {
return new CKEDITOR.dom.nodeList( this.$.querySelectorAll( selector ) );
},
/**
* Wrapper for `querySelector`. Returns the first element within this document that matches
* the specified `selector`.
*
* @since 4.3.0
* @param {String} selector A valid [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors).
* @returns {CKEDITOR.dom.element}
*/
findOne: function( selector ) {
var el = this.$.querySelector( selector );
return el ? new CKEDITOR.dom.element( el ) : null;
},
/**
* Internet Explorer 8 only method. It returns a document fragment which has all HTML5 elements enabled.
*
* @since 4.3.0
* @private
* @returns DocumentFragment
*/
_getHtml5ShivFrag: function() {
var $frag = this.getCustomData( 'html5ShivFrag' );
if ( !$frag ) {
$frag = this.$.createDocumentFragment();
CKEDITOR.tools.enableHtml5Elements( $frag, true );
this.setCustomData( 'html5ShivFrag', $frag );
}
return $frag;
}
} );

View file

@ -1,194 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* DocumentFragment is a "lightweight" or "minimal" Document object. It is
* commonly used to extract a portion of the document's tree or to create a new
* fragment of the document. Various operations may take document fragment objects
* as arguments and result in all the child nodes of the document fragment being
* moved to the child list of this node.
*
* @class
* @constructor Creates a document fragment class instance.
* @param {CKEDITOR.dom.document/DocumentFragment} [nodeOrDoc=CKEDITOR.document]
*/
CKEDITOR.dom.documentFragment = function( nodeOrDoc ) {
nodeOrDoc = nodeOrDoc || CKEDITOR.document;
if ( nodeOrDoc.type == CKEDITOR.NODE_DOCUMENT )
this.$ = nodeOrDoc.$.createDocumentFragment();
else
this.$ = nodeOrDoc;
};
CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype, CKEDITOR.dom.element.prototype, {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
*/
type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
/**
* Inserts the document fragment content after the specified node.
*
* @param {CKEDITOR.dom.node} node
*/
insertAfterNode: function( node ) {
node = node.$;
node.parentNode.insertBefore( this.$, node.nextSibling );
},
/**
* Gets the HTML of this document fragment's children.
*
* @since 4.5.0
* @returns {String} The HTML of this document fragment's children.
*/
getHtml: function() {
var container = new CKEDITOR.dom.element( 'div' );
this.clone( 1, 1 ).appendTo( container );
return container.getHtml().replace( /\s*data-cke-expando=".*?"/g, '' );
}
}, true, {
'append': 1, 'appendBogus': 1, 'clone': 1, 'getFirst': 1, 'getHtml': 1, 'getLast': 1, 'getParent': 1, 'getNext': 1, 'getPrevious': 1,
'appendTo': 1, 'moveChildren': 1, 'insertBefore': 1, 'insertAfterNode': 1, 'replace': 1, 'trim': 1, 'type': 1,
'ltrim': 1, 'rtrim': 1, 'getDocument': 1, 'getChildCount': 1, 'getChild': 1, 'getChildren': 1
} );
CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype, CKEDITOR.dom.document.prototype, true, {
'find': 1, 'findOne': 1
} );
/**
* @member CKEDITOR.dom.documentFragment
* @method append
* @inheritdoc CKEDITOR.dom.element#append
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method appendBogus
* @inheritdoc CKEDITOR.dom.element#appendBogus
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method clone
* @inheritdoc CKEDITOR.dom.element#clone
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getFirst
* @inheritdoc CKEDITOR.dom.element#getFirst
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getLast
* @inheritdoc CKEDITOR.dom.element#getLast
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getParent
* @inheritdoc CKEDITOR.dom.element#getParent
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getNext
* @inheritdoc CKEDITOR.dom.element#getNext
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getPrevious
* @inheritdoc CKEDITOR.dom.element#getPrevious
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method appendTo
* @inheritdoc CKEDITOR.dom.element#appendTo
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method moveChildren
* @inheritdoc CKEDITOR.dom.element#moveChildren
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method insertBefore
* @inheritdoc CKEDITOR.dom.element#insertBefore
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method replace
* @inheritdoc CKEDITOR.dom.element#replace
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method trim
* @inheritdoc CKEDITOR.dom.element#trim
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method ltrim
* @inheritdoc CKEDITOR.dom.element#ltrim
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method rtrim
* @inheritdoc CKEDITOR.dom.element#rtrim
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getDocument
* @inheritdoc CKEDITOR.dom.element#getDocument
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getChildCount
* @inheritdoc CKEDITOR.dom.element#getChildCount
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getChild
* @inheritdoc CKEDITOR.dom.element#getChild
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method getChildren
* @inheritdoc CKEDITOR.dom.element#getChildren
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method find
* @since 4.12.0
* @inheritdoc CKEDITOR.dom.document#find
*/
/**
* @member CKEDITOR.dom.documentFragment
* @method findOne
* @since 4.12.0
* @inheritdoc CKEDITOR.dom.document#findOne
*/

View file

@ -1,275 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base
* for other classes representing DOM objects.
*/
/**
* Represents a DOM object. This class is not intended to be used directly. It
* serves as the base class for other classes representing specific DOM
* objects.
*
* @class
* @mixins CKEDITOR.event
* @constructor Creates a domObject class instance.
* @param {Object} nativeDomObject A native DOM object.
*/
CKEDITOR.dom.domObject = function( nativeDomObject ) {
if ( nativeDomObject ) {
/**
* The native DOM object represented by this class instance.
*
* var element = new CKEDITOR.dom.element( 'span' );
* alert( element.$.nodeType ); // '1'
*
* @readonly
* @property {Object}
*/
this.$ = nativeDomObject;
}
};
CKEDITOR.dom.domObject.prototype = ( function() {
// Do not define other local variables here. We want to keep the native
// listener closures as clean as possible.
var getNativeListener = function( domObject, eventName ) {
return function( domEvent ) {
// In FF, when reloading the page with the editor focused, it may
// throw an error because the CKEDITOR global is not anymore
// available. So, we check it here first. (https://dev.ckeditor.com/ticket/2923)
if ( typeof CKEDITOR != 'undefined' )
domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );
};
};
return {
/**
* Gets the private `_` object which is bound to the native
* DOM object using {@link #getCustomData}.
*
* var elementA = new CKEDITOR.dom.element( nativeElement );
* elementA.getPrivate().value = 1;
* ...
* var elementB = new CKEDITOR.dom.element( nativeElement );
* elementB.getPrivate().value; // 1
*
* @returns {Object} The private object.
*/
getPrivate: function() {
var priv;
// Get the main private object from the custom data. Create it if not defined.
if ( !( priv = this.getCustomData( '_' ) ) )
this.setCustomData( '_', ( priv = {} ) );
return priv;
},
// Docs inherited from event.
on: function( eventName ) {
// We customize the "on" function here. The basic idea is that we'll have
// only one listener for a native event, which will then call all listeners
// set to the event.
// Get the listeners holder object.
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
if ( !nativeListeners ) {
nativeListeners = {};
this.setCustomData( '_cke_nativeListeners', nativeListeners );
}
// Check if we have a listener for that event.
if ( !nativeListeners[ eventName ] ) {
var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );
if ( this.$.addEventListener )
this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );
else if ( this.$.attachEvent )
this.$.attachEvent( 'on' + eventName, listener );
}
// Call the original implementation.
return CKEDITOR.event.prototype.on.apply( this, arguments );
},
// Docs inherited from event.
removeListener: function( eventName ) {
// Call the original implementation.
CKEDITOR.event.prototype.removeListener.apply( this, arguments );
// If we don't have listeners for this event, clean the DOM up.
if ( !this.hasListeners( eventName ) ) {
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
var listener = nativeListeners && nativeListeners[ eventName ];
if ( listener ) {
if ( this.$.removeEventListener )
this.$.removeEventListener( eventName, listener, false );
else if ( this.$.detachEvent )
this.$.detachEvent( 'on' + eventName, listener );
delete nativeListeners[ eventName ];
}
}
},
/**
* Removes any listener set on this object.
*
* To avoid memory leaks we must assure that there are no
* references left after the object is no longer needed.
*/
removeAllListeners: function() {
try {
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
for ( var eventName in nativeListeners ) {
var listener = nativeListeners[ eventName ];
if ( this.$.detachEvent ) {
this.$.detachEvent( 'on' + eventName, listener );
} else if ( this.$.removeEventListener ) {
this.$.removeEventListener( eventName, listener, false );
}
delete nativeListeners[ eventName ];
}
// Catch Edge `Permission denied` error which occurs randomly. Since the error is quite
// random, catching allows to continue the code execution and cleanup (#3419).
} catch ( error ) {
if ( !CKEDITOR.env.edge || error.number !== -2146828218 ) {
throw( error );
}
}
// Remove events from events object so fire() method will not call
// listeners (https://dev.ckeditor.com/ticket/11400).
CKEDITOR.event.prototype.removeAllListeners.call( this );
}
};
} )();
( function( domObjectProto ) {
var customData = {};
CKEDITOR.on( 'reset', function() {
customData = {};
} );
/**
* Determines whether the specified object is equal to the current object.
*
* var doc = new CKEDITOR.dom.document( document );
* alert( doc.equals( CKEDITOR.document ) ); // true
* alert( doc == CKEDITOR.document ); // false
*
* @param {Object} object The object to compare with the current object.
* @returns {Boolean} `true` if the object is equal.
*/
domObjectProto.equals = function( object ) {
// Try/Catch to avoid IE permission error when object is from different document.
try {
return ( object && object.$ === this.$ );
} catch ( er ) {
return false;
}
};
/**
* Sets a data slot value for this object. These values are shared by all
* instances pointing to that same DOM object.
*
* **Note:** The created data slot is only guaranteed to be available on this unique DOM node,
* thus any wish to continue access to it from other element clones (either created by
* clone node or from `innerHtml`) will fail. For such usage please use
* {@link CKEDITOR.dom.element#setAttribute} instead.
*
* **Note**: This method does not work on text nodes prior to Internet Explorer 9.
*
* var element = new CKEDITOR.dom.element( 'span' );
* element.setCustomData( 'hasCustomData', true );
*
* @param {String} key A key used to identify the data slot.
* @param {Object} value The value to set to the data slot.
* @returns {CKEDITOR.dom.domObject} This DOM object instance.
* @chainable
*/
domObjectProto.setCustomData = function( key, value ) {
var expandoNumber = this.getUniqueId(),
dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );
dataSlot[ key ] = value;
return this;
};
/**
* Gets the value set to a data slot in this object.
*
* var element = new CKEDITOR.dom.element( 'span' );
* alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
* alert( element.getCustomData( 'nonExistingKey' ) ); // null
*
* @param {String} key The key used to identify the data slot.
* @returns {Object} This value set to the data slot.
*/
domObjectProto.getCustomData = function( key ) {
var expandoNumber = this.$[ 'data-cke-expando' ],
dataSlot = expandoNumber && customData[ expandoNumber ];
return ( dataSlot && key in dataSlot ) ? dataSlot[ key ] : null;
};
/**
* Removes the value in the data slot under the given `key`.
*
* @param {String} key
* @returns {Object} Removed value or `null` if not found.
*/
domObjectProto.removeCustomData = function( key ) {
var expandoNumber = this.$[ 'data-cke-expando' ],
dataSlot = expandoNumber && customData[ expandoNumber ],
retval, hadKey;
if ( dataSlot ) {
retval = dataSlot[ key ];
hadKey = key in dataSlot;
delete dataSlot[ key ];
}
return hadKey ? retval : null;
};
/**
* Removes any data stored in this object.
* To avoid memory leaks we must assure that there are no
* references left after the object is no longer needed.
*/
domObjectProto.clearCustomData = function() {
// Clear all event listeners
this.removeAllListeners();
var expandoNumber = this.getUniqueId();
expandoNumber && delete customData[ expandoNumber ];
};
/**
* Gets an ID that can be used to identify this DOM object in
* the running session.
*
* **Note**: This method does not work on text nodes prior to Internet Explorer 9.
*
* @returns {Number} A unique ID.
*/
domObjectProto.getUniqueId = function() {
return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() );
};
// Implement CKEDITOR.event.
CKEDITOR.event.implementOn( domObjectProto );
} )( CKEDITOR.dom.domObject.prototype );

File diff suppressed because it is too large Load diff

View file

@ -1,265 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
( function() {
var pathBlockLimitElements = {},
pathBlockElements = {},
tag;
// Elements that are considered the "Block limit" in an element path.
for ( tag in CKEDITOR.dtd.$blockLimit ) {
// Exclude from list roots.
if ( !( tag in CKEDITOR.dtd.$list ) )
pathBlockLimitElements[ tag ] = 1;
}
// Elements that are considered the "End level Block" in an element path.
for ( tag in CKEDITOR.dtd.$block ) {
// Exclude block limits, and empty block element, e.g. hr.
if ( !( tag in CKEDITOR.dtd.$blockLimit || tag in CKEDITOR.dtd.$empty ) )
pathBlockElements[ tag ] = 1;
}
// Check if an element contains any block element.
function checkHasBlock( element ) {
var childNodes = element.getChildren();
for ( var i = 0, count = childNodes.count(); i < count; i++ ) {
var child = childNodes.getItem( i );
if ( child.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$block[ child.getName() ] )
return true;
}
return false;
}
/**
* Retrieve the list of nodes walked from the start node up to the editable element of the editor.
*
* @class
* @constructor Creates an element path class instance.
* @param {CKEDITOR.dom.element} startNode From which the path should start.
* @param {CKEDITOR.dom.element} root To which element the path should stop, defaults to the `body` element.
*/
CKEDITOR.dom.elementPath = function( startNode, root ) {
var block = null,
blockLimit = null,
elements = [],
e = startNode,
elementName;
// Backward compact.
root = root || startNode.getDocument().getBody();
// Assign root value if startNode is null (#424)(https://dev.ckeditor.com/ticket/17028).
if ( !e ) {
e = root;
}
do {
if ( e.type == CKEDITOR.NODE_ELEMENT ) {
elements.push( e );
if ( !this.lastElement ) {
this.lastElement = e;
// If an object or non-editable element is fully selected at the end of the element path,
// it must not become the block limit.
if ( e.is( CKEDITOR.dtd.$object ) || e.getAttribute( 'contenteditable' ) == 'false' )
continue;
}
if ( e.equals( root ) )
break;
if ( !blockLimit ) {
elementName = e.getName();
// First editable element becomes a block limit, because it cannot be split.
if ( e.getAttribute( 'contenteditable' ) == 'true' )
blockLimit = e;
// "Else" because element cannot be both - block and block levelimit.
else if ( !block && pathBlockElements[ elementName ] )
block = e;
if ( pathBlockLimitElements[ elementName ] ) {
// End level DIV is considered as the block, if no block is available. (https://dev.ckeditor.com/ticket/525)
// But it must NOT be the root element (checked above).
if ( !block && elementName == 'div' && !checkHasBlock( e ) )
block = e;
else
blockLimit = e;
}
}
}
}
while ( ( e = e.getParent() ) );
// Block limit defaults to root.
if ( !blockLimit )
blockLimit = root;
/**
* First non-empty block element which:
*
* * is not a {@link CKEDITOR.dtd#$blockLimit},
* * or is a `div` which does not contain block elements and is not a `root`.
*
* This means a first, splittable block in elements path.
*
* @readonly
* @property {CKEDITOR.dom.element}
*/
this.block = block;
/**
* See the {@link CKEDITOR.dtd#$blockLimit} description.
*
* @readonly
* @property {CKEDITOR.dom.element}
*/
this.blockLimit = blockLimit;
/**
* The root of the elements path - `root` argument passed to class constructor or a `body` element.
*
* @readonly
* @property {CKEDITOR.dom.element}
*/
this.root = root;
/**
* An array of elements (from `startNode` to `root`) in the path.
*
* @readonly
* @property {CKEDITOR.dom.element[]}
*/
this.elements = elements;
/**
* The last element of the elements path - `startNode` or its parent.
*
* @readonly
* @property {CKEDITOR.dom.element} lastElement
*/
};
} )();
CKEDITOR.dom.elementPath.prototype = {
/**
* Compares this element path with another one.
*
* @param {CKEDITOR.dom.elementPath} otherPath The elementPath object to be
* compared with this one.
* @returns {Boolean} `true` if the paths are equal, containing the same
* number of elements and the same elements in the same order.
*/
compare: function( otherPath ) {
var thisElements = this.elements;
var otherElements = otherPath && otherPath.elements;
if ( !otherElements || thisElements.length != otherElements.length )
return false;
for ( var i = 0; i < thisElements.length; i++ ) {
if ( !thisElements[ i ].equals( otherElements[ i ] ) )
return false;
}
return true;
},
/**
* Search the path elements that meets the specified criteria.
*
* @param {String/Array/Function/Object/CKEDITOR.dom.element} query The criteria that can be
* either a tag name, list (array and object) of tag names, element or an node evaluator function.
* @param {Boolean} [excludeRoot] Not taking path root element into consideration.
* @param {Boolean} [fromTop] Search start from the topmost element instead of bottom.
* @returns {CKEDITOR.dom.element} The first matched dom element or `null`.
*/
contains: function( query, excludeRoot, fromTop ) {
var i = 0,
evaluator;
if ( typeof query == 'string' )
evaluator = function( node ) {
return node.getName() == query;
};
if ( query instanceof CKEDITOR.dom.element )
evaluator = function( node ) {
return node.equals( query );
};
else if ( CKEDITOR.tools.isArray( query ) )
evaluator = function( node ) {
return CKEDITOR.tools.indexOf( query, node.getName() ) > -1;
};
else if ( typeof query == 'function' )
evaluator = query;
else if ( typeof query == 'object' )
evaluator = function( node ) {
return node.getName() in query;
};
var elements = this.elements,
length = elements.length;
if ( excludeRoot ) {
if ( !fromTop ) {
length -= 1;
} else {
i += 1;
}
}
if ( fromTop ) {
elements = Array.prototype.slice.call( elements, 0 );
elements.reverse();
}
for ( ; i < length; i++ ) {
if ( evaluator( elements[ i ] ) )
return elements[ i ];
}
return null;
},
/**
* Check whether the elements path is the proper context for the specified
* tag name in the DTD.
*
* @param {String} tag The tag name.
* @returns {Boolean}
*/
isContextFor: function( tag ) {
var holder;
// Check for block context.
if ( tag in CKEDITOR.dtd.$block ) {
// Indeterminate elements which are not subjected to be splitted or surrounded must be checked first.
var inter = this.contains( CKEDITOR.dtd.$intermediate );
holder = inter || ( this.root.equals( this.block ) && this.block ) || this.blockLimit;
return !!holder.getDtd()[ tag ];
}
return true;
},
/**
* Retrieve the text direction for this elements path.
*
* @returns {'ltr'/'rtl'}
*/
direction: function() {
var directionNode = this.block || this.blockLimit || this.root;
return directionNode.getDirection( 1 );
}
};

View file

@ -1,238 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.event} class, which
* represents the a native DOM event object.
*/
/**
* Represents a native DOM event object.
*
* @class
* @constructor Creates an event class instance.
* @param {Object} domEvent A native DOM event object.
*/
CKEDITOR.dom.event = function( domEvent ) {
/**
* The native DOM event object represented by this class instance.
*
* @readonly
*/
this.$ = domEvent;
};
CKEDITOR.dom.event.prototype = {
/**
* Gets the key code associated to the event.
*
* alert( event.getKey() ); // '65' if 'a' has been pressed
*
* @returns {Number} The key code.
*/
getKey: function() {
return this.$.keyCode || this.$.which;
},
/**
* Gets a number represeting the combination of the keys pressed during the
* event. It is the sum with the current key code and the {@link CKEDITOR#CTRL},
* {@link CKEDITOR#SHIFT} and {@link CKEDITOR#ALT} constants.
*
* alert( event.getKeystroke() == 65 ); // 'a' key
* alert( event.getKeystroke() == CKEDITOR.CTRL + 65 ); // CTRL + 'a' key
* alert( event.getKeystroke() == CKEDITOR.CTRL + CKEDITOR.SHIFT + 65 ); // CTRL + SHIFT + 'a' key
*
* @returns {Number} The number representing the keys combination.
*/
getKeystroke: function() {
var keystroke = this.getKey();
if ( this.$.ctrlKey || this.$.metaKey )
keystroke += CKEDITOR.CTRL;
if ( this.$.shiftKey )
keystroke += CKEDITOR.SHIFT;
if ( this.$.altKey )
keystroke += CKEDITOR.ALT;
return keystroke;
},
/**
* Prevents the original behavior of the event to happen. It can optionally
* stop propagating the event in the event chain.
*
* var element = CKEDITOR.document.getById( 'myElement' );
* element.on( 'click', function( ev ) {
* // The DOM event object is passed by the 'data' property.
* var domEvent = ev.data;
* // Prevent the click to chave any effect in the element.
* domEvent.preventDefault();
* } );
*
* @param {Boolean} [stopPropagation=false] Stop propagating this event in the
* event chain.
*/
preventDefault: function( stopPropagation ) {
var $ = this.$;
if ( $.preventDefault )
$.preventDefault();
else
$.returnValue = false;
if ( stopPropagation )
this.stopPropagation();
},
/**
* Stops this event propagation in the event chain.
*/
stopPropagation: function() {
var $ = this.$;
if ( $.stopPropagation )
$.stopPropagation();
else
$.cancelBubble = true;
},
/**
* Returns the DOM node where the event was targeted to.
*
* var element = CKEDITOR.document.getById( 'myElement' );
* element.on( 'click', function( ev ) {
* // The DOM event object is passed by the 'data' property.
* var domEvent = ev.data;
* // Add a CSS class to the event target.
* domEvent.getTarget().addClass( 'clicked' );
* } );
*
* @returns {CKEDITOR.dom.node} The target DOM node.
*/
getTarget: function() {
var rawNode = this.$.target || this.$.srcElement;
return rawNode ? new CKEDITOR.dom.node( rawNode ) : null;
},
/**
* Returns an integer value that indicates the current processing phase of an event.
* For browsers that doesn't support event phase, {@link CKEDITOR#EVENT_PHASE_AT_TARGET} is always returned.
*
* @returns {Number} One of {@link CKEDITOR#EVENT_PHASE_CAPTURING},
* {@link CKEDITOR#EVENT_PHASE_AT_TARGET}, or {@link CKEDITOR#EVENT_PHASE_BUBBLING}.
*/
getPhase: function() {
return this.$.eventPhase || 2;
},
/**
* Retrieves the coordinates of the mouse pointer relative to the top-left
* corner of the document, in mouse related event.
*
* element.on( 'mousemouse', function( ev ) {
* var pageOffset = ev.data.getPageOffset();
* alert( pageOffset.x ); // page offset X
* alert( pageOffset.y ); // page offset Y
* } );
*
* @returns {Object} The object contains the position.
* @returns {Number} return.x
* @returns {Number} return.y
*/
getPageOffset: function() {
var doc = this.getTarget().getDocument().$;
var pageX = this.$.pageX || this.$.clientX + ( doc.documentElement.scrollLeft || doc.body.scrollLeft );
var pageY = this.$.pageY || this.$.clientY + ( doc.documentElement.scrollTop || doc.body.scrollTop );
return { x: pageX, y: pageY };
}
};
// For the followind constants, we need to go over the Unicode boundaries
// (0x10FFFF) to avoid collision.
/**
* CTRL key (0x110000).
*
* @readonly
* @property {Number} [=0x110000]
* @member CKEDITOR
*/
CKEDITOR.CTRL = 0x110000;
/**
* SHIFT key (0x220000).
*
* @readonly
* @property {Number} [=0x220000]
* @member CKEDITOR
*/
CKEDITOR.SHIFT = 0x220000;
/**
* ALT key (0x440000).
*
* @readonly
* @property {Number} [=0x440000]
* @member CKEDITOR
*/
CKEDITOR.ALT = 0x440000;
/**
* Capturing phase.
*
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.EVENT_PHASE_CAPTURING = 1;
/**
* Event at target.
*
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.EVENT_PHASE_AT_TARGET = 2;
/**
* Bubbling phase.
*
* @readonly
* @property {Number} [=3]
* @member CKEDITOR
*/
CKEDITOR.EVENT_PHASE_BUBBLING = 3;
/**
* Integration with browser's "Go back" and "Go forward" buttons using Native History API.
*
* @since 4.17.0
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.HISTORY_NATIVE = 1;
/**
* Integration with browser's "Go back" and "Go forward" buttons using hash-based navigation.
*
* @since 4.17.0
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.HISTORY_HASH = 2;
/**
* Switch off integration with browser's "Go back" and "Go forward" buttons.
*
* @since 4.17.0
* @readonly
* @property {Number} [=0]
* @member CKEDITOR
*/
CKEDITOR.HISTORY_OFF = 0;

View file

@ -1,565 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @ignore
* File overview: DOM iterator which iterates over list items, lines and paragraphs.
*/
'use strict';
( function() {
/**
* Represents the iterator class. It can be used to iterate
* over all elements (or even text nodes in case of {@link #enlargeBr} set to `false`)
* which establish "paragraph-like" spaces within the passed range.
*
* // <h1>[foo</h1><p>bar]</p>
* var iterator = range.createIterator();
* iterator.getNextParagraph(); // h1 element
* iterator.getNextParagraph(); // p element
*
* // <ul><li>[foo</li><li>bar]</li>
* // With enforceRealBlocks set to false the iterator will return two list item elements.
* // With enforceRealBlocks set to true the iterator will return two paragraphs and the DOM will be changed to:
* // <ul><li><p>foo</p></li><li><p>bar</p></li>
*
* @class CKEDITOR.dom.iterator
* @constructor Creates an iterator class instance.
* @param {CKEDITOR.dom.range} range
*/
function iterator( range ) {
if ( arguments.length < 1 )
return;
/**
* @readonly
* @property {CKEDITOR.dom.range}
*/
this.range = range;
/**
* @property {Boolean} [forceBrBreak=false]
*/
this.forceBrBreak = 0;
// (https://dev.ckeditor.com/ticket/3730).
/**
* Whether to include `<br>` elements in the enlarged range. Should be
* set to `false` when using the iterator in the {@link CKEDITOR#ENTER_BR} mode.
*
* @property {Boolean} [enlargeBr=true]
*/
this.enlargeBr = 1;
/**
* Whether the iterator should create a transformable block
* if the current one contains text and cannot be transformed.
* For example new blocks will be established in elements like
* `<li>` or `<td>`.
*
* @property {Boolean} [enforceRealBlocks=false]
*/
this.enforceRealBlocks = 0;
this._ || ( this._ = {} );
}
/**
* Default iterator's filter. It is set only for nested iterators.
*
* @since 4.3.0
* @readonly
* @property {CKEDITOR.filter} filter
*/
/**
* Iterator's active filter. It is set by the {@link #getNextParagraph} method
* when it enters a nested editable.
*
* @since 4.3.0
* @readonly
* @property {CKEDITOR.filter} activeFilter
*/
var beginWhitespaceRegex = /^[\r\n\t ]+$/,
// Ignore bookmark nodes.(https://dev.ckeditor.com/ticket/3783)
bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ),
whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ),
skipGuard = function( node ) {
return bookmarkGuard( node ) && whitespacesGuard( node );
},
listItemNames = { dd: 1, dt: 1, li: 1 };
iterator.prototype = {
/**
* Returns the next paragraph-like element or `null` if the end of a range is reached.
*
* @param {String} [blockTag='p'] Name of a block element which will be established by
* the iterator in block-less elements (see {@link #enforceRealBlocks}).
*/
getNextParagraph: function( blockTag ) {
// The block element to be returned.
var block;
// The range object used to identify the paragraph contents.
var range;
// Indicats that the current element in the loop is the last one.
var isLast;
// Instructs to cleanup remaining BRs.
var removePreviousBr, removeLastBr;
blockTag = blockTag || 'p';
// We're iterating over nested editable.
if ( this._.nestedEditable ) {
// Get next block from nested iterator and returns it if was found.
block = this._.nestedEditable.iterator.getNextParagraph( blockTag );
if ( block ) {
// Inherit activeFilter from the nested iterator.
this.activeFilter = this._.nestedEditable.iterator.activeFilter;
return block;
}
// No block in nested iterator means that we reached the end of the nested editable.
// Reset the active filter to the default filter (or undefined if this iterator didn't have it).
this.activeFilter = this.filter;
// Try to find next nested editable or get back to parent (this) iterator.
if ( startNestedEditableIterator( this, blockTag, this._.nestedEditable.container, this._.nestedEditable.remaining ) ) {
// Inherit activeFilter from the nested iterator.
this.activeFilter = this._.nestedEditable.iterator.activeFilter;
return this._.nestedEditable.iterator.getNextParagraph( blockTag );
} else {
this._.nestedEditable = null;
}
}
// Block-less range should be checked first.
if ( !this.range.root.getDtd()[ blockTag ] )
return null;
// This is the first iteration. Let's initialize it.
if ( !this._.started )
range = startIterator.call( this );
var currentNode = this._.nextNode,
lastNode = this._.lastNode;
this._.nextNode = null;
while ( currentNode ) {
// closeRange indicates that a paragraph boundary has been found,
// so the range can be closed.
var closeRange = 0,
parentPre = currentNode.hasAscendant( 'pre' );
// includeNode indicates that the current node is good to be part
// of the range. By default, any non-element node is ok for it.
var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
continueFromSibling = 0;
// If it is an element node, let's check if it can be part of the range.
if ( !includeNode ) {
var nodeName = currentNode.getName();
// Non-editable block was found - return it and move to processing
// its nested editables if they exist.
if ( CKEDITOR.dtd.$block[ nodeName ] && currentNode.getAttribute( 'contenteditable' ) == 'false' ) {
block = currentNode;
// Setup iterator for first of nested editables.
// If there's no editable, then algorithm will move to next element after current block.
startNestedEditableIterator( this, blockTag, block );
// Gets us straight to the end of getParagraph() because block variable is set.
break;
} else if ( currentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
// <br> boundaries must be part of the range. It will
// happen only if ForceBrBreak.
if ( nodeName == 'br' )
includeNode = 1;
else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' ) {
// If we have found an empty block, and haven't started
// the range yet, it means we must return this block.
block = currentNode;
isLast = currentNode.equals( lastNode );
break;
}
// The range must finish right before the boundary,
// including possibly skipped empty spaces. (https://dev.ckeditor.com/ticket/1603)
if ( range ) {
range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
// The found boundary must be set as the next one at this
// point. (https://dev.ckeditor.com/ticket/1717)
if ( nodeName != 'br' ) {
this._.nextNode = currentNode;
}
}
closeRange = 1;
} else {
// If we have child nodes, let's check them.
if ( currentNode.getFirst() ) {
// If we don't have a range yet, let's start it.
if ( !range ) {
range = this.range.clone();
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
}
currentNode = currentNode.getFirst();
continue;
}
includeNode = 1;
}
} else if ( currentNode.type == CKEDITOR.NODE_TEXT ) {
// Ignore normal whitespaces (i.e. not including &nbsp; or
// other unicode whitespaces) before/after a block node.
if ( beginWhitespaceRegex.test( currentNode.getText() ) )
includeNode = 0;
}
// The current node is good to be part of the range and we are
// starting a new range, initialize it first.
if ( includeNode && !range ) {
range = this.range.clone();
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
}
// The last node has been found.
isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
// If we are in an element boundary, let's check if it is time
// to close the range, otherwise we include the parent within it.
if ( range && !closeRange ) {
while ( !currentNode.getNext( skipGuard ) && !isLast ) {
var parentNode = currentNode.getParent();
if ( parentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
closeRange = 1;
includeNode = 0;
isLast = isLast || ( parentNode.equals( lastNode ) );
// Make sure range includes bookmarks at the end of the block. (https://dev.ckeditor.com/ticket/7359)
range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END );
break;
}
currentNode = parentNode;
includeNode = 1;
isLast = ( currentNode.equals( lastNode ) );
continueFromSibling = 1;
}
}
// Now finally include the node.
if ( includeNode )
range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
currentNode = this._getNextSourceNode( currentNode, continueFromSibling, lastNode );
isLast = !currentNode;
// We have found a block boundary. Let's close the range and move out of the
// loop.
if ( isLast || ( closeRange && range ) )
break;
}
// Now, based on the processed range, look for (or create) the block to be returned.
if ( !block ) {
// If no range has been found, this is the end.
if ( !range ) {
this._.docEndMarker && this._.docEndMarker.remove();
this._.nextNode = null;
return null;
}
var startPath = new CKEDITOR.dom.elementPath( range.startContainer, range.root );
var startBlockLimit = startPath.blockLimit,
checkLimits = { div: 1, th: 1, td: 1 };
block = startPath.block;
if ( !block && startBlockLimit && !this.enforceRealBlocks && checkLimits[ startBlockLimit.getName() ] &&
range.checkStartOfBlock() && range.checkEndOfBlock() && !startBlockLimit.equals( range.root ) ) {
block = startBlockLimit;
} else if ( !block || ( this.enforceRealBlocks && block.is( listItemNames ) ) ) {
// Create the fixed block.
block = this.range.document.createElement( blockTag );
// Move the contents of the temporary range to the fixed block.
range.extractContents().appendTo( block );
block.trim();
// Insert the fixed block into the DOM.
range.insertNode( block );
removePreviousBr = removeLastBr = true;
} else if ( block.getName() != 'li' ) {
// If the range doesn't includes the entire contents of the
// block, we must split it, isolating the range in a dedicated
// block.
if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() ) {
// The resulting block will be a clone of the current one.
block = block.clone( false );
// Extract the range contents, moving it to the new block.
range.extractContents().appendTo( block );
block.trim();
// Split the block. At this point, the range will be in the
// right position for our intents.
var splitInfo = range.splitBlock();
removePreviousBr = !splitInfo.wasStartOfBlock;
removeLastBr = !splitInfo.wasEndOfBlock;
// Insert the new block into the DOM.
range.insertNode( block );
}
} else if ( !isLast ) {
// LIs are returned as is, with all their children (due to the
// nested lists). But, the next node is the node right after
// the current range, which could be an <li> child (nested
// lists) or the next sibling <li>.
this._.nextNode = ( block.equals( lastNode ) ? null : this._getNextSourceNode( range.getBoundaryNodes().endNode, 1, lastNode ) );
}
}
if ( removePreviousBr ) {
var previousSibling = block.getPrevious();
if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT ) {
if ( previousSibling.getName() == 'br' )
previousSibling.remove();
else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
previousSibling.getLast().remove();
}
}
if ( removeLastBr ) {
var lastChild = block.getLast();
if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' ) {
// Remove br filler on browser which do not need it.
if ( !CKEDITOR.env.needsBrFiller || lastChild.getPrevious( bookmarkGuard ) || lastChild.getNext( bookmarkGuard ) )
lastChild.remove();
}
}
// Get a reference for the next element. This is important because the
// above block can be removed or changed, so we can rely on it for the
// next interation.
if ( !this._.nextNode ) {
this._.nextNode = ( isLast || block.equals( lastNode ) || !lastNode ) ? null : this._getNextSourceNode( block, 1, lastNode );
}
return block;
},
/**
* Gets the next element to check or `null` when the `lastNode` or the
* {@link #range}'s {@link CKEDITOR.dom.range#root root} is reached. Bookmarks are skipped.
*
* @since 4.4.6
* @private
* @param {CKEDITOR.dom.node} node
* @param {Boolean} startFromSibling
* @param {CKEDITOR.dom.node} lastNode
* @returns {CKEDITOR.dom.node}
*/
_getNextSourceNode: function( node, startFromSibling, lastNode ) {
var rootNode = this.range.root,
next;
// Here we are checking in guard function whether current element
// reach lastNode(default behaviour) and root node to prevent against
// getting out of editor instance root DOM object.
// https://dev.ckeditor.com/ticket/12484
function guardFunction( node ) {
return !( node.equals( lastNode ) || node.equals( rootNode ) );
}
next = node.getNextSourceNode( startFromSibling, null, guardFunction );
while ( !bookmarkGuard( next ) ) {
next = next.getNextSourceNode( startFromSibling, null, guardFunction );
}
return next;
}
};
// @context CKEDITOR.dom.iterator
// @returns Collapsed range which will be reused when during furter processing.
function startIterator() {
var range = this.range.clone(),
// Indicate at least one of the range boundaries is inside a preformat block.
touchPre,
// (https://dev.ckeditor.com/ticket/12178)
// Remember if following situation takes place:
// * startAtInnerBoundary: <p>foo[</p>...
// * endAtInnerBoundary: ...<p>]bar</p>
// Because information about line break will be lost when shrinking range.
// Note that we test only if path block exist, because we must properly shrink
// range containing table and/or table cells.
// Note: When range is collapsed there's no way it can be shrinked.
// By checking if range is collapsed we also prevent https://dev.ckeditor.com/ticket/12308.
startPath = range.startPath(),
endPath = range.endPath(),
startAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, startPath.block ),
endAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, endPath.block, 1 );
// Shrink the range to exclude harmful "noises" (https://dev.ckeditor.com/ticket/4087, https://dev.ckeditor.com/ticket/4450, https://dev.ckeditor.com/ticket/5435).
range.shrink( CKEDITOR.SHRINK_ELEMENT, true );
if ( startAtInnerBoundary )
range.setStartAt( startPath.block, CKEDITOR.POSITION_BEFORE_END );
if ( endAtInnerBoundary )
range.setEndAt( endPath.block, CKEDITOR.POSITION_AFTER_START );
touchPre = range.endContainer.hasAscendant( 'pre', true ) || range.startContainer.hasAscendant( 'pre', true );
range.enlarge( this.forceBrBreak && !touchPre || !this.enlargeBr ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
if ( !range.collapsed ) {
var walker = new CKEDITOR.dom.walker( range.clone() ),
ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
// Avoid anchor inside bookmark inner text.
walker.evaluator = ignoreBookmarkTextEvaluator;
this._.nextNode = walker.next();
// TODO: It's better to have walker.reset() used here.
walker = new CKEDITOR.dom.walker( range.clone() );
walker.evaluator = ignoreBookmarkTextEvaluator;
var lastNode = walker.previous();
this._.lastNode = lastNode.getNextSourceNode( true, null, range.root );
// We may have an empty text node at the end of block due to [3770].
// If that node is the lastNode, it would cause our logic to leak to the
// next block.(https://dev.ckeditor.com/ticket/3887)
if ( this._.lastNode && this._.lastNode.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( this._.lastNode.getText() ) && this._.lastNode.getParent().isBlockBoundary() ) {
var testRange = this.range.clone();
testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END );
if ( testRange.checkEndOfBlock() ) {
var path = new CKEDITOR.dom.elementPath( testRange.endContainer, testRange.root ),
lastBlock = path.block || path.blockLimit;
this._.lastNode = lastBlock.getNextSourceNode( true );
}
}
// The end of document or range.root was reached, so we need a marker node inside.
if ( !this._.lastNode || !range.root.contains( this._.lastNode ) ) {
this._.lastNode = this._.docEndMarker = range.document.createText( '' );
this._.lastNode.insertAfter( lastNode );
}
// Let's reuse this variable.
range = null;
}
this._.started = 1;
return range;
}
// Does a nested editables lookup inside editablesContainer.
// If remainingEditables is set will lookup inside this array.
// @param {CKEDITOR.dom.element} editablesContainer
// @param {CKEDITOR.dom.element[]} [remainingEditables]
function getNestedEditableIn( editablesContainer, remainingEditables ) {
if ( remainingEditables == null )
remainingEditables = findNestedEditables( editablesContainer );
var editable;
while ( ( editable = remainingEditables.shift() ) ) {
if ( isIterableEditable( editable ) )
return { element: editable, remaining: remainingEditables };
}
return null;
}
// Checkes whether we can iterate over this editable.
function isIterableEditable( editable ) {
// Reject blockless editables.
return editable.getDtd().p;
}
// Finds nested editables within container. Does not return
// editables nested in another editable (twice).
function findNestedEditables( container ) {
var editables = [];
container.forEach( function( element ) {
if ( element.getAttribute( 'contenteditable' ) == 'true' ) {
editables.push( element );
return false; // Skip children.
}
}, CKEDITOR.NODE_ELEMENT, true );
return editables;
}
// Looks for a first nested editable after previousEditable (if passed) and creates
// nested iterator for it.
function startNestedEditableIterator( parentIterator, blockTag, editablesContainer, remainingEditables ) {
var editable = getNestedEditableIn( editablesContainer, remainingEditables );
if ( !editable )
return 0;
var filter = CKEDITOR.filter.instances[ editable.element.data( 'cke-filter' ) ];
// If current editable has a filter and this filter does not allow for block tag,
// search for next nested editable in remaining ones.
if ( filter && !filter.check( blockTag ) )
return startNestedEditableIterator( parentIterator, blockTag, editablesContainer, editable.remaining );
var range = new CKEDITOR.dom.range( editable.element );
range.selectNodeContents( editable.element );
var iterator = range.createIterator();
// This setting actually does not change anything in this case,
// because entire range contents is selected, so there're no <br>s to be included.
// But it seems right to copy it too.
iterator.enlargeBr = parentIterator.enlargeBr;
// Inherit configuration from parent iterator.
iterator.enforceRealBlocks = parentIterator.enforceRealBlocks;
// Set the activeFilter (which can be overriden when this iteator will start nested iterator)
// and the default filter, which will make it possible to reset to
// current iterator's activeFilter after leaving nested editable.
iterator.activeFilter = iterator.filter = filter;
parentIterator._.nestedEditable = {
element: editable.element,
container: editablesContainer,
remaining: editable.remaining,
iterator: iterator
};
return 1;
}
// Checks whether range starts or ends at inner block boundary.
// See usage comments to learn more.
function rangeAtInnerBlockBoundary( range, block, checkEnd ) {
if ( !block )
return false;
var testRange = range.clone();
testRange.collapse( !checkEnd );
return testRange.checkBoundaryOfElement( block, checkEnd ? CKEDITOR.START : CKEDITOR.END );
}
/**
* Creates a {@link CKEDITOR.dom.iterator} instance for this range.
*
* @member CKEDITOR.dom.range
* @returns {CKEDITOR.dom.iterator}
*/
CKEDITOR.dom.range.prototype.createIterator = function() {
return new iterator( this );
};
} )();

View file

@ -1,898 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.node} class which is the base
* class for classes that represent DOM nodes.
*/
/**
* Base class for classes representing DOM nodes. This constructor may return
* an instance of a class that inherits from this class, like
* {@link CKEDITOR.dom.element} or {@link CKEDITOR.dom.text}.
*
* @class
* @extends CKEDITOR.dom.domObject
* @constructor Creates a node class instance.
* @param {Object} domNode A native DOM node.
* @see CKEDITOR.dom.element
* @see CKEDITOR.dom.text
*/
CKEDITOR.dom.node = function( domNode ) {
if ( domNode ) {
var type =
domNode.nodeType == CKEDITOR.NODE_DOCUMENT ? 'document' :
domNode.nodeType == CKEDITOR.NODE_ELEMENT ? 'element' :
domNode.nodeType == CKEDITOR.NODE_TEXT ? 'text' :
domNode.nodeType == CKEDITOR.NODE_COMMENT ? 'comment' :
domNode.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 'documentFragment' :
'domObject'; // Call the base constructor otherwise.
return new CKEDITOR.dom[ type ]( domNode );
}
return this;
};
CKEDITOR.dom.node.prototype = new CKEDITOR.dom.domObject();
/**
* Element node type.
*
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.NODE_ELEMENT = 1;
/**
* Document node type.
*
* @readonly
* @property {Number} [=9]
* @member CKEDITOR
*/
CKEDITOR.NODE_DOCUMENT = 9;
/**
* Text node type.
*
* @readonly
* @property {Number} [=3]
* @member CKEDITOR
*/
CKEDITOR.NODE_TEXT = 3;
/**
* Comment node type.
*
* @readonly
* @property {Number} [=8]
* @member CKEDITOR
*/
CKEDITOR.NODE_COMMENT = 8;
/**
* Document fragment node type.
*
* @readonly
* @property {Number} [=11]
* @member CKEDITOR
*/
CKEDITOR.NODE_DOCUMENT_FRAGMENT = 11;
/**
* Indicates that positions of both nodes are identical (this is the same node). See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=0]
* @member CKEDITOR
*/
CKEDITOR.POSITION_IDENTICAL = 0;
/**
* Indicates that nodes are in different (detached) trees. See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.POSITION_DISCONNECTED = 1;
/**
* Indicates that the context node follows the other node. See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.POSITION_FOLLOWING = 2;
/**
* Indicates that the context node precedes the other node. See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=4]
* @member CKEDITOR
*/
CKEDITOR.POSITION_PRECEDING = 4;
/**
* Indicates that the context node is a descendant of the other node. See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=8]
* @member CKEDITOR
*/
CKEDITOR.POSITION_IS_CONTAINED = 8;
/**
* Indicates that the context node contains the other node. See {@link CKEDITOR.dom.node#getPosition}.
*
* @readonly
* @property {Number} [=16]
* @member CKEDITOR
*/
CKEDITOR.POSITION_CONTAINS = 16;
CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, {
/**
* Makes this node a child of another element.
*
* var p = new CKEDITOR.dom.element( 'p' );
* var strong = new CKEDITOR.dom.element( 'strong' );
* strong.appendTo( p );
*
* // Result: '<p><strong></strong></p>'.
*
* @param {CKEDITOR.dom.element} element The target element to which this node will be appended.
* @returns {CKEDITOR.dom.element} The target element.
*/
appendTo: function( element, toStart ) {
element.append( this, toStart );
return element;
},
/**
* Clones this node.
*
* **Note**: Values set by {#setCustomData} will not be available in the clone.
*
* @param {Boolean} [includeChildren=false] If `true` then all node's
* children will be cloned recursively.
* @param {Boolean} [cloneId=false] Whether ID attributes should be cloned, too.
* @returns {CKEDITOR.dom.node} Clone of this node.
*/
clone: function( includeChildren, cloneId ) {
var $clone = this.$.cloneNode( includeChildren );
// The "id" attribute should never be cloned to avoid duplication.
removeIds( $clone );
var node = new CKEDITOR.dom.node( $clone );
// On IE8 we need to fixed HTML5 node name, see details below.
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 &&
( this.type == CKEDITOR.NODE_ELEMENT || this.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) ) {
renameNodes( node );
}
return node;
function removeIds( node ) {
// Reset data-cke-expando only when has been cloned (IE and only for some types of objects).
if ( node[ 'data-cke-expando' ] )
node[ 'data-cke-expando' ] = false;
if ( node.nodeType != CKEDITOR.NODE_ELEMENT && node.nodeType != CKEDITOR.NODE_DOCUMENT_FRAGMENT )
return;
if ( !cloneId && node.nodeType == CKEDITOR.NODE_ELEMENT )
node.removeAttribute( 'id', false );
if ( includeChildren ) {
var childs = node.childNodes;
for ( var i = 0; i < childs.length; i++ )
removeIds( childs[ i ] );
}
}
// IE8 rename HTML5 nodes by adding `:` at the begging of the tag name when the node is cloned,
// so `<figure>` will be `<:figure>` after 'cloneNode'. We need to fix it (https://dev.ckeditor.com/ticket/13101).
function renameNodes( node ) {
if ( node.type != CKEDITOR.NODE_ELEMENT && node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT )
return;
if ( node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT ) {
var name = node.getName();
if ( name[ 0 ] == ':' ) {
node.renameNode( name.substring( 1 ) );
}
}
if ( includeChildren ) {
for ( var i = 0; i < node.getChildCount(); i++ )
renameNodes( node.getChild( i ) );
}
}
},
/**
* Checks if the node is preceded by any sibling.
*
* @returns {Boolean}
*/
hasPrevious: function() {
return !!this.$.previousSibling;
},
/**
* Checks if the node is succeeded by any sibling.
*
* @returns {Boolean}
*/
hasNext: function() {
return !!this.$.nextSibling;
},
/**
* Inserts this element after a node.
*
* var em = new CKEDITOR.dom.element( 'em' );
* var strong = new CKEDITOR.dom.element( 'strong' );
* strong.insertAfter( em );
*
* // Result: '<em></em><strong></strong>'
*
* @param {CKEDITOR.dom.node} node The node that will precede this element.
* @returns {CKEDITOR.dom.node} The node preceding this one after insertion.
*/
insertAfter: function( node ) {
node.$.parentNode.insertBefore( this.$, node.$.nextSibling );
return node;
},
/**
* Inserts this element before a node.
*
* var em = new CKEDITOR.dom.element( 'em' );
* var strong = new CKEDITOR.dom.element( 'strong' );
* strong.insertBefore( em );
*
* // result: '<strong></strong><em></em>'
*
* @param {CKEDITOR.dom.node} node The node that will succeed this element.
* @returns {CKEDITOR.dom.node} The node being inserted.
*/
insertBefore: function( node ) {
node.$.parentNode.insertBefore( this.$, node.$ );
return node;
},
/**
* Inserts a node before this node.
*
* var em = new CKEDITOR.dom.element( 'em' );
* var strong = new CKEDITOR.dom.element( 'strong' );
* strong.insertBeforeMe( em );
*
* // result: '<em></em><strong></strong>'
*
* @param {CKEDITOR.dom.node} node The node that will preceed this element.
* @returns {CKEDITOR.dom.node} The node being inserted.
*/
insertBeforeMe: function( node ) {
this.$.parentNode.insertBefore( node.$, this.$ );
return node;
},
/**
* Retrieves a uniquely identifiable tree address for this node.
* The tree address returned is an array of integers, with each integer
* indicating a child index of a DOM node, starting from
* `document.documentElement`.
*
* For example, assuming `<body>` is the second child
* of `<html>` (`<head>` being the first),
* and we would like to address the third child under the
* fourth child of `<body>`, the tree address returned would be:
* `[1, 3, 2]`.
*
* The tree address cannot be used for finding back the DOM tree node once
* the DOM tree structure has been modified.
*
* @param {Boolean} [normalized=false] See {@link #getIndex}.
* @returns {Array} The address.
*/
getAddress: function( normalized ) {
var address = [];
var $documentElement = this.getDocument().$.documentElement;
var node = this;
while ( node && node != $documentElement ) {
var parentNode = node.getParent();
if ( parentNode ) {
// Get the node index. For performance, call getIndex
// directly, instead of creating a new node object.
address.unshift( this.getIndex.call( node, normalized ) );
}
node = parentNode;
}
return address;
},
/**
* Gets the document containing this element.
*
* var element = CKEDITOR.document.getById( 'example' );
* alert( element.getDocument().equals( CKEDITOR.document ) ); // true
*
* @returns {CKEDITOR.dom.document} The document.
*/
getDocument: function() {
return new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument );
},
/**
* Gets the index of a node in an array of its `parent.childNodes`.
* Returns `-1` if a node does not have a parent or when the `normalized` argument is set to `true`
* and the text node is empty and will be removed during the normalization.
*
* Let us assume having the following `childNodes` array:
*
* [ emptyText, element1, text, text, element2, emptyText2 ]
*
* emptyText.getIndex() // 0
* emptyText.getIndex( true ) // -1
* element1.getIndex(); // 1
* element1.getIndex( true ); // 0
* element2.getIndex(); // 4
* element2.getIndex( true ); // 2
* emptyText2.getIndex(); // 5
* emptyText2.getIndex( true ); // -1
*
* @param {Boolean} normalized When `true`, adjacent text nodes are merged and empty text nodes are removed.
* @returns {Number} Index of a node or `-1` if a node does not have a parent or is removed during the normalization.
*/
getIndex: function( normalized ) {
// Attention: getAddress depends on this.$
// getIndex is called on a plain object: { $ : node }
var current = this,
index = -1,
isNormalizing;
if ( !this.getParent() )
return -1;
// The idea is - all empty text nodes will be virtually merged into their adjacent text nodes.
// If an empty text node does not have an adjacent non-empty text node we can return -1 straight away,
// because it and all its sibling text nodes will be merged into an empty text node and then totally ignored.
if ( normalized && current.type == CKEDITOR.NODE_TEXT && current.isEmpty() ) {
var adjacent = getAdjacentNonEmptyTextNode( current ) || getAdjacentNonEmptyTextNode( current, true );
if ( !adjacent )
return -1;
}
do {
// Bypass blank node and adjacent text nodes.
if ( normalized && !current.equals( this ) && current.type == CKEDITOR.NODE_TEXT && ( isNormalizing || current.isEmpty() ) ) {
continue;
}
index++;
isNormalizing = current.type == CKEDITOR.NODE_TEXT;
}
while ( ( current = current.getPrevious() ) );
return index;
function getAdjacentNonEmptyTextNode( node, lookForward ) {
var sibling = lookForward ? node.getNext() : node.getPrevious();
if ( !sibling || sibling.type != CKEDITOR.NODE_TEXT ) {
return null;
}
// If found a non-empty text node, then return it.
// If not, then continue search.
return sibling.isEmpty() ? getAdjacentNonEmptyTextNode( sibling, lookForward ) : sibling;
}
},
/**
* @todo
*/
getNextSourceNode: function( startFromSibling, nodeType, guard ) {
// If "guard" is a node, transform it in a function.
if ( guard && !guard.call ) {
var guardNode = guard;
guard = function( node ) {
return !node.equals( guardNode );
};
}
var node = ( !startFromSibling && this.getFirst && this.getFirst() ),
parent;
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
// send the 'moving out' signal even we don't actually dive into.
if ( !node ) {
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
return null;
node = this.getNext();
}
while ( !node && ( parent = ( parent || this ).getParent() ) ) {
// The guard check sends the "true" paramenter to indicate that
// we are moving "out" of the element.
if ( guard && guard( parent, true ) === false )
return null;
node = parent.getNext();
}
if ( !node )
return null;
if ( guard && guard( node ) === false )
return null;
if ( nodeType && nodeType != node.type )
return node.getNextSourceNode( false, nodeType, guard );
return node;
},
/**
* @todo
*/
getPreviousSourceNode: function( startFromSibling, nodeType, guard ) {
if ( guard && !guard.call ) {
var guardNode = guard;
guard = function( node ) {
return !node.equals( guardNode );
};
}
var node = ( !startFromSibling && this.getLast && this.getLast() ),
parent;
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
// send the 'moving out' signal even we don't actually dive into.
if ( !node ) {
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
return null;
node = this.getPrevious();
}
while ( !node && ( parent = ( parent || this ).getParent() ) ) {
// The guard check sends the "true" paramenter to indicate that
// we are moving "out" of the element.
if ( guard && guard( parent, true ) === false )
return null;
node = parent.getPrevious();
}
if ( !node )
return null;
if ( guard && guard( node ) === false )
return null;
if ( nodeType && node.type != nodeType )
return node.getPreviousSourceNode( false, nodeType, guard );
return node;
},
/**
* Gets the node that preceeds this element in its parent's child list.
*
* var element = CKEDITOR.dom.element.createFromHtml( '<div><i>prev</i><b>Example</b></div>' );
* var first = element.getLast().getPrev();
* alert( first.getName() ); // 'i'
*
* @param {Function} [evaluator] Filtering the result node.
* @returns {CKEDITOR.dom.node} The previous node or null if not available.
*/
getPrevious: function( evaluator ) {
var previous = this.$,
retval;
do {
previous = previous.previousSibling;
// Avoid returning the doc type node.
// http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-412266927
retval = previous && previous.nodeType != 10 && new CKEDITOR.dom.node( previous );
}
while ( retval && evaluator && !evaluator( retval ) );
return retval;
},
/**
* Gets the node that follows this element in its parent's child list.
*
* var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b><i>next</i></div>' );
* var last = element.getFirst().getNext();
* alert( last.getName() ); // 'i'
*
* @param {Function} [evaluator] Filtering the result node.
* @returns {CKEDITOR.dom.node} The next node or null if not available.
*/
getNext: function( evaluator ) {
var next = this.$,
retval;
do {
next = next.nextSibling;
retval = next && new CKEDITOR.dom.node( next );
}
while ( retval && evaluator && !evaluator( retval ) );
return retval;
},
/**
* Gets the parent element for this node.
*
* var node = editor.document.getBody().getFirst();
* var parent = node.getParent();
* alert( parent.getName() ); // 'body'
*
* @param {Boolean} [allowFragmentParent=false] Consider also parent node that is of
* fragment type {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
* @returns {CKEDITOR.dom.element} The parent element.
*/
getParent: function( allowFragmentParent ) {
var parent = this.$.parentNode;
return ( parent && ( parent.nodeType == CKEDITOR.NODE_ELEMENT || allowFragmentParent && parent.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) ) ? new CKEDITOR.dom.node( parent ) : null;
},
/**
* Returns an array containing node parents and the node itself. By default nodes are in _descending_ order.
*
* // Assuming that body has paragraph as the first child.
* var node = editor.document.getBody().getFirst();
* var parents = node.getParents();
* alert( parents[ 0 ].getName() + ',' + parents[ 2 ].getName() ); // 'html,p'
*
* @param {Boolean} [closerFirst=false] Determines the order of returned nodes.
* @returns {Array} Returns an array of {@link CKEDITOR.dom.node}.
*/
getParents: function( closerFirst ) {
var node = this;
var parents = [];
do {
parents[ closerFirst ? 'push' : 'unshift' ]( node );
}
while ( ( node = node.getParent() ) );
return parents;
},
/**
* @todo
*/
getCommonAncestor: function( node ) {
if ( node.equals( this ) )
return this;
if ( node.contains && node.contains( this ) )
return node;
var start = this.contains ? this : this.getParent();
do {
if ( start.contains( node ) ) return start;
}
while ( ( start = start.getParent() ) );
return null;
},
/**
* Determines the position relation between this node and the given {@link CKEDITOR.dom.node} in the document.
* This node can be preceding ({@link CKEDITOR#POSITION_PRECEDING}) or following ({@link CKEDITOR#POSITION_FOLLOWING})
* the given node. This node can also contain ({@link CKEDITOR#POSITION_CONTAINS}) or be contained by
* ({@link CKEDITOR#POSITION_IS_CONTAINED}) the given node. The function returns a bitmask of constants
* listed above or {@link CKEDITOR#POSITION_IDENTICAL} if the given node is the same as this node.
*
* @param {CKEDITOR.dom.node} otherNode A node to check relation with.
* @returns {Number} Position relation between this node and given node.
*/
getPosition: function( otherNode ) {
var $ = this.$;
var $other = otherNode.$;
if ( $.compareDocumentPosition )
return $.compareDocumentPosition( $other );
// IE and Safari have no support for compareDocumentPosition.
if ( $ == $other )
return CKEDITOR.POSITION_IDENTICAL;
// Only element nodes support contains and sourceIndex.
if ( this.type == CKEDITOR.NODE_ELEMENT && otherNode.type == CKEDITOR.NODE_ELEMENT ) {
if ( $.contains ) {
if ( $.contains( $other ) )
return CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING;
if ( $other.contains( $ ) )
return CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
}
if ( 'sourceIndex' in $ )
return ( $.sourceIndex < 0 || $other.sourceIndex < 0 ) ? CKEDITOR.POSITION_DISCONNECTED : ( $.sourceIndex < $other.sourceIndex ) ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
}
// For nodes that don't support compareDocumentPosition, contains
// or sourceIndex, their "address" is compared.
var addressOfThis = this.getAddress(),
addressOfOther = otherNode.getAddress(),
minLevel = Math.min( addressOfThis.length, addressOfOther.length );
// Determinate preceding/following relationship.
for ( var i = 0; i < minLevel; i++ ) {
if ( addressOfThis[ i ] != addressOfOther[ i ] ) {
return addressOfThis[ i ] < addressOfOther[ i ] ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
}
}
// Determinate contains/contained relationship.
return ( addressOfThis.length < addressOfOther.length ) ? CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
},
/**
* Gets the closest ancestor node of this node, specified by its name or using an evaluator function.
*
* // Suppose we have the following HTML structure:
* // <div id="outer"><div id="inner"><p><b>Some text</b></p></div></div>
* // If node == <b>
* ascendant = node.getAscendant( 'div' ); // ascendant == <div id="inner">
* ascendant = node.getAscendant( 'b' ); // ascendant == null
* ascendant = node.getAscendant( 'b', true ); // ascendant == <b>
* ascendant = node.getAscendant( { div:1, p:1 } ); // Searches for the first 'div' or 'p': ascendant == <div id="inner">
*
* // Using custom evaluator:
* ascendant = node.getAscendant( function( el ) {
* return el.getId() == 'inner';
* } );
* // ascendant == <div id="inner">
*
* @since 3.6.1
* @param {String/Function/Object} query The name of the ancestor node to search or
* an object with the node names to search for or an evaluator function.
* @param {Boolean} [includeSelf] Whether to include the current
* node in the search.
* @returns {CKEDITOR.dom.node} The located ancestor node or `null` if not found.
*/
getAscendant: function( query, includeSelf ) {
var $ = this.$,
evaluator,
isCustomEvaluator;
if ( !includeSelf ) {
$ = $.parentNode;
}
// Custom checker provided in an argument.
if ( typeof query == 'function' ) {
isCustomEvaluator = true;
evaluator = query;
} else {
// Predefined tag name checker.
isCustomEvaluator = false;
evaluator = function( $ ) {
var name = ( typeof $.nodeName == 'string' ? $.nodeName.toLowerCase() : '' );
return ( typeof query == 'string' ? name == query : name in query );
};
}
while ( $ ) {
// For user provided checker we use CKEDITOR.dom.node.
if ( evaluator( isCustomEvaluator ? new CKEDITOR.dom.node( $ ) : $ ) ) {
return new CKEDITOR.dom.node( $ );
}
try {
$ = $.parentNode;
} catch ( e ) {
$ = null;
}
}
return null;
},
/**
* @todo
*/
hasAscendant: function( name, includeSelf ) {
var $ = this.$;
if ( !includeSelf )
$ = $.parentNode;
while ( $ ) {
if ( $.nodeName && $.nodeName.toLowerCase() == name )
return true;
$ = $.parentNode;
}
return false;
},
/**
* @todo
*/
move: function( target, toStart ) {
target.append( this.remove(), toStart );
},
/**
* Removes this node from the document DOM.
*
* var element = CKEDITOR.document.getById( 'MyElement' );
* element.remove();
*
* @param {Boolean} [preserveChildren=false] Indicates that the children
* elements must remain in the document, removing only the outer tags.
*/
remove: function( preserveChildren ) {
var $ = this.$;
var parent = $.parentNode;
if ( parent ) {
if ( preserveChildren ) {
// Move all children before the node.
for ( var child;
( child = $.firstChild ); ) {
parent.insertBefore( $.removeChild( child ), $ );
}
}
parent.removeChild( $ );
}
return this;
},
/**
* @todo
*/
replace: function( nodeToReplace ) {
this.insertBefore( nodeToReplace );
nodeToReplace.remove();
},
/**
* @todo
*/
trim: function() {
this.ltrim();
this.rtrim();
},
/**
* @todo
*/
ltrim: function() {
var child;
while ( this.getFirst && ( child = this.getFirst() ) ) {
if ( child.type == CKEDITOR.NODE_TEXT ) {
var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
originalLength = child.getLength();
if ( !trimmed ) {
child.remove();
continue;
} else if ( trimmed.length < originalLength ) {
child.split( originalLength - trimmed.length );
// IE BUG: child.remove() may raise JavaScript errors here. (https://dev.ckeditor.com/ticket/81)
this.$.removeChild( this.$.firstChild );
}
}
break;
}
},
/**
* @todo
*/
rtrim: function() {
var child;
while ( this.getLast && ( child = this.getLast() ) ) {
if ( child.type == CKEDITOR.NODE_TEXT ) {
var trimmed = CKEDITOR.tools.rtrim( child.getText() ),
originalLength = child.getLength();
if ( !trimmed ) {
child.remove();
continue;
} else if ( trimmed.length < originalLength ) {
child.split( trimmed.length );
// IE BUG: child.getNext().remove() may raise JavaScript errors here.
// (https://dev.ckeditor.com/ticket/81)
this.$.lastChild.parentNode.removeChild( this.$.lastChild );
}
}
break;
}
if ( CKEDITOR.env.needsBrFiller ) {
child = this.$.lastChild;
if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' ) {
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (https://dev.ckeditor.com/ticket/324).
child.parentNode.removeChild( child );
}
}
},
/**
* Checks if this node is read-only (should not be changed).
*
* // For the following HTML:
* // <b>foo</b><div contenteditable="false"><i>bar</i></div>
*
* elB.isReadOnly(); // -> false
* foo.isReadOnly(); // -> false
* elDiv.isReadOnly(); // -> true
* elI.isReadOnly(); // -> true
*
* This method works in two modes depending on browser support for the `element.isContentEditable` property and
* the value of the `checkOnlyAttributes` parameter. The `element.isContentEditable` check is faster, but it is known
* to malfunction in hidden or detached nodes. Additionally, when processing some detached DOM tree you may want to imitate
* that this happens inside an editable container (like it would happen inside the {@link CKEDITOR.editable}). To do so,
* you can temporarily attach this tree to an element with the `data-cke-editable` attribute and use the
* `checkOnlyAttributes` mode.
*
* @since 3.5.0
* @param {Boolean} [checkOnlyAttributes=false] If `true`, only attributes will be checked, native methods will not
* be used. This parameter needs to be `true` to check hidden or detached elements. Introduced in 4.5.0.
* @returns {Boolean}
*/
isReadOnly: function( checkOnlyAttributes ) {
var element = this;
if ( this.type != CKEDITOR.NODE_ELEMENT )
element = this.getParent();
// Prevent Edge crash (https://dev.ckeditor.com/ticket/13609, https://dev.ckeditor.com/ticket/13919).
if ( CKEDITOR.env.edge && element && element.is( 'textarea', 'input' ) ) {
checkOnlyAttributes = true;
}
if ( !checkOnlyAttributes && element && typeof element.$.isContentEditable != 'undefined' ) {
return !( element.$.isContentEditable || element.data( 'cke-editable' ) );
}
else {
// Degrade for old browsers which don't support "isContentEditable", e.g. FF3
while ( element ) {
if ( element.data( 'cke-editable' ) ) {
return false;
} else if ( element.hasAttribute( 'contenteditable' ) ) {
return element.getAttribute( 'contenteditable' ) == 'false';
}
element = element.getParent();
}
// Reached the root of DOM tree, no editable found.
return true;
}
}
} );

View file

@ -1,54 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* Represents a list of {@link CKEDITOR.dom.node} objects.
* It is a wrapper for a native nodes list.
*
* var nodeList = CKEDITOR.document.getBody().getChildren();
* alert( nodeList.count() ); // number [0;N]
*
* @class
* @constructor Creates a document class instance.
* @param {Object} nativeList
*/
CKEDITOR.dom.nodeList = function( nativeList ) {
this.$ = nativeList;
};
CKEDITOR.dom.nodeList.prototype = {
/**
* Gets the count of nodes in this list.
*
* @returns {Number}
*/
count: function() {
return this.$.length;
},
/**
* Gets the node from the list.
*
* @returns {CKEDITOR.dom.node}
*/
getItem: function( index ) {
if ( index < 0 || index >= this.$.length )
return null;
var $node = this.$[ index ];
return $node ? new CKEDITOR.dom.node( $node ) : null;
},
/**
* Returns a node list as an array.
*
* @returns {CKEDITOR.dom.node[]}
*/
toArray: function() {
return CKEDITOR.tools.array.map( this.$, function( nativeEl ) {
return new CKEDITOR.dom.node( nativeEl );
} );
}
};

File diff suppressed because it is too large Load diff

View file

@ -1,199 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
( function() {
/**
* Represents a list os CKEDITOR.dom.range objects, which can be easily
* iterated sequentially.
*
* @class
* @extends Array
* @constructor Creates a rangeList class instance.
* @param {CKEDITOR.dom.range/CKEDITOR.dom.range[]} [ranges] The ranges contained on this list.
* Note that, if an array of ranges is specified, the range sequence
* should match its DOM order. This class will not help to sort them.
*/
CKEDITOR.dom.rangeList = function( ranges ) {
if ( ranges instanceof CKEDITOR.dom.rangeList )
return ranges;
if ( !ranges )
ranges = [];
else if ( ranges instanceof CKEDITOR.dom.range )
ranges = [ ranges ];
return CKEDITOR.tools.extend( ranges, mixins );
};
var mixins = {
/**
* Creates an instance of the rangeList iterator, it should be used
* only when the ranges processing could be DOM intrusive, which
* means it may pollute and break other ranges in this list.
* Otherwise, it's enough to just iterate over this array in a for loop.
*
* @returns {CKEDITOR.dom.rangeListIterator}
*/
createIterator: function() {
var rangeList = this,
bookmark = CKEDITOR.dom.walker.bookmark(),
bookmarks = [],
current;
return {
/**
* Retrieves the next range in the list.
*
* @member CKEDITOR.dom.rangeListIterator
* @param {Boolean} [mergeConsequent=false] Whether join two adjacent
* ranges into single, e.g. consequent table cells.
*/
getNextRange: function( mergeConsequent ) {
current = current === undefined ? 0 : current + 1;
var range = rangeList[ current ];
// Multiple ranges might be mangled by each other.
if ( range && rangeList.length > 1 ) {
// Bookmarking all other ranges on the first iteration,
// the range correctness after it doesn't matter since we'll
// restore them before the next iteration.
if ( !current ) {
// Make sure bookmark correctness by reverse processing.
for ( var i = rangeList.length - 1; i >= 0; i-- )
bookmarks.unshift( rangeList[ i ].createBookmark( true ) );
}
if ( mergeConsequent ) {
// Figure out how many ranges should be merged.
var mergeCount = 0;
while ( rangeList[ current + mergeCount + 1 ] ) {
var doc = range.document,
found = 0,
left = doc.getById( bookmarks[ mergeCount ].endNode ),
right = doc.getById( bookmarks[ mergeCount + 1 ].startNode ),
next;
// Check subsequent range.
while ( 1 ) {
next = left.getNextSourceNode( false );
if ( !right.equals( next ) ) {
// This could be yet another bookmark or
// walking across block boundaries.
if ( bookmark( next ) || ( next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() ) ) {
left = next;
continue;
}
} else {
found = 1;
}
break;
}
if ( !found )
break;
mergeCount++;
}
}
range.moveToBookmark( bookmarks.shift() );
// Merge ranges finally after moving to bookmarks.
while ( mergeCount-- ) {
next = rangeList[ ++current ];
next.moveToBookmark( bookmarks.shift() );
range.setEnd( next.endContainer, next.endOffset );
}
}
return range;
}
};
},
/**
* Create bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark}.
*
* @param {Boolean} [serializable=false] See {@link CKEDITOR.dom.range#createBookmark}.
* @returns {Array} Array of bookmarks.
*/
createBookmarks: function( serializable ) {
var retval = [],
bookmark;
for ( var i = 0; i < this.length; i++ ) {
retval.push( bookmark = this[ i ].createBookmark( serializable, true ) );
// Updating the container & offset values for ranges
// that have been touched.
for ( var j = i + 1; j < this.length; j++ ) {
this[ j ] = updateDirtyRange( bookmark, this[ j ] );
this[ j ] = updateDirtyRange( bookmark, this[ j ], true );
}
}
return retval;
},
/**
* Create "unobtrusive" bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark2}.
*
* @param {Boolean} [normalized=false] See {@link CKEDITOR.dom.range#createBookmark2}.
* @returns {Array} Array of bookmarks.
*/
createBookmarks2: function( normalized ) {
var bookmarks = [];
for ( var i = 0; i < this.length; i++ )
bookmarks.push( this[ i ].createBookmark2( normalized ) );
return bookmarks;
},
/**
* Move each range in the list to the position specified by a list of bookmarks.
*
* @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.
*/
moveToBookmarks: function( bookmarks ) {
for ( var i = 0; i < this.length; i++ )
this[ i ].moveToBookmark( bookmarks[ i ] );
}
};
// Update the specified range which has been mangled by previous insertion of
// range bookmark nodes.(https://dev.ckeditor.com/ticket/3256)
function updateDirtyRange( bookmark, dirtyRange, checkEnd ) {
var serializable = bookmark.serializable,
container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],
offset = checkEnd ? 'endOffset' : 'startOffset';
var bookmarkStart = serializable ? dirtyRange.document.getById( bookmark.startNode ) : bookmark.startNode;
var bookmarkEnd = serializable ? dirtyRange.document.getById( bookmark.endNode ) : bookmark.endNode;
if ( container.equals( bookmarkStart.getPrevious() ) ) {
dirtyRange.startOffset = dirtyRange.startOffset - container.getLength() - bookmarkEnd.getPrevious().getLength();
container = bookmarkEnd.getNext();
} else if ( container.equals( bookmarkEnd.getPrevious() ) ) {
dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();
container = bookmarkEnd.getNext();
}
container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;
container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;
// Update and return this range.
dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;
return dirtyRange;
}
} )();
/**
* (Virtual Class) Do not call this constructor. This class is not really part
* of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.
*
* @class CKEDITOR.dom.rangeListIterator
*/

View file

@ -1,74 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.dom.rect} class
* that contains the definition of the element's DOM rectangle. This file is for
* documentation purposes only.
*/
/**
* Virtual class that illustrates the {@link CKEDITOR.dom.element} DOM rectangle (dimensions and coordinates
* of the area that the element occupies on the page).
*
* @class CKEDITOR.dom.rect
* @abstract
*/
/**
* Element's offset from the viewport's top edge.
*
* @property {Number} top
*/
/**
* Element's bottom edge offset from the viewport's top edge.
*
* This value is the same as the {@link CKEDITOR.dom.rect#top} value plus the {@link CKEDITOR.dom.rect#height} value.
*
* @property {Number} bottom
*/
/**
* Element's offset from the viewport's left edge.
*
* @property {Number} left
*/
/**
* Element's right edge offset from the viewport's left edge.
*
* This value is the same as the {@link CKEDITOR.dom.rect#left} value plus the {@link CKEDITOR.dom.rect#width} value.
*
* @property {Number} right
*/
/**
* Element's height.
*
* @property {Number} height
*/
/**
* Element's width.
*
* @property {Number} width
*/
/**
* Element's offset from the viewport's left edge.
*
* This property is not available in Internet Explorer or Edge.
*
* @property {Number} x
*/
/**
* Element's offset from the viewport's top edge.
*
* This property is not available in Internet Explorer or Edge.
*
* @property {Number} y
*/

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.text} class, which represents
* a DOM text node.
*/
/**
* Represents a DOM text node.
*
* var nativeNode = document.createTextNode( 'Example' );
* var text = new CKEDITOR.dom.text( nativeNode );
*
* var text = new CKEDITOR.dom.text( 'Example' );
*
* @class
* @extends CKEDITOR.dom.node
* @constructor Creates a text class instance.
* @param {Object/String} text A native DOM text node or a string containing
* the text to use to create a new text node.
* @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
* the node in case of new node creation. Defaults to the current document.
*/
CKEDITOR.dom.text = function( text, ownerDocument ) {
if ( typeof text == 'string' )
text = ( ownerDocument ? ownerDocument.$ : document ).createTextNode( text );
// Theoretically, we should call the base constructor here
// (not CKEDITOR.dom.node though). But, IE doesn't support expando
// properties on text node, so the features provided by domObject will not
// work for text nodes (which is not a big issue for us).
//
// CKEDITOR.dom.domObject.call( this, element );
this.$ = text;
};
CKEDITOR.dom.text.prototype = new CKEDITOR.dom.node();
CKEDITOR.tools.extend( CKEDITOR.dom.text.prototype, {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_TEXT]
*/
type: CKEDITOR.NODE_TEXT,
/**
* Gets length of node's value.
*
* @returns {Number}
*/
getLength: function() {
return this.$.nodeValue.length;
},
/**
* Gets node's value.
*
* @returns {String}
*/
getText: function() {
return this.$.nodeValue;
},
/**
* Sets node's value.
*
* @param {String} text
*/
setText: function( text ) {
this.$.nodeValue = text;
},
/**
* Checks whether a node is empty or is a
* {@link CKEDITOR.dom.selection#FILLING_CHAR_SEQUENCE FILLING_CHAR_SEQUENCE} string.
*
* @since 4.13.0
* @param {Boolean} [ignoreWhiteSpace] Specifies whether the content that consists of only whitespace characters
* should be treated as an empty one.
* @returns {Boolean}
*/
isEmpty: function( ignoreWhiteSpace ) {
var text = this.getText();
if ( ignoreWhiteSpace ) {
text = CKEDITOR.tools.trim( text );
}
return !text || text === CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE;
},
/**
* Breaks this text node into two nodes at the specified offset,
* keeping both in the tree as siblings. This node then only contains
* all the content up to the offset point. A new text node, which is
* inserted as the next sibling of this node, contains all the content
* at and after the offset point. When the offset is equal to the
* length of this node, the new node has no data.
*
* @param {Number} The position at which to split, starting from zero.
* @returns {CKEDITOR.dom.text} The new text node.
*/
split: function( offset ) {
// Saved the children count and text length beforehand.
var parent = this.$.parentNode,
count = parent.childNodes.length,
length = this.getLength();
var doc = this.getDocument();
var retval = new CKEDITOR.dom.text( this.$.splitText( offset ), doc );
if ( parent.childNodes.length == count ) {
// If the offset is after the last char, IE creates the text node
// on split, but don't include it into the DOM. So, we have to do
// that manually here.
if ( offset >= length ) {
retval = doc.createText( '' );
retval.insertAfter( this );
} else {
// IE BUG: IE8+ does not update the childNodes array in DOM after splitText(),
// we need to make some DOM changes to make it update. (https://dev.ckeditor.com/ticket/3436)
var workaround = doc.createText( '' );
workaround.insertAfter( retval );
workaround.remove();
}
}
return retval;
},
/**
* Extracts characters from indexA up to but not including `indexB`.
*
* @param {Number} indexA An integer between `0` and one less than the
* length of the text.
* @param {Number} [indexB] An integer between `0` and the length of the
* string. If omitted, extracts characters to the end of the text.
*/
substring: function( indexA, indexB ) {
// We need the following check due to a Firefox bug
// https://bugzilla.mozilla.org/show_bug.cgi?id=458886
if ( typeof indexB != 'number' )
return this.$.nodeValue.substr( indexA );
else
return this.$.nodeValue.substring( indexA, indexB );
}
} );

View file

@ -1,652 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
( function() {
// This function is to be called under a "walker" instance scope.
function iterate( rtl, breakOnFalse ) {
var range = this.range;
// Return null if we have reached the end.
if ( this._.end )
return null;
// This is the first call. Initialize it.
if ( !this._.start ) {
this._.start = 1;
// A collapsed range must return null at first call.
if ( range.collapsed ) {
this.end();
return null;
}
// Move outside of text node edges.
range.optimize();
}
var node,
startCt = range.startContainer,
endCt = range.endContainer,
startOffset = range.startOffset,
endOffset = range.endOffset,
guard,
userGuard = this.guard,
type = this.type,
getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
// Create the LTR guard function, if necessary.
if ( !rtl && !this._.guardLTR ) {
// The node that stops walker from moving up.
var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt : endCt.getParent();
// The node that stops the walker from going to next.
var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt.getChild( endOffset ) : endCt.getNext();
this._.guardLTR = function( node, movingOut ) {
return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
};
}
// Create the RTL guard function, if necessary.
if ( rtl && !this._.guardRTL ) {
// The node that stops walker from moving up.
var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startCt : startCt.getParent();
// The node that stops the walker from going to next.
var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startOffset ? startCt.getChild( startOffset - 1 ) : null : startCt.getPrevious();
this._.guardRTL = function( node, movingOut ) {
return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
};
}
// Define which guard function to use.
var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
// Make the user defined guard function participate in the process,
// otherwise simply use the boundary guard.
if ( userGuard ) {
guard = function( node, movingOut ) {
if ( stopGuard( node, movingOut ) === false )
return false;
return userGuard( node, movingOut );
};
} else {
guard = stopGuard;
}
if ( this.current )
node = this.current[ getSourceNodeFn ]( false, type, guard );
else {
// Get the first node to be returned.
if ( rtl ) {
node = endCt;
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
if ( endOffset > 0 )
node = node.getChild( endOffset - 1 );
else
node = ( guard( node, true ) === false ) ? null : node.getPreviousSourceNode( true, type, guard );
}
} else {
node = startCt;
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
if ( !( node = node.getChild( startOffset ) ) )
node = ( guard( startCt, true ) === false ) ? null : startCt.getNextSourceNode( true, type, guard );
}
}
if ( node && guard( node ) === false )
node = null;
}
while ( node && !this._.end ) {
this.current = node;
if ( !this.evaluator || this.evaluator( node ) !== false ) {
if ( !breakOnFalse )
return node;
} else if ( breakOnFalse && this.evaluator ) {
return false;
}
node = node[ getSourceNodeFn ]( false, type, guard );
}
this.end();
return this.current = null;
}
function iterateToLast( rtl ) {
var node,
last = null;
while ( ( node = iterate.call( this, rtl ) ) )
last = node;
return last;
}
/**
* Utility class to "walk" the DOM inside range boundaries. If the
* range starts or ends in the middle of the text node, this node will
* be included as a whole. Outside changes to the range may break the walker.
*
* The walker may return nodes that are not totally included in the
* range boundaries. Let us take the following range representation,
* where the square brackets indicate the boundaries:
*
* [<p>Some <b>sample] text</b>
*
* While walking forward into the above range, the following nodes are
* returned: `<p>`, `"Some "`, `<b>` and `"sample"`. Going
* backwards instead we have: `"sample"` and `"Some "`. So note that the
* walker always returns nodes when "entering" them, but not when
* "leaving" them. The {@link #guard} function is instead called both when
* entering and when leaving nodes.
*
* @class
*/
CKEDITOR.dom.walker = CKEDITOR.tools.createClass( {
/**
* Creates a walker class instance.
*
* @constructor
* @param {CKEDITOR.dom.range} range The range within which to walk.
*/
$: function( range ) {
this.range = range;
/**
* A function executed for every matched node to check whether
* it is to be considered in the walk or not. If not provided, all
* matched nodes are considered good.
*
* If the function returns `false`, the node is ignored.
*
* @property {Function} evaluator
*/
// this.evaluator = null;
/**
* A function executed for every node the walk passes by to check
* whether the walk is to be finished. It is called both when
* entering and when exiting nodes, as well as for the matched nodes.
*
* If this function returns `false`, the walking ends and no more
* nodes are evaluated.
* @property {Function} guard
*/
// this.guard = null;
/** @private */
this._ = {};
},
// statics :
// {
// /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
// * @param {CKEDITOR.dom.node} startNode The node from which the walk
// * will start.
// * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
// * in the walk. No more nodes are retrieved after touching or
// * passing it. If not provided, the walker stops at the
// * &lt;body&gt; closing boundary.
// * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
// * provided nodes.
// */
// createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
// {
// var range = new CKEDITOR.dom.range();
// if ( startNode )
// range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
// else
// range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;
//
// if ( endNode )
// range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
// else
// range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
//
// return new CKEDITOR.dom.walker( range );
// }
// },
//
proto: {
/**
* Stops walking. No more nodes are retrieved if this function is called.
*/
end: function() {
this._.end = 1;
},
/**
* Retrieves the next node (on the right).
*
* @returns {CKEDITOR.dom.node} The next node or `null` if no more
* nodes are available.
*/
next: function() {
return iterate.call( this );
},
/**
* Retrieves the previous node (on the left).
*
* @returns {CKEDITOR.dom.node} The previous node or `null` if no more
* nodes are available.
*/
previous: function() {
return iterate.call( this, 1 );
},
/**
* Checks all nodes on the right, executing the evaluation function.
*
* @returns {Boolean} `false` if the evaluator function returned
* `false` for any of the matched nodes. Otherwise `true`.
*/
checkForward: function() {
return iterate.call( this, 0, 1 ) !== false;
},
/**
* Check all nodes on the left, executing the evaluation function.
*
* @returns {Boolean} `false` if the evaluator function returned
* `false` for any of the matched nodes. Otherwise `true`.
*/
checkBackward: function() {
return iterate.call( this, 1, 1 ) !== false;
},
/**
* Executes a full walk forward (to the right), until no more nodes
* are available, returning the last valid node.
*
* @returns {CKEDITOR.dom.node} The last node on the right or `null`
* if no valid nodes are available.
*/
lastForward: function() {
return iterateToLast.call( this );
},
/**
* Executes a full walk backwards (to the left), until no more nodes
* are available, returning the last valid node.
*
* @returns {CKEDITOR.dom.node} The last node on the left or `null`
* if no valid nodes are available.
*/
lastBackward: function() {
return iterateToLast.call( this, 1 );
},
/**
* Resets the walker.
*/
reset: function() {
delete this.current;
this._ = {};
}
}
} );
// Anything whose display computed style is block, list-item, table,
// table-row-group, table-header-group, table-footer-group, table-row,
// table-column-group, table-column, table-cell, table-caption, or whose node
// name is hr, br (when enterMode is br only) is a block boundary.
var blockBoundaryDisplayMatch = {
block: 1, 'list-item': 1, table: 1, 'table-row-group': 1,
'table-header-group': 1, 'table-footer-group': 1, 'table-row': 1, 'table-column-group': 1,
'table-column': 1, 'table-cell': 1, 'table-caption': 1
},
outOfFlowPositions = { absolute: 1, fixed: 1 };
/**
* Checks whether an element is displayed as a block.
*
* @member CKEDITOR.dom.element
* @param [customNodeNames] Custom list of nodes which will extend
* the default {@link CKEDITOR.dtd#$block} list.
* @returns {Boolean}
*/
CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) {
// Whether element is in normal page flow. Floated or positioned elements are out of page flow.
// Don't consider floated or positioned formatting as block boundary, fall back to dtd check in that case. (https://dev.ckeditor.com/ticket/6297)
var inPageFlow = this.getComputedStyle( 'float' ) == 'none' && !( this.getComputedStyle( 'position' ) in outOfFlowPositions );
if ( inPageFlow && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] )
return true;
// Either in $block or in customNodeNames if defined.
return !!( this.is( CKEDITOR.dtd.$block ) || customNodeNames && this.is( customNodeNames ) );
};
/**
* Returns a function which checks whether the node is a block boundary.
* See {@link CKEDITOR.dom.element#isBlockBoundary}.
*
* @static
* @param customNodeNames
* @returns {Function}
*/
CKEDITOR.dom.walker.blockBoundary = function( customNodeNames ) {
return function( node ) {
return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary( customNodeNames ) );
};
};
/**
* @static
* @todo
*/
CKEDITOR.dom.walker.listItemBoundary = function() {
return this.blockBoundary( { br: 1 } );
};
/**
* Returns a function which checks whether the node is a bookmark node or the bookmark node
* inner content.
*
* @static
* @param {Boolean} [contentOnly=false] Whether only test against the text content of
* a bookmark node instead of the element itself (default).
* @param {Boolean} [isReject=false] Whether to return `false` for the bookmark
* node instead of `true` (default).
* @returns {Function}
*/
CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject ) {
function isBookmarkNode( node ) {
return ( node && node.getName && node.getName() == 'span' && node.data( 'cke-bookmark' ) );
}
return function( node ) {
var isBookmark, parent;
// Is bookmark inner text node?
isBookmark = ( node && node.type != CKEDITOR.NODE_ELEMENT && ( parent = node.getParent() ) && isBookmarkNode( parent ) );
// Is bookmark node?
isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node );
return !!( isReject ^ isBookmark );
};
};
/**
* Returns a function which checks whether the node is a text node containing only whitespace characters.
*
* @static
* @param {Boolean} [isReject=false]
* @returns {Function}
*/
CKEDITOR.dom.walker.whitespaces = function( isReject ) {
return function( node ) {
var isWhitespace;
if ( node && node.type == CKEDITOR.NODE_TEXT ) {
// Whitespace, as well as the Filling Char Sequence text node used in Webkit. (https://dev.ckeditor.com/ticket/9384, https://dev.ckeditor.com/ticket/13816)
isWhitespace = !CKEDITOR.tools.trim( node.getText() ) ||
CKEDITOR.env.webkit && node.getText() == CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE;
}
return !!( isReject ^ isWhitespace );
};
};
/**
* Returns a function which checks whether the node is invisible in the WYSIWYG mode.
*
* @static
* @param {Boolean} [isReject=false]
* @returns {Function}
*/
CKEDITOR.dom.walker.invisible = function( isReject ) {
var whitespace = CKEDITOR.dom.walker.whitespaces(),
// https://dev.ckeditor.com/ticket/12221 (Chrome) plus https://dev.ckeditor.com/ticket/11111 (Safari).
offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0;
return function( node ) {
var invisible;
if ( whitespace( node ) )
invisible = 1;
else {
// Visibility should be checked on element.
if ( node.type == CKEDITOR.NODE_TEXT )
node = node.getParent();
// Nodes that take no spaces in wysiwyg:
// 1. White-spaces but not including NBSP.
// 2. Empty inline elements, e.g. <b></b>.
// 3. <br> elements (bogus, surrounded by text) (https://dev.ckeditor.com/ticket/12423).
invisible = node.$.offsetWidth <= offsetWidth0;
}
return !!( isReject ^ invisible );
};
};
/**
* Returns a function which checks whether the node type is equal to the passed one.
*
* @static
* @param {Number} type
* @param {Boolean} [isReject=false]
* @returns {Function}
*/
CKEDITOR.dom.walker.nodeType = function( type, isReject ) {
return function( node ) {
return !!( isReject ^ ( node.type == type ) );
};
};
/**
* Returns a function which checks whether the node is a bogus (filler) node from
* `contenteditable` element's point of view.
*
* @static
* @param {Boolean} [isReject=false]
* @returns {Function}
*/
CKEDITOR.dom.walker.bogus = function( isReject ) {
function nonEmpty( node ) {
return !isWhitespaces( node ) && !isBookmark( node );
}
return function( node ) {
var isBogus = CKEDITOR.env.needsBrFiller ? node.is && node.is( 'br' ) : node.getText && tailNbspRegex.test( node.getText() );
if ( isBogus ) {
var parent = node.getParent(),
next = node.getNext( nonEmpty );
isBogus = parent.isBlockBoundary() && ( !next || next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() );
}
return !!( isReject ^ isBogus );
};
};
/**
* Returns a function which checks whether the node is a temporary element
* (element with the `data-cke-temp` attribute) or its child.
*
* @since 4.3.0
* @static
* @param {Boolean} [isReject=false] Whether to return `false` for the
* temporary element instead of `true` (default).
* @returns {Function}
*/
CKEDITOR.dom.walker.temp = function( isReject ) {
return function( node ) {
if ( node.type != CKEDITOR.NODE_ELEMENT )
node = node.getParent();
var isTemp = node && node.hasAttribute( 'data-cke-temp' );
return !!( isReject ^ isTemp );
};
};
var tailNbspRegex = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/,
isWhitespaces = CKEDITOR.dom.walker.whitespaces(),
isBookmark = CKEDITOR.dom.walker.bookmark(),
isTemp = CKEDITOR.dom.walker.temp(),
toSkip = function( node ) {
return isBookmark( node ) ||
isWhitespaces( node ) ||
node.type == CKEDITOR.NODE_ELEMENT && node.is( CKEDITOR.dtd.$inline ) && !node.is( CKEDITOR.dtd.$empty );
};
/**
* Returns a function which checks whether the node should be ignored in terms of "editability".
*
* This includes:
*
* * whitespaces (see {@link CKEDITOR.dom.walker#whitespaces}),
* * bookmarks (see {@link CKEDITOR.dom.walker#bookmark}),
* * temporary elements (see {@link CKEDITOR.dom.walker#temp}).
*
* @since 4.3.0
* @static
* @param {Boolean} [isReject=false] Whether to return `false` for the
* ignored element instead of `true` (default).
* @returns {Function}
*/
CKEDITOR.dom.walker.ignored = function( isReject ) {
return function( node ) {
var isIgnored = isWhitespaces( node ) || isBookmark( node ) || isTemp( node );
return !!( isReject ^ isIgnored );
};
};
var isIgnored = CKEDITOR.dom.walker.ignored();
/**
* Returns a function which checks whether the node is empty.
*
* @since 4.5.0
* @static
* @param {Boolean} [isReject=false] Whether to return `false` for the
* ignored element instead of `true` (default).
* @returns {Function}
*/
CKEDITOR.dom.walker.empty = function( isReject ) {
return function( node ) {
var i = 0,
l = node.getChildCount();
for ( ; i < l; ++i ) {
if ( !isIgnored( node.getChild( i ) ) ) {
return !!isReject;
}
}
return !isReject;
};
};
var isEmpty = CKEDITOR.dom.walker.empty();
function filterTextContainers( dtd ) {
var hash = {},
name;
for ( name in dtd ) {
if ( CKEDITOR.dtd[ name ][ '#' ] )
hash[ name ] = 1;
}
return hash;
}
/**
* A hash of element names which in browsers that {@link CKEDITOR.env#needsBrFiller do not need `<br>` fillers}
* can be selection containers despite being empty.
*
* @since 4.5.0
* @static
* @property {Object} validEmptyBlockContainers
*/
var validEmptyBlocks = CKEDITOR.dom.walker.validEmptyBlockContainers = CKEDITOR.tools.extend(
filterTextContainers( CKEDITOR.dtd.$block ),
{ caption: 1, td: 1, th: 1 }
);
function isEditable( node ) {
// Skip temporary elements, bookmarks and whitespaces.
if ( isIgnored( node ) )
return false;
if ( node.type == CKEDITOR.NODE_TEXT )
return true;
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
// All inline and non-editable elements are valid editable places.
// Note: the <hr> is currently the only element in CKEDITOR.dtd.$empty and CKEDITOR.dtd.$block,
// but generally speaking we need an intersection of these two sets.
// Note: non-editable block has to be treated differently (should be selected entirely).
if ( node.is( CKEDITOR.dtd.$inline ) || node.is( 'hr' ) || node.getAttribute( 'contenteditable' ) == 'false' )
return true;
// Empty blocks are editable on IE.
if ( !CKEDITOR.env.needsBrFiller && node.is( validEmptyBlocks ) && isEmpty( node ) )
return true;
}
// Skip all other nodes.
return false;
}
/**
* Returns a function which checks whether the node can be a container or a sibling
* of the selection end.
*
* This includes:
*
* * text nodes (but not whitespaces),
* * inline elements,
* * intersection of {@link CKEDITOR.dtd#$empty} and {@link CKEDITOR.dtd#$block} (currently
* it is only `<hr>`),
* * non-editable blocks (special case &mdash; such blocks cannot be containers nor
* siblings, they need to be selected entirely),
* * empty {@link #validEmptyBlockContainers blocks} which can contain text
* ({@link CKEDITOR.env#needsBrFiller old IEs only}).
*
* @since 4.3.0
* @static
* @param {Boolean} [isReject=false] Whether to return `false` for the
* ignored element instead of `true` (default).
* @returns {Function}
*/
CKEDITOR.dom.walker.editable = function( isReject ) {
return function( node ) {
return !!( isReject ^ isEditable( node ) );
};
};
/**
* Checks if there is a filler node at the end of an element, and returns it.
*
* @member CKEDITOR.dom.element
* @returns {CKEDITOR.dom.node/Boolean} Bogus node or `false`.
*/
CKEDITOR.dom.element.prototype.getBogus = function() {
// Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (https://dev.ckeditor.com/ticket/7070).
var tail = this;
do {
tail = tail.getPreviousSourceNode();
}
while ( toSkip( tail ) );
if ( tail && ( CKEDITOR.env.needsBrFiller ? tail.is && tail.is( 'br' ) : tail.getText && tailNbspRegex.test( tail.getText() ) ) )
return tail;
return false;
};
} )();

View file

@ -1,95 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
* represents a DOM document.
*/
/**
* Represents a DOM window.
*
* var document = new CKEDITOR.dom.window( window );
*
* @class
* @extends CKEDITOR.dom.domObject
* @constructor Creates a window class instance.
* @param {Object} domWindow A native DOM window.
*/
CKEDITOR.dom.window = function( domWindow ) {
CKEDITOR.dom.domObject.call( this, domWindow );
};
CKEDITOR.dom.window.prototype = new CKEDITOR.dom.domObject();
CKEDITOR.tools.extend( CKEDITOR.dom.window.prototype, {
/**
* Moves the selection focus to this window.
*
* var win = new CKEDITOR.dom.window( window );
* win.focus();
*/
focus: function() {
this.$.focus();
},
/**
* Gets the width and height of this window's viewable area.
*
* var win = new CKEDITOR.dom.window( window );
* var size = win.getViewPaneSize();
* alert( size.width );
* alert( size.height );
*
* @returns {Object} An object with the `width` and `height`
* properties containing the size.
*/
getViewPaneSize: function() {
var doc = this.$.document,
stdMode = doc.compatMode == 'CSS1Compat';
return {
width: ( stdMode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
height: ( stdMode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
};
},
/**
* Gets the current position of the window's scroll.
*
* var win = new CKEDITOR.dom.window( window );
* var pos = win.getScrollPosition();
* alert( pos.x );
* alert( pos.y );
*
* @returns {Object} An object with the `x` and `y` properties
* containing the scroll position.
*/
getScrollPosition: function() {
var $ = this.$;
if ( 'pageXOffset' in $ ) {
return {
x: $.pageXOffset || 0,
y: $.pageYOffset || 0
};
} else {
var doc = $.document;
return {
x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
};
}
},
/**
* Gets the frame element containing this window context.
*
* @returns {CKEDITOR.dom.element} The frame element or `null` if not in a frame context.
*/
getFrame: function() {
var iframe = this.$.frameElement;
return iframe ? new CKEDITOR.dom.element.get( iframe ) : null;
}
} );

View file

@ -1,370 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.dtd} object, which holds the DTD
* mapping for XHTML 1.0 Transitional. This file was automatically
* generated from the file: xhtml1-transitional.dtd.
*/
/**
* Holds and object representation of the HTML DTD to be used by the
* editor in its internal operations.
*
* Each element in the DTD is represented by a property in this object. Each
* property contains the list of elements that can be contained by the element.
* Text is represented by the `#` property.
*
* Several special grouping properties are also available. Their names start
* with the `$` character.
*
* // Check if <div> can be contained in a <p> element.
* alert( !!CKEDITOR.dtd[ 'p' ][ 'div' ] ); // false
*
* // Check if <p> can be contained in a <div> element.
* alert( !!CKEDITOR.dtd[ 'div' ][ 'p' ] ); // true
*
* // Check if <p> is a block element.
* alert( !!CKEDITOR.dtd.$block[ 'p' ] ); // true
*
* It is also possible to add a new element to DTD. It will ensure it is handled correctly e.g. in terms of nesting or positioning.
*
* For example, you can define a block element, which can be empty:
*
* ```js
* // Let's add a DTD for a new element <signature>
* // and specify it can contain <p> and <img> elements:
* CKEDITOR.dtd[ 'signature' ] = {
* p: 1,
* img: 1
* };
*
* // Define <signature> as a block element.
* CKEDITOR.dtd.$block[ 'signature' ] = 1;
*
* // Allow <signature> element to be empty.
* CKEDITOR.dtd.$empty[ 'signature' ] = 1;
* ```
*
* **Note**: Editing the DTD for existing elements is also possible this way, but may cause an unexpected outcome and inconsistent editing behaviour, so **it is not recommended**.
*
* @class CKEDITOR.dtd
* @singleton
*/
CKEDITOR.dtd = ( function() {
'use strict';
var X = CKEDITOR.tools.extend,
// Subtraction rest of sets, from the first set.
Y = function( source, removed ) {
var substracted = CKEDITOR.tools.clone( source );
for ( var i = 1; i < arguments.length; i++ ) {
removed = arguments[ i ];
for ( var name in removed )
delete substracted[ name ];
}
return substracted;
};
// Phrasing elements.
// P = { a: 1, em: 1, strong: 1, small: 1, abbr: 1, dfn: 1, i: 1, b: 1, s: 1,
// u: 1, code: 1, 'var': 1, samp: 1, kbd: 1, sup: 1, sub: 1, q: 1, cite: 1,
// span: 1, bdo: 1, bdi: 1, br: 1, wbr: 1, ins: 1, del: 1, img: 1, embed: 1,
// object: 1, iframe: 1, map: 1, area: 1, script: 1, noscript: 1, ruby: 1,
// video: 1, audio: 1, input: 1, textarea: 1, select: 1, button: 1, label: 1,
// output: 1, keygen: 1, progress: 1, command: 1, canvas: 1, time: 1,
// meter: 1, detalist: 1 },
// Flow elements.
// F = { a: 1, p: 1, hr: 1, pre: 1, ul: 1, ol: 1, dl: 1, div: 1, h1: 1, h2: 1,
// h3: 1, h4: 1, h5: 1, h6: 1, hgroup: 1, address: 1, blockquote: 1, ins: 1,
// del: 1, object: 1, map: 1, noscript: 1, section: 1, nav: 1, article: 1,
// aside: 1, header: 1, footer: 1, video: 1, audio: 1, figure: 1, table: 1,
// form: 1, fieldset: 1, menu: 1, canvas: 1, details:1 },
// Text can be everywhere.
// X( P, T );
// Flow elements set consists of phrasing elements set.
// X( F, P );
var P = {}, F = {},
// Intersection of flow elements set and phrasing elements set.
PF = {
a: 1, abbr: 1, area: 1, audio: 1, b: 1, bdi: 1, bdo: 1, br: 1, button: 1, canvas: 1, cite: 1,
code: 1, command: 1, datalist: 1, del: 1, dfn: 1, em: 1, embed: 1, i: 1, iframe: 1, img: 1,
input: 1, ins: 1, kbd: 1, keygen: 1, label: 1, map: 1, mark: 1, meter: 1, noscript: 1, object: 1,
output: 1, progress: 1, q: 1, ruby: 1, s: 1, samp: 1, script: 1, select: 1, small: 1, span: 1,
strong: 1, sub: 1, sup: 1, textarea: 1, time: 1, u: 1, 'var': 1, video: 1, wbr: 1
},
// F - PF (Flow Only).
FO = {
address: 1, article: 1, aside: 1, blockquote: 1, details: 1, div: 1, dl: 1, fieldset: 1,
figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
hr: 1, main: 1, menu: 1, nav: 1, ol: 1, p: 1, pre: 1, section: 1, table: 1, ul: 1
},
// Metadata elements.
M = { command: 1, link: 1, meta: 1, noscript: 1, script: 1, style: 1 },
// Empty.
E = {},
// Text.
T = { '#': 1 },
// Deprecated phrasing elements.
DP = { acronym: 1, applet: 1, basefont: 1, big: 1, font: 1, isindex: 1, strike: 1, style: 1, tt: 1 }, // TODO remove "style".
// Deprecated flow only elements.
DFO = { center: 1, dir: 1, noframes: 1 };
// Phrasing elements := PF + T + DP
X( P, PF, T, DP );
// Flow elements := FO + P + DFO
X( F, FO, P, DFO );
var dtd = {
a: Y( P, { a: 1, button: 1 } ), // Treat as normal inline element (not a transparent one).
abbr: P,
address: F,
area: E,
article: F,
aside: F,
audio: X( { source: 1, track: 1 }, F ),
b: P,
base: E,
bdi: P,
bdo: P,
blockquote: F,
body: F,
br: E,
button: Y( P, { a: 1, button: 1 } ),
canvas: P, // Treat as normal inline element (not a transparent one).
caption: F,
cite: P,
code: P,
col: E,
colgroup: { col: 1 },
command: E,
datalist: X( { option: 1 }, P ),
dd: F,
del: P, // Treat as normal inline element (not a transparent one).
details: X( { summary: 1 }, F ),
dfn: P,
div: F,
dl: { dt: 1, dd: 1 },
dt: F,
em: P,
embed: E,
fieldset: X( { legend: 1 }, F ),
figcaption: F,
figure: X( { figcaption: 1 }, F ),
footer: F,
form: F,
h1: P,
h2: P,
h3: P,
h4: P,
h5: P,
h6: P,
head: X( { title: 1, base: 1 }, M ),
header: F,
hgroup: { h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 },
hr: E,
html: X( { head: 1, body: 1 }, F, M ), // Head and body are optional...
i: P,
iframe: T,
img: E,
input: E,
ins: P, // Treat as normal inline element (not a transparent one).
kbd: P,
keygen: E,
label: P,
legend: P,
li: F,
link: E,
// Can't be a descendant of article, aside, footer, header, nav, but we don't need this
// complication. As well as checking if it's used only once.
main: F,
map: F,
mark: P, // Treat as normal inline element (not a transparent one).
menu: X( { li: 1 }, F ),
meta: E,
meter: Y( P, { meter: 1 } ),
nav: F,
noscript: X( { link: 1, meta: 1, style: 1 }, P ), // Treat as normal inline element (not a transparent one).
object: X( { param: 1 }, P ), // Treat as normal inline element (not a transparent one).
ol: { li: 1 },
optgroup: { option: 1 },
option: T,
output: P,
p: P,
param: E,
pre: P,
progress: Y( P, { progress: 1 } ),
q: P,
rp: P,
rt: P,
ruby: X( { rp: 1, rt: 1 }, P ),
s: P,
samp: P,
script: T,
section: F,
select: { optgroup: 1, option: 1 },
small: P,
source: E,
span: P,
strong: P,
style: T,
sub: P,
summary: X( { h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 }, P ),
sup: P,
table: { caption: 1, colgroup: 1, thead: 1, tfoot: 1, tbody: 1, tr: 1 },
tbody: { tr: 1 },
td: F,
textarea: T,
tfoot: { tr: 1 },
th: F,
thead: { tr: 1 },
time: Y( P, { time: 1 } ),
title: T,
tr: { th: 1, td: 1 },
track: E,
u: P,
ul: { li: 1 },
'var': P,
video: X( { source: 1, track: 1 }, F ),
wbr: E,
// Deprecated tags.
acronym: P,
applet: X( { param: 1 }, F ),
basefont: E,
big: P,
center: F,
dialog: E,
dir: { li: 1 },
font: P,
isindex: E,
noframes: F,
strike: P,
tt: P
};
X( dtd, {
/**
* List of block elements, like `<p>` or `<div>`.
*/
$block: X( { audio: 1, dd: 1, dt: 1, figcaption: 1, li: 1, video: 1 }, FO, DFO ),
/**
* List of elements that contain other blocks, in which block-level operations should be limited,
* this property is not intended to be checked directly, use {@link CKEDITOR.dom.elementPath#blockLimit} instead.
*
* Some examples of editor behaviors that are impacted by block limits:
*
* * Enter key never split a block-limit element;
* * Style application is constraint by the block limit of the current selection.
* * Pasted html will be inserted into the block limit of the current selection.
*
* **Note:** As an exception `<li>` is not considered as a block limit, as it's generally used as a text block.
*/
$blockLimit: {
article: 1, aside: 1, audio: 1, body: 1, caption: 1, details: 1, dir: 1, div: 1, dl: 1,
fieldset: 1, figcaption: 1, figure: 1, footer: 1, form: 1, header: 1, hgroup: 1, main: 1, menu: 1, nav: 1,
ol: 1, section: 1, table: 1, td: 1, th: 1, tr: 1, ul: 1, video: 1
},
/**
* List of elements that contain character data.
*/
$cdata: { script: 1, style: 1 },
/**
* List of elements that are accepted as inline editing hosts.
*/
$editable: {
address: 1, article: 1, aside: 1, blockquote: 1, body: 1, details: 1, div: 1, fieldset: 1,
figcaption: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
main: 1, nav: 1, p: 1, pre: 1, section: 1
},
/**
* List of empty (self-closing) elements, like `<br>` or `<img>`.
*/
$empty: {
area: 1, base: 1, basefont: 1, br: 1, col: 1, command: 1, dialog: 1, embed: 1, hr: 1, img: 1,
input: 1, isindex: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, track: 1, wbr: 1
},
/**
* List of inline (`<span>` like) elements.
*/
$inline: P,
/**
* List of list root elements.
*/
$list: { dl: 1, ol: 1, ul: 1 },
/**
* List of list item elements, like `<li>` or `<dd>`.
*/
$listItem: { dd: 1, dt: 1, li: 1 },
/**
* List of elements which may live outside body.
*/
$nonBodyContent: X( { body: 1, head: 1, html: 1 }, dtd.head ),
/**
* Elements that accept text nodes, but are not possible to edit into the browser.
*/
$nonEditable: {
applet: 1, audio: 1, button: 1, embed: 1, iframe: 1, map: 1, object: 1, option: 1,
param: 1, script: 1, textarea: 1, video: 1
},
/**
* Elements that are considered objects, therefore selected as a whole in the editor.
*/
$object: {
applet: 1, audio: 1, button: 1, hr: 1, iframe: 1, img: 1, input: 1, object: 1, select: 1,
table: 1, textarea: 1, video: 1
},
/**
* List of elements that can be ignored if empty, like `<b>` or `<span>`.
*/
$removeEmpty: {
abbr: 1, acronym: 1, b: 1, bdi: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1,
em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, mark: 1, meter: 1, output: 1, q: 1, ruby: 1, s: 1,
samp: 1, small: 1, span: 1, strike: 1, strong: 1, sub: 1, sup: 1, time: 1, tt: 1, u: 1, 'var': 1
},
/**
* List of elements that have tabindex set to zero by default.
*/
$tabIndex: { a: 1, area: 1, button: 1, input: 1, object: 1, select: 1, textarea: 1 },
/**
* List of elements used inside the `<table>` element, like `<tbody>` or `<td>`.
*/
$tableContent: { caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1 },
/**
* List of "transparent" elements. See [W3C's definition of "transparent" element](http://dev.w3.org/html5/markup/terminology.html#transparent).
*/
$transparent: { a: 1, audio: 1, canvas: 1, del: 1, ins: 1, map: 1, noscript: 1, object: 1, video: 1 },
/**
* List of elements that are not to exist standalone that must live under it's parent element.
*/
$intermediate: {
caption: 1, colgroup: 1, dd: 1, dt: 1, figcaption: 1, legend: 1, li: 1, optgroup: 1,
option: 1, rp: 1, rt: 1, summary: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1
}
} );
return dtd;
} )();
// PACKAGER_RENAME( CKEDITOR.dtd )

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
if ( !CKEDITOR.editor ) {
// Documented at editor.js.
CKEDITOR.editor = function() {
// Push this editor to the pending list. It'll be processed later once
// the full editor code is loaded.
CKEDITOR._.pending.push( [ this, arguments ] );
// Call the CKEDITOR.event constructor to initialize this instance.
CKEDITOR.event.call( this );
};
// Both fire and fireOnce will always pass this editor instance as the
// "editor" param in CKEDITOR.event.fire. So, we override it to do that
// automaticaly.
CKEDITOR.editor.prototype.fire = function( eventName, data ) {
if ( eventName in { instanceReady: 1, loaded: 1 } )
this[ eventName ] = true;
return CKEDITOR.event.prototype.fire.call( this, eventName, data, this );
};
CKEDITOR.editor.prototype.fireOnce = function( eventName, data ) {
if ( eventName in { instanceReady: 1, loaded: 1 } )
this[ eventName ] = true;
return CKEDITOR.event.prototype.fireOnce.call( this, eventName, data, this );
};
// "Inherit" (copy actually) from CKEDITOR.event.
CKEDITOR.event.implementOn( CKEDITOR.editor.prototype );
}

View file

@ -1,361 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.env} object which contains
* environment and browser information.
*/
if ( !CKEDITOR.env ) {
/**
* Environment and browser information.
*
* @class CKEDITOR.env
* @singleton
*/
CKEDITOR.env = ( function() {
var agent = navigator.userAgent.toLowerCase(),
edge = agent.match( /edge[ \/](\d+.?\d*)/ ),
trident = agent.indexOf( 'trident/' ) > -1,
ie = !!( edge || trident );
var env = {
/**
* Indicates that CKEditor is running in Internet Explorer.
*
* if ( CKEDITOR.env.ie )
* alert( 'I\'m running in IE!' );
*
* **Note:** This property is also set to `true` if CKEditor is running
* in {@link #edge Microsoft Edge}.
*
* @property {Boolean}
*/
ie: ie,
/**
* Indicates that CKEditor is running in Microsoft Edge.
*
* if ( CKEDITOR.env.edge )
* alert( 'I\'m running in Edge!' );
*
* See also {@link #ie}.
*
* @since 4.5.0
* @property {Boolean}
*/
edge: !!edge,
/**
* Indicates that CKEditor is running in a WebKit-based browser, like Safari,
* or Blink-based browser, like Chrome.
*
* if ( CKEDITOR.env.webkit )
* alert( 'I\'m running in a WebKit browser!' );
*
* @property {Boolean}
*/
webkit: !ie && ( agent.indexOf( ' applewebkit/' ) > -1 ),
/**
* Indicates that CKEditor is running in Adobe AIR.
*
* if ( CKEDITOR.env.air )
* alert( 'I\'m on AIR!' );
*
* @property {Boolean}
*/
air: ( agent.indexOf( ' adobeair/' ) > -1 ),
/**
* Indicates that CKEditor is running on Macintosh.
*
* if ( CKEDITOR.env.mac )
* alert( 'I love apples!'' );
*
* @property {Boolean}
*/
mac: ( agent.indexOf( 'macintosh' ) > -1 ),
/**
* Indicates that CKEditor is running in a Quirks Mode environment.
*
* if ( CKEDITOR.env.quirks )
* alert( 'Nooooo!' );
*
* Internet Explorer 10 introduced the _New Quirks Mode_, which is similar to the _Quirks Mode_
* implemented in other modern browsers and defined in the HTML5 specification. It can be handled
* as the Standards mode, so the value of this property will be set to `false`.
*
* The _Internet Explorer 5 Quirks_ mode which is still available in Internet Explorer 10+
* sets this value to `true` and {@link #version} to `7`.
*
* Read more: [IEBlog](http://blogs.msdn.com/b/ie/archive/2011/12/14/interoperable-html5-quirks-mode-in-ie10.aspx)
*
* @property {Boolean}
*/
quirks: ( document.compatMode == 'BackCompat' && ( !document.documentMode || document.documentMode < 10 ) ),
/**
* Indicates that CKEditor is running in a mobile environemnt.
*
* if ( CKEDITOR.env.mobile )
* alert( 'I\'m running with CKEditor today!' );
*
* @deprecated
* @property {Boolean}
*/
mobile: ( agent.indexOf( 'mobile' ) > -1 ),
/**
* Indicates that CKEditor is running on Apple iPhone/iPad/iPod devices.
*
* if ( CKEDITOR.env.iOS )
* alert( 'I like little apples!' );
*
* @property {Boolean}
*/
iOS: /(ipad|iphone|ipod)/.test( agent ),
/**
* Indicates that the browser has a custom domain enabled. This has
* been set with `document.domain`.
*
* if ( CKEDITOR.env.isCustomDomain() )
* alert( 'I\'m in a custom domain!' );
*
* @returns {Boolean} `true` if a custom domain is enabled.
* @deprecated
*/
isCustomDomain: function() {
if ( !this.ie )
return false;
var domain = document.domain,
hostname = window.location.hostname;
return domain != hostname && domain != ( '[' + hostname + ']' ); // IPv6 IP support (https://dev.ckeditor.com/ticket/5434)
},
/**
* Indicates that the page is running under an encrypted connection.
*
* if ( CKEDITOR.env.secure )
* alert( 'I\'m on SSL!' );
*
* @returns {Boolean} `true` if the page has an encrypted connection.
*/
secure: location.protocol == 'https:'
};
/**
* Indicates that CKEditor is running in a Gecko-based browser, like
* Firefox.
*
* if ( CKEDITOR.env.gecko )
* alert( 'I\'m riding a gecko!' );
*
* @property {Boolean}
*/
env.gecko = ( navigator.product == 'Gecko' && !env.webkit && !env.ie );
/**
* Indicates that CKEditor is running in a Blink-based browser like Chrome.
*
* if ( CKEDITOR.env.chrome )
* alert( 'I\'m running in Chrome!' );
*
* @property {Boolean} chrome
*/
/**
* Indicates that CKEditor is running in Safari (including the mobile version).
*
* if ( CKEDITOR.env.safari )
* alert( 'I\'m on Safari!' );
*
* @property {Boolean} safari
*/
if ( env.webkit ) {
if ( agent.indexOf( 'chrome' ) > -1 )
env.chrome = true;
else
env.safari = true;
}
var version = 0;
// Internet Explorer 6.0+
if ( env.ie ) {
// We use env.version for feature detection, so set it properly.
if ( edge ) {
version = parseFloat( edge[ 1 ] );
} else if ( env.quirks || !document.documentMode ) {
version = parseFloat( agent.match( /msie (\d+)/ )[ 1 ] );
} else {
version = document.documentMode;
}
// Deprecated features available just for backwards compatibility.
env.ie9Compat = version == 9;
env.ie8Compat = version == 8;
env.ie7Compat = version == 7;
env.ie6Compat = version < 7 || env.quirks;
/**
* Indicates that CKEditor is running in an IE6-like environment, which
* includes IE6 itself as well as IE7, IE8 and IE9 in Quirks Mode.
*
* @deprecated
* @property {Boolean} ie6Compat
*/
/**
* Indicates that CKEditor is running in an IE7-like environment, which
* includes IE7 itself and IE8's IE7 Document Mode.
*
* @deprecated
* @property {Boolean} ie7Compat
*/
/**
* Indicates that CKEditor is running in Internet Explorer 8 on
* Standards Mode.
*
* @deprecated
* @property {Boolean} ie8Compat
*/
/**
* Indicates that CKEditor is running in Internet Explorer 9 on
* Standards Mode.
*
* @deprecated
* @property {Boolean} ie9Compat
*/
}
// Gecko.
if ( env.gecko ) {
var geckoRelease = agent.match( /rv:([\d\.]+)/ );
if ( geckoRelease ) {
geckoRelease = geckoRelease[ 1 ].split( '.' );
version = geckoRelease[ 0 ] * 10000 + ( geckoRelease[ 1 ] || 0 ) * 100 + ( geckoRelease[ 2 ] || 0 ) * 1;
}
}
// Adobe AIR 1.0+
// Checked before Safari because AIR have the WebKit rich text editor
// features from Safari 3.0.4, but the version reported is 420.
if ( env.air )
version = parseFloat( agent.match( / adobeair\/(\d+)/ )[ 1 ] );
// WebKit 522+ (Safari 3+)
if ( env.webkit )
version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[ 1 ] );
/**
* Contains the browser version.
*
* For Gecko-based browsers (like Firefox) it contains the revision
* number with first three parts concatenated with a padding zero
* (e.g. for revision 1.9.0.2 we have 10900).
*
* For WebKit-based browsers (like Safari and Chrome) it contains the
* WebKit build version (e.g. 522).
*
* For IE browsers, it matches the "Document Mode".
*
* if ( CKEDITOR.env.ie && CKEDITOR.env.version <= 6 )
* alert( 'Ouch!' );
*
* @property {Number}
*/
env.version = version;
/**
* Since CKEditor 4.5.0 this property is a blacklist of browsers incompatible with CKEditor. It means that it is
* set to `false` only in browsers that are known to be incompatible. Before CKEditor 4.5.0 this
* property was a whitelist of browsers that were known to be compatible with CKEditor.
*
* The reason for this change is the rising fragmentation of the browser market (especially the mobile segment).
* It became too complicated to check in which new environments CKEditor is going to work.
*
* In order to enable CKEditor 4.4.x and below in unsupported environments see the
* {@glink guide/dev_unsupported_environments Enabling CKEditor in Unsupported Environments} article.
*
* if ( CKEDITOR.env.isCompatible )
* alert( 'Your browser is not known to be incompatible with CKEditor!' );
*
* @property {Boolean}
*/
env.isCompatible =
// IE 7+ (IE 7 is not supported, but IE Compat Mode is and it is recognized as IE7).
!( env.ie && version < 7 ) &&
// Firefox 4.0+.
!( env.gecko && version < 40000 ) &&
// Chrome 6+, Safari 5.1+, iOS 5+.
!( env.webkit && version < 534 );
/**
* Indicates that CKEditor is running in the HiDPI environment.
*
* if ( CKEDITOR.env.hidpi )
* alert( 'You are using a screen with high pixel density.' );
*
* @property {Boolean}
*/
env.hidpi = window.devicePixelRatio >= 2;
/**
* Indicates that CKEditor is running in a browser which uses a bogus
* `<br>` filler in order to correctly display caret in empty blocks.
*
* @since 4.3.0
* @property {Boolean}
*/
env.needsBrFiller = env.gecko || env.webkit || ( env.ie && version > 10 );
/**
* Indicates that CKEditor is running in a browser which needs a
* non-breaking space filler in order to correctly display caret in empty blocks.
*
* @since 4.3.0
* @property {Boolean}
*/
env.needsNbspFiller = env.ie && version < 11;
/**
* A CSS class that denotes the browser where CKEditor runs and is appended
* to the HTML element that contains the editor. It makes it easier to apply
* browser-specific styles to editor instances.
*
* myDiv.className = CKEDITOR.env.cssClass;
*
* @property {String}
*/
env.cssClass = 'cke_browser_' + ( env.ie ? 'ie' : env.gecko ? 'gecko' : env.webkit ? 'webkit' : 'unknown' );
if ( env.quirks )
env.cssClass += ' cke_browser_quirks';
if ( env.ie )
env.cssClass += ' cke_browser_ie' + ( env.quirks ? '6 cke_browser_iequirks' : env.version );
if ( env.air )
env.cssClass += ' cke_browser_air';
if ( env.iOS )
env.cssClass += ' cke_browser_ios';
if ( env.hidpi )
env.cssClass += ' cke_hidpi';
return env;
} )();
}
// PACKAGER_RENAME( CKEDITOR.env )
// PACKAGER_RENAME( CKEDITOR.env.ie )

View file

@ -1,413 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.event} class, which serves as the
* base for classes and objects that require event handling features.
*/
( function() {
'use strict';
// Instead of false, we mark event cancellation with unique object (#4652).
var EVENT_CANCELED = {};
if ( !CKEDITOR.event ) {
/**
* Creates an event class instance. This constructor is rarely used, being
* the {@link #implementOn} function used in class prototypes directly
* instead.
*
* This is a base class for classes and objects that require event
* handling features.
*
* Do not confuse this class with {@link CKEDITOR.dom.event} which is
* instead used for DOM events. The CKEDITOR.event class implements the
* internal event system used by the CKEditor to fire API related events.
*
* @class
* @constructor Creates an event class instance.
*/
CKEDITOR.event = function() {};
/**
* Implements the {@link CKEDITOR.event} features in an object.
*
* var myObject = { message: 'Example' };
* CKEDITOR.event.implementOn( myObject );
*
* myObject.on( 'testEvent', function() {
* alert( this.message );
* } );
* myObject.fire( 'testEvent' ); // 'Example'
*
* @static
* @param {Object} targetObject The object into which implement the features.
*/
CKEDITOR.event.implementOn = function( targetObject ) {
var eventProto = CKEDITOR.event.prototype;
for ( var prop in eventProto ) {
if ( targetObject[ prop ] == null )
targetObject[ prop ] = eventProto[ prop ];
}
};
CKEDITOR.event.prototype = ( function() {
// Returns the private events object for a given object.
var getPrivate = function( obj ) {
var _ = ( obj.getPrivate && obj.getPrivate() ) || obj._ || ( obj._ = {} );
return _.events || ( _.events = {} );
};
var eventEntry = function( eventName ) {
this.name = eventName;
this.listeners = [];
};
eventEntry.prototype = {
// Get the listener index for a specified function.
// Returns -1 if not found.
getListenerIndex: function( listenerFunction ) {
for ( var i = 0, listeners = this.listeners; i < listeners.length; i++ ) {
if ( listeners[ i ].fn == listenerFunction )
return i;
}
return -1;
}
};
// Retrieve the event entry on the event host (create it if needed).
function getEntry( name ) {
// Get the event entry (create it if needed).
var events = getPrivate( this );
return events[ name ] || ( events[ name ] = new eventEntry( name ) );
}
return {
/**
* Predefine some intrinsic properties on a specific event name.
*
* @param {String} name The event name
* @param meta
* @param [meta.errorProof=false] Whether the event firing should catch error thrown from a per listener call.
*/
define: function( name, meta ) {
var entry = getEntry.call( this, name );
CKEDITOR.tools.extend( entry, meta, true );
},
/**
* Registers a listener to a specific event in the current object.
*
* ```javascript
* someObject.on( 'someEvent', function() {
* alert( this == someObject ); // true
* } );
*
* someObject.on( 'someEvent', function() {
* alert( this == anotherObject ); // true
* }, anotherObject );
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.listenerData ); // 'Example'
* }, null, 'Example' );
*
* someObject.on( 'someEvent', function() { ... } ); // 2nd called
* someObject.on( 'someEvent', function() { ... }, null, null, 100 ); // 3rd called
* someObject.on( 'someEvent', function() { ... }, null, null, 1 ); // 1st called
* ```
*
* **Note**: CKEditor's event system has a limitation that one function cannot be used as a listener for the same event more than once.
* Hence, to reuse it with multiple listeners, it should be wrapped into additional wrapper function:
*
* ```javascript
* function listener( evt ) { ... };
*
* someObject.on( 'someEvent', function() {
* listener();
* } );
*
* someObject.on( 'someEvent', function( evt ) {
* listener( evt );
* } );
* ```
*
* @param {String} eventName The event name to which listen.
* @param {Function} listenerFunction The function listening to the
* event. A single {@link CKEDITOR.eventInfo} object instanced
* is passed to this function containing all the event data.
* @param {Object} [scopeObj] The object used to scope the listener
* call (the `this` object). If omitted, the current object is used.
* @param {Object} [listenerData] Data to be sent as the
* {@link CKEDITOR.eventInfo#listenerData} when calling the
* listener.
* @param {Number} [priority=10] The listener priority. Lower priority
* listeners are called first. Listeners with the same priority
* value are called in registration order.
* @returns {Object} An object containing the `removeListener`
* function, which can be used to remove the listener at any time.
*/
on: function( eventName, listenerFunction, scopeObj, listenerData, priority ) {
var me = this;
// Create the function to be fired for this listener.
function listenerFirer( editor, publisherData, stopFn, cancelFn ) {
var ev = {
name: eventName,
sender: this,
editor: editor,
data: publisherData,
listenerData: listenerData,
stop: stopFn,
cancel: cancelFn,
removeListener: removeListener
};
var ret = listenerFunction.call( scopeObj, ev );
return ret === false ? EVENT_CANCELED : ev.data;
}
function removeListener() {
me.removeListener( eventName, listenerFunction );
}
var event = getEntry.call( this, eventName );
if ( event.getListenerIndex( listenerFunction ) < 0 ) {
// Get the listeners.
var listeners = event.listeners;
// Fill the scope.
if ( !scopeObj )
scopeObj = this;
// Default the priority, if needed.
if ( isNaN( priority ) )
priority = 10;
listenerFirer.fn = listenerFunction;
listenerFirer.priority = priority;
// Search for the right position for this new listener, based on its
// priority.
for ( var i = listeners.length - 1; i >= 0; i-- ) {
// Find the item which should be before the new one.
if ( listeners[ i ].priority <= priority ) {
// Insert the listener in the array.
listeners.splice( i + 1, 0, listenerFirer );
return { removeListener: removeListener };
}
}
// If no position has been found (or zero length), put it in
// the front of list.
listeners.unshift( listenerFirer );
}
return { removeListener: removeListener };
},
/**
* Similiar with {@link #on} but the listener will be called only once upon the next event firing.
*
* @see CKEDITOR.event#on
*/
once: function() {
var args = Array.prototype.slice.call( arguments ),
fn = args[ 1 ];
args[ 1 ] = function( evt ) {
evt.removeListener();
return fn.apply( this, arguments );
};
return this.on.apply( this, args );
},
/**
* @static
* @property {Boolean} useCapture
* @todo
*/
/**
* Register event handler under the capturing stage on supported target.
*/
capture: function() {
CKEDITOR.event.useCapture = 1;
var retval = this.on.apply( this, arguments );
CKEDITOR.event.useCapture = 0;
return retval;
},
/**
* Fires an specific event in the object. All registered listeners are
* called at this point.
*
* someObject.on( 'someEvent', function() { ... } );
* someObject.on( 'someEvent', function() { ... } );
* someObject.fire( 'someEvent' ); // Both listeners are called.
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.data ); // 'Example'
* } );
* someObject.fire( 'someEvent', 'Example' );
*
* @method
* @param {String} eventName The event name to fire.
* @param {Object} [data] Data to be sent as the
* {@link CKEDITOR.eventInfo#data} when calling the listeners.
* @param {CKEDITOR.editor} [editor] The editor instance to send as the
* {@link CKEDITOR.eventInfo#editor} when calling the listener.
* @returns {Boolean/Object} A boolean indicating that the event is to be
* canceled, or data returned by one of the listeners.
*/
fire: ( function() {
// Create the function that marks the event as stopped.
var stopped = 0;
var stopEvent = function() {
stopped = 1;
};
// Create the function that marks the event as canceled.
var canceled = 0;
var cancelEvent = function() {
canceled = 1;
};
return function( eventName, data, editor ) {
// Get the event entry.
var event = getPrivate( this )[ eventName ];
// Save the previous stopped and cancelled states. We may
// be nesting fire() calls.
var previousStopped = stopped,
previousCancelled = canceled;
// Reset the stopped and canceled flags.
stopped = canceled = 0;
if ( event ) {
var listeners = event.listeners;
if ( listeners.length ) {
// As some listeners may remove themselves from the
// event, the original array length is dinamic. So,
// let's make a copy of all listeners, so we are
// sure we'll call all of them.
listeners = listeners.slice( 0 );
var retData;
// Loop through all listeners.
for ( var i = 0; i < listeners.length; i++ ) {
// Call the listener, passing the event data.
if ( event.errorProof ) {
try {
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
} catch ( er ) {}
} else {
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
}
if ( retData === EVENT_CANCELED )
canceled = 1;
else if ( typeof retData != 'undefined' )
data = retData;
// No further calls is stopped or canceled.
if ( stopped || canceled )
break;
}
}
}
var ret = canceled ? false : ( typeof data == 'undefined' ? true : data );
// Restore the previous stopped and canceled states.
stopped = previousStopped;
canceled = previousCancelled;
return ret;
};
} )(),
/**
* Fires an specific event in the object, releasing all listeners
* registered to that event. The same listeners are not called again on
* successive calls of it or of {@link #fire}.
*
* someObject.on( 'someEvent', function() { ... } );
* someObject.fire( 'someEvent' ); // Above listener called.
* someObject.fireOnce( 'someEvent' ); // Above listener called.
* someObject.fire( 'someEvent' ); // No listeners called.
*
* @param {String} eventName The event name to fire.
* @param {Object} [data] Data to be sent as the
* {@link CKEDITOR.eventInfo#data} when calling the listeners.
* @param {CKEDITOR.editor} [editor] The editor instance to send as the
* {@link CKEDITOR.eventInfo#editor} when calling the listener.
* @returns {Boolean/Object} A booloan indicating that the event is to be
* canceled, or data returned by one of the listeners.
*/
fireOnce: function( eventName, data, editor ) {
var ret = this.fire( eventName, data, editor );
delete getPrivate( this )[ eventName ];
return ret;
},
/**
* Unregisters a listener function from being called at the specified
* event. No errors are thrown if the listener has not been registered previously.
*
* var myListener = function() { ... };
* someObject.on( 'someEvent', myListener );
* someObject.fire( 'someEvent' ); // myListener called.
* someObject.removeListener( 'someEvent', myListener );
* someObject.fire( 'someEvent' ); // myListener not called.
*
* @param {String} eventName The event name.
* @param {Function} listenerFunction The listener function to unregister.
*/
removeListener: function( eventName, listenerFunction ) {
// Get the event entry.
var event = getPrivate( this )[ eventName ];
if ( event ) {
var index = event.getListenerIndex( listenerFunction );
if ( index >= 0 )
event.listeners.splice( index, 1 );
}
},
/**
* Remove all existing listeners on this object, for cleanup purpose.
*/
removeAllListeners: function() {
var events = getPrivate( this );
for ( var i in events )
delete events[ i ];
},
/**
* Checks if there is any listener registered to a given event.
*
* var myListener = function() { ... };
* someObject.on( 'someEvent', myListener );
* alert( someObject.hasListeners( 'someEvent' ) ); // true
* alert( someObject.hasListeners( 'noEvent' ) ); // false
*
* @param {String} eventName The event name.
* @returns {Boolean}
*/
hasListeners: function( eventName ) {
var event = getPrivate( this )[ eventName ];
return ( event && event.listeners.length > 0 );
}
};
} )();
}
} )();

View file

@ -1,115 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.eventInfo} class, which
* contains the defintions of the event object passed to event listeners.
* This file is for documentation purposes only.
*/
/**
* Virtual class that illustrates the features of the event object to be
* passed to event listeners by a {@link CKEDITOR.event} based object.
*
* This class is not really part of the API.
*
* @class CKEDITOR.eventInfo
* @abstract
*/
/**
* The event name.
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.name ); // 'someEvent'
* } );
* someObject.fire( 'someEvent' );
*
* @property {String} name
*/
/**
* The object that publishes (sends) the event.
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.sender == someObject ); // true
* } );
* someObject.fire( 'someEvent' );
*
* @property sender
*/
/**
* The editor instance that holds the sender. May be the same as sender. May be
* null if the sender is not part of an editor instance, like a component
* running in standalone mode.
*
* myButton.on( 'someEvent', function( event ) {
* alert( event.editor == myEditor ); // true
* } );
* myButton.fire( 'someEvent', null, myEditor );
*
* @property {CKEDITOR.editor} editor
*/
/**
* Any kind of additional data. Its format and usage is event dependent.
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.data ); // 'Example'
* } );
* someObject.fire( 'someEvent', 'Example' );
*
* @property data
*/
/**
* Any extra data appended during the listener registration.
*
* someObject.on( 'someEvent', function( event ) {
* alert( event.listenerData ); // 'Example'
* }, null, 'Example' );
*
* @property listenerData
*/
/**
* Indicates that no further listeners are to be called.
*
* someObject.on( 'someEvent', function( event ) {
* event.stop();
* } );
* someObject.on( 'someEvent', function( event ) {
* // This one will not be called.
* } );
* alert( someObject.fire( 'someEvent' ) ); // true
*
* @method stop
*/
/**
* Indicates that the event is to be cancelled (if cancelable).
*
* someObject.on( 'someEvent', function( event ) {
* event.cancel();
* } );
* someObject.on( 'someEvent', function( event ) {
* // This one will not be called.
* } );
* alert( someObject.fire( 'someEvent' ) ); // false
*
* @method cancel
*/
/**
* Removes the current listener.
*
* someObject.on( 'someEvent', function( event ) {
* event.removeListener();
* // Now this function won't be called again by 'someEvent'.
* } );
*
* @method removeListener
*/

File diff suppressed because it is too large Load diff

View file

@ -1,275 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.focusManager} class, which is used
* to handle the focus in editor instances.
*/
( function() {
/**
* Manages the focus activity in an editor instance. This class is to be
* used mainly by UI element coders when adding interface elements that need
* to set the focus state of the editor.
*
* var focusManager = new CKEDITOR.focusManager( editor );
* focusManager.focus();
*
* @class
* @constructor Creates a focusManager class instance.
* @param {CKEDITOR.editor} editor The editor instance.
*/
CKEDITOR.focusManager = function( editor ) {
if ( editor.focusManager )
return editor.focusManager;
/**
* Indicates that the editor instance has focus.
*
* alert( CKEDITOR.instances.editor1.focusManager.hasFocus ); // e.g. true
*/
this.hasFocus = false;
/**
* Indicates the currently focused DOM element that makes the editor activated.
*
* @property {CKEDITOR.dom.domObject}
*/
this.currentActive = null;
/**
* Object used to store private stuff.
*
* @private
*/
this._ = {
editor: editor
};
return this;
};
var SLOT_NAME = 'focusmanager',
SLOT_NAME_LISTENERS = 'focusmanager_handlers';
/**
* Object used to store private stuff.
*
* @private
* @class
* @singleton
*/
CKEDITOR.focusManager._ = {
/**
* The delay (in milliseconds) to deactivate the editor when a UI DOM element has lost focus.
*
* @private
* @property {Number} [blurDelay=200]
* @member CKEDITOR.focusManager._
*/
blurDelay: 200
};
CKEDITOR.focusManager.prototype = {
/**
* Indicates that this editor instance is activated (due to a DOM focus change).
* The `activated` state is a symbolic indicator of an active user
* interaction session.
*
* **Note:** This method will not introduce UI focus
* impact on DOM, it is here to record the editor UI focus state internally.
* If you want to make the cursor blink inside the editable, use
* {@link CKEDITOR.editor#method-focus} instead.
*
* var editor = CKEDITOR.instances.editor1;
* editor.focusManager.focus( editor.editable() );
*
* @param {CKEDITOR.dom.element} [currentActive] The new value of the {@link #currentActive} property.
* @member CKEDITOR.focusManager
*/
focus: function( currentActive ) {
if ( this._.timer )
clearTimeout( this._.timer );
if ( currentActive )
this.currentActive = currentActive;
if ( !( this.hasFocus || this._.locked ) ) {
// If another editor has the current focus, we first "blur" it. In
// this way the events happen in a more logical sequence, like:
// "focus 1" > "blur 1" > "focus 2"
// ... instead of:
// "focus 1" > "focus 2" > "blur 1"
var current = CKEDITOR.currentInstance;
current && current.focusManager.blur( 1 );
this.hasFocus = true;
var ct = this._.editor.container;
ct && ct.addClass( 'cke_focus' );
this._.editor.fire( 'focus' );
}
},
/**
* Prevents from changing the focus manager state until the next {@link #unlock} is called.
*
* @member CKEDITOR.focusManager
*/
lock: function() {
this._.locked = 1;
},
/**
* Restores the automatic focus management if {@link #lock} is called.
*
* @member CKEDITOR.focusManager
*/
unlock: function() {
delete this._.locked;
},
/**
* Used to indicate that the editor instance has been deactivated by the specified
* element which has just lost focus.
*
* **Note:** This function acts asynchronously with a delay of 100ms to
* avoid temporary deactivation. Use the `noDelay` parameter instead
* to deactivate immediately.
*
* var editor = CKEDITOR.instances.editor1;
* editor.focusManager.blur();
*
* @param {Boolean} [noDelay=false] Immediately deactivate the editor instance synchronously.
* @member CKEDITOR.focusManager
*/
blur: function( noDelay ) {
if ( this._.locked ) {
return;
}
function doBlur() {
if ( this.hasFocus ) {
this.hasFocus = false;
var ct = this._.editor.container;
ct && ct.removeClass( 'cke_focus' );
this._.editor.fire( 'blur' );
}
}
if ( this._.timer ) {
clearTimeout( this._.timer );
}
var delay = CKEDITOR.focusManager._.blurDelay;
if ( noDelay || !delay ) {
doBlur.call( this );
} else {
this._.timer = CKEDITOR.tools.setTimeout( function() {
delete this._.timer;
doBlur.call( this );
}, delay, this );
}
},
/**
* Registers a UI DOM element to the focus manager, which will make the focus manager "hasFocus"
* once the input focus is relieved on the element.
* This method is designed to be used by plugins to expand the jurisdiction of the editor focus.
*
* @param {CKEDITOR.dom.element} element The container (topmost) element of one UI part.
* @param {Boolean} isCapture If specified, {@link CKEDITOR.event#useCapture} will be used when listening to the focus event.
* @member CKEDITOR.focusManager
*/
add: function( element, isCapture ) {
var fm = element.getCustomData( SLOT_NAME );
if ( !fm || fm != this ) {
// If this element is already taken by another instance, dismiss it first.
fm && fm.remove( element );
var focusEvent = 'focus',
blurEvent = 'blur';
// Bypass the element's internal DOM focus change.
if ( isCapture ) {
// Use "focusin/focusout" events instead of capture phase in IEs,
// which fires synchronously.
if ( CKEDITOR.env.ie ) {
focusEvent = 'focusin';
blurEvent = 'focusout';
} else {
CKEDITOR.event.useCapture = 1;
}
}
var listeners = {
blur: function() {
if ( element.equals( this.currentActive ) )
this.blur();
},
focus: function() {
this.focus( element );
}
};
element.on( focusEvent, listeners.focus, this );
element.on( blurEvent, listeners.blur, this );
if ( isCapture )
CKEDITOR.event.useCapture = 0;
element.setCustomData( SLOT_NAME, this );
element.setCustomData( SLOT_NAME_LISTENERS, listeners );
}
},
/**
* Dismisses an element from the focus manager delegations added by {@link #add}.
*
* @param {CKEDITOR.dom.element} element The element to be removed from the focus manager.
* @member CKEDITOR.focusManager
*/
remove: function( element ) {
element.removeCustomData( SLOT_NAME );
var listeners = element.removeCustomData( SLOT_NAME_LISTENERS );
element.removeListener( 'blur', listeners.blur );
element.removeListener( 'focus', listeners.focus );
}
};
} )();
/**
* Fired when the editor instance receives the input focus.
*
* editor.on( 'focus', function( e ) {
* alert( 'The editor named ' + e.editor.name + ' is now focused' );
* } );
*
* @event focus
* @member CKEDITOR.editor
* @param {CKEDITOR.editor} editor The editor instance.
*/
/**
* Fired when the editor instance loses the input focus.
*
* **Note:** This event will **NOT** be triggered when focus is moved internally, e.g. from
* an editable to another part of the editor UI like a dialog window.
* If you are interested only in the focus state of the editable, listen to the `focus`
* and `blur` events of the {@link CKEDITOR.editable} instead.
*
* editor.on( 'blur', function( e ) {
* alert( 'The editor named ' + e.editor.name + ' lost the focus' );
* } );
*
* @event blur
* @member CKEDITOR.editor
* @param {CKEDITOR.editor} editor The editor instance.
*/

File diff suppressed because it is too large Load diff

View file

@ -1,205 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* Provides an "event like" system to parse strings of HTML data.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onTagOpen = function( tagName, attributes, selfClosing ) {
* alert( tagName );
* };
* parser.parse( '<p>Some <b>text</b>.</p>' ); // Alerts 'p', 'b'.
*
* @class
* @constructor Creates a htmlParser class instance.
*/
CKEDITOR.htmlParser = function() {
this._ = {
htmlPartsRegex: /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)--!?>)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g
};
};
( function() {
var attribsRegex = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,
emptyAttribs = { checked: 1, compact: 1, declare: 1, defer: 1, disabled: 1, ismap: 1, multiple: 1, nohref: 1, noresize: 1, noshade: 1, nowrap: 1, readonly: 1, selected: 1 };
CKEDITOR.htmlParser.prototype = {
/**
* Function to be fired when a tag opener is found. This function
* should be overriden when using this class.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onTagOpen = function( tagName, attributes, selfClosing ) {
* alert( tagName ); // e.g. 'b'
* } );
* parser.parse( '<!-- Example --><b>Hello</b>' );
*
* @param {String} tagName The tag name. The name is guarantted to be lowercased.
* @param {Object} attributes An object containing all tag attributes. Each
* property in this object represent and attribute name and its value is the attribute value.
* @param {Boolean} selfClosing `true` if the tag closes itself, false if the tag doesn't.
*/
onTagOpen: function() {},
/**
* Function to be fired when a tag closer is found. This function
* should be overriden when using this class.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onTagClose = function( tagName ) {
* alert( tagName ); // 'b'
* } );
* parser.parse( '<!-- Example --><b>Hello</b>' );
*
* @param {String} tagName The tag name. The name is guarantted to be lowercased.
*/
onTagClose: function() {},
/**
* Function to be fired when text is found. This function
* should be overriden when using this class.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onText = function( text ) {
* alert( text ); // 'Hello'
* } );
* parser.parse( '<!-- Example --><b>Hello</b>' );
*
* @param {String} text The text found.
*/
onText: function() {},
/**
* Function to be fired when CDATA section is found. This function
* should be overriden when using this class.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onCDATA = function( cdata ) {
* alert( cdata ); // 'var hello;'
* } );
* parser.parse( '<script>var hello;</script>' );
*
* @param {String} cdata The CDATA been found.
*/
onCDATA: function() {},
/**
* Function to be fired when a commend is found. This function
* should be overriden when using this class.
*
* var parser = new CKEDITOR.htmlParser();
* parser.onComment = function( comment ) {
* alert( comment ); // ' Example '
* } );
* parser.parse( '<!-- Example --><b>Hello</b>' );
*
* @param {String} comment The comment text.
*/
onComment: function() {},
/**
* Parses text, looking for HTML tokens, like tag openers or closers,
* or comments. This function fires the onTagOpen, onTagClose, onText
* and onComment function during its execution.
*
* var parser = new CKEDITOR.htmlParser();
* // The onTagOpen, onTagClose, onText and onComment should be overriden
* // at this point.
* parser.parse( '<!-- Example --><b>Hello</b>' );
*
* @param {String} html The HTML to be parsed.
*/
parse: function( html ) {
var parts, tagName,
nextIndex = 0,
cdata; // The collected data inside a CDATA section.
while ( ( parts = this._.htmlPartsRegex.exec( html ) ) ) {
var tagIndex = parts.index;
if ( tagIndex > nextIndex ) {
var text = html.substring( nextIndex, tagIndex );
if ( cdata )
cdata.push( text );
else
this.onText( text );
}
nextIndex = this._.htmlPartsRegex.lastIndex;
// "parts" is an array with the following items:
// 0 : The entire match for opening/closing tags and comments.
// : Group filled with the tag name for closing tags.
// 2 : Group filled with the comment text.
// 3 : Group filled with the tag name for opening tags.
// 4 : Group filled with the attributes part of opening tags.
// Closing tag
if ( ( tagName = parts[ 1 ] ) ) {
tagName = tagName.toLowerCase();
if ( cdata && CKEDITOR.dtd.$cdata[ tagName ] ) {
// Send the CDATA data.
this.onCDATA( cdata.join( '' ) );
cdata = null;
}
if ( !cdata ) {
this.onTagClose( tagName );
continue;
}
}
// If CDATA is enabled, just save the raw match.
if ( cdata ) {
cdata.push( parts[ 0 ] );
continue;
}
// Opening tag
if ( ( tagName = parts[ 3 ] ) ) {
tagName = tagName.toLowerCase();
// There are some tag names that can break things, so let's
// simply ignore them when parsing. (https://dev.ckeditor.com/ticket/5224)
if ( /="/.test( tagName ) )
continue;
var attribs = {},
attribMatch,
attribsPart = parts[ 4 ],
selfClosing = !!parts[ 5 ];
if ( attribsPart ) {
while ( ( attribMatch = attribsRegex.exec( attribsPart ) ) ) {
var attName = attribMatch[ 1 ].toLowerCase(),
attValue = attribMatch[ 2 ] || attribMatch[ 3 ] || attribMatch[ 4 ] || '';
if ( !attValue && emptyAttribs[ attName ] )
attribs[ attName ] = attName;
else
attribs[ attName ] = CKEDITOR.tools.htmlDecodeAttr( attValue );
}
}
this.onTagOpen( tagName, attribs, selfClosing );
// Open CDATA mode when finding the appropriate tags.
if ( !cdata && CKEDITOR.dtd.$cdata[ tagName ] )
cdata = [];
continue;
}
// Comment
if ( ( tagName = parts[ 2 ] ) )
this.onComment( tagName );
}
if ( html.length > nextIndex )
this.onText( html.substring( nextIndex, html.length ) );
}
};
} )();

View file

@ -1,152 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* TODO
*
* @class
* @todo
*/
CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass( {
/**
* Creates a basicWriter class instance.
*
* @constructor
*/
$: function() {
this._ = {
output: []
};
},
proto: {
/**
* Writes the tag opening part for a opener tag.
*
* // Writes '<p'.
* writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
*
* @param {String} tagName The element name for this tag.
* @param {Object} attributes The attributes defined for this tag. The
* attributes could be used to inspect the tag.
*/
openTag: function( tagName ) {
this._.output.push( '<', tagName );
},
/**
* Writes the tag closing part for a opener tag.
*
* // Writes '>'.
* writer.openTagClose( 'p', false );
*
* // Writes ' />'.
* writer.openTagClose( 'br', true );
*
* @param {String} tagName The element name for this tag.
* @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
* like `<br>` or `<img>`.
*/
openTagClose: function( tagName, isSelfClose ) {
if ( isSelfClose )
this._.output.push( ' />' );
else
this._.output.push( '>' );
},
/**
* Writes an attribute. This function should be called after opening the
* tag with {@link #openTagClose}.
*
* // Writes ' class="MyClass"'.
* writer.attribute( 'class', 'MyClass' );
*
* @param {String} attName The attribute name.
* @param {String} attValue The attribute value.
*/
attribute: function( attName, attValue ) {
// Browsers don't always escape special character in attribute values. (https://dev.ckeditor.com/ticket/4683, https://dev.ckeditor.com/ticket/4719).
if ( typeof attValue == 'string' )
attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );
this._.output.push( ' ', attName, '="', attValue, '"' );
},
/**
* Writes a closer tag.
*
* // Writes '</p>'.
* writer.closeTag( 'p' );
*
* @param {String} tagName The element name for this tag.
*/
closeTag: function( tagName ) {
this._.output.push( '</', tagName, '>' );
},
/**
* Writes text.
*
* // Writes 'Hello Word'.
* writer.text( 'Hello Word' );
*
* @param {String} text The text value.
*/
text: function( text ) {
this._.output.push( text );
},
/**
* Writes a comment.
*
* // Writes '<!-- My comment -->'.
* writer.comment( ' My comment ' );
*
* @param {String} comment The comment text.
*/
comment: function( comment ) {
this._.output.push( '<!--', comment, '-->' );
},
/**
* Writes any kind of data to the ouput.
*
* writer.write( 'This is an <b>example</b>.' );
*
* @param {String} data
*/
write: function( data ) {
this._.output.push( data );
},
/**
* Empties the current output buffer.
*
* writer.reset();
*/
reset: function() {
this._.output = [];
this._.indent = false;
},
/**
* Empties the current output buffer.
*
* var html = writer.getHtml();
*
* @param {Boolean} reset Indicates that the {@link #reset} method is to
* be automatically called after retrieving the HTML.
* @returns {String} The HTML written to the writer so far.
*/
getHtml: function( reset ) {
var html = this._.output.join( '' );
if ( reset )
this.reset();
return html;
}
}
} );

View file

@ -1,70 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
( function() {
/**
* A lightweight representation of HTML CDATA.
*
* @class
* @extends CKEDITOR.htmlParser.node
* @constructor Creates a cdata class instance.
* @param {String} value The CDATA section value.
*/
CKEDITOR.htmlParser.cdata = function( value ) {
/**
* The CDATA value.
*
* @property {String}
*/
this.value = value;
};
CKEDITOR.htmlParser.cdata.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
/**
* CDATA has the same type as {@link CKEDITOR.htmlParser.text} This is
* a constant value set to {@link CKEDITOR#NODE_TEXT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_TEXT]
*/
type: CKEDITOR.NODE_TEXT,
filter: function( filter ) {
var style = this.getAscendant( 'style' );
if ( !style ) {
return;
}
// MathML and SVG namespaces processing parsers `style` content as a normal HTML, not text.
// Make sure to filter such content also.
var nonHtmlElementNamespace = style.getAscendant( { math: 1, svg: 1 } );
if ( !nonHtmlElementNamespace ) {
return;
}
var fragment = CKEDITOR.htmlParser.fragment.fromHtml( this.value ),
writer = new CKEDITOR.htmlParser.basicWriter();
filter.applyTo( fragment );
fragment.writeHtml( writer );
this.value = writer.getHtml();
},
/**
* Writes the CDATA with no special manipulations.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
*/
writeHtml: function( writer ) {
writer.write( this.value );
}
} );
} )();

View file

@ -1,80 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
/**
* A lightweight representation of an HTML comment.
*
* @class
* @extends CKEDITOR.htmlParser.node
* @constructor Creates a comment class instance.
* @param {String} value The comment text value.
*/
CKEDITOR.htmlParser.comment = function( value ) {
/**
* The comment text.
*
* @property {String}
*/
this.value = value;
/** @private */
this._ = {
isBlockLike: false
};
};
CKEDITOR.htmlParser.comment.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_COMMENT]
*/
type: CKEDITOR.NODE_COMMENT,
/**
* Filter this comment with given filter.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.filter} filter
* @returns {Boolean} Method returns `false` when this comment has
* been removed or replaced with other node. This is an information for
* {@link CKEDITOR.htmlParser.element#filterChildren} that it has
* to repeat filter on current position in parent's children array.
*/
filter: function( filter, context ) {
var comment = this.value;
if ( !( comment = filter.onComment( context, comment, this ) ) ) {
this.remove();
return false;
}
if ( typeof comment != 'string' ) {
this.replaceWith( comment );
return false;
}
this.value = comment;
return true;
},
/**
* Writes the HTML representation of this comment to a CKEDITOR.htmlWriter.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
* **Note:** it's unsafe to filter offline (not appended) node.
*/
writeHtml: function( writer, filter ) {
if ( filter )
this.filter( filter );
writer.comment( this.value );
}
} );

View file

@ -1,593 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
/**
* A lightweight representation of an HTML element.
*
* @class
* @extends CKEDITOR.htmlParser.node
* @constructor Creates an element class instance.
* @param {String} name The element name.
* @param {Object} attributes An object storing all attributes defined for
* this element.
*/
CKEDITOR.htmlParser.element = function( name, attributes ) {
/**
* The element name.
*
* @property {String}
*/
this.name = name;
/**
* Stores the attributes defined for this element.
*
* @property {Object}
*/
this.attributes = attributes || {};
/**
* The nodes that are direct children of this element.
*/
this.children = [];
// Reveal the real semantic of our internal custom tag name (https://dev.ckeditor.com/ticket/6639),
// when resolving whether it's block like.
var realName = name || '',
prefixed = realName.match( /^cke:(.*)/ );
prefixed && ( realName = prefixed[ 1 ] );
var isBlockLike = !!( CKEDITOR.dtd.$nonBodyContent[ realName ] || CKEDITOR.dtd.$block[ realName ] ||
CKEDITOR.dtd.$listItem[ realName ] || CKEDITOR.dtd.$tableContent[ realName ] ||
CKEDITOR.dtd.$nonEditable[ realName ] || realName == 'br' );
this.isEmpty = !!CKEDITOR.dtd.$empty[ name ];
this.isUnknown = !CKEDITOR.dtd[ name ];
/** @private */
this._ = {
isBlockLike: isBlockLike,
hasInlineStarted: this.isEmpty || !isBlockLike
};
};
/**
* Object presentation of the CSS style declaration text.
*
* @class
* @constructor Creates a `cssStyle` class instance.
* @param {CKEDITOR.htmlParser.element/String} elementOrStyleText
* An HTML parser element or the inline style text.
*/
CKEDITOR.htmlParser.cssStyle = function() {
var styleText,
arg = arguments[ 0 ],
rules = {};
styleText = arg instanceof CKEDITOR.htmlParser.element ? arg.attributes.style : arg;
// html-encoded quote might be introduced by 'font-family'
// from MS-Word which confused the following regexp. e.g.
//'font-family: &quot;Lucida, Console&quot;'
// TODO reuse CSS methods from tools.
( styleText || '' ).replace( /&quot;/g, '"' ).replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) {
name == 'font-family' && ( value = value.replace( /["']/g, '' ) );
rules[ name.toLowerCase() ] = value;
} );
return {
rules: rules,
/**
* Applies the styles to the specified element or object.
*
* @param {CKEDITOR.htmlParser.element/CKEDITOR.dom.element/Object} obj
*/
populate: function( obj ) {
var style = this.toString();
if ( style )
obj instanceof CKEDITOR.dom.element ? obj.setAttribute( 'style', style ) : obj instanceof CKEDITOR.htmlParser.element ? obj.attributes.style = style : obj.style = style;
},
/**
* Serializes CSS style declaration to a string.
*
* @returns {String}
*/
toString: function() {
var output = [];
for ( var i in rules )
rules[ i ] && output.push( i, ':', rules[ i ], ';' );
return output.join( '' );
}
};
};
/** @class CKEDITOR.htmlParser.element */
( function() {
// Used to sort attribute entries in an array, where the first element of
// each object is the attribute name.
var sortAttribs = function( a, b ) {
a = a[ 0 ];
b = b[ 0 ];
return a < b ? -1 : a > b ? 1 : 0;
},
fragProto = CKEDITOR.htmlParser.fragment.prototype;
CKEDITOR.htmlParser.element.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_ELEMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_ELEMENT]
*/
type: CKEDITOR.NODE_ELEMENT,
/**
* Adds a node to the element children list.
*
* @method
* @param {CKEDITOR.htmlParser.node} node The node to be added.
* @param {Number} [index] From where the insertion happens.
*/
add: fragProto.add,
/**
* Clones this element.
*
* @returns {CKEDITOR.htmlParser.element} The element clone.
*/
clone: function() {
return new CKEDITOR.htmlParser.element( this.name, this.attributes );
},
/**
* Filters this element and its children with the given filter.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.filter} filter
* @returns {Boolean} The method returns `false` when this element has
* been removed or replaced with another. This information means that
* {@link #filterChildren} has to repeat the filter on the current
* position in parent's children array.
*/
filter: function( filter, context ) {
var element = this,
originalName, name;
context = element.getFilterContext( context );
// Filtering if it's the root node.
if ( !element.parent )
filter.onRoot( context, element );
while ( true ) {
originalName = element.name;
if ( !( name = filter.onElementName( context, originalName ) ) ) {
this.remove();
return false;
}
element.name = name;
if ( !( element = filter.onElement( context, element ) ) ) {
this.remove();
return false;
}
// New element has been returned - replace current one
// and process it (stop processing this and return false, what
// means that element has been removed).
if ( element !== this ) {
this.replaceWith( element );
return false;
}
// If name has been changed - continue loop, so in next iteration
// filters for new name will be applied to this element.
// If name hasn't been changed - stop.
if ( element.name == originalName )
break;
// If element has been replaced with something of a
// different type, then make the replacement filter itself.
if ( element.type != CKEDITOR.NODE_ELEMENT ) {
this.replaceWith( element );
return false;
}
// This indicate that the element has been dropped by
// filter but not the children.
if ( !element.name ) {
this.replaceWithChildren();
return false;
}
}
var attributes = element.attributes,
a, value, newAttrName;
for ( a in attributes ) {
newAttrName = a;
value = attributes[ a ];
// Loop until name isn't modified.
// A little bit senseless, but IE would do that anyway
// because it iterates with for-in loop even over properties
// created during its run.
while ( true ) {
if ( !( newAttrName = filter.onAttributeName( context, a ) ) ) {
delete attributes[ a ];
break;
} else if ( newAttrName != a ) {
delete attributes[ a ];
a = newAttrName;
continue;
} else {
break;
}
}
if ( newAttrName ) {
if ( ( value = filter.onAttribute( context, element, newAttrName, value ) ) === false )
delete attributes[ newAttrName ];
else
attributes[ newAttrName ] = value;
}
}
if ( !element.isEmpty )
this.filterChildren( filter, false, context );
return true;
},
/**
* Filters this element's children with the given filter.
*
* Element's children may only be filtered once by one
* instance of the filter.
*
* @method filterChildren
* @param {CKEDITOR.htmlParser.filter} filter
*/
filterChildren: fragProto.filterChildren,
/**
* Writes the element HTML to the CKEDITOR.htmlWriter.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
* **Note:** It is unsafe to filter an offline (not appended) node.
*/
writeHtml: function( writer, filter ) {
if ( filter )
this.filter( filter );
var name = this.name,
attribsArray = [],
attributes = this.attributes,
attrName,
attr, i, l;
// Open element tag.
writer.openTag( name, attributes );
// Copy all attributes to an array.
for ( attrName in attributes )
attribsArray.push( [ attrName, attributes[ attrName ] ] );
// Sort the attributes by name.
if ( writer.sortAttributes )
attribsArray.sort( sortAttribs );
// Send the attributes.
for ( i = 0, l = attribsArray.length; i < l; i++ ) {
attr = attribsArray[ i ];
writer.attribute( attr[ 0 ], attr[ 1 ] );
}
// Close the tag.
writer.openTagClose( name, this.isEmpty );
this.writeChildrenHtml( writer );
// Close the element.
if ( !this.isEmpty )
writer.closeTag( name );
},
/**
* Sends children of this element to the writer.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
* @param {CKEDITOR.htmlParser.filter} [filter]
*/
writeChildrenHtml: fragProto.writeChildrenHtml,
/**
* Replaces this element with its children.
*
* @since 4.1.0
*/
replaceWithChildren: function() {
var children = this.children;
for ( var i = children.length; i; )
children[ --i ].insertAfter( this );
this.remove();
},
/**
* Executes a callback on each node (of the given type) in this element.
*
* // Create a <p> element with foo<b>bar</b>bom as its content.
* var elP = CKEDITOR.htmlParser.fragment.fromHtml( 'foo<b>bar</b>bom', 'p' );
* elP.forEach( function( node ) {
* console.log( node );
* } );
* // Will log:
* // 1. document fragment,
* // 2. <p> element,
* // 3. "foo" text node,
* // 4. <b> element,
* // 5. "bar" text node,
* // 6. "bom" text node.
*
* @since 4.1.0
* @param {Function} callback Function to be executed on every node.
* **Since 4.3**: If `callback` returned `false`, the descendants of the current node will be ignored.
* @param {CKEDITOR.htmlParser.node} callback.node Node passed as an argument.
* @param {Number} [type] Whether the specified `callback` will be executed only on nodes of this type.
* @param {Boolean} [skipRoot] Do not execute `callback` on this element.
*/
forEach: fragProto.forEach,
/**
* Gets this element's first child. If `condition` is given, this method returns
* the first child which satisfies that condition.
*
* @since 4.3.0
* @param {String/Object/Function} condition Name of a child, a hash of names, or a validator function.
* @returns {CKEDITOR.htmlParser.node}
*/
getFirst: function( condition ) {
if ( !condition )
return this.children.length ? this.children[ 0 ] : null;
if ( typeof condition != 'function' )
condition = nameCondition( condition );
for ( var i = 0, l = this.children.length; i < l; ++i ) {
if ( condition( this.children[ i ] ) )
return this.children[ i ];
}
return null;
},
/**
* Gets this element's inner HTML.
*
* @since 4.3.0
* @returns {String}
*/
getHtml: function() {
var writer = new CKEDITOR.htmlParser.basicWriter();
this.writeChildrenHtml( writer );
return writer.getHtml();
},
/**
* Sets this element's inner HTML.
*
* @since 4.3.0
* @param {String} html
*/
setHtml: function( html ) {
var children = this.children = CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
for ( var i = 0, l = children.length; i < l; ++i )
children[ i ].parent = this;
},
/**
* Gets this element's outer HTML.
*
* @since 4.3.0
* @returns {String}
*/
getOuterHtml: function() {
var writer = new CKEDITOR.htmlParser.basicWriter();
this.writeHtml( writer );
return writer.getHtml();
},
/**
* Splits this element at the given index.
*
* @since 4.3.0
* @param {Number} index Index at which the element will be split &mdash; `0` means the beginning,
* `1` after the first child node, etc.
* @returns {CKEDITOR.htmlParser.element} The new element following this one.
*/
split: function( index ) {
var cloneChildren = this.children.splice( index, this.children.length - index ),
clone = this.clone();
for ( var i = 0; i < cloneChildren.length; ++i )
cloneChildren[ i ].parent = clone;
clone.children = cloneChildren;
if ( cloneChildren[ 0 ] )
cloneChildren[ 0 ].previous = null;
if ( index > 0 )
this.children[ index - 1 ].next = null;
this.parent.add( clone, this.getIndex() + 1 );
return clone;
},
/**
* Searches through the current node children to find nodes matching the `criteria`.
*
* @param {String/Function} criteria Tag name or evaluator function.
* @param {Boolean} [recursive=false]
* @returns {CKEDITOR.htmlParser.node[]}
*/
find: function( criteria, recursive ) {
if ( recursive === undefined ) {
recursive = false;
}
var ret = [],
i;
for ( i = 0; i < this.children.length; i++ ) {
var curChild = this.children[ i ];
if ( typeof criteria == 'function' && criteria( curChild ) ) {
ret.push( curChild );
} else if ( typeof criteria == 'string' && curChild.name === criteria ) {
ret.push( curChild );
}
if ( recursive && curChild.find ) {
ret = ret.concat( curChild.find( criteria, recursive ) );
}
}
return ret;
},
/**
* Searches through the children of the current element to find the first child matching the `criteria`.
*
* ```js
* element.findOne( function( child ) {
* return child.name === 'span' || child.name === 'strong';
* } ); // Will return the first child which is a <span> or a <strong> element.
* ```
*
* @param {String/Function} criteria Tag name or evaluator function.
* @param {Boolean} [recursive=false] If set to `true`, it will iterate over all descendants. Otherwise the method will
* only iterate over direct children.
* @returns {CKEDITOR.htmlParser.node/null} The first matched child, `null` otherwise.
*/
findOne: function( criteria, recursive ) {
var nestedMatch = null,
match = CKEDITOR.tools.array.find( this.children, function( child ) {
var isMatching = typeof criteria === 'function' ? criteria( child ) : child.name === criteria;
if ( isMatching || !recursive ) {
return isMatching;
}
if ( child.children && child.findOne ) {
nestedMatch = child.findOne( criteria, true );
}
return !!nestedMatch;
} );
return nestedMatch || match || null;
},
/**
* Adds a class name to the list of classes.
*
* @since 4.4.0
* @param {String} className The class name to be added.
*/
addClass: function( className ) {
if ( this.hasClass( className ) )
return;
var c = this.attributes[ 'class' ] || '';
this.attributes[ 'class' ] = c + ( c ? ' ' : '' ) + className;
},
/**
* Removes a class name from the list of classes.
*
* @since 4.3.0
* @param {String} className The class name to be removed.
*/
removeClass: function( className ) {
var classes = this.attributes[ 'class' ];
if ( !classes )
return;
// We can safely assume that className won't break regexp.
// http://stackoverflow.com/questions/448981/what-characters-are-valid-in-css-class-names
classes = CKEDITOR.tools.trim( classes.replace( new RegExp( '(?:\\s+|^)' + className + '(?:\\s+|$)' ), ' ' ) );
if ( classes )
this.attributes[ 'class' ] = classes;
else
delete this.attributes[ 'class' ];
},
/**
* Checkes whether this element has a class name.
*
* @since 4.3.0
* @param {String} className The class name to be checked.
* @returns {Boolean} Whether this element has a `className`.
*/
hasClass: function( className ) {
var classes = this.attributes[ 'class' ];
if ( !classes )
return false;
return ( new RegExp( '(?:^|\\s)' + className + '(?=\\s|$)' ) ).test( classes );
},
getFilterContext: function( ctx ) {
var changes = [];
if ( !ctx ) {
ctx = {
nonEditable: false,
nestedEditable: false
};
}
if ( !ctx.nonEditable && this.attributes.contenteditable == 'false' )
changes.push( 'nonEditable', true );
// A context to be given nestedEditable must be nonEditable first (by inheritance) (https://dev.ckeditor.com/ticket/11372, https://dev.ckeditor.com/ticket/11698).
// Special case: https://dev.ckeditor.com/ticket/11504 - filter starts on <body contenteditable=true>,
// so ctx.nonEditable has not been yet set to true.
else if ( ctx.nonEditable && !ctx.nestedEditable && this.attributes.contenteditable == 'true' )
changes.push( 'nestedEditable', true );
if ( changes.length ) {
ctx = CKEDITOR.tools.copy( ctx );
for ( var i = 0; i < changes.length; i += 2 )
ctx[ changes[ i ] ] = changes[ i + 1 ];
}
return ctx;
}
}, true );
function nameCondition( condition ) {
return function( el ) {
return el.type == CKEDITOR.NODE_ELEMENT &&
( typeof condition == 'string' ? el.name == condition : el.name in condition );
};
}
} )();

View file

@ -1,402 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
( function() {
/**
* Filter is a configurable tool for transforming and filtering {@link CKEDITOR.htmlParser.node nodes}.
* It is mainly used during data processing phase which is done not on real DOM nodes,
* but on their simplified form represented by {@link CKEDITOR.htmlParser.node} class and its subclasses.
*
* var filter = new CKEDITOR.htmlParser.filter( {
* text: function( value ) {
* return '@' + value + '@';
* },
* elements: {
* p: function( element ) {
* element.attributes.foo = '1';
* }
* }
* } );
*
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>Foo<b>bar!</b></p>' ),
* writer = new CKEDITOR.htmlParser.basicWriter();
* filter.applyTo( fragment );
* fragment.writeHtml( writer );
* writer.getHtml(); // '<p foo="1">@Foo@<b>@bar!@</b></p>'
*
* @class
*/
CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass( {
/**
* @constructor Creates a filter class instance.
* @param {CKEDITOR.htmlParser.filterRulesDefinition} [rules]
*/
$: function( rules ) {
/**
* ID of filter instance, which is used to mark elements
* to which this filter has been already applied.
*
* @property {Number} id
* @readonly
*/
this.id = CKEDITOR.tools.getNextNumber();
/**
* Rules for element names.
*
* @property {CKEDITOR.htmlParser.filterRulesGroup}
* @readonly
*/
this.elementNameRules = new filterRulesGroup();
/**
* Rules for attribute names.
*
* @property {CKEDITOR.htmlParser.filterRulesGroup}
* @readonly
*/
this.attributeNameRules = new filterRulesGroup();
/**
* Hash of elementName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for elements}.
*
* @readonly
*/
this.elementsRules = {};
/**
* Hash of attributeName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for attributes}.
*
* @readonly
*/
this.attributesRules = {};
/**
* Rules for text nodes.
*
* @property {CKEDITOR.htmlParser.filterRulesGroup}
* @readonly
*/
this.textRules = new filterRulesGroup();
/**
* Rules for comment nodes.
*
* @property {CKEDITOR.htmlParser.filterRulesGroup}
* @readonly
*/
this.commentRules = new filterRulesGroup();
/**
* Rules for a root node.
*
* @property {CKEDITOR.htmlParser.filterRulesGroup}
* @readonly
*/
this.rootRules = new filterRulesGroup();
if ( rules )
this.addRules( rules, 10 );
},
proto: {
/**
* Add rules to this filter.
*
* @param {CKEDITOR.htmlParser.filterRulesDefinition} rules Object containing filter rules.
* @param {Object/Number} [options] Object containing rules' options or a priority
* (for a backward compatibility with CKEditor versions up to 4.2.x).
* @param {Number} [options.priority=10] The priority of a rule.
* @param {Boolean} [options.applyToAll=false] Whether to apply rule to non-editable
* elements and their descendants too.
*/
addRules: function( rules, options ) {
var priority;
// Backward compatibility.
if ( typeof options == 'number' )
priority = options;
// New version - try reading from options.
else if ( options && ( 'priority' in options ) )
priority = options.priority;
// Defaults.
if ( typeof priority != 'number' )
priority = 10;
if ( typeof options != 'object' )
options = {};
// Add the elementNames.
if ( rules.elementNames )
this.elementNameRules.addMany( rules.elementNames, priority, options );
// Add the attributeNames.
if ( rules.attributeNames )
this.attributeNameRules.addMany( rules.attributeNames, priority, options );
// Add the elements.
if ( rules.elements )
addNamedRules( this.elementsRules, rules.elements, priority, options );
// Add the attributes.
if ( rules.attributes )
addNamedRules( this.attributesRules, rules.attributes, priority, options );
// Add the text.
if ( rules.text )
this.textRules.add( rules.text, priority, options );
// Add the comment.
if ( rules.comment )
this.commentRules.add( rules.comment, priority, options );
// Add root node rules.
if ( rules.root )
this.rootRules.add( rules.root, priority, options );
},
/**
* Apply this filter to given node.
*
* @param {CKEDITOR.htmlParser.node} node The node to be filtered.
*/
applyTo: function( node ) {
node.filter( this );
},
onElementName: function( context, name ) {
return this.elementNameRules.execOnName( context, name );
},
onAttributeName: function( context, name ) {
return this.attributeNameRules.execOnName( context, name );
},
onText: function( context, text, node ) {
return this.textRules.exec( context, text, node );
},
onComment: function( context, commentText, comment ) {
return this.commentRules.exec( context, commentText, comment );
},
onRoot: function( context, element ) {
return this.rootRules.exec( context, element );
},
onElement: function( context, element ) {
// We must apply filters set to the specific element name as
// well as those set to the generic ^/$ name. So, add both to an
// array and process them in a small loop.
var rulesGroups = [ this.elementsRules[ '^' ], this.elementsRules[ element.name ], this.elementsRules.$ ],
rulesGroup, ret;
for ( var i = 0; i < 3; i++ ) {
rulesGroup = rulesGroups[ i ];
if ( rulesGroup ) {
ret = rulesGroup.exec( context, element, this );
if ( ret === false )
return null;
if ( ret && ret != element )
return this.onNode( context, ret );
// The non-root element has been dismissed by one of the filters.
if ( element.parent && !element.name )
break;
}
}
return element;
},
onNode: function( context, node ) {
var type = node.type;
return type == CKEDITOR.NODE_ELEMENT ? this.onElement( context, node ) :
type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( context, node.value, node ) ) :
type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( context, node.value, node ) ) : null;
},
onAttribute: function( context, element, name, value ) {
var rulesGroup = this.attributesRules[ name ];
if ( rulesGroup )
return rulesGroup.exec( context, value, element, this );
return value;
}
}
} );
/**
* Class grouping filter rules for one subject (like element or attribute names).
*
* @class CKEDITOR.htmlParser.filterRulesGroup
*/
function filterRulesGroup() {
/**
* Array of objects containing rule, priority and options.
*
* @property {Object[]}
* @readonly
*/
this.rules = [];
}
CKEDITOR.htmlParser.filterRulesGroup = filterRulesGroup;
filterRulesGroup.prototype = {
/**
* Adds specified rule to this group.
*
* @param {Function/Array} rule Function for function based rule or [ pattern, replacement ] array for
* rule applicable to names.
* @param {Number} priority
* @param options
*/
add: function( rule, priority, options ) {
this.rules.splice( this.findIndex( priority ), 0, {
value: rule,
priority: priority,
options: options
} );
},
/**
* Adds specified rules to this group.
*
* @param {Array} rules Array of rules - see {@link #add}.
* @param {Number} priority
* @param options
*/
addMany: function( rules, priority, options ) {
var args = [ this.findIndex( priority ), 0 ];
for ( var i = 0, len = rules.length; i < len; i++ ) {
args.push( {
value: rules[ i ],
priority: priority,
options: options
} );
}
this.rules.splice.apply( this.rules, args );
},
/**
* Finds an index at which rule with given priority should be inserted.
*
* @param {Number} priority
* @returns {Number} Index.
*/
findIndex: function( priority ) {
var rules = this.rules,
len = rules.length,
i = len - 1;
// Search from the end, because usually rules will be added with default priority, so
// we will be able to stop loop quickly.
while ( i >= 0 && priority < rules[ i ].priority )
i--;
return i + 1;
},
/**
* Executes this rules group on given value. Applicable only if function based rules were added.
*
* All arguments passed to this function will be forwarded to rules' functions.
*
* @param {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} currentValue The value to be filtered.
* @returns {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} Filtered value.
*/
exec: function( context, currentValue ) {
var isNode = currentValue instanceof CKEDITOR.htmlParser.node || currentValue instanceof CKEDITOR.htmlParser.fragment,
// Splice '1' to remove context, which we don't want to pass to filter rules.
args = Array.prototype.slice.call( arguments, 1 ),
rules = this.rules,
len = rules.length,
orgType, orgName, ret, i, rule;
for ( i = 0; i < len; i++ ) {
// Backup the node info before filtering.
if ( isNode ) {
orgType = currentValue.type;
orgName = currentValue.name;
}
rule = rules[ i ];
if ( isRuleApplicable( context, rule ) ) {
ret = rule.value.apply( null, args );
if ( ret === false )
return ret;
// We're filtering node (element/fragment).
// No further filtering if it's not anymore fitable for the subsequent filters.
if ( isNode && ret && ( ret.name != orgName || ret.type != orgType ) )
return ret;
// Update currentValue and corresponding argument in args array.
// Updated values will be used in next for-loop step.
if ( ret != null )
args[ 0 ] = currentValue = ret;
// ret == undefined will continue loop as nothing has happened.
}
}
return currentValue;
},
/**
* Executes this rules group on name. Applicable only if filter rules for names were added.
*
* @param {String} currentName The name to be filtered.
* @returns {String} Filtered name.
*/
execOnName: function( context, currentName ) {
var i = 0,
rules = this.rules,
len = rules.length,
rule;
for ( ; currentName && i < len; i++ ) {
rule = rules[ i ];
if ( isRuleApplicable( context, rule ) )
currentName = currentName.replace( rule.value[ 0 ], rule.value[ 1 ] );
}
return currentName;
}
};
function addNamedRules( rulesGroups, newRules, priority, options ) {
var ruleName, rulesGroup;
for ( ruleName in newRules ) {
rulesGroup = rulesGroups[ ruleName ];
if ( !rulesGroup )
rulesGroup = rulesGroups[ ruleName ] = new filterRulesGroup();
rulesGroup.add( newRules[ ruleName ], priority, options );
}
}
function isRuleApplicable( context, rule ) {
if ( context.nonEditable && !rule.options.applyToAll )
return false;
if ( context.nestedEditable && rule.options.excludeNestedEditable )
return false;
return true;
}
} )();

View file

@ -1,156 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.htmlParser.filterRulesDefinition} class
* that contains the definition of filter rules. This file is for
* documentation purposes only.
*/
/**
* Abstract class describing the definition of {@link CKEDITOR.htmlParser.filter} rules.
*
* Definition object represents rules as a set of properties with callback functions
* to be applied for transforming and filtering content upon data processing.
*
* It can be used with {@link CKEDITOR.htmlParser.filter} and {@link CKEDITOR.htmlParser.filter#addRules}.
*
* @class CKEDITOR.htmlParser.filterRulesDefinition
* @abstract
*/
/**
* @property {CKEDITOR.htmlParser.nameTransformRule[]} elementNames An array of rules for element names transformation.
* Every rule match will be replaced by the given string.
*
* Examples:
*
* ```javascript
* elementNames: [
* [ /^div$/, 'p' ], // Converts 'div' into 'p'.
* [ /^cke:?/, '' ] // Removes 'cke:' prefixes.
* ]
* ```
*
*/
/**
* @property {CKEDITOR.htmlParser.nameTransformRule[]} attributeNames An array of rules for attribute names transformation.
* Every matching string from the first item will be converted into the second.
*
* Examples:
*
* ```javascript
* attributeNames: [
* [ 'data-foo', 'data-bar' ],
* // Converts the string in the attribute name from 'data-foo' into 'data-bar'.
* // Note that the 'data-foo-baz' attribute will be converted into 'data-bar-baz'.
*
* [ /^data-custom$/, 'data-cke' ]
* // Converts the 'data-custom' attribute into 'data-cke'.
* ]
* ```
*
*/
/**
* @property {Object.<String, Function>} elements An object containing pairs of element selectors
* and functions used upon element filtering and transformation.
*
* A selector can be either an element name or one of the following: `^`, `$`.
*
* `^` and `$` are to be applied on every filtered element. The first is applied before the element-specific filter,
* and the second is applied after the element-specific filter.
*
* The function can contain a return statement:
*
* * If `false` is returned, the element is removed.
* * If another element is returned, it overwrites the original element.
*
* Examples:
*
* ```javascript
* elements: {
* '^': function( element ) {
* // Element transformation to be applied on every filtered element.
* // This will be applied as the first filter.
* },
* div: function( element ) {
* // Element transformation.
* },
* p: function() {
* return false; // Removes each '<p>' element.
* },
* '$': function( element ) {
* // Element transformation to be applied on every filtered element.
* // This will be applied after other defined filters.
* },
* }
* ```
*
*/
/**
* @property {Object.<String, Function>} attributes An object containing pairs of element attribute names
* and functions used upon attribute filtering and transformation.
*
* Returning `false` removes the attribute.
*
* Examples:
*
* ```javascript
* attributes: {
* 'class': function( value, element ) {
* if ( element.name === 'div' ) {
* return value + ' cke_div' // Adds the 'cke_div' class to every filtered div element.
* }
* },
* id: function() {
* return false; // Removes the 'id' attribute from every filtered element.
* }
* }
* ```
*
*/
/**
* @property {Function} text Function for text content transforming. Returned value replaces text.
*
* Examples:
*
* ```javascript
* text: function( value, element ) {
* return value.toLowerCase(); // Transforms each text into lower case.
* }
* ```
*
*/
/**
* @property {Function} comment Function for comments filtering and transforming. Returned value replaces comment text.
* If `false` is returned, the comment is removed.
*
* Examples:
*
* ```javascript
* comment: function( value, element ) {
* return false; // Removes the comment.
* }
* ```
*
*/
/**
* @property {Function} root Function for root element transforming.
*
* Examples:
*
* ```javascript
* root: function( element ) {
* element.children.push( someElement ); // Appends a child to the root element.
* }
* ```
*
*/

View file

@ -1,743 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
/**
* A lightweight representation of an HTML DOM structure.
*
* @class
* @constructor Creates a fragment class instance.
*/
CKEDITOR.htmlParser.fragment = function() {
/**
* The nodes contained in the root of this fragment.
*
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
* alert( fragment.children.length ); // 2
*/
this.children = [];
/**
* Get the fragment parent. Should always be null.
*
* @property {Object} [=null]
*/
this.parent = null;
/** @private */
this._ = {
isBlockLike: true,
hasInlineStarted: false
};
};
( function() {
// Block-level elements whose internal structure should be respected during
// parser fixing.
var nonBreakingBlocks = CKEDITOR.tools.extend( { table: 1, ul: 1, ol: 1, dl: 1 }, CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl );
var listBlocks = { ol: 1, ul: 1 };
// Dtd of the fragment element, basically it accept anything except for intermediate structure, e.g. orphan <li>.
var rootDtd = CKEDITOR.tools.extend( {}, { html: 1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style: 1, script: 1 } );
// Which element to create when encountered not allowed content.
var structureFixes = {
ul: 'li',
ol: 'li',
dl: 'dd',
table: 'tbody',
tbody: 'tr',
thead: 'tr',
tfoot: 'tr',
tr: 'td'
};
function isRemoveEmpty( node ) {
// Keep marked element event if it is empty.
if ( node.attributes[ 'data-cke-survive' ] )
return false;
// Empty link is to be removed when empty but not anchor. (https://dev.ckeditor.com/ticket/7894)
return node.name == 'a' && node.attributes.href || CKEDITOR.dtd.$removeEmpty[ node.name ];
}
/**
* Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
*
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
* alert( fragment.children[ 0 ].name ); // 'b'
* alert( fragment.children[ 1 ].value ); // ' Text'
*
* @static
* @param {String} fragmentHtml The HTML to be parsed, filling the fragment.
* @param {CKEDITOR.htmlParser.element/String} [parent] Optional contextual
* element which makes the content been parsed as the content of this element and fix
* to match it.
* If not provided, then {@link CKEDITOR.htmlParser.fragment} will be used
* as the parent and it will be returned.
* @param {String/Boolean} [fixingBlock] When `parent` is a block limit element,
* and the param is a string value other than `false`, it is to
* avoid having block-less content as the direct children of parent by wrapping
* the content with a block element of the specified tag, e.g.
* when `fixingBlock` specified as `p`, the content `<body><i>foo</i></body>`
* will be fixed into `<body><p><i>foo</i></p></body>`.
* @returns {CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} The created fragment or passed `parent`.
*/
CKEDITOR.htmlParser.fragment.fromHtml = function( fragmentHtml, parent, fixingBlock ) {
var parser = new CKEDITOR.htmlParser();
var root = parent instanceof CKEDITOR.htmlParser.element ? parent : typeof parent == 'string' ? new CKEDITOR.htmlParser.element( parent ) : new CKEDITOR.htmlParser.fragment();
var pendingInline = [],
pendingBRs = [],
currentNode = root,
// Indicate we're inside a <textarea> element, spaces should be touched differently.
inTextarea = root.name == 'textarea',
// Indicate we're inside a <pre> element, spaces should be touched differently.
inPre = root.name == 'pre';
function checkPending( newTagName ) {
var pendingBRsSent;
if ( pendingInline.length > 0 ) {
for ( var i = 0; i < pendingInline.length; i++ ) {
var pendingElement = pendingInline[ i ],
pendingName = pendingElement.name,
pendingDtd = CKEDITOR.dtd[ pendingName ],
currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ];
if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) ) {
if ( !pendingBRsSent ) {
sendPendingBRs();
pendingBRsSent = 1;
}
// Get a clone for the pending element.
pendingElement = pendingElement.clone();
// Add it to the current node and make it the current,
// so the new element will be added inside of it.
pendingElement.parent = currentNode;
currentNode = pendingElement;
// Remove the pending element (back the index by one
// to properly process the next entry).
pendingInline.splice( i, 1 );
i--;
} else {
// Some element of the same type cannot be nested, flat them,
// e.g. <a href="#">foo<a href="#">bar</a></a>. (https://dev.ckeditor.com/ticket/7894)
if ( pendingName == currentNode.name )
addElement( currentNode, currentNode.parent, 1 ), i--;
}
}
}
}
function sendPendingBRs() {
while ( pendingBRs.length )
addElement( pendingBRs.shift(), currentNode );
}
function shiftBRsPosition() {
var shiftLineBreaks = CKEDITOR.config.shiftLineBreaks;
if ( shiftLineBreaks === true || !pendingBRs.length ) {
return;
}
if ( typeof shiftLineBreaks !== 'function' ) {
sendPendingBRs();
return;
}
var result = shiftLineBreaks( pendingBRs[ pendingBRs.length - 1 ] );
if ( result === true ) {
return;
}
sendPendingBRs();
if ( result instanceof CKEDITOR.htmlParser.text ) {
currentNode.add( result );
}
if ( result instanceof CKEDITOR.htmlParser.element ) {
addElement( result, currentNode );
}
}
// Rtrim empty spaces on block end boundary. (https://dev.ckeditor.com/ticket/3585)
function removeTailWhitespace( element ) {
if ( element._.isBlockLike && element.name != 'pre' && element.name != 'textarea' ) {
var length = element.children.length,
lastChild = element.children[ length - 1 ],
text;
if ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT ) {
if ( !( text = CKEDITOR.tools.rtrim( lastChild.value ) ) )
element.children.length = length - 1;
else
lastChild.value = text;
}
}
}
// Beside of simply append specified element to target, this function also takes
// care of other dirty lifts like forcing block in body, trimming spaces at
// the block boundaries etc.
//
// @param {Element} element The element to be added as the last child of {@link target}.
// @param {Element} target The parent element to relieve the new node.
// @param {Boolean} [moveCurrent=false] Don't change the "currentNode" global unless
// there's a return point node specified on the element, otherwise move current onto {@link target} node.
//
function addElement( element, target, moveCurrent ) {
target = target || currentNode || root;
// Current element might be mangled by fix body below,
// save it for restore later.
var savedCurrent = currentNode;
// Ignore any element that has already been added.
if ( element.previous === undefined ) {
if ( checkAutoParagraphing( target, element ) ) {
// Create a <p> in the fragment.
currentNode = target;
parser.onTagOpen( fixingBlock, {} );
// The new target now is the <p>.
element.returnPoint = target = currentNode;
}
removeTailWhitespace( element );
// Avoid adding empty inline.
if ( !( isRemoveEmpty( element ) && !element.children.length ) )
target.add( element );
if ( element.name == 'pre' )
inPre = false;
if ( element.name == 'textarea' )
inTextarea = false;
}
if ( element.returnPoint ) {
currentNode = element.returnPoint;
delete element.returnPoint;
} else {
currentNode = moveCurrent ? target : savedCurrent;
}
}
// Auto paragraphing should happen when inline content enters the root element.
function checkAutoParagraphing( parent, node ) {
// Check for parent that can contain block.
if ( ( parent == root || parent.name == 'body' ) && fixingBlock &&
( !parent.name || CKEDITOR.dtd[ parent.name ][ fixingBlock ] ) ) {
var name, realName;
if ( node.attributes && ( realName = node.attributes[ 'data-cke-real-element-type' ] ) )
name = realName;
else
name = node.name;
// Text node, inline elements are subjected, except for <script>/<style>.
return name && name in CKEDITOR.dtd.$inline &&
!( name in CKEDITOR.dtd.head ) &&
!node.isOrphan ||
node.type == CKEDITOR.NODE_TEXT;
}
}
// Judge whether two element tag names are likely the siblings from the same
// structural element.
function possiblySibling( tag1, tag2 ) {
if ( tag1 in CKEDITOR.dtd.$listItem || tag1 in CKEDITOR.dtd.$tableContent )
return tag1 == tag2 || tag1 == 'dt' && tag2 == 'dd' || tag1 == 'dd' && tag2 == 'dt';
return false;
}
parser.onTagOpen = function( tagName, attributes, selfClosing, optionalClose ) {
var element = new CKEDITOR.htmlParser.element( tagName, attributes );
// "isEmpty" will be always "false" for unknown elements, so we
// must force it if the parser has identified it as a selfClosing tag.
if ( element.isUnknown && selfClosing )
element.isEmpty = true;
// Check for optional closed elements, including browser quirks and manually opened blocks.
element.isOptionalClose = optionalClose;
// This is a tag to be removed if empty, so do not add it immediately.
if ( isRemoveEmpty( element ) ) {
pendingInline.push( element );
return;
} else if ( tagName == 'pre' )
inPre = true;
else if ( tagName == 'br' && inPre ) {
currentNode.add( new CKEDITOR.htmlParser.text( '\n' ) );
return;
} else if ( tagName == 'textarea' ) {
inTextarea = true;
}
if ( tagName == 'br' ) {
pendingBRs.push( element );
return;
}
while ( 1 ) {
var currentName = currentNode.name;
var currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
// If the element cannot be child of the current element.
if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) {
// Current node doesn't have a close tag, time for a close
// as this element isn't fit in. (https://dev.ckeditor.com/ticket/7497)
if ( currentNode.isOptionalClose )
parser.onTagClose( currentName );
// Fixing malformed nested lists by moving it into a previous list item. (https://dev.ckeditor.com/ticket/3828)
else if ( tagName in listBlocks && currentName in listBlocks ) {
var children = currentNode.children,
lastChild = children[ children.length - 1 ];
// Establish the list item if it's not existed.
if ( !( lastChild && lastChild.name == 'li' ) )
addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
!element.returnPoint && ( element.returnPoint = currentNode );
currentNode = lastChild;
}
// Establish new list root for orphan list items, but NOT to create
// new list for the following ones, fix them instead. (https://dev.ckeditor.com/ticket/6975)
// <dl><dt>foo<dd>bar</dl>
// <ul><li>foo<li>bar</ul>
else if ( tagName in CKEDITOR.dtd.$listItem &&
!possiblySibling( tagName, currentName ) ) {
parser.onTagOpen( tagName == 'li' ? 'ul' : 'dl', {}, 0, 1 );
}
// We're inside a structural block like table and list, AND the incoming element
// is not of the same type (e.g. <td>td1<td>td2</td>), we simply add this new one before it,
// and most importantly, return back to here once this element is added,
// e.g. <table><tr><td>td1</td><p>p1</p><td>td2</td></tr></table>
else if ( currentName in nonBreakingBlocks &&
!possiblySibling( tagName, currentName ) ) {
!element.returnPoint && ( element.returnPoint = currentNode );
currentNode = currentNode.parent;
} else {
// The current element is an inline element, which
// need to be continued even after the close, so put
// it in the pending list.
if ( currentName in CKEDITOR.dtd.$inline )
pendingInline.unshift( currentNode );
// The most common case where we just need to close the
// current one and append the new one to the parent.
if ( currentNode.parent )
addElement( currentNode, currentNode.parent, 1 );
// We've tried our best to fix the embarrassment here, while
// this element still doesn't find it's parent, mark it as
// orphan and show our tolerance to it.
else {
element.isOrphan = 1;
break;
}
}
} else {
break;
}
}
checkPending( tagName );
sendPendingBRs();
element.parent = currentNode;
if ( element.isEmpty )
addElement( element );
else
currentNode = element;
};
parser.onTagClose = function( tagName ) {
// Check if there is any pending tag to be closed.
for ( var i = pendingInline.length - 1; i >= 0; i-- ) {
// If found, just remove it from the list.
if ( tagName == pendingInline[ i ].name ) {
pendingInline.splice( i, 1 );
return;
}
}
var pendingAdd = [],
newPendingInline = [],
candidate = currentNode;
while ( candidate != root && candidate.name != tagName ) {
// If this is an inline element, add it to the pending list, if we're
// really closing one of the parents element later, they will continue
// after it.
if ( !candidate._.isBlockLike )
newPendingInline.unshift( candidate );
// This node should be added to it's parent at this point. But,
// it should happen only if the closing tag is really closing
// one of the nodes. So, for now, we just cache it.
pendingAdd.push( candidate );
// Make sure return point is properly restored.
candidate = candidate.returnPoint || candidate.parent;
}
if ( candidate != root ) {
// Add all elements that have been found in the above loop.
for ( i = 0; i < pendingAdd.length; i++ ) {
var node = pendingAdd[ i ];
addElement( node, node.parent );
}
currentNode = candidate;
if ( candidate._.isBlockLike ) {
sendPendingBRs();
} else {
shiftBRsPosition();
}
addElement( candidate, candidate.parent );
// The parent should start receiving new nodes now, except if
// addElement changed the currentNode.
if ( candidate == currentNode )
currentNode = currentNode.parent;
pendingInline = pendingInline.concat( newPendingInline );
}
if ( tagName == 'body' )
fixingBlock = false;
};
parser.onText = function( text ) {
// Trim empty spaces at beginning of text contents except <pre> and <textarea>.
if ( ( !currentNode._.hasInlineStarted || pendingBRs.length ) && !inPre && !inTextarea ) {
text = CKEDITOR.tools.ltrim( text );
if ( text.length === 0 )
return;
}
var currentName = currentNode.name,
currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
// Fix orphan text in list/table. (https://dev.ckeditor.com/ticket/8540) (https://dev.ckeditor.com/ticket/8870)
if ( !inTextarea && !currentDtd[ '#' ] && currentName in nonBreakingBlocks ) {
parser.onTagOpen( structureFixes[ currentName ] || '' );
parser.onText( text );
return;
}
sendPendingBRs();
checkPending();
// Shrinking consequential spaces into one single for all elements
// text contents.
if ( !inPre && !inTextarea )
text = text.replace( /[\t\r\n ]{2,}|[\t\r\n]/g, ' ' );
text = new CKEDITOR.htmlParser.text( text );
if ( checkAutoParagraphing( currentNode, text ) )
this.onTagOpen( fixingBlock, {}, 0, 1 );
currentNode.add( text );
};
parser.onCDATA = function( cdata ) {
currentNode.add( new CKEDITOR.htmlParser.cdata( cdata ) );
};
parser.onComment = function( comment ) {
sendPendingBRs();
checkPending();
currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
};
// Parse it.
parser.parse( fragmentHtml );
sendPendingBRs();
// Close all pending nodes, make sure return point is properly restored.
while ( currentNode != root )
addElement( currentNode, currentNode.parent, 1 );
removeTailWhitespace( root );
return root;
};
CKEDITOR.htmlParser.fragment.prototype = {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
*/
type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
/**
* Adds a node to this fragment.
*
* @param {CKEDITOR.htmlParser.node} node The node to be added.
* @param {Number} [index] From where the insertion happens.
*/
add: function( node, index ) {
isNaN( index ) && ( index = this.children.length );
var previous = index > 0 ? this.children[ index - 1 ] : null;
if ( previous ) {
// If the block to be appended is following text, trim spaces at
// the right of it.
if ( node._.isBlockLike && previous.type == CKEDITOR.NODE_TEXT ) {
previous.value = CKEDITOR.tools.rtrim( previous.value );
// If we have completely cleared the previous node.
if ( previous.value.length === 0 ) {
// Remove it from the list and add the node again.
this.children.pop();
this.add( node );
return;
}
}
previous.next = node;
}
node.previous = previous;
node.parent = this;
this.children.splice( index, 0, node );
if ( !this._.hasInlineStarted )
this._.hasInlineStarted = node.type == CKEDITOR.NODE_TEXT || ( node.type == CKEDITOR.NODE_ELEMENT && !node._.isBlockLike );
},
/**
* Filter this fragment's content with given filter.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.filter} filter
*/
filter: function( filter, context ) {
context = this.getFilterContext( context );
// Apply the root filter.
filter.onRoot( context, this );
this.filterChildren( filter, false, context );
},
/**
* Filter this fragment's children with given filter.
*
* Element's children may only be filtered once by one
* instance of filter.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.filter} filter
* @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
*/
filterChildren: function( filter, filterRoot, context ) {
// If this element's children were already filtered
// by current filter, don't filter them 2nd time.
// This situation may occur when filtering bottom-up
// (filterChildren() called manually in element's filter),
// or in unpredictable edge cases when filter
// is manipulating DOM structure.
if ( this.childrenFilteredBy == filter.id )
return;
context = this.getFilterContext( context );
// Filtering root if enforced.
if ( filterRoot && !this.parent )
filter.onRoot( context, this );
this.childrenFilteredBy = filter.id;
// Don't cache anything, children array may be modified by filter rule.
for ( var i = 0; i < this.children.length; i++ ) {
// Stay in place if filter returned false, what means
// that node has been removed.
if ( this.children[ i ].filter( filter, context ) === false )
i--;
}
},
/**
* Writes the fragment HTML to a {@link CKEDITOR.htmlParser.basicWriter}.
*
* var writer = new CKEDITOR.htmlWriter();
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<P><B>Example' );
* fragment.writeHtml( writer );
* alert( writer.getHtml() ); // '<p><b>Example</b></p>'
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
*/
writeHtml: function( writer, filter ) {
if ( filter )
this.filter( filter );
this.writeChildrenHtml( writer );
},
/**
* Write and filtering the child nodes of this fragment.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
* @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
*/
writeChildrenHtml: function( writer, filter, filterRoot ) {
var context = this.getFilterContext();
// Filtering root if enforced.
if ( filterRoot && !this.parent && filter )
filter.onRoot( context, this );
if ( filter )
this.filterChildren( filter, false, context );
for ( var i = 0, children = this.children, l = children.length; i < l; i++ )
children[ i ].writeHtml( writer );
},
/**
* Execute callback on each node (of a given type) in this document fragment.
*
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>foo<b>bar</b>bom</p>' );
* fragment.forEach( function( node ) {
* console.log( node );
* } );
* // Will log:
* // 1. document fragment,
* // 2. <p> element,
* // 3. "foo" text node,
* // 4. <b> element,
* // 5. "bar" text node,
* // 6. "bom" text node.
*
* @since 4.1.0
* @param {Function} callback Function to be executed on every node.
* **Since 4.3.0** if `callback` returned `false` descendants of current node will be ignored.
* @param {CKEDITOR.htmlParser.node} callback.node Node passed as argument.
* @param {Number} [type] If specified `callback` will be executed only on nodes of this type.
* @param {Boolean} [skipRoot] Don't execute `callback` on this fragment.
*/
forEach: function( callback, type, skipRoot ) {
if ( !skipRoot && ( !type || this.type == type ) )
var ret = callback( this );
// Do not filter children if callback returned false.
if ( ret === false )
return;
var children = this.children,
node,
i = 0;
// We do not cache the size, because the list of nodes may be changed by the callback.
for ( ; i < children.length; i++ ) {
node = children[ i ];
if ( node.type == CKEDITOR.NODE_ELEMENT )
node.forEach( callback, type );
else if ( !type || node.type == type )
callback( node );
}
},
getFilterContext: function( context ) {
return context || {};
}
};
/**
* Indicates if line breaks (`br`) should be moved outside inline elements.
*
* **Note:** This is a global configuration that applies to all instances.
*
* By default, all children `br` elements, placed at the end of an inline element,
* are shifted outside that element. Shifted elements are attached at the end of the parent block element.
* It allows producing more clean HTML output without an abundance of
* orphaned styling markers. This logic can be changed by disabling shifting line breaks or providing
* a custom function allowing to conditionally choose proper behavior.
*
* * `shiftLineBreaks = true`
*
* Shift line breaks outside inline element:
*
* <p><strong>hello, world!<br><br></strong></p>
*
* will become:
*
* <p><strong>hello, world!</strong><br><br></p>
*
* * `shiftLineBreaks = false`
*
* Keep line breaks inside an inline element:
*
* <p><strong>hello, world!<br><br></strong></p>
*
* * `shiftLineBreaks = customFunction`
*
* Provide a callback function allowing to decide if a line break should be shifted:
*
* ```javascript
* CKEDITOR.config.shiftLineBreaks = function() {
* if ( condition ) {
* // Shift line break outside element.
* return true;
* }
* // Keep line break inside element.
* return false;
* }
* ```
*
* You can also decide to return the {@link CKEDITOR.htmlParser.text} or {@link CKEDITOR.htmlParser.element}
* node that will be attached **at the end of the last `br` node** inside an inline element.
*
* As an example, you may want to add an additional `&nbsp;` filler to make sure that a user will be
* able to place caret after break lines:
*
* ```javascript
* CKEDITOR.config.shiftLineBreaks = function() {
* // Append `nbsp;` character at the end.
* return new CKEDITOR.htmlParser.text( '&nbsp;' );
* }
* ```
*
* resulting in:
*
* <p><strong>hello, world!<br><br>&nbsp;</strong></p>
*
* @cfg {Boolean/Function} [shiftLineBreaks=true]
* @member CKEDITOR.config
*/
CKEDITOR.config.shiftLineBreaks = true;
} )();

View file

@ -1,29 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.htmlParser.nameTransformRule} class
* that contains the definition of rule for filtering element names or attribute names. This file is for
* documentation purposes only.
*/
/**
* Abstract class describing the definition of {@link CKEDITOR.htmlParser.filterRulesDefinition} `elementNames` and `attributesNames` filtering rules.
*
* ```javascript
* var rule = [ /^div$/, 'p' ];
* ```
*
* @class CKEDITOR.htmlParser.nameTransformRule
* @abstract
*/
/**
* @property {RegExp} 0 A regular expression to match the element name or attribute.
*/
/**
* @property {String} 1 A string used to replace the match.
*/

View file

@ -1,156 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
( function() {
/**
* A lightweight representation of HTML node.
*
* @since 4.1.0
* @class
* @constructor Creates a node class instance.
*/
CKEDITOR.htmlParser.node = function() {};
CKEDITOR.htmlParser.node.prototype = {
/**
* Remove this node from a tree.
*
* @since 4.1.0
*/
remove: function() {
var children = this.parent.children,
index = CKEDITOR.tools.indexOf( children, this ),
previous = this.previous,
next = this.next;
previous && ( previous.next = next );
next && ( next.previous = previous );
children.splice( index, 1 );
this.parent = null;
},
/**
* Replace this node with given one.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.node} node The node that will replace this one.
*/
replaceWith: function( node ) {
var children = this.parent.children,
index = CKEDITOR.tools.indexOf( children, this ),
previous = node.previous = this.previous,
next = node.next = this.next;
previous && ( previous.next = node );
next && ( next.previous = node );
children[ index ] = node;
node.parent = this.parent;
this.parent = null;
},
/**
* Insert this node after given one.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.node} node The node that will precede this element.
*/
insertAfter: function( node ) {
var children = node.parent.children,
index = CKEDITOR.tools.indexOf( children, node ),
next = node.next;
children.splice( index + 1, 0, this );
this.next = node.next;
this.previous = node;
node.next = this;
next && ( next.previous = this );
this.parent = node.parent;
},
/**
* Insert this node before given one.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.node} node The node that will follow this element.
*/
insertBefore: function( node ) {
var children = node.parent.children,
index = CKEDITOR.tools.indexOf( children, node );
children.splice( index, 0, this );
this.next = node;
this.previous = node.previous;
node.previous && ( node.previous.next = this );
node.previous = this;
this.parent = node.parent;
},
/**
* Gets the closest ancestor element of this element which satisfies given condition
*
* @since 4.3.0
* @param {String/Object/Function} condition Name of an ancestor, hash of names or validator function.
* @returns {CKEDITOR.htmlParser.element} The closest ancestor which satisfies given condition or `null`.
*/
getAscendant: function( condition ) {
var checkFn =
typeof condition == 'function' ?
condition :
typeof condition == 'string' ?
function( el ) {
return el.name == condition;
} :
function( el ) {
return el.name in condition;
};
var parent = this.parent;
// Parent has to be an element - don't check doc fragment.
while ( parent && parent.type == CKEDITOR.NODE_ELEMENT ) {
if ( checkFn( parent ) )
return parent;
parent = parent.parent;
}
return null;
},
/**
* Wraps this element with given `wrapper`.
*
* @since 4.3.0
* @param {CKEDITOR.htmlParser.element} wrapper The element which will be this element's new parent.
* @returns {CKEDITOR.htmlParser.element} Wrapper.
*/
wrapWith: function( wrapper ) {
this.replaceWith( wrapper );
wrapper.add( this );
return wrapper;
},
/**
* Gets this node's index in its parent's children array.
*
* @since 4.3.0
* @returns {Number}
*/
getIndex: function() {
return CKEDITOR.tools.indexOf( this.parent.children, this );
},
getFilterContext: function( context ) {
return context || {};
}
};
} )();

View file

@ -1,70 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
( function() {
/**
* A lightweight representation of HTML text.
*
* @class
* @extends CKEDITOR.htmlParser.node
* @constructor Creates a text class instance.
* @param {String} value The text node value.
*/
CKEDITOR.htmlParser.text = function( value ) {
/**
* The text value.
*
* @property {String}
*/
this.value = value;
/** @private */
this._ = {
isBlockLike: false
};
};
CKEDITOR.htmlParser.text.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
/**
* The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
*
* @readonly
* @property {Number} [=CKEDITOR.NODE_TEXT]
*/
type: CKEDITOR.NODE_TEXT,
/**
* Filter this text node with given filter.
*
* @since 4.1.0
* @param {CKEDITOR.htmlParser.filter} filter
* @returns {Boolean} Method returns `false` when this text node has
* been removed. This is an information for {@link CKEDITOR.htmlParser.element#filterChildren}
* that it has to repeat filter on current position in parent's children array.
*/
filter: function( filter, context ) {
if ( !( this.value = filter.onText( context, this.value, this ) ) ) {
this.remove();
return false;
}
},
/**
* Writes the HTML representation of this text to a {CKEDITOR.htmlParser.basicWriter}.
*
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
* **Note:** it's unsafe to filter offline (not appended) node.
*/
writeHtml: function( writer, filter ) {
if ( filter )
this.filter( filter );
writer.text( this.value );
}
} );
} )();

View file

@ -1,169 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* Controls keystrokes typing in an editor instance.
*
* @class
* @constructor Creates a keystrokeHandler class instance.
* @param {CKEDITOR.editor} editor The editor instance.
*/
CKEDITOR.keystrokeHandler = function( editor ) {
if ( editor.keystrokeHandler )
return editor.keystrokeHandler;
/**
* A list of keystrokes associated with commands. Each entry points to the
* command to be executed.
*
* Since CKEditor 4 there is no need to modify this property directly during the runtime.
* Use {@link CKEDITOR.editor#setKeystroke} instead.
*/
this.keystrokes = {};
/**
* A list of keystrokes that should be blocked if not defined in
* {@link #keystrokes}. In this way it is possible to block the default
* browser behavior for those keystrokes.
*/
this.blockedKeystrokes = {};
this._ = {
editor: editor
};
return this;
};
( function() {
var cancel;
var onKeyDown = function( event ) {
// The DOM event object is passed by the "data" property.
event = event.data;
var keyCombination = event.getKeystroke();
var command = this.keystrokes[ keyCombination ];
var editor = this._.editor;
cancel = ( editor.fire( 'key', { keyCode: keyCombination, domEvent: event } ) === false );
if ( !cancel ) {
if ( command ) {
var data = { from: 'keystrokeHandler' };
cancel = ( editor.execCommand( command, data ) !== false );
}
if ( !cancel )
cancel = !!this.blockedKeystrokes[ keyCombination ];
}
if ( cancel )
event.preventDefault( true );
return !cancel;
};
var onKeyPress = function( event ) {
if ( cancel ) {
cancel = false;
event.data.preventDefault( true );
}
};
CKEDITOR.keystrokeHandler.prototype = {
/**
* Attaches this keystroke handle to a DOM object. Keystrokes typed
* over this object will be handled by this keystrokeHandler.
*
* @param {CKEDITOR.dom.domObject} domObject The DOM object to attach to.
*/
attach: function( domObject ) {
// For most browsers, it is enough to listen to the keydown event
// only.
domObject.on( 'keydown', onKeyDown, this );
// Some browsers instead, don't cancel key events in the keydown, but in the
// keypress. So we must do a longer trip in those cases.
if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
domObject.on( 'keypress', onKeyPress, this );
}
};
} )();
/**
* A list associating keystrokes with editor commands. Each element in the list
* is an array where the first item is the keystroke, and the second is the
* name of the command to be executed.
*
* This setting should be used to define (as well as to overwrite or remove) keystrokes
* set by plugins (like `link` and `basicstyles`). If you want to set a keystroke
* for your plugin or during the runtime, use {@link CKEDITOR.editor#setKeystroke} instead.
*
* Since default keystrokes are set by the {@link CKEDITOR.editor#setKeystroke}
* method, by default `config.keystrokes` is an empty array.
*
* See {@link CKEDITOR.editor#setKeystroke} documentation for more details
* regarding the start up order.
*
* // Change default Ctrl+L keystroke for 'link' command to Ctrl+Shift+L.
* config.keystrokes = [
* ...
* [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 76, 'link' ], // Ctrl+Shift+L
* ...
* ];
*
* To reset a particular keystroke, the following approach can be used:
*
* // Disable default Ctrl+L keystroke which executes the 'link' command by default.
* config.keystrokes = [
* ...
* [ CKEDITOR.CTRL + 76, null ], // Ctrl+L
* ...
* ];
*
* In order to reset all default keystrokes, a {@link CKEDITOR#instanceReady} callback should be
* used. This is since editor defaults are merged rather than overwritten by
* user keystrokes.
*
* **Note**: This can be potentially harmful for the editor. Avoid this unless you are
* aware of the consequences.
*
* // Reset all default keystrokes.
* config.on.instanceReady = function() {
* this.keystrokeHandler.keystrokes = [];
* };
*
* @cfg {Array} [keystrokes=[]]
* @member CKEDITOR.config
*/
/**
* Fired when any keyboard key (or a combination thereof) is pressed in the editing area.
*
* editor.on( 'key', function( evt ) {
* if ( evt.data.keyCode == CKEDITOR.CTRL + 90 ) {
* // Do something...
*
* // Cancel the event, so other listeners will not be executed and
* // the keydown's default behavior will be prevented.
* evt.cancel();
* }
* } );
*
* Usually you will want to use the {@link CKEDITOR.editor#setKeystroke} method or
* the {@link CKEDITOR.config#keystrokes} option to attach a keystroke to some {@link CKEDITOR.command command}.
* Key event listeners are usuful when some action should be executed conditionally, based
* for example on precise selection location.
*
* @event key
* @member CKEDITOR.editor
* @param data
* @param {Number} data.keyCode A number representing the key code (or a combination thereof).
* It is the sum of the current key code and the {@link CKEDITOR#CTRL}, {@link CKEDITOR#SHIFT}
* and {@link CKEDITOR#ALT} constants, if those are pressed.
* @param {CKEDITOR.dom.event} data.domEvent A `keydown` DOM event instance. Available since CKEditor 4.4.1.
* @param {CKEDITOR.editor} editor This editor instance.
*/

View file

@ -1,103 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
( function() {
/**
* Stores language-related functions.
*
* @class
* @singleton
*/
CKEDITOR.lang = {
/**
* The list of languages available in the editor core.
*
* alert( CKEDITOR.lang.languages.en ); // 1
*/
languages: {
af: 1, ar: 1, az: 1, bg: 1, bn: 1, bs: 1, ca: 1, cs: 1, cy: 1, da: 1, de: 1, 'de-ch': 1, el: 1,
'en-au': 1, 'en-ca': 1, 'en-gb': 1, en: 1, eo: 1, es: 1, 'es-mx':1, et: 1, eu: 1, fa: 1, fi: 1, fo: 1,
'fr-ca': 1, fr: 1, gl: 1, gu: 1, he: 1, hi: 1, hr: 1, hu: 1, id: 1, is: 1, it: 1, ja: 1, ka: 1,
km: 1, ko: 1, ku: 1, lt: 1, lv: 1, mk: 1, mn: 1, ms: 1, nb: 1, nl: 1, no: 1, oc: 1, pl: 1, 'pt-br': 1,
pt: 1, ro: 1, ru: 1, si: 1, sk: 1, sl: 1, sq: 1, 'sr-latn': 1, sr: 1, sv: 1, th: 1, tr: 1, tt: 1, ug: 1,
uk: 1, vi: 1, 'zh-cn': 1, zh: 1
},
/**
* The list of languages that are written Right-To-Left (RTL) and are supported by the editor.
*/
rtl: { ar: 1, fa: 1, he: 1, ku: 1, ug: 1 },
/**
* Loads a specific language file, or auto detects it. A callback is
* then called when the file gets loaded.
*
* @param {String} languageCode The code of the language file to be
* loaded. If null or empty, autodetection will be performed. The
* same happens if the language is not supported.
* @param {String} defaultLanguage The language to be used if
* `languageCode` is not supported or if the autodetection fails.
* @param {Function} callback A function to be called once the
* language file is loaded. Two parameters are passed to this
* function: the language code and the loaded language entries.
*/
load: function( languageCode, defaultLanguage, callback ) {
// If no languageCode - fallback to browser or default.
// If languageCode - fallback to no-localized version or default.
if ( !languageCode || !CKEDITOR.lang.languages[ languageCode ] )
languageCode = this.detect( defaultLanguage, languageCode );
var that = this,
loadedCallback = function() {
that[ languageCode ].dir = that.rtl[ languageCode ] ? 'rtl' : 'ltr';
callback( languageCode, that[ languageCode ] );
};
if ( !this[ languageCode ] )
CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( 'lang/' + languageCode + '.js' ), loadedCallback, this );
else
loadedCallback();
},
/**
* Returns the language that best fits the user language. For example,
* suppose that the user language is "pt-br". If this language is
* supported by the editor, it is returned. Otherwise, if only "pt" is
* supported, it is returned instead. If none of the previous are
* supported, a default language is then returned.
*
* alert( CKEDITOR.lang.detect( 'en' ) ); // e.g., in a German browser: 'de'
*
* @param {String} defaultLanguage The default language to be returned
* if the user language is not supported.
* @param {String} [probeLanguage] A language code to try to use,
* instead of the browser-based autodetection.
* @returns {String} The detected language code.
*/
detect: function( defaultLanguage, probeLanguage ) {
var languages = this.languages;
probeLanguage = probeLanguage || navigator.userLanguage || navigator.language || defaultLanguage;
var parts = probeLanguage.toLowerCase().match( /([a-z]+)(?:-([a-z]+))?/ ),
lang = parts[ 1 ],
locale = parts[ 2 ];
if ( languages[ lang + '-' + locale ] )
lang = lang + '-' + locale;
else if ( !languages[ lang ] )
lang = null;
CKEDITOR.lang.detect = lang ?
function() {
return lang;
} : function( defaultLanguage ) {
return defaultLanguage;
};
return lang || defaultLanguage;
}
};
} )();

View file

@ -1,233 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.loader} objects, which is used to
* load core scripts and their dependencies from _source.
*/
if ( typeof CKEDITOR == 'undefined' )
CKEDITOR = {}; // jshint ignore:line
if ( !CKEDITOR.loader ) {
/**
* Load core scripts and their dependencies from `_source`.
*
* @class
* @singleton
*/
CKEDITOR.loader = ( function() {
// Table of script names and their dependencies.
var scripts = {
'_bootstrap': [
'config', 'creators/inline', 'creators/themedui', 'editable', 'ckeditor', 'plugins',
'scriptloader', 'style', 'tools', 'promise', 'selection/optimization', 'tools/color',
// The following are entries that we want to force loading at the end to avoid dependence recursion.
'dom/comment', 'dom/elementpath', 'dom/text', 'dom/rangelist', 'skin'
],
'ckeditor': [
'ckeditor_basic', 'log', 'dom', 'dtd', 'dom/document', 'dom/element',
'dom/iterator', 'editor', 'event', 'htmldataprocessor', 'htmlparser', 'htmlparser/element',
'htmlparser/fragment', 'htmlparser/filter', 'htmlparser/basicwriter', 'template', 'tools',
'ckeditor_version-check'
],
'ckeditor_base': [],
'ckeditor_basic': [ 'editor_basic', 'env', 'event' ],
'ckeditor_version-check': [ 'ckeditor_basic', 'config', 'tools' ],
'command': [],
'config': [ 'ckeditor_base' ],
'dom': [],
'dom/comment': [ 'dom/node' ],
'dom/document': [ 'dom/node', 'dom/window' ],
'dom/documentfragment': [ 'dom/element' ],
'dom/element': [ 'dom', 'dom/document', 'dom/domobject', 'dom/node', 'dom/nodelist', 'tools' ],
'dom/elementpath': [ 'dom/element' ],
'dom/event': [],
'dom/iterator': [ 'dom/range' ],
'dom/node': [ 'dom/domobject', 'tools' ],
'dom/nodelist': [ 'dom/node' ],
'dom/domobject': [ 'dom/event' ],
'dom/range': [ 'dom/document', 'dom/documentfragment', 'dom/element', 'dom/walker' ],
'dom/rangelist': [ 'dom/range' ],
'dom/text': [ 'dom/node', 'dom/domobject' ],
'dom/walker': [ 'dom/node' ],
'dom/window': [ 'dom/domobject' ],
'dtd': [ 'tools' ],
'editable': [ 'editor', 'tools' ],
'editor': [
'command', 'config', 'editor_basic', 'filter', 'focusmanager', 'keystrokehandler', 'lang',
'plugins', 'tools', 'ui'
],
'editor_basic': [ 'event' ],
'env': [],
'event': [],
'filter': [ 'dtd', 'tools' ],
'focusmanager': [],
'htmldataprocessor': [ 'htmlparser', 'htmlparser/basicwriter', 'htmlparser/fragment', 'htmlparser/filter' ],
'htmlparser': [],
'htmlparser/comment': [ 'htmlparser', 'htmlparser/node' ],
'htmlparser/element': [ 'htmlparser', 'htmlparser/fragment', 'htmlparser/node' ],
'htmlparser/fragment': [ 'htmlparser', 'htmlparser/comment', 'htmlparser/text', 'htmlparser/cdata' ],
'htmlparser/text': [ 'htmlparser', 'htmlparser/node' ],
'htmlparser/cdata': [ 'htmlparser', 'htmlparser/node' ],
'htmlparser/filter': [ 'htmlparser' ],
'htmlparser/basicwriter': [ 'htmlparser' ],
'htmlparser/node': [ 'htmlparser' ],
'keystrokehandler': [ 'event' ],
'lang': [],
'log': [ 'ckeditor_basic' ],
'plugins': [ 'resourcemanager' ],
'resourcemanager': [ 'scriptloader', 'tools' ],
'scriptloader': [ 'dom/element', 'env' ],
'selection': [ 'dom/range', 'dom/walker' ],
'skin': [],
'style': [ 'selection' ],
'template': [],
'tools': [ 'env' ],
'ui': [],
'creators/themedui': [],
'creators/inline': [],
'promise': [ 'tools' ],
'selection/optimization': [ 'selection' ],
'tools/color': [ 'tools' ]
};
// The production implementation contains a fixed timestamp generated by the releaser.
var timestamp = '%TIMESTAMP%';
// The development implementation contains a current timestamp. // %REMOVE_LINE%
timestamp = ( CKEDITOR && CKEDITOR.timestamp ) || ( new Date() ).valueOf(); // %REMOVE_LINE%
var getUrl = function( resource ) {
if ( CKEDITOR && CKEDITOR.getUrl )
return CKEDITOR.getUrl( resource );
return CKEDITOR.basePath + resource + ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + timestamp;
};
var pendingLoad = [];
return {
/**
* The list of loaded scripts in their loading order.
*
* // Alert the loaded script names.
* alert( CKEDITOR.loader.loadedScripts );
*/
loadedScripts: [],
/**
* Table of script names and their dependencies.
*
* @property {Array}
*/
scripts: scripts,
/**
* @todo
*/
loadPending: function() {
var scriptName = pendingLoad.shift();
if ( !scriptName )
return;
var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = scriptSrc;
function onScriptLoaded() {
// Append this script to the list of loaded scripts.
CKEDITOR.loader.loadedScripts.push( scriptName );
// Load the next.
CKEDITOR.loader.loadPending();
}
// We must guarantee the execution order of the scripts, so we
// need to load them one by one. (https://dev.ckeditor.com/ticket/4145)
// The following if/else block has been taken from the scriptloader core code.
if ( typeof script.onreadystatechange !== 'undefined' ) {
/** @ignore */
script.onreadystatechange = function() {
if ( script.readyState == 'loaded' || script.readyState == 'complete' ) {
script.onreadystatechange = null;
onScriptLoaded();
}
};
} else {
/** @ignore */
script.onload = function() {
// Some browsers, such as Safari, may call the onLoad function
// immediately. Which will break the loading sequence. (https://dev.ckeditor.com/ticket/3661)
setTimeout( function() {
// Once the script is loaded, remove the listener as this might lead to memory leaks (#589).
script.onload = null;
onScriptLoaded( scriptName );
}, 0 );
};
}
document.body.appendChild( script );
},
/**
* Loads a specific script, including its dependencies. The loading process
* is not synchronous, which means that the code to be loaded will
* not necessarily be available after this call.
*
* CKEDITOR.loader.load( 'dom/element' );
*
* @param {String} scriptName
* @param {Boolean} [defer=false]
* @todo params
*/
load: function( scriptName, defer ) {
// Check if the script has already been loaded.
if ( ( 's:' + scriptName ) in this.loadedScripts )
return;
// Get the script dependencies list.
var dependencies = scripts[ scriptName ];
if ( !dependencies )
throw 'The script name"' + scriptName + '" is not defined.';
// Mark the script as loaded, even before really loading it, to
// avoid cross references recursion.
// Prepend script name with 's:' to avoid conflict with Array's methods.
this.loadedScripts[ 's:' + scriptName ] = true;
// Load all dependencies first.
for ( var i = 0; i < dependencies.length; i++ )
this.load( dependencies[ i ], true );
var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
// Append the <script> element to the DOM.
// If the page is fully loaded, we can't use document.write
// but if the script is run while the body is loading then it's safe to use it
// Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement
if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) {
pendingLoad.push( scriptName );
if ( !defer )
this.loadPending();
} else {
// Append this script to the list of loaded scripts.
this.loadedScripts.push( scriptName );
document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' );
}
}
};
} )();
}
// Check if any script has been defined for autoload.
if ( CKEDITOR._autoLoad ) {
CKEDITOR.loader.load( CKEDITOR._autoLoad );
delete CKEDITOR._autoLoad;
}

View file

@ -1,127 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines {@link CKEDITOR#verbosity} and binary flags {@link CKEDITOR#VERBOSITY_WARN} and
* {@link CKEDITOR#VERBOSITY_ERROR}. Defines also the {@link CKEDITOR#error} and {@link CKEDITOR#warn} functions
* and the default handler for the {@link CKEDITOR#log} event.
*/
/* global console */
'use strict';
/**
* Warning reporting verbosity level. When {@link CKEDITOR#verbosity} is set to this value, only {@link CKEDITOR#warn}
* messages will be output to the console. It is a binary flag so it might be combined with
* the {@link CKEDITOR#VERBOSITY_ERROR} flag.
*
* @since 4.5.4
* @readonly
* @property {Number} [=1]
* @member CKEDITOR
*/
CKEDITOR.VERBOSITY_WARN = 1;
/**
* Error reporting verbosity level. When {@link CKEDITOR#verbosity} is set to this value, only {@link CKEDITOR#error}
* messages will be output to the console. It is a binary flag so it might be combined with
* the {@link CKEDITOR#VERBOSITY_WARN} flag.
*
* @since 4.5.4
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.VERBOSITY_ERROR = 2;
/**
* Verbosity of {@link CKEDITOR#error} and {@link CKEDITOR#warn} methods. Accepts binary flags
* {@link CKEDITOR#VERBOSITY_WARN} and {@link CKEDITOR#VERBOSITY_ERROR}.
*
* CKEDITOR.verbosity = 0; // No console output after CKEDITOR.warn and CKEDITOR.error methods.
* CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN; // Console output after CKEDITOR.warn only.
* CKEDITOR.verbosity = CKEDITOR.VERBOSITY_ERROR; // Console output after CKEDITOR.error only.
* CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN | CKEDITOR.VERBOSITY_ERROR; // Console output after both methods.
*
* Default value enables both {@link CKEDITOR#VERBOSITY_WARN} and {@link CKEDITOR#VERBOSITY_ERROR}.
*
* @since 4.5.4
* @member CKEDITOR
* @type {Number}
*/
CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN | CKEDITOR.VERBOSITY_ERROR;
/**
* Warning reporting function. When {@link CKEDITOR#verbosity} has the {@link CKEDITOR#VERBOSITY_WARN} flag set, it fires
* the {@link CKEDITOR#log} event with type set to `warn`. Fired event contains also provided `errorCode` and `additionalData`.
*
* @since 4.5.4
* @member CKEDITOR
* @param {String} errorCode Error code describing reported problem.
* @param {Object} [additionalData] Additional data associated with reported problem.
*/
CKEDITOR.warn = function( errorCode, additionalData ) {
if ( CKEDITOR.verbosity & CKEDITOR.VERBOSITY_WARN ) {
CKEDITOR.fire( 'log', { type: 'warn', errorCode: errorCode, additionalData: additionalData } );
}
};
/**
* Error reporting function. When {@link CKEDITOR#verbosity} has {@link CKEDITOR#VERBOSITY_ERROR} flag set, it fires
* {@link CKEDITOR#log} event with the type set to `error`. The fired event also contains the provided `errorCode` and
* `additionalData`.
*
* @since 4.5.4
* @member CKEDITOR
* @param {String} errorCode Error code describing the reported problem.
* @param {Object} [additionalData] Additional data associated with the reported problem.
*/
CKEDITOR.error = function( errorCode, additionalData ) {
if ( CKEDITOR.verbosity & CKEDITOR.VERBOSITY_ERROR ) {
CKEDITOR.fire( 'log', { type: 'error', errorCode: errorCode, additionalData: additionalData } );
}
};
/**
* Fired by {@link CKEDITOR#warn} and {@link CKEDITOR#error} methods.
* Default listener logs provided information to the console.
*
* This event can be used to provide a custom error/warning handler:
*
* CKEDTIOR.on( 'log', function( evt ) {
* // Cancel default listener.
* evt.cancel();
* // Log event data.
* console.log( evt.data.type, evt.data.errorCode, evt.data.additionalData );
* } );
*
* @since 4.5.4
* @event log
* @member CKEDITOR
* @param data
* @param {String} data.type Log type. Can be `error` or `warn`.
* @param {String} data.errorCode Error code describing the reported problem.
* @param {Object} [data.additionalData] Additional data associated with this log event.
*/
CKEDITOR.on( 'log', function( evt ) {
if ( !window.console || !window.console.log ) {
return;
}
var type = console[ evt.data.type ] ? evt.data.type : 'log',
errorCode = evt.data.errorCode,
additionalData = evt.data.additionalData,
prefix = '[CKEDITOR] ',
errorCodeLabel = 'Error code: ';
if ( additionalData ) {
console[ type ]( prefix + errorCodeLabel + errorCode + '.', additionalData );
} else {
console[ type ]( prefix + errorCodeLabel + errorCode + '.' );
}
console[ type ]( prefix + 'For more information about this error go to https://ckeditor.com/docs/ckeditor4/latest/guide/dev_errors.html#' + errorCode );
}, null, null, 999 );

View file

@ -1,217 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the "virtual" {@link CKEDITOR.pluginDefinition} class which
* contains the defintion of a plugin. This file serves documentation
* purposes only.
*/
/**
* A virtual class that just illustrates the features of plugin objects which are
* passed to the {@link CKEDITOR.plugins#add} method.
*
* This class is not really a part of the API, so its constructor should not be called.
*
* See also:
*
* * {@glink guide/plugin_sdk_intro The Plugin SDK}
* * {@glink guide/plugin_sdk_sample Creating a CKEditor plugin in 20 Lines of Code}
* * {@glink guide/plugin_sdk_sample_1 Creating a Simple Plugin Tutorial}
*
* @class CKEDITOR.pluginDefinition
* @abstract
*/
/**
* A list of plugins that are required by this plugin. Note that this property
* does not determine the loading order of the plugins.
*
* CKEDITOR.plugins.add( 'sample', {
* requires: 'button,selection'
* } );
*
* Or:
*
* CKEDITOR.plugins.add( 'sample', {
* requires: [ 'button', 'selection' ]
* } );
*
* @property {String/String[]} requires
*/
/**
* The list of language files available for this plugin. These files are stored inside
* the `lang` directory in the plugin directory, follow the name
* pattern of `langCode.js`, and contain the language definition created with
* {@link CKEDITOR.plugins#setLang}.
*
* When the plugin is being loaded, the editor checks this list to see if
* a language file in the current editor language ({@link CKEDITOR.editor#langCode})
* is available, and if so, loads it. Otherwise, the file represented by the first item
* in the list is loaded.
*
* CKEDITOR.plugins.add( 'sample', {
* lang: 'en,fr'
* } );
*
* Or:
*
* CKEDITOR.plugins.add( 'sample', {
* lang: [ 'en', 'fr' ]
* } );
*
* @property {String/String[]} lang
*/
/**
* A function called when the plugin definition is loaded for the first time.
* It is usually used to execute some code once for the entire page,
* for instance code that uses the {@link CKEDITOR}'s methods such as the {@link CKEDITOR#addCss} method.
*
* CKEDITOR.plugins.add( 'sample', {
* onLoad: function() {
* CKEDITOR.addCss( '.cke_some_class { ... }' );
* }
* } );
*
* Read more about the initialization order in the {@link #init} method documentation.
*
* @method onLoad
*/
/**
* A function called on initialization of every editor instance created on the
* page before the {@link #init} call task. This feature makes it possible to
* initialize things that could be used in the `init` function of other plugins.
*
* CKEDITOR.plugins.add( 'sample1', {
* beforeInit: function( editor ) {
* editor.foo = 'bar';
* }
* } );
*
* CKEDITOR.plugins.add( 'sample2', {
* init: function( editor ) {
* // This will work regardless of order in which
* // plugins sample1 and sample2 where initialized.
* console.log( editor.foo ); // 'bar'
* }
* } );
*
* Read more about the initialization order in the {@link #init} method documentation.
*
* @method beforeInit
* @param {CKEDITOR.editor} editor The editor instance being initialized.
*/
/**
* A function called on initialization of every editor instance created on the page.
*
* CKEDITOR.plugins.add( 'sample', {
* init: function( editor ) {
* console.log( 'Editor "' + editor.name + '" is being initialized!' );
* }
* } );
*
* Initialization order:
*
* 1. The {@link #beforeInit} methods of all enabled plugins are executed.
* 2. The {@link #init} methods of all enabled plugins are executed.
* 3. The {@link #afterInit} methods of all enabled plugins are executed.
* 4. The {@link CKEDITOR.editor#pluginsLoaded} event is fired.
*
* **Note:** The order in which the `init` methods are called does not depend on the plugins' {@link #requires requirements}
* or the order set in the {@link CKEDITOR.config#plugins} option. It may be random and therefore it is
* recommended to use the {@link #beforeInit} and {@link #afterInit} methods in order to ensure
* the right execution sequence.
*
* See also the {@link #onLoad} method.
*
* @method init
* @param {CKEDITOR.editor} editor The editor instance being initialized.
*/
/**
* A function called on initialization of every editor instance created on the
* page after the {@link #init} call task. This feature makes it possible to use things
* that were initialized in the `init` function of other plugins.
*
* CKEDITOR.plugins.add( 'sample1', {
* afterInit: function( editor ) {
* // This will work regardless of order in which
* // plugins sample1 and sample2 where initialized.
* console.log( editor.foo ); // 'bar'
* }
* } );
*
* CKEDITOR.plugins.add( 'sample2', {
* init: function( editor ) {
* editor.foo = 'bar';
* }
* } );
*
* Read more about the initialization order in the {@link #init} method documentation.
*
* @method afterInit
* @param {CKEDITOR.editor} editor The editor instance being initialized.
*/
/**
* Announces the plugin as HiDPI-ready (optimized for high pixel density screens, e.g. *Retina*)
* by providing high-resolution icons and images. HiDPI icons must be twice as big
* (defaults are `16px x 16px`) and stored under `plugin_name/icons/hidpi/` directory.
*
* The common place for additional HiDPI images used by the plugin (**but not icons**)
* is the `plugin_name/images/hidpi/` directory.
*
* This property is optional and only makes sense if `32px x 32px` icons
* and high-resolution images actually exist. If this flag is set to `true`, the editor
* will automatically detect the HiDPI environment and attempt to load the
* high-resolution resources.
*
* @since 4.2.0
* @property {Boolean} hidpi
*/
/**
* The list of icon files registered by this plugin. These files are stored inside
* the `icons` directory in the plugin directory and follow the name
* pattern of `name.png`.
*
* ```javascript
* CKEDITOR.plugins.add( 'sample', {
* icons: 'first,second'
* } );
* ```
*
* @property {String} [icons]
*/
/**
* A function that should be implemented if a plugin is not supported in every
* available environment according to
* [Browser Compatibility](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_browsers.html)
* or a specific editor configuration.
*
* This function will not be called by the plugin loader itself and it is not required for a proper
* plugin initialization. However, it is recommended to implement the function if a plugin
* has environment requirements. This information may be important for related features
* and the testing environment.
*
* ```javascript
* CKEDITOR.plugins.add( 'sample', {
* isSupportedEnvironment: function( editor ) {
* // A plugin supported only in modern browsers.
* return !CKEDITOR.env.ie || CKEDITOR.env.edge;
* }
* } );
* ```
*
* @since 4.12.0
* @method isSupportedEnvironment
* @param {CKEDITOR.editor} editor
* @returns {Boolean} Information whether the plugin is supported in the current environment.
*/

View file

@ -1,140 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.plugins} object, which is used to
* manage plugins registration and loading.
*/
/**
* Manages plugins registration and loading.
*
* **Note** This object is an instance of {@link CKEDITOR.resourceManager}.
*
* @class
* @extends CKEDITOR.resourceManager
* @singleton
*/
CKEDITOR.plugins = new CKEDITOR.resourceManager( 'plugins/', 'plugin' );
// PACKAGER_RENAME( CKEDITOR.plugins )
CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function( originalLoad ) {
var initialized = {};
return function( name, callback, scope ) {
var allPlugins = {};
var loadPlugins = function( names ) {
originalLoad.call( this, names, function( plugins ) {
CKEDITOR.tools.extend( allPlugins, plugins );
var requiredPlugins = [];
for ( var pluginName in plugins ) {
var plugin = plugins[ pluginName ],
requires = plugin && plugin.requires;
if ( !initialized[ pluginName ] ) {
// Register all icons eventually defined by this plugin.
if ( plugin.icons ) {
var icons = plugin.icons.split( ',' );
for ( var ic = icons.length; ic--; ) {
CKEDITOR.skin.addIcon( icons[ ic ],
plugin.path +
'icons/' +
( CKEDITOR.env.hidpi && plugin.hidpi ? 'hidpi/' : '' ) +
icons[ ic ] +
'.png' );
}
}
// Plugin is supported by default (#2692).
plugin.isSupportedEnvironment = plugin.isSupportedEnvironment || function() {
return true;
};
initialized[ pluginName ] = 1;
}
if ( requires ) {
// Trasnform it into an array, if it's not one.
if ( requires.split )
requires = requires.split( ',' );
for ( var i = 0; i < requires.length; i++ ) {
if ( !allPlugins[ requires[ i ] ] )
requiredPlugins.push( requires[ i ] );
}
}
}
if ( requiredPlugins.length )
loadPlugins.call( this, requiredPlugins );
else {
// Call the "onLoad" function for all plugins.
for ( pluginName in allPlugins ) {
plugin = allPlugins[ pluginName ];
if ( plugin.onLoad && !plugin.onLoad._called ) {
// Make it possible to return false from plugin::onLoad to disable it.
if ( plugin.onLoad() === false )
delete allPlugins[ pluginName ];
plugin.onLoad._called = 1;
}
}
// Call the callback.
if ( callback )
callback.call( scope || window, allPlugins );
}
}, this );
};
loadPlugins.call( this, name );
};
} );
/**
* Loads a specific language file, or auto detect it. A callback is
* then called when the file gets loaded.
*
* CKEDITOR.plugins.setLang( 'myPlugin', 'en', {
* title: 'My plugin',
* selectOption: 'Please select an option'
* } );
*
* @param {String} pluginName The name of the plugin to which the provided translation
* should be attached.
* @param {String} languageCode The code of the language translation provided.
* @param {Object} languageEntries An object that contains pairs of label and
* the respective translation.
*/
CKEDITOR.plugins.setLang = function( pluginName, languageCode, languageEntries ) {
var plugin = this.get( pluginName ),
pluginLangEntries = plugin.langEntries || ( plugin.langEntries = {} ),
pluginLang = plugin.lang || ( plugin.lang = [] );
if ( pluginLang.split )
pluginLang = pluginLang.split( ',' );
if ( CKEDITOR.tools.indexOf( pluginLang, languageCode ) == -1 )
pluginLang.push( languageCode );
pluginLangEntries[ languageCode ] = languageEntries;
};
/**
* Virtual class that illustrates the API of {@link CKEDITOR.editor} instance plugins dictionary.
*
* Such object contains references to all plugins used by a related editor instance.
*
* See {@link CKEDITOR.editor#property-plugins} for example use.
*
* This class is not really a part of the API, so its constructor can not be called.
*
* @abstract
* @class CKEDITOR.editor.plugins
*/

View file

@ -1,87 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* global Promise, ES6Promise */
( function() {
'use strict';
if ( window.Promise ) {
CKEDITOR.tools.promise = Promise;
} else {
var polyfillURL = CKEDITOR.getUrl( 'vendor/promise.js' ),
isAmdEnv = typeof window.define === 'function' && window.define.amd && typeof window.require === 'function';
if ( isAmdEnv ) {
return window.require( [ polyfillURL ], function( Promise ) {
CKEDITOR.tools.promise = Promise;
} );
}
CKEDITOR.scriptLoader.load( polyfillURL, function( success ) {
if ( !success ) {
return CKEDITOR.error( 'no-vendor-lib', {
path: polyfillURL
} );
}
if ( typeof window.ES6Promise !== 'undefined' ) {
return CKEDITOR.tools.promise = ES6Promise;
}
} );
}
/**
* An alias for the [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
* object representing an asynchronous operation.
*
* It uses the native `Promise` browser implementation if it is available. For older browsers with lack of `Promise` support,
* the [`ES6-Promise`](https://github.com/stefanpenner/es6-promise) polyfill is used.
* See the [Promise Browser Compatibility table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility)
* to learn more.
*
* Refer to [MDN Using Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) guide for
* more details on how to work with promises.
*
* **NOTE:** `catch` and `finally` are reserved keywords in IE<9 browsers. Use bracket notation instead:
*
* ```js
* promise[ 'catch' ]( function( err ) {
* // ...
* } );
*
* promise[ 'finally' ]( function() {
* // ...
* } );
* ```
*
* @since 4.12.0
* @class CKEDITOR.tools.promise
*/
/**
* Creates a new `Promise` instance.
*
* ```js
* new CKEDITOR.tools.promise( function( resolve, reject ) {
* setTimeout( function() {
* var timestamp;
* try {
* timestamp = ( new Date() ).getTime();
* } catch ( e ) {
* reject( e );
* }
* resolve( timestamp );
* }, 5000 );
* } );
* ```
*
* @param {Function} resolver
* @param {Function} resolver.resolve
* @param {Function} resolver.reject
* @constructor
*/
} )();

View file

@ -1,235 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.resourceManager} class, which is
* the base for resource managers, like plugins.
*/
/**
* Base class for resource managers, like plugins. This class is not
* intended to be used out of the CKEditor core code.
*
* @class
* @constructor Creates a resourceManager class instance.
* @param {String} basePath The path for the resources folder.
* @param {String} fileName The name used for resource files.
*/
CKEDITOR.resourceManager = function( basePath, fileName ) {
/**
* The base directory containing all resources.
*
* @property {String}
*/
this.basePath = basePath;
/**
* The name used for resource files.
*
* @property {String}
*/
this.fileName = fileName;
/**
* Contains references to all resources that have already been registered
* with {@link #add}.
*/
this.registered = {};
/**
* Contains references to all resources that have already been loaded
* with {@link #load}.
*/
this.loaded = {};
/**
* Contains references to all resources that have already been registered
* with {@link #addExternal}.
*/
this.externals = {};
/**
* @private
*/
this._ = {
// List of callbacks waiting for plugins to be loaded.
waitingList: {}
};
};
CKEDITOR.resourceManager.prototype = {
/**
* Registers a resource.
*
* CKEDITOR.plugins.add( 'sample', { ... plugin definition ... } );
*
* @param {String} name The resource name.
* @param {Object} [definition] The resource definition.
* @see CKEDITOR.pluginDefinition
*/
add: function( name, definition ) {
if ( this.registered[ name ] )
throw new Error( '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.' );
var resource = this.registered[ name ] = definition || {};
resource.name = name;
resource.path = this.getPath( name );
CKEDITOR.fire( name + CKEDITOR.tools.capitalize( this.fileName ) + 'Ready', resource );
return this.get( name );
},
/**
* Gets the definition of a specific resource.
*
* var definition = CKEDITOR.plugins.get( 'sample' );
*
* @param {String} name The resource name.
* @returns {Object} The registered object.
*/
get: function( name ) {
return this.registered[ name ] || null;
},
/**
* Get the folder path for a specific loaded resource.
*
* alert( CKEDITOR.plugins.getPath( 'sample' ) ); // '<editor path>/plugins/sample/'
*
* @param {String} name The resource name.
* @returns {String}
*/
getPath: function( name ) {
var external = this.externals[ name ];
return CKEDITOR.getUrl( ( external && external.dir ) || this.basePath + name + '/' );
},
/**
* Get the file path for a specific loaded resource.
*
* alert( CKEDITOR.plugins.getFilePath( 'sample' ) ); // '<editor path>/plugins/sample/plugin.js'
*
* @param {String} name The resource name.
* @returns {String}
*/
getFilePath: function( name ) {
var external = this.externals[ name ];
return CKEDITOR.getUrl( this.getPath( name ) + ( external ? external.file : this.fileName + '.js' ) );
},
/**
* Registers one or more resources to be loaded from an external path
* instead of the core base path.
*
* ```js
* // Loads a plugin from '/myplugins/sample/plugin.js'.
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/' );
*
* // Loads a plugin from '/myplugins/sample/my_plugin.js'.
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/', 'my_plugin.js' );
*
* // Loads a plugin from '/myplugins/sample/my_plugin.js'.
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/my_plugin.js', '' );
*
* // Loads a plugin from '/myplugins/sample/my_plugin.js'.
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/my_plugin.js' );
* ```
*
* @param {String} names Comma-separated resource names.
* @param {String} path The path of the folder containing the resource.
* @param {String} [fileName] The resource file name. If not provided and
* the `path` argument ends with a slash (`/`), the default `plugin.js` filename is used.
* Otherwise, if not provided and the `path` argument does not end with a slash (`/`)
* or if an empty string is provided, the function assumes that the `path` argument contains the full path.
*/
addExternal: function( names, path, fileName ) {
// If "fileName" is not provided, we assume that it may be available
// in "path". Try to extract it in this case.
if ( !fileName ) {
path = path.replace( /[^\/]+$/, function( match ) {
fileName = match;
return '';
} );
}
// Use the default file name if there is no "fileName" and it
// was not found in "path".
fileName = fileName || ( this.fileName + '.js' );
names = names.split( ',' );
for ( var i = 0; i < names.length; i++ ) {
var name = names[ i ];
this.externals[ name ] = {
dir: path,
file: fileName
};
}
},
/**
* Loads one or more resources.
*
* CKEDITOR.plugins.load( 'myplugin', function( plugins ) {
* alert( plugins[ 'myplugin' ] ); // object
* } );
*
* @param {String/Array} name The name of the resource to load. It may be a
* string with a single resource name, or an array with several names.
* @param {Function} callback A function to be called when all resources
* are loaded. The callback will receive an array containing all loaded names.
* @param {Object} [scope] The scope object to be used for the callback call.
*/
load: function( names, callback, scope ) {
// Ensure that we have an array of names.
if ( !CKEDITOR.tools.isArray( names ) )
names = names ? [ names ] : [];
var loaded = this.loaded,
registered = this.registered,
urls = [],
urlsNames = {},
resources = {};
// Loop through all names.
for ( var i = 0; i < names.length; i++ ) {
var name = names[ i ];
if ( !name )
continue;
// If not available yet.
if ( !loaded[ name ] && !registered[ name ] ) {
var url = this.getFilePath( name );
urls.push( url );
if ( !( url in urlsNames ) )
urlsNames[ url ] = [];
urlsNames[ url ].push( name );
} else {
resources[ name ] = this.get( name );
}
}
CKEDITOR.scriptLoader.load( urls, function( completed, failed ) {
if ( failed.length ) {
throw new Error( '[CKEDITOR.resourceManager.load] Resource name "' + urlsNames[ failed[ 0 ] ].join( ',' ) +
'" was not found at "' + failed[ 0 ] + '".' );
}
for ( var i = 0; i < completed.length; i++ ) {
var nameList = urlsNames[ completed[ i ] ];
for ( var j = 0; j < nameList.length; j++ ) {
var name = nameList[ j ];
resources[ name ] = this.get( name );
loaded[ name ] = 1;
}
}
callback.call( scope, resources );
}, this );
}
};

View file

@ -1,212 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.scriptLoader} object, used to load scripts
* asynchronously.
*/
/**
* Load scripts asynchronously.
*
* @class
* @singleton
*/
CKEDITOR.scriptLoader = ( function() {
var uniqueScripts = {},
waitingList = {};
return {
/**
* Loads one or more external scripts checking if it has not been loaded
* previously by this function.
*
* CKEDITOR.scriptLoader.load( '/myscript.js' );
*
* CKEDITOR.scriptLoader.load( '/myscript.js', function( success ) {
* // Alerts true if the script has been properly loaded.
* // HTTP error 404 should return false.
* alert( success );
* } );
*
* CKEDITOR.scriptLoader.load( [ '/myscript1.js', '/myscript2.js' ], function( completed, failed ) {
* alert( 'Number of scripts loaded: ' + completed.length );
* alert( 'Number of failures: ' + failed.length );
* } );
*
* @param {String/Array} scriptUrl One or more URLs pointing to the
* scripts to be loaded.
* @param {Function} [callback] A function to be called when the script
* is loaded and executed. If a string is passed to `scriptUrl`, a
* Boolean parameter is passed to the callback, indicating the
* success of the load. If an array is passed instead, two array
* parameters are passed to the callback: the first contains the
* URLs that have been properly loaded and the second the failed ones.
* @param {Object} [scope] The scope (`this` reference) to be used for
* the callback call. Defaults to {@link CKEDITOR}.
* @param {Boolean} [showBusy] Changes the cursor of the document while
* the script is loaded.
*/
load: function( scriptUrl, callback, scope, showBusy ) {
var isString = ( typeof scriptUrl == 'string' );
if ( isString )
scriptUrl = [ scriptUrl ];
if ( !scope )
scope = CKEDITOR;
var scriptCount = scriptUrl.length,
scriptCountDoCallback = scriptCount,
completed = [],
failed = [];
var doCallback = function( success ) {
if ( callback ) {
if ( isString )
callback.call( scope, success );
else
callback.call( scope, completed, failed );
}
};
if ( scriptCountDoCallback === 0 ) {
doCallback( true );
return;
}
var checkLoaded = function( url, success ) {
( success ? completed : failed ).push( url );
if ( --scriptCountDoCallback <= 0 ) {
showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' );
doCallback( success );
}
};
var onLoad = function( url, success ) {
// Mark this script as loaded.
uniqueScripts[ url ] = 1;
// Get the list of callback checks waiting for this file.
var waitingInfo = waitingList[ url ];
delete waitingList[ url ];
// Check all callbacks waiting for this file.
for ( var i = 0; i < waitingInfo.length; i++ )
waitingInfo[ i ]( url, success );
};
var loadScript = function( url ) {
if ( uniqueScripts[ url ] ) {
checkLoaded( url, true );
return;
}
var waitingInfo = waitingList[ url ] || ( waitingList[ url ] = [] );
waitingInfo.push( checkLoaded );
// Load it only for the first request.
if ( waitingInfo.length > 1 )
return;
// Create the <script> element.
var script = new CKEDITOR.dom.element( 'script' );
script.setAttributes( {
type: 'text/javascript',
src: url
} );
if ( callback ) {
// The onload or onerror event does not fire in IE8 and IE9 Quirks Mode (https://dev.ckeditor.com/ticket/14849).
if ( CKEDITOR.env.ie && ( CKEDITOR.env.version <= 8 || CKEDITOR.env.ie9Compat ) ) {
script.$.onreadystatechange = function() {
if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' ) {
script.$.onreadystatechange = null;
onLoad( url, true );
}
};
} else {
script.$.onload = function() {
// Some browsers, such as Safari, may call the onLoad function
// immediately. This will break the loading sequence. (https://dev.ckeditor.com/ticket/3661)
setTimeout( function() {
removeListeners( script );
onLoad( url, true );
}, 0 );
};
script.$.onerror = function() {
removeListeners( script );
onLoad( url, false );
};
}
}
// Append it to <head>.
script.appendTo( CKEDITOR.document.getHead() );
CKEDITOR.fire( 'download', url ); // %REMOVE_LINE%
};
showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' );
for ( var i = 0; i < scriptCount; i++ ) {
loadScript( scriptUrl[ i ] );
}
function removeListeners( script ) {
// Once the script loaded or failed to load, remove listeners as this might lead to memory leaks (#589).
script.$.onload = null;
script.$.onerror = null;
}
},
/**
* Loads a script in a queue, so only one is loaded at the same time.
*
* @since 4.1.2
* @param {String} scriptUrl The URL pointing to the script to be loaded.
* @param {Function} [callback] A function to be called when the script
* is loaded and executed. A Boolean parameter is passed to the callback,
* indicating the success of the load.
*
* @see CKEDITOR.scriptLoader#load
*/
queue: ( function() {
var pending = [];
// Loads the very first script from queue and removes it.
function loadNext() {
var script;
if ( ( script = pending[ 0 ] ) )
this.load( script.scriptUrl, script.callback, CKEDITOR, 0 );
}
return function( scriptUrl, callback ) {
var that = this;
// This callback calls the standard callback for the script
// and loads the very next script from pending list.
function callbackWrapper() {
callback && callback.apply( this, arguments );
// Removed the just loaded script from the queue.
pending.shift();
loadNext.call( that );
}
// Let's add this script to the queue
pending.push( { scriptUrl: scriptUrl, callback: callbackWrapper } );
// If the queue was empty, then start loading.
if ( pending.length == 1 )
loadNext.call( this );
};
} )()
};
} )();

File diff suppressed because it is too large Load diff

View file

@ -1,163 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines methods used for selection optimization.
*/
( function() {
var preventListener = true,
preventOptimization = false;
/**
* Sets editor listeners up to optimize the selection.
*
* **Note**: This method is called automatically during the editor initialization and should not be called manually.
*
* @since 4.13.0
* @static
* @see CKEDITOR.dom.selection.optimizeInElementEnds
* @param {CKEDITOR.editor} editor
* @member CKEDITOR.dom.selection
*/
CKEDITOR.dom.selection.setupEditorOptimization = function( editor ) {
editor.on( 'selectionCheck', function( evt ) {
if ( evt.data && !preventOptimization ) {
evt.data.optimizeInElementEnds();
}
preventOptimization = false;
} );
editor.on( 'contentDom', function() {
var editable = editor.editable();
if ( !editable ) {
return;
}
editable.attachListener( editable, 'keydown', function( evt ) {
this._.shiftPressed = evt.data.$.shiftKey;
}, this );
editable.attachListener( editable, 'keyup', function( evt ) {
this._.shiftPressed = evt.data.$.shiftKey;
}, this );
} );
};
/**
* Performs an optimization on the current selection if necessary.
*
* The general idea is to shrink the range to text when:
*
* * The range starts at the end of an element.
* * The range ends at the start of an element.
* * One of the range ends is anchored in a text node and another in an element.
*
* For example:
*
* ```html
* <p>{foo</p>
* <p>]bar</p>
* ```
*
* is optimized too:
*
* ```html
* <p>{foo}</p>
* <p>bar</p>
* ```
*
* @since 4.13.0
* @member CKEDITOR.dom.selection
*/
CKEDITOR.dom.selection.prototype.optimizeInElementEnds = function() {
var range = this.getRanges()[ 0 ],
editor = this.root.editor;
if ( !shouldOptimize( range, this ) ) {
return;
}
var oldRange = range.clone();
range.shrink( CKEDITOR.SHRINK_TEXT, false, { skipBogus: !CKEDITOR.env.webkit } );
preventListener = false;
preventRecurrency( editor, range, oldRange );
range.select();
preventListener = true;
};
function isText( node ) {
return node.type === CKEDITOR.NODE_TEXT;
}
// Returns `true` if any condition is met:
// * The range starts at the end of an element.
// * The range ends at the start of an element.
// * One end of the range is in text and another one is not.
//
// Always returns `false` when:
// * The Shift key is pressed.
// * The selection is fake.
// * The range is collapsed.
// * The range start and end container is the same element.
function shouldOptimize( range, selection ) {
if ( selection.root.editor._.shiftPressed ) {
return false;
}
if ( selection.isFake || range.isCollapsed || range.startContainer.equals( range.endContainer ) ) {
return false;
}
// The endContainer might be a text inside li element (in IE8).
var isInList = range.endContainer.is ?
range.endContainer.is( 'li' ) :
range.endContainer.getParent().is && range.endContainer.getParent().is( 'li' );
// Prevent optimization in lists (#4931).
if ( isInList ) {
return false;
}
if ( range.endOffset === 0 ) {
return true;
}
var startsInText = isText( range.startContainer ),
endsInText = isText( range.endContainer ),
limit = startsInText ? range.startContainer.getLength() : range.startContainer.getChildCount();
return range.startOffset === limit || startsInText ^ endsInText;
}
// Prevent infinite recurrency when the browser does not allow the expected selection.
// There are two cases to handle:
// - When the browser modified the range in a way that it is the same as before the optimization.
// The second event is canceled, we do not need to fire listeners two times with the exact same selection.
// - When the browser does not modify the range.
// The event is not canceled, as the selection changed, however, the next optimization is prevented.
function preventRecurrency( editor, targetRange, initialRange ) {
editor.once( 'selectionCheck', function( evt ) {
if ( preventListener ) {
return;
}
var newRange = evt.data.getRanges()[ 0 ];
if ( initialRange.equals( newRange ) ) {
evt.cancel();
} else if ( targetRange.equals( newRange ) ) {
preventOptimization = true;
}
}, null, null, -1 );
}
} )();

View file

@ -1,378 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.skin} class that is used to manage skin parts.
*/
( function() {
var cssLoaded = {};
function getName() {
return CKEDITOR.skinName.split( ',' )[ 0 ];
}
function getConfigPath() {
return CKEDITOR.getUrl( CKEDITOR.skinName.split( ',' )[ 1 ] || ( 'skins/' + getName() + '/' ) );
}
/**
* Manages the loading of skin parts among all editor instances.
*
* @class
* @singleton
*/
CKEDITOR.skin = {
/**
* Returns the root path to the skin directory.
*
* @method
* @todo
*/
path: getConfigPath,
/**
* Loads a skin part into the page. Does nothing if the part has already been loaded.
*
* **Note:** The "editor" part is always auto loaded upon instance creation,
* thus this function is mainly used to **lazy load** other parts of the skin
* that do not have to be displayed until requested.
*
* // Load the dialog part.
* editor.skin.loadPart( 'dialog' );
*
* @param {String} part The name of the skin part CSS file that resides in the skin directory.
* @param {Function} fn The provided callback function which is invoked after the part is loaded.
*/
loadPart: function( part, fn ) {
if ( CKEDITOR.skin.name != getName() ) {
CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( getConfigPath() + 'skin.js' ), function() {
loadCss( part, fn );
} );
} else {
loadCss( part, fn );
}
},
/**
* Retrieves the real URL of a (CSS) skin part.
*
* @param {String} part
*/
getPath: function( part ) {
return CKEDITOR.getUrl( getCssPath( part ) );
},
/**
* The list of registered icons. To add new icons to this list, use {@link #addIcon}.
*/
icons: {},
/**
* Registers an icon.
*
* @param {String} name The icon name.
* @param {String} path The path to the icon image file.
* @param {Number} [offset] The vertical offset position of the icon, if
* available inside a strip image.
* @param {String} [bgsize] The value of the CSS "background-size" property to
* use for this icon
*/
addIcon: function( name, path, offset, bgsize ) {
name = name.toLowerCase();
if ( !this.icons[ name ] ) {
this.icons[ name ] = {
path: path,
offset: offset || 0,
bgsize: bgsize || '16px'
};
}
},
/**
* Gets the CSS background styles to be used to render a specific icon.
*
* @param {String} name The icon name, as registered with {@link #addIcon}.
* @param {Boolean} [rtl] Indicates that the RTL version of the icon is
* to be used, if available.
* @param {String} [overridePath] The path to the icon image file. It
* overrides the path defined by the named icon, if available, and is
* used if the named icon was not registered.
* @param {Number} [overrideOffset] The vertical offset position of the
* icon. It overrides the offset defined by the named icon, if
* available, and is used if the named icon was not registered.
* @param {String} [overrideBgsize] The value of the CSS "background-size" property
* to use for the icon. It overrides the value defined by the named icon,
* if available, and is used if the named icon was not registered.
*/
getIconStyle: function( name, rtl, overridePath, overrideOffset, overrideBgsize ) {
var icon, path, offset, bgsize;
if ( name ) {
name = name.toLowerCase();
// If we're in RTL, try to get the RTL version of the icon.
if ( rtl )
icon = this.icons[ name + '-rtl' ];
// If not in LTR or no RTL version available, get the generic one.
if ( !icon )
icon = this.icons[ name ];
}
path = overridePath || ( icon && icon.path ) || '';
offset = overrideOffset || ( icon && icon.offset );
bgsize = overrideBgsize || ( icon && icon.bgsize ) || '16px';
// If we use apostrophes in background-image, we must escape apostrophes in path (just to be sure). (https://dev.ckeditor.com/ticket/13361)
if ( path )
path = path.replace( /'/g, '\\\'' );
return path &&
( 'background-image:url(\'' + CKEDITOR.getUrl( path ) + '\');background-position:0 ' + offset + 'px;background-size:' + bgsize + ';' );
}
};
function getCssPath( part ) {
// Check for ua-specific version of skin part.
var uas = CKEDITOR.skin[ 'ua_' + part ], env = CKEDITOR.env;
if ( uas ) {
// Having versioned UA checked first.
uas = uas.split( ',' ).sort( function( a, b ) {
return a > b ? -1 : 1;
} );
// Loop through all ua entries, checking is any of them match the current ua.
for ( var i = 0, ua; i < uas.length; i++ ) {
ua = uas[ i ];
if ( env.ie ) {
if ( ( ua.replace( /^ie/, '' ) == env.version ) || ( env.quirks && ua == 'iequirks' ) )
ua = 'ie';
}
if ( env[ ua ] ) {
part += '_' + uas[ i ];
break;
}
}
}
return CKEDITOR.getUrl( getConfigPath() + part + '.css' );
}
function loadCss( part, callback ) {
// Avoid reload.
if ( !cssLoaded[ part ] ) {
CKEDITOR.document.appendStyleSheet( getCssPath( part ) );
cssLoaded[ part ] = 1;
}
// CSS loading should not be blocking.
callback && callback();
}
CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
/** Gets the color of the editor user interface.
*
* CKEDITOR.instances.editor1.getUiColor();
*
* @method
* @member CKEDITOR.editor
* @returns {String} uiColor The editor UI color or `undefined` if the UI color is not set.
*/
getUiColor: function() {
return this.uiColor;
},
/** Sets the color of the editor user interface. This method accepts a color value in
* hexadecimal notation, with a `#` character (e.g. #ffffff).
*
* CKEDITOR.instances.editor1.setUiColor( '#ff00ff' );
*
* @method
* @member CKEDITOR.editor
* @param {String} color The desired editor UI color in hexadecimal notation.
*/
setUiColor: function( color ) {
var uiStyle = getStylesheet( CKEDITOR.document );
return ( this.setUiColor = function( color ) {
this.uiColor = color;
var chameleon = CKEDITOR.skin.chameleon,
editorStyleContent = '',
panelStyleContent = '';
if ( typeof chameleon == 'function' ) {
editorStyleContent = chameleon( this, 'editor' );
panelStyleContent = chameleon( this, 'panel' );
}
var replace = [ [ uiColorRegexp, color ] ];
// Update general style.
updateStylesheets( [ uiStyle ], editorStyleContent, replace );
// Update panel styles.
updateStylesheets( uiColorMenus, panelStyleContent, replace );
} ).call( this, color );
}
} );
var uiColorStylesheetId = 'cke_ui_color',
uiColorMenus = [],
uiColorRegexp = /\$color/g;
function getStylesheet( document ) {
var node = document.getById( uiColorStylesheetId );
if ( !node ) {
node = document.getHead().append( 'style' );
node.setAttribute( 'id', uiColorStylesheetId );
node.setAttribute( 'type', 'text/css' );
}
return node;
}
function updateStylesheets( styleNodes, styleContent, replace ) {
var r, i, content;
// We have to split CSS declarations for webkit.
if ( CKEDITOR.env.webkit ) {
styleContent = styleContent.split( '}' ).slice( 0, -1 );
for ( i = 0; i < styleContent.length; i++ )
styleContent[ i ] = styleContent[ i ].split( '{' );
}
for ( var id = 0; id < styleNodes.length; id++ ) {
if ( CKEDITOR.env.webkit ) {
for ( i = 0; i < styleContent.length; i++ ) {
content = styleContent[ i ][ 1 ];
for ( r = 0; r < replace.length; r++ )
content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
styleNodes[ id ].$.sheet.addRule( styleContent[ i ][ 0 ], content );
}
} else {
content = styleContent;
for ( r = 0; r < replace.length; r++ )
content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 )
styleNodes[ id ].$.styleSheet.cssText += content;
else
styleNodes[ id ].$.innerHTML += content;
}
}
}
CKEDITOR.on( 'instanceLoaded', function( evt ) {
// The chameleon feature is not for IE quirks.
if ( CKEDITOR.env.ie && CKEDITOR.env.quirks ) {
return;
}
var editor = evt.editor,
showCallback = function( event ) {
var panel = event.data[ 0 ] || event.data,
iframe = panel.element.getElementsByTag( 'iframe' ).getItem( 0 ).getFrameDocument();
// Add the stylesheet if missing.
if ( !iframe.getById( 'cke_ui_color' ) ) {
var node = getStylesheet( iframe );
uiColorMenus.push( node );
// Cleanup after destroying the editor (#589).
editor.on( 'destroy', function() {
uiColorMenus = CKEDITOR.tools.array.filter( uiColorMenus, function( storedNode ) {
return node !== storedNode;
} );
} );
var color = editor.getUiColor();
// Set uiColor for the new panel.
if ( color ) {
updateStylesheets( [ node ], CKEDITOR.skin.chameleon( editor, 'panel' ), [ [ uiColorRegexp, color ] ] );
}
}
};
editor.on( 'panelShow', showCallback );
editor.on( 'menuShow', showCallback );
// Apply UI color if specified in config.
if ( editor.config.uiColor )
editor.setUiColor( editor.config.uiColor );
} );
} )();
/**
* The list of file names matching the browser user agent string from
* {@link CKEDITOR.env}. This is used to load the skin part file in addition
* to the "main" skin file for a particular browser.
*
* **Note:** For each of the defined skin parts the corresponding
* CSS file with the same name as the user agent must exist inside
* the skin directory.
*
* @property ua
* @todo type?
*/
/**
* The name of the skin that is currently used.
*
* @property {String} name
* @todo
*/
/**
* The editor skin name. Note that it is not possible to have editors with
* different skin settings in the same page. In such case just one of the
* skins will be used for all editors.
*
* This is a shortcut to {@link CKEDITOR#skinName}.
*
* It is possible to install skins outside the default `skin` folder in the
* editor installation. In that case, the absolute URL path to that folder
* should be provided, separated by a comma (`'skin_name,skin_path'`).
*
* config.skin = 'moono';
*
* config.skin = 'myskin,/customstuff/myskin/';
*
* @cfg {String} skin
* @member CKEDITOR.config
*/
/**
* A function that supports the chameleon (skin color switch) feature, providing
* the skin color style updates to be applied in runtime.
*
* **Note:** The embedded `$color` variable is to be substituted with a specific UI color.
*
* @method chameleon
* @param {String} editor The editor instance that the color changes apply to.
* @param {String} part The name of the skin part where the color changes take place.
*/
/**
* To help implement browser-specific "hacks" to the skin files and make it easy to maintain,
* it is possible to have dedicated files for such browsers. The browser files must be named after the main file names,
* appended by an underscore and the browser name (e.g. `editor_ie.css`, `editor_ie8.css`). The accepted browser names
* must match the {@link CKEDITOR.env} properties. You can find more information about browser "hacks" in the
* {@glink guide/skin_sdk_browser_hacks Dedicated Browser Hacks} guide.
*
* CKEDITOR.skin.ua_editor = 'ie,iequirks,ie8,gecko';
*
* @property {String} ua_editor
*/
/**
* Similar to {@link #ua_editor} but used for dialog stylesheets.
*
* CKEDITOR.skin.ua_dialog = 'ie,iequirks,ie8,gecko';
*
* @property {String} ua_dialog
*/

File diff suppressed because it is too large Load diff

View file

@ -1,69 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.template} class, which represents
* an UI template for an editor instance.
*/
( function() {
var rePlaceholder = /{([^}]+)}/g;
/**
* Lightweight template used to build the output string from variables.
*
* // HTML template for presenting a label UI.
* var tpl = new CKEDITOR.template( '<div class="{cls}">{label}</div>' );
* alert( tpl.output( { cls: 'cke-label', label: 'foo'} ) ); // '<div class="cke-label">foo</div>'
*
* // Since 4.12.0 it is possible to pass a callback function that returns a template.
* var tpl2 = new CKEDITOR.template( function( data ) {
* return data.image ? '<img src="{image}" alt="{label}"/>' : '{label}';
* } );
* alert( tpl2.output( { image: null, label: 'foo'} ) ); // 'foo'
* alert( tpl2.output( { image: '/some-image.jpg', label: 'foo'} ) ); // <img src="/some-image.jpg" alt="foo"/>
*
* @class
* @constructor Creates a template class instance.
* @param {String/Function} source A string with the template source or a callback that will return such string.
* The handling of the `Function` type was added in version 4.12.0 .
*/
CKEDITOR.template = function( source ) {
/**
* The current template source.
*
* Note that support for the `Function` type was added in version 4.12.0 .
*
* @readonly
* @member CKEDITOR.template
* @property {String/Function} source
*/
this.source = typeof source === 'function' ? source : String( source );
};
/**
* Processes the template, filling its variables with the provided data.
*
* @method
* @member CKEDITOR.template
* @param {Object} data An object containing properties whose values will be
* used to fill the template variables. The property names must match the
* template variables names. Variables without matching properties will be
* kept untouched.
* @param {Array} [buffer] An array that the output data will be pushed into.
* The number of entries appended to the array is unknown.
* @returns {String/Number} If `buffer` has not been provided, the processed
* template output data; otherwise the new length of `buffer`.
*/
CKEDITOR.template.prototype.output = function( data, buffer ) {
var template = typeof this.source === 'function' ? this.source( data ) : this.source,
output = template.replace( rePlaceholder, function( fullMatch, dataKey ) {
return data[ dataKey ] !== undefined ? data[ dataKey ] : fullMatch;
} );
return buffer ? buffer.push( output ) : output;
};
} )();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,186 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* Contains UI features related to an editor instance.
*
* @class
* @mixins CKEDITOR.event
* @constructor Creates a `ui` class instance.
* @param {CKEDITOR.editor} editor The editor instance.
*/
CKEDITOR.ui = function( editor ) {
if ( editor.ui )
return editor.ui;
this.items = {};
this.instances = {};
this.editor = editor;
/**
* Object used to store private stuff.
*
* @private
*/
this._ = {
handlers: {}
};
return this;
};
// PACKAGER_RENAME( CKEDITOR.ui )
CKEDITOR.ui.prototype = {
/**
* Adds a UI item to the items collection. These items can be later used in
* the interface.
*
* // Add a new button named 'MyBold'.
* editorInstance.ui.add( 'MyBold', CKEDITOR.UI_BUTTON, {
* label: 'My Bold',
* command: 'bold'
* } );
*
* @param {String} name The UI item name.
* @param {Object} type The item type.
* @param {Object} definition The item definition. The properties of this
* object depend on the item type.
*/
add: function( name, type, definition ) {
// Compensate the unique name of this ui item to definition.
definition.name = name.toLowerCase();
var item = this.items[ name ] = {
type: type,
// The name of {@link CKEDITOR.command} which associate with this UI.
command: definition.command || null,
args: Array.prototype.slice.call( arguments, 2 )
};
CKEDITOR.tools.extend( item, definition );
},
/**
* Retrieves the created UI objects by name.
*
* @param {String} name The name of the UI definition.
* @returns {Object} The UI object.
*/
get: function( name ) {
return this.instances[ name ];
},
/**
* Gets a UI object.
*
* @param {String} name The UI item name.
* @returns {Object} The UI element.
*/
create: function( name ) {
var item = this.items[ name ],
handler = item && this._.handlers[ item.type ],
command = item && item.command && this.editor.getCommand( item.command );
var result = handler && handler.create.apply( this, item.args );
this.instances[ name ] = result;
// Add reference inside command object.
if ( command )
command.uiItems.push( result );
if ( result && !result.type )
result.type = item.type;
return result;
},
/**
* Adds a handler for a UI item type. The handler is responsible for
* transforming UI item definitions into UI objects.
*
* @param {Object} type The item type.
* @param {Object} handler The handler definition.
*/
addHandler: function( type, handler ) {
this._.handlers[ type ] = handler;
},
/**
* Returns the unique DOM element that represents one editor's UI part, also known as "space".
* There are 3 main editor spaces available: `top`, `contents` and `bottom`
* and their availability depends on editor type.
*
* // Hide the bottom space in the UI.
* var bottom = editor.ui.space( 'bottom' );
* bottom.setStyle( 'display', 'none' );
*
* @param {String} name The name of the space.
* @returns {CKEDITOR.dom.element} The element that represents the space.
*/
space: function( name ) {
return CKEDITOR.document.getById( this.spaceId( name ) );
},
/**
* Returns the HTML ID for a specific UI space name.
*
* @param {String} name The name of the space.
* @returns {String} The ID of an element representing this space in the DOM.
*/
spaceId: function( name ) {
return this.editor.id + '_' + name;
}
};
CKEDITOR.event.implementOn( CKEDITOR.ui );
/**
* Internal event fired when a new UI element is ready.
*
* @event ready
* @param {Object} data The new UI element.
*/
/**
* Virtual class which just illustrates the features of handler objects to be
* passed to the {@link CKEDITOR.ui#addHandler} function.
* This class is not really a part of the API, so do not call its constructor.
*
* @class CKEDITOR.ui.handlerDefinition
*/
/**
* Transforms an item definition into a UI item object.
*
* editorInstance.ui.addHandler( CKEDITOR.UI_BUTTON, {
* create: function( definition ) {
* return new CKEDITOR.ui.button( definition );
* }
* } );
*
* @method create
* @param {Object} definition The item definition.
* @returns {Object} The UI element.
* @todo We lack the "UI element" abstract super class.
*/
/**
* The element in the {@link CKEDITOR#document host page's document} that contains the editor content.
* If the {@glink features/uitypes#fixed-user-interface fixed editor UI} is used, then it will be set to
* `editor.ui.space( 'contents' )` &mdash; i.e. the `<div>` which contains the editor `<iframe>` (in case of classic editor)
* or {@link CKEDITOR.editable} (in case of inline editor). Otherwise it is set to the {@link CKEDITOR.editable} itself.
*
* Use the position of this element if you need to position elements placed in the host page's document relatively to the
* editor content.
*
* var editor = CKEDITOR.instances.editor1;
* console.log( editor.ui.contentsElement.getName() ); // 'div'
*
* @since 4.5.0
* @readonly
* @property {CKEDITOR.dom.element} contentsElement
*/

View file

@ -1,63 +0,0 @@
Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
af.js Found: 62 Missing: 4
ar.js Found: 51 Missing: 15
bg.js Found: 58 Missing: 8
bn.js Found: 40 Missing: 26
bs.js Found: 29 Missing: 37
ca.js Found: 61 Missing: 5
cs.js Found: 66 Missing: 0
cy.js Found: 66 Missing: 0
da.js Found: 66 Missing: 0
de.js Found: 66 Missing: 0
el.js Found: 59 Missing: 7
en-au.js Found: 38 Missing: 28
en-ca.js Found: 37 Missing: 29
en-gb.js Found: 61 Missing: 5
eo.js Found: 66 Missing: 0
es.js Found: 66 Missing: 0
et.js Found: 66 Missing: 0
eu.js Found: 48 Missing: 18
fa.js Found: 66 Missing: 0
fi.js Found: 66 Missing: 0
fo.js Found: 66 Missing: 0
fr-ca.js Found: 42 Missing: 24
fr.js Found: 66 Missing: 0
gl.js Found: 40 Missing: 26
gu.js Found: 66 Missing: 0
he.js Found: 66 Missing: 0
hi.js Found: 43 Missing: 23
hr.js Found: 66 Missing: 0
hu.js Found: 63 Missing: 3
is.js Found: 41 Missing: 25
it.js Found: 66 Missing: 0
ja.js Found: 62 Missing: 4
ka.js Found: 62 Missing: 4
km.js Found: 40 Missing: 26
ko.js Found: 40 Missing: 26
lt.js Found: 66 Missing: 0
lv.js Found: 40 Missing: 26
mk.js Found: 0 Missing: 66
mn.js Found: 40 Missing: 26
ms.js Found: 39 Missing: 27
nb.js Found: 66 Missing: 0
nl.js Found: 65 Missing: 1
no.js Found: 66 Missing: 0
pl.js Found: 66 Missing: 0
pt-br.js Found: 66 Missing: 0
pt.js Found: 52 Missing: 14
ro.js Found: 61 Missing: 5
ru.js Found: 66 Missing: 0
sk.js Found: 49 Missing: 17
sl.js Found: 48 Missing: 18
sr-latn.js Found: 40 Missing: 26
sr.js Found: 40 Missing: 26
sv.js Found: 62 Missing: 4
th.js Found: 40 Missing: 26
tr.js Found: 66 Missing: 0
ug.js Found: 66 Missing: 0
uk.js Found: 66 Missing: 0
vi.js Found: 66 Missing: 0
zh-cn.js Found: 66 Missing: 0
zh.js Found: 58 Missing: 8

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Afrikaans language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'af' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Woordverwerker',
editorPanel: 'Woordverwerkerpaneel',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Druk op ALT 0 vir hulp',
browseServer: 'Blaai op bediener',
url: 'URL',
protocol: 'Protokol',
upload: 'Oplaai',
uploadSubmit: 'Stuur aan die bediener',
image: 'Beeld',
form: 'Vorm',
checkbox: 'Merkhokkie',
radio: 'Radioknoppie',
textField: 'Teksveld',
textarea: 'Teksarea',
hiddenField: 'Versteekteveld',
button: 'Knop',
select: 'Keuseveld',
imageButton: 'Beeldknop',
notSet: '<geen instelling>',
id: 'Id',
name: 'Naam',
langDir: 'Skryfrigting',
langDirLtr: 'Links na regs (LTR)',
langDirRtl: 'Regs na links (RTL)',
langCode: 'Taalkode',
longDescr: 'Lang beskrywing URL',
cssClass: 'CSS klasse',
advisoryTitle: 'Aanbevole titel',
cssStyle: 'Styl',
ok: 'OK',
cancel: 'Kanselleer',
close: 'Sluit',
preview: 'Voorbeeld',
resize: 'Skalierung',
generalTab: 'Algemeen',
advancedTab: 'Gevorderd',
validateNumberFailed: 'Hierdie waarde is nie \'n nommer nie.',
confirmNewPage: 'Alle wysiginge sal verlore gaan. Is jy seker dat jy \'n nuwe bladsy wil laai?',
confirmCancel: 'Sommige opsies is gewysig. Is jy seker dat jy hierdie dialoogvenster wil sluit?',
options: 'Opsies',
target: 'Teiken',
targetNew: 'Nuwe venster (_blank)',
targetTop: 'Boonste venster (_top)',
targetSelf: 'Selfde venster (_self)',
targetParent: 'Oorspronklike venster (_parent)',
langDirLTR: 'Links na Regs (LTR)',
langDirRTL: 'Regs na Links (RTL)',
styles: 'Styl',
cssClasses: 'CSS klasse',
width: 'Breedte',
height: 'Hoogte',
align: 'Orienteerung',
left: 'Links',
right: 'Regs',
center: 'Middel',
justify: 'Eweredig',
alignLeft: 'Links oplyn',
alignRight: 'Regs oplyn',
alignCenter: 'Middel oplyn',
alignTop: 'Bo',
alignMiddle: 'Middel',
alignBottom: 'Onder',
alignNone: 'Geen',
invalidValue: 'Ongeldige waarde',
invalidHeight: 'Hoogte moet \'n getal wees',
invalidWidth: 'Breedte moet \'n getal wees.',
invalidLength: 'Die waarde vir die veld "%1" moet \'n posetiewe nommer wees met of sonder die meeteenheid (%2).',
invalidCssLength: 'Die waarde vir die "%1" veld moet \'n posetiewe getal wees met of sonder \'n geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).',
invalidHtmlLength: 'Die waarde vir die "%1" veld moet \'n posetiewe getal wees met of sonder \'n geldige HTML eenheid (px of %).',
invalidInlineStyle: 'Ongeldige CSS. Formaat is een of meer sleutel-wert paare, "naam : wert" met kommapunte gesky.',
cssLengthTooltip: 'Voeg \'n getal wert in pixel in, of \'n waarde met geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, nie beskikbaar nie</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Skuif',
17: 'Ctrl',
18: 'Alt',
32: 'Spasie',
35: 'Einde',
36: 'Tuis',
46: 'Verwyder',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Bevel'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Sleutel kombenasie',
optionDefault: 'Verstek'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Arabic language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'ar' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'محرر النص الغني',
editorPanel: 'لائحة محرر النص المنسق',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'إضغط على ALT + 0 للحصول على المساعدة.',
browseServer: 'تصفح',
url: 'الرابط',
protocol: 'البروتوكول',
upload: 'رفع',
uploadSubmit: 'أرسل',
image: 'صورة',
form: 'نموذج',
checkbox: 'خانة إختيار',
radio: 'زر اختيار',
textField: 'مربع نص',
textarea: 'مساحة نصية',
hiddenField: 'إدراج حقل خفي',
button: 'زر ضغط',
select: 'اختار',
imageButton: 'زر صورة',
notSet: '<بدون تحديد>',
id: 'الرقم',
name: 'إسم',
langDir: 'إتجاه النص',
langDirLtr: 'اليسار لليمين (LTR)',
langDirRtl: 'اليمين لليسار (RTL)',
langCode: 'رمز اللغة',
longDescr: 'الوصف التفصيلى',
cssClass: 'فئات التنسيق',
advisoryTitle: 'عنوان التقرير',
cssStyle: 'نمط',
ok: 'موافق',
cancel: 'إلغاء الأمر',
close: 'أغلق',
preview: 'استعراض',
resize: 'تغيير الحجم',
generalTab: 'عام',
advancedTab: 'متقدم',
validateNumberFailed: 'لايوجد نتيجة',
confirmNewPage: 'ستفقد أي متغييرات اذا لم تقم بحفظها اولا. هل أنت متأكد أنك تريد صفحة جديدة؟',
confirmCancel: 'بعض الخيارات قد تغيرت. هل أنت متأكد من إغلاق مربع النص؟',
options: 'خيارات',
target: 'هدف الرابط',
targetNew: 'نافذة جديدة',
targetTop: 'النافذة الأعلى',
targetSelf: 'داخل النافذة',
targetParent: 'النافذة الأم',
langDirLTR: 'اليسار لليمين (LTR)',
langDirRTL: 'اليمين لليسار (RTL)',
styles: 'نمط',
cssClasses: 'فئات التنسيق',
width: 'العرض',
height: 'الإرتفاع',
align: 'محاذاة',
left: 'يسار',
right: 'يمين',
center: 'وسط',
justify: 'ضبط',
alignLeft: 'محاذاة إلى اليسار',
alignRight: 'محاذاة إلى اليمين',
alignCenter: 'Align Center', // MISSING
alignTop: 'أعلى',
alignMiddle: 'وسط',
alignBottom: 'أسفل',
alignNone: 'None', // MISSING
invalidValue: 'قيمة غير مفبولة.',
invalidHeight: 'الارتفاع يجب أن يكون عدداً.',
invalidWidth: 'العرض يجب أن يكون عدداً.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'قيمة الخانة المخصصة لـ "%1" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة CSS قياس مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).',
invalidHtmlLength: 'قيمة الخانة المخصصة لـ "%1" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة HTML قياس مقبولة (px or %).',
invalidInlineStyle: 'قيمة الخانة المخصصة لـ Inline Style يجب أن تختوي على مجموع واحد أو أكثر بالشكل التالي: "name : value", مفصولة بفاصلة منقزطة.',
cssLengthTooltip: 'أدخل رقما للقيمة بالبكسل أو رقما بوحدة CSS مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, غير متاح</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object for the
* Azerbaijani language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'az' ] = {
// ARIA description.
application: 'Rich Text Redaktoru',
editor: 'Redaktor',
editorPanel: 'Mətn Redaktorun Paneli',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Yardım üçün ALT 0 düymələrini basın',
browseServer: 'Fayların siyahı',
url: 'URL',
protocol: 'Protokol',
upload: 'Serverə yüklə',
uploadSubmit: 'Göndər',
image: 'Şəkil',
form: 'Forma',
checkbox: 'Çekboks',
radio: 'Radio düyməsi',
textField: 'Mətn xanası',
textarea: 'Mətn',
hiddenField: 'Gizli xana',
button: 'Düymə',
select: 'Opsiyaların seçilməsi',
imageButton: 'Şəkil tipli düymə',
notSet: '<seçilməmiş>',
id: 'Id',
name: 'Ad',
langDir: 'Yaziların istiqaməti',
langDirLtr: 'Soldan sağa (LTR)',
langDirRtl: 'Sağdan sola (RTL)',
langCode: 'Dilin kodu',
longDescr: 'URL-ın ətraflı izahı',
cssClass: 'CSS klassları',
advisoryTitle: 'Başlıq',
cssStyle: 'CSS',
ok: 'Tədbiq et',
cancel: 'İmtina et',
close: 'Bağla',
preview: 'Baxış',
resize: 'Eni dəyiş',
generalTab: 'Əsas',
advancedTab: 'Əlavə',
validateNumberFailed: 'Rəqəm deyil.',
confirmNewPage: 'Yadda saxlanılmamış dəyişikliklər itiriləcək. Davam etmək istədiyinizə əminsinizmi?',
confirmCancel: 'Dəyişikliklər edilib. Pəncərəni bağlamaq istəyirsizə əminsinizmi?',
options: 'Seçimlər',
target: 'Hədəf çərçivə',
targetNew: 'Yeni pəncərə (_blank)',
targetTop: 'Əsas pəncərə (_top)',
targetSelf: 'Carı pəncərə (_self)',
targetParent: 'Ana pəncərə (_parent)',
langDirLTR: 'Soldan sağa (LTR)',
langDirRTL: 'Sağdan sola (RTL)',
styles: 'Üslub',
cssClasses: 'Üslub klası',
width: 'En',
height: 'Uzunluq',
align: 'Yerləşmə',
left: 'Sol',
right: 'Sağ',
center: 'Mərkəz',
justify: 'Eninə görə',
alignLeft: 'Soldan düzləndir',
alignRight: 'Sağdan düzləndir',
alignCenter: 'Mərkəzə düzləndir',
alignTop: 'Yuxarı',
alignMiddle: 'Orta',
alignBottom: 'Aşağı',
alignNone: 'Yoxdur',
invalidValue: 'Yanlışdır.',
invalidHeight: 'Hündürlük rəqəm olmalıdır.',
invalidWidth: 'En rəqəm olmalıdır.',
invalidLength: '"%1" xanasına, ölçü vahidinin (%2) göstərilməsindən asılı olmayaraq, müsbət ədəd qeyd olunmalıdır.',
invalidCssLength: '"%1" xanasında göstərilən məzmun tam və müsbət olmalıdır, CSS-də olan ölçü vahidlərin (px, %, in, cm, mm, em, ex, pt, or pc) istifadısinə icazə verilir.',
invalidHtmlLength: '"%1" xanasında göstərilən məzmun tam və müsbət olmalıdır HTML-də olan ölçü vahidlərin (px və ya %) istifadısinə icazə verilir.',
invalidInlineStyle: 'Teq içində olan üslub "ad : məzmun" şəklidə, nöqtə-verqül işarəsi ilə bitməlidir',
cssLengthTooltip: 'Piksel sayı və ya digər CSS ölçü vahidləri (px, %, in, cm, mm, em, ex, pt, or pc) daxil edin.',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, mövcud deyil</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Boşluq',
35: 'Son',
36: 'Evə',
46: 'Sil',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Əmr'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Qısayol düymələri',
optionDefault: 'Standart'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Bulgarian language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'bg' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Редактор за форматиран текст',
editorPanel: 'Панел на текстовия редактор',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'натиснете ALT+0 за помощ',
browseServer: 'Избор от сървъра',
url: 'URL адрес',
protocol: 'Протокол',
upload: 'Качване',
uploadSubmit: 'Изпращане към сървъра',
image: 'Изображение',
form: 'Форма',
checkbox: 'Поле за избор',
radio: 'Радио бутон',
textField: 'Текстово поле',
textarea: 'Текстова зона',
hiddenField: 'Скрито поле',
button: 'Бутон',
select: 'Поле за избор',
imageButton: 'Бутон за изображение',
notSet: '<не е избрано>',
id: 'ID',
name: 'Име',
langDir: 'Посока на езика',
langDirLtr: 'От ляво надясно (LTR)',
langDirRtl: 'От дясно наляво (RTL)',
langCode: 'Код на езика',
longDescr: 'Уеб адрес за дълго описание',
cssClass: 'Класове за CSS',
advisoryTitle: 'Заглавие',
cssStyle: 'Стил',
ok: 'ОК',
cancel: 'Отказ',
close: 'Затвори',
preview: 'Преглед',
resize: 'Влачете за да оразмерите',
generalTab: 'Общи',
advancedTab: 'Разширено',
validateNumberFailed: 'Тази стойност не е число',
confirmNewPage: 'Всички незапазени промени ще бъдат изгубени. Сигурни ли сте, че желаете да заредите нова страница?',
confirmCancel: 'Някои от опциите са променени. Сигурни ли сте, че желаете да затворите прозореца?',
options: 'Опции',
target: 'Цел',
targetNew: 'Нов прозорец (_blank)',
targetTop: 'Най-горният прозорец (_top)',
targetSelf: 'Текущият прозорец (_self)',
targetParent: 'Горният прозорец (_parent)',
langDirLTR: 'От ляво надясно (LTR)',
langDirRTL: 'От дясно наляво (RTL)',
styles: 'Стил',
cssClasses: 'Класове за CSS',
width: 'Ширина',
height: 'Височина',
align: 'Подравняване',
left: 'Ляво',
right: 'Дясно',
center: 'Център',
justify: 'Двустранно',
alignLeft: 'Подравни ляво',
alignRight: 'Подравни дясно',
alignCenter: 'Подравни център',
alignTop: 'Горе',
alignMiddle: 'По средата',
alignBottom: 'Долу',
alignNone: 'Без подравняване',
invalidValue: 'Невалидна стойност.',
invalidHeight: 'Височината трябва да е число.',
invalidWidth: 'Ширина трябва да е число.',
invalidLength: 'Стойността на полето "%1" трябва да е положително число с или без валидна мерна единица (%2).',
invalidCssLength: 'Стойността на полето "%1" трябва да е положително число с или без валидна CSS мерна единица (px, %, in, cm, mm, em, ex, pt, или pc).',
invalidHtmlLength: 'Стойността на полето "%1" трябва да е положително число с или без валидна HTML мерна единица (px или %).',
invalidInlineStyle: 'Стойността на стилa трябва да съдържат една или повече двойки във формат "name : value", разделени с двоеточие.',
cssLengthTooltip: 'Въведете числена стойност в пиксели или друга валидна CSS единица (px, %, in, cm, mm, em, ex, pt, или pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, недостъпно</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Space',
35: 'End',
36: 'Home',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Command'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Клавишна комбинация',
optionDefault: 'По подразбиране'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Bengali/Bangla language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'bn' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Editor', // MISSING
editorPanel: 'Rich Text Editor panel', // MISSING
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help', // MISSING
browseServer: 'ব্রাউজ সার্ভার',
url: 'URL',
protocol: 'প্রোটোকল',
upload: 'আপলোড',
uploadSubmit: 'ইহাকে সার্ভারে প্রেরন কর',
image: 'ছবির লেবেল যুক্ত কর',
form: 'ফর্ম',
checkbox: 'চেক বাক্স',
radio: 'রেডিও বাটন',
textField: 'টেক্সট ফীল্ড',
textarea: 'টেক্সট এরিয়া',
hiddenField: 'গুপ্ত ফীল্ড',
button: 'বাটন',
select: 'বাছাই ফীল্ড',
imageButton: 'ছবির বাটন',
notSet: '<সেট নেই>',
id: 'আইডি',
name: 'নাম',
langDir: 'ভাষা লেখার দিক',
langDirLtr: 'বাম থেকে ডান (LTR)',
langDirRtl: 'ডান থেকে বাম (RTL)',
langCode: 'ভাষা কোড',
longDescr: 'URL এর লম্বা বর্ণনা',
cssClass: 'স্টাইল-শীট ক্লাস',
advisoryTitle: 'পরামর্শ শীর্ষক',
cssStyle: 'স্টাইল',
ok: 'ওকে',
cancel: 'বাতিল',
close: 'Close', // MISSING
preview: 'প্রিভিউ',
resize: 'Resize', // MISSING
generalTab: 'General', // MISSING
advancedTab: 'এডভান্সড',
validateNumberFailed: 'This value is not a number.', // MISSING
confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
options: 'Options', // MISSING
target: 'টার্গেট',
targetNew: 'New Window (_blank)', // MISSING
targetTop: 'Topmost Window (_top)', // MISSING
targetSelf: 'Same Window (_self)', // MISSING
targetParent: 'Parent Window (_parent)', // MISSING
langDirLTR: 'বাম থেকে ডান (LTR)',
langDirRTL: 'ডান থেকে বাম (RTL)',
styles: 'স্টাইল',
cssClasses: 'স্টাইল-শীট ক্লাস',
width: 'প্রস্থ',
height: 'দৈর্ঘ্য',
align: 'এলাইন',
left: 'বামে',
right: 'ডানে',
center: 'মাঝখানে',
justify: 'ব্লক জাস্টিফাই',
alignLeft: 'বা দিকে ঘেঁষা',
alignRight: 'ডান দিকে ঘেঁষা',
alignCenter: 'Align Center', // MISSING
alignTop: 'উপর',
alignMiddle: 'মধ্য',
alignBottom: 'নীচে',
alignNone: 'None', // MISSING
invalidValue: 'Invalid value.', // MISSING
invalidHeight: 'Height must be a number.', // MISSING
invalidWidth: 'Width must be a number.', // MISSING
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Bosnian language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'bs' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Editor', // MISSING
editorPanel: 'Rich Text Editor panel', // MISSING
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help', // MISSING
browseServer: 'Browse Server', // MISSING
url: 'URL',
protocol: 'Protokol',
upload: 'Šalji',
uploadSubmit: 'Šalji na server',
image: 'Slika',
form: 'Forma',
checkbox: 'Checkbox', // MISSING
radio: 'Radio Button', // MISSING
textField: 'Polje za unos teksta',
textarea: 'Textarea', // MISSING
hiddenField: 'Skriveno polje',
button: 'Button',
select: 'Selection Field', // MISSING
imageButton: 'Image Button', // MISSING
notSet: '<nije podešeno>',
id: 'Id',
name: 'Naziv',
langDir: 'Smjer pisanja',
langDirLtr: 'S lijeva na desno (LTR)',
langDirRtl: 'S desna na lijevo (RTL)',
langCode: 'Jezièni kôd',
longDescr: 'Dugaèki opis URL-a',
cssClass: 'Klase CSS stilova',
advisoryTitle: 'Advisory title',
cssStyle: 'Stil',
ok: 'OK',
cancel: 'Odustani',
close: 'Zatvori',
preview: 'Prikaži',
resize: 'Promijeni veličinu',
generalTab: 'Generalno',
advancedTab: 'Naprednije',
validateNumberFailed: 'Unesena vrijednost nije broj',
confirmNewPage: 'Nesačuvane izmjene će biti izgubljene. Da li ste sigurni da želite otvoriti novu stranicu ?',
confirmCancel: 'Napravili ste par izmjena. Da li želite zatvoriti prozor ?',
options: 'Opcije',
target: 'Prozor',
targetNew: 'New Window (_blank)', // MISSING
targetTop: 'Topmost Window (_top)', // MISSING
targetSelf: 'Same Window (_self)', // MISSING
targetParent: 'Parent Window (_parent)', // MISSING
langDirLTR: 'S lijeva na desno (LTR)',
langDirRTL: 'S desna na lijevo (RTL)',
styles: 'Stil',
cssClasses: 'Klase CSS stilova',
width: 'Širina',
height: 'Visina',
align: 'Poravnanje',
left: 'Lijevo',
right: 'Desno',
center: 'Centar',
justify: 'Puno poravnanje',
alignLeft: 'Lijevo poravnanje',
alignRight: 'Desno poravnanje',
alignCenter: 'Centriranje',
alignTop: 'Vrh',
alignMiddle: 'Sredina',
alignBottom: 'Dno',
alignNone: 'Bez poravnanja',
invalidValue: 'Nepravilna vrijednost',
invalidHeight: 'Vrijednost visine mora biti broj.',
invalidWidth: 'Vrijednost širine mora biti broj.',
invalidLength: 'Vrijednost za "%1" polje mora biti pozitivan broj ili bez ispravne mjerne jedinice (%2).',
invalidCssLength: 'Vrijednost za "%1" polje mora biti pozitivan broj ili bez validne CSS mjerne jedinice (px, %, in, cm, mm, em, ex, pt ili pc).',
invalidHtmlLength: 'Vrijednost za "%1" polje mora biti pozitivan broj ili bez validne HTML mjerne jedinice (px ili %).',
invalidInlineStyle: 'Vrijednost za inline stil mora sadržavati jedan ili više parova u formatu "name: value", razdvojenih tačka-zarezom.',
cssLengthTooltip: 'Unesite vrijednost u pikselima ili kao broj sa ispravnom CSS jedinicom (px, %, in, cm, mm, em, ex, pt ili pc).',
// Put the voice-only part of the label in the span.
unavailable: '$1<span class="cke_accessibility">, nedostupno</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Zadano'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Catalan language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'ca' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Editor de text enriquit',
editorPanel: 'Panell de l\'editor de text enriquit',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Premeu ALT 0 per ajuda',
browseServer: 'Veure servidor',
url: 'URL',
protocol: 'Protocol',
upload: 'Puja',
uploadSubmit: 'Envia-la al servidor',
image: 'Imatge',
form: 'Formulari',
checkbox: 'Casella de verificació',
radio: 'Botó d\'opció',
textField: 'Camp de text',
textarea: 'Àrea de text',
hiddenField: 'Camp ocult',
button: 'Botó',
select: 'Camp de selecció',
imageButton: 'Botó d\'imatge',
notSet: '<no definit>',
id: 'Id',
name: 'Nom',
langDir: 'Direcció de l\'idioma',
langDirLtr: 'D\'esquerra a dreta (LTR)',
langDirRtl: 'De dreta a esquerra (RTL)',
langCode: 'Codi d\'idioma',
longDescr: 'Descripció llarga de la URL',
cssClass: 'Classes del full d\'estil',
advisoryTitle: 'Títol consultiu',
cssStyle: 'Estil',
ok: 'D\'acord',
cancel: 'Cancel·la',
close: 'Tanca',
preview: 'Previsualitza',
resize: 'Arrossegueu per redimensionar',
generalTab: 'General',
advancedTab: 'Avançat',
validateNumberFailed: 'Aquest valor no és un número.',
confirmNewPage: 'Els canvis en aquest contingut que no es desin es perdran. Esteu segur que voleu carregar una pàgina nova?',
confirmCancel: 'Algunes opcions s\'han canviat. Esteu segur que voleu tancar el quadre de diàleg?',
options: 'Opcions',
target: 'Destí',
targetNew: 'Nova finestra (_blank)',
targetTop: 'Finestra superior (_top)',
targetSelf: 'Mateixa finestra (_self)',
targetParent: 'Finestra pare (_parent)',
langDirLTR: 'D\'esquerra a dreta (LTR)',
langDirRTL: 'De dreta a esquerra (RTL)',
styles: 'Estil',
cssClasses: 'Classes del full d\'estil',
width: 'Amplada',
height: 'Alçada',
align: 'Alineació',
left: 'Ajusta a l\'esquerra',
right: 'Ajusta a la dreta',
center: 'Centre',
justify: 'Justificat',
alignLeft: 'Alinea a l\'esquerra',
alignRight: 'Alinea a la dreta',
alignCenter: 'Align Center', // MISSING
alignTop: 'Superior',
alignMiddle: 'Centre',
alignBottom: 'Inferior',
alignNone: 'Cap',
invalidValue: 'Valor no vàlid.',
invalidHeight: 'L\'alçada ha de ser un número.',
invalidWidth: 'L\'amplada ha de ser un número.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'El valor especificat per als "%1" camps ha de ser un número positiu amb o sense unitat de mesura vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).',
invalidHtmlLength: 'El valor especificat per als "%1" camps ha de ser un número positiu amb o sense unitat de mesura vàlida d\'HTML (px o %).',
invalidInlineStyle: 'El valor especificat per l\'estil en línia ha de constar d\'una o més tuples amb el format "name: value", separats per punt i coma.',
cssLengthTooltip: 'Introduïu un número per un valor en píxels o un número amb una unitat vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, no disponible</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Retrocés',
13: 'Intro',
16: 'Majúscules',
17: 'Ctrl',
18: 'Alt',
32: 'Space', // MISSING
35: 'Fi',
36: 'Inici',
46: 'Eliminar',
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Czech language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'cs' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Textový editor',
editorPanel: 'Panel textového editoru',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Stiskněte ALT 0 pro nápovědu',
browseServer: 'Vybrat na serveru',
url: 'URL',
protocol: 'Protokol',
upload: 'Odeslat',
uploadSubmit: 'Odeslat na server',
image: 'Obrázek',
form: 'Formulář',
checkbox: 'Zaškrtávací políčko',
radio: 'Přepínač',
textField: 'Textové pole',
textarea: 'Textová oblast',
hiddenField: 'Skryté pole',
button: 'Tlačítko',
select: 'Seznam',
imageButton: 'Obrázkové tlačítko',
notSet: '<nenastaveno>',
id: 'Id',
name: 'Jméno',
langDir: 'Směr jazyka',
langDirLtr: 'Zleva doprava (LTR)',
langDirRtl: 'Zprava doleva (RTL)',
langCode: 'Kód jazyka',
longDescr: 'Dlouhý popis URL',
cssClass: 'Třída stylu',
advisoryTitle: 'Pomocný titulek',
cssStyle: 'Styl',
ok: 'OK',
cancel: 'Zrušit',
close: 'Zavřít',
preview: 'Náhled',
resize: 'Uchopit pro změnu velikosti',
generalTab: 'Obecné',
advancedTab: 'Rozšířené',
validateNumberFailed: 'Zadaná hodnota není číselná.',
confirmNewPage: 'Jakékoliv neuložené změny obsahu budou ztraceny. Skutečně chcete otevřít novou stránku?',
confirmCancel: 'Některá z nastavení byla změněna. Skutečně chcete zavřít dialogové okno?',
options: 'Nastavení',
target: 'Cíl',
targetNew: 'Nové okno (_blank)',
targetTop: 'Okno nejvyšší úrovně (_top)',
targetSelf: 'Stejné okno (_self)',
targetParent: 'Rodičovské okno (_parent)',
langDirLTR: 'Zleva doprava (LTR)',
langDirRTL: 'Zprava doleva (RTL)',
styles: 'Styly',
cssClasses: 'Třídy stylů',
width: 'Šířka',
height: 'Výška',
align: 'Zarovnání',
left: 'Vlevo',
right: 'Vpravo',
center: 'Na střed',
justify: 'Zarovnat do bloku',
alignLeft: 'Zarovnat vlevo',
alignRight: 'Zarovnat vpravo',
alignCenter: 'Zarovnat na střed',
alignTop: 'Nahoru',
alignMiddle: 'Na střed',
alignBottom: 'Dolů',
alignNone: 'Žádné',
invalidValue: 'Neplatná hodnota.',
invalidHeight: 'Zadaná výška musí být číslo.',
invalidWidth: 'Šířka musí být číslo.',
invalidLength: 'Hodnota určená pro pole "%1" musí být kladné číslo bez nebo s platnou jednotkou míry (%2).',
invalidCssLength: 'Hodnota určená pro pole "%1" musí být kladné číslo bez nebo s platnou jednotkou míry CSS (px, %, in, cm, mm, em, ex, pt, nebo pc).',
invalidHtmlLength: 'Hodnota určená pro pole "%1" musí být kladné číslo bez nebo s platnou jednotkou míry HTML (px nebo %).',
invalidInlineStyle: 'Hodnota určená pro řádkový styl se musí skládat z jedné nebo více n-tic ve formátu "název : hodnota", oddělené středníky',
cssLengthTooltip: 'Zadejte číslo jako hodnotu v pixelech nebo číslo s platnou jednotkou CSS (px, %, v cm, mm, em, ex, pt, nebo pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, nedostupné</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Mezerník',
35: 'Konec',
36: 'Domů',
46: 'Smazat',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Command'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Klávesová zkratka',
optionDefault: 'Výchozí'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Welsh language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'cy' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Golygydd Testun Cyfoethog',
editorPanel: 'Panel Golygydd Testun Cyfoethog',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Gwasgwch ALT 0 am gymorth',
browseServer: 'Pori\'r Gweinydd',
url: 'URL',
protocol: 'Protocol',
upload: 'Lanlwytho',
uploadSubmit: 'Anfon i\'r Gweinydd',
image: 'Delwedd',
form: 'Ffurflen',
checkbox: 'Blwch ticio',
radio: 'Botwm Radio',
textField: 'Maes Testun',
textarea: 'Ardal Testun',
hiddenField: 'Maes Cudd',
button: 'Botwm',
select: 'Maes Dewis',
imageButton: 'Botwm Delwedd',
notSet: '<heb osod>',
id: 'Id',
name: 'Name',
langDir: 'Cyfeiriad Iaith',
langDirLtr: 'Chwith i\'r Dde (LTR)',
langDirRtl: 'Dde i\'r Chwith (RTL)',
langCode: 'Cod Iaith',
longDescr: 'URL Disgrifiad Hir',
cssClass: 'Dosbarthiadau Dalen Arddull',
advisoryTitle: 'Teitl Cynghorol',
cssStyle: 'Arddull',
ok: 'Iawn',
cancel: 'Diddymu',
close: 'Cau',
preview: 'Rhagolwg',
resize: 'Ailfeintio',
generalTab: 'Cyffredinol',
advancedTab: 'Uwch',
validateNumberFailed: '\'Dyw\'r gwerth hwn ddim yn rhif.',
confirmNewPage: 'Byddwch chi\'n colli unrhyw newidiadau i\'r cynnwys sydd heb eu cadw. Ydych am barhau i lwytho tudalen newydd?',
confirmCancel: 'Cafodd rhai o\'r opsiynau eu newid. Ydych chi wir am gau\'r deialog?',
options: 'Opsiynau',
target: 'Targed',
targetNew: 'Ffenest Newydd (_blank)',
targetTop: 'Ffenest ar y Brig (_top)',
targetSelf: 'Yr un Ffenest (_self)',
targetParent: 'Ffenest y Rhiant (_parent)',
langDirLTR: 'Chwith i\'r Dde (LTR)',
langDirRTL: 'Dde i\'r Chwith (RTL)',
styles: 'Arddull',
cssClasses: 'Dosbarthiadau Dalen Arddull',
width: 'Lled',
height: 'Uchder',
align: 'Alinio',
left: 'Chwith',
right: 'Dde',
center: 'Canol',
justify: 'Unioni',
alignLeft: 'Alinio i\'r Chwith',
alignRight: 'Alinio i\'r Dde',
alignCenter: 'Align Center', // MISSING
alignTop: 'Brig',
alignMiddle: 'Canol',
alignBottom: 'Gwaelod',
alignNone: 'None', // MISSING
invalidValue: 'Gwerth annilys.',
invalidHeight: 'Mae\'n rhaid i\'r uchder fod yn rhif.',
invalidWidth: 'Mae\'n rhaid i\'r lled fod yn rhif.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'Mae\'n rhaid i\'r gwerth ar gyfer maes "%1" fod yn rhif positif gyda neu heb uned fesuriad CSS dilys (px, %, in, cm, mm, em, ex, pt, neu pc).',
invalidHtmlLength: 'Mae\'n rhaid i\'r gwerth ar gyfer maes "%1" fod yn rhif positif gyda neu heb uned fesuriad HTML dilys (px neu %).',
invalidInlineStyle: 'Mae\'n rhaid i\'r gwerth ar gyfer arddull mewn-llinell gynnwys un set neu fwy ar y fformat "enw : gwerth", wedi\'u gwahanu gyda hanner colon.',
cssLengthTooltip: 'Rhowch rif am werth mewn picsel neu rhif gydag uned CSS dilys (px, %, in, cm, mm, em, pt neu pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, ddim ar gael</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Danish language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'da' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Rich Text Editor',
editorPanel: 'Rich Text Editor panel',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Tryk ALT 0 for hjælp',
browseServer: 'Gennemse...',
url: 'URL',
protocol: 'Protokol',
upload: 'Upload',
uploadSubmit: 'Upload',
image: 'Indsæt billede',
form: 'Indsæt formular',
checkbox: 'Indsæt afkrydsningsfelt',
radio: 'Indsæt alternativknap',
textField: 'Indsæt tekstfelt',
textarea: 'Indsæt tekstboks',
hiddenField: 'Indsæt skjult felt',
button: 'Indsæt knap',
select: 'Indsæt liste',
imageButton: 'Indsæt billedknap',
notSet: '<intet valgt>',
id: 'Id',
name: 'Navn',
langDir: 'Tekstretning',
langDirLtr: 'Fra venstre mod højre (LTR)',
langDirRtl: 'Fra højre mod venstre (RTL)',
langCode: 'Sprogkode',
longDescr: 'Udvidet beskrivelse',
cssClass: 'Typografiark (CSS)',
advisoryTitle: 'Titel',
cssStyle: 'Typografi (CSS)',
ok: 'OK',
cancel: 'Annullér',
close: 'Luk',
preview: 'Forhåndsvisning',
resize: 'Træk for at skalere',
generalTab: 'Generelt',
advancedTab: 'Avanceret',
validateNumberFailed: 'Værdien er ikke et tal.',
confirmNewPage: 'Alt indhold, der ikke er blevet gemt, vil gå tabt. Er du sikker på, at du vil indlæse en ny side?',
confirmCancel: 'Nogle af indstillingerne er blevet ændret. Er du sikker på, at du vil lukke vinduet?',
options: 'Vis muligheder',
target: 'Mål',
targetNew: 'Nyt vindue (_blank)',
targetTop: 'Øverste vindue (_top)',
targetSelf: 'Samme vindue (_self)',
targetParent: 'Samme vindue (_parent)',
langDirLTR: 'Venstre til højre (LTR)',
langDirRTL: 'Højre til venstre (RTL)',
styles: 'Style',
cssClasses: 'Stylesheetklasser',
width: 'Bredde',
height: 'Højde',
align: 'Justering',
left: 'Venstre',
right: 'Højre',
center: 'Center',
justify: 'Lige margener',
alignLeft: 'Venstrestillet',
alignRight: 'Højrestillet',
alignCenter: 'Centreret',
alignTop: 'Øverst',
alignMiddle: 'Centreret',
alignBottom: 'Nederst',
alignNone: 'Ingen',
invalidValue: 'Ugyldig værdi.',
invalidHeight: 'Højde skal være et tal.',
invalidWidth: 'Bredde skal være et tal.',
invalidLength: 'Værdien angivet for feltet "%1" skal være et positivt heltal med eller uden en gyldig måleenhed (%2).',
invalidCssLength: 'Værdien specificeret for "%1" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px, %, in, cm, mm, em, ex, pt, eller pc).',
invalidHtmlLength: 'Værdien specificeret for "%1" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px eller %).',
invalidInlineStyle: 'Værdien specificeret for inline style skal indeholde en eller flere elementer med et format som "name:value", separeret af semikoloner',
cssLengthTooltip: 'Indsæt en numerisk værdi i pixel eller nummer med en gyldig CSS værdi (px, %, in, cm, mm, em, ex, pt, eller pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, ikke tilgængelig</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Retur',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Mellemrum',
35: 'Slut',
36: 'Hjem',
46: 'Slet',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Kommando'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Tastatur genvej',
optionDefault: 'Standard'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,153 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'de-ch' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'WYSIWYG-Editor',
editorPanel: 'WYSIWYG-Editor-Leiste',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Drücken Sie ALT 0 für Hilfe',
browseServer: 'Server durchsuchen',
url: 'URL',
protocol: 'Protokoll',
upload: 'Hochladen',
uploadSubmit: 'Zum Server senden',
image: 'Bild',
form: 'Formular',
checkbox: 'Kontrollbox',
radio: 'Optionsfeld',
textField: 'Textfeld',
textarea: 'Textfeld',
hiddenField: 'Verstecktes Feld',
button: 'Schaltfläche',
select: 'Auswahlfeld',
imageButton: 'Bildschaltfläche',
notSet: '<nicht festgelegt>',
id: 'Kennung',
name: 'Name',
langDir: 'Schreibrichtung',
langDirLtr: 'Links nach Rechts (LTR)',
langDirRtl: 'Rechts nach Links (RTL)',
langCode: 'Sprachcode',
longDescr: 'Langbeschreibungs-URL',
cssClass: 'Formatvorlagenklassen',
advisoryTitle: 'Titel Beschreibung',
cssStyle: 'Stil',
ok: 'OK',
cancel: 'Abbrechen',
close: 'Schliessen',
preview: 'Vorschau',
resize: 'Grösse ändern',
generalTab: 'Allgemein',
advancedTab: 'Erweitert',
validateNumberFailed: 'Dieser Wert ist keine Nummer.',
confirmNewPage: 'Alle nicht gespeicherten Änderungen gehen verloren. Sind Sie sicher, die neue Seite zu laden?',
confirmCancel: 'Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schliessen?',
options: 'Optionen',
target: 'Zielseite',
targetNew: 'Neues Fenster (_blank)',
targetTop: 'Oberstes Fenster (_top)',
targetSelf: 'Gleiches Fenster (_self)',
targetParent: 'Oberes Fenster (_parent)',
langDirLTR: 'Links nach Rechts (LNR)',
langDirRTL: 'Rechts nach Links (RNL)',
styles: 'Style',
cssClasses: 'Stylesheet Klasse',
width: 'Breite',
height: 'Höhe',
align: 'Ausrichtung',
left: 'Links',
right: 'Rechts',
center: 'Zentriert',
justify: 'Blocksatz',
alignLeft: 'Linksbündig',
alignRight: 'Rechtsbündig',
alignCenter: 'Zentriert',
alignTop: 'Oben',
alignMiddle: 'Mitte',
alignBottom: 'Unten',
alignNone: 'Keine',
invalidValue: 'Ungültiger Wert.',
invalidHeight: 'Höhe muss eine Zahl sein.',
invalidWidth: 'Breite muss eine Zahl sein.',
invalidLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekter HTML-Masseinheit (px oder %).',
invalidCssLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekter CSS-Masseinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
invalidHtmlLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekter HTML-Masseinheit (px oder %).',
invalidInlineStyle: 'Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Wertepaare mit dem Format "Name : Wert" getrennt durch Semikolons.',
cssLengthTooltip: 'Geben Sie eine Zahl ein für ein Wert in Pixel oder eine Zahl mit einer korrekten CSS-Masseinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, nicht verfügbar</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Rücktaste',
13: 'Eingabe',
16: 'Umschalt',
17: 'Strg',
18: 'Alt',
32: 'Leertaste',
35: 'Ende',
36: 'Pos1',
46: 'Entfernen',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Befehl'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Tastaturkürzel',
optionDefault: 'Standard'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* German language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'de' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'WYSIWYG-Editor',
editorPanel: 'WYSIWYG-Editor-Leiste',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Drücken Sie ALT 0 für Hilfe',
browseServer: 'Server durchsuchen',
url: 'URL',
protocol: 'Protokoll',
upload: 'Hochladen',
uploadSubmit: 'Zum Server senden',
image: 'Bild',
form: 'Formular',
checkbox: 'Kontrollbox',
radio: 'Optionsfeld',
textField: 'Textfeld',
textarea: 'Textfeld',
hiddenField: 'Verstecktes Feld',
button: 'Schaltfläche',
select: 'Auswahlfeld',
imageButton: 'Bildschaltfläche',
notSet: '<nicht festgelegt>',
id: 'Kennung',
name: 'Name',
langDir: 'Schreibrichtung',
langDirLtr: 'Links nach Rechts (LTR)',
langDirRtl: 'Rechts nach Links (RTL)',
langCode: 'Sprachcode',
longDescr: 'Langbeschreibungs-URL',
cssClass: 'Formatvorlagenklassen',
advisoryTitle: 'Titel Beschreibung',
cssStyle: 'Stil',
ok: 'OK',
cancel: 'Abbrechen',
close: 'Schließen',
preview: 'Vorschau',
resize: 'Größe ändern',
generalTab: 'Allgemein',
advancedTab: 'Erweitert',
validateNumberFailed: 'Dieser Wert ist keine Nummer.',
confirmNewPage: 'Alle nicht gespeicherten Änderungen gehen verloren. Sind Sie sicher, die neue Seite zu laden?',
confirmCancel: 'Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schließen?',
options: 'Optionen',
target: 'Zielseite',
targetNew: 'Neues Fenster (_blank)',
targetTop: 'Oberstes Fenster (_top)',
targetSelf: 'Gleiches Fenster (_self)',
targetParent: 'Oberes Fenster (_parent)',
langDirLTR: 'Links nach Rechts (LNR)',
langDirRTL: 'Rechts nach Links (RNL)',
styles: 'Style',
cssClasses: 'Stylesheet Klasse',
width: 'Breite',
height: 'Höhe',
align: 'Ausrichtung',
left: 'Links',
right: 'Rechts',
center: 'Zentriert',
justify: 'Blocksatz',
alignLeft: 'Linksbündig',
alignRight: 'Rechtsbündig',
alignCenter: 'Zentriert',
alignTop: 'Oben',
alignMiddle: 'Mitte',
alignBottom: 'Unten',
alignNone: 'Keine',
invalidValue: 'Ungültiger Wert.',
invalidHeight: 'Höhe muss eine Zahl sein.',
invalidWidth: 'Breite muss eine Zahl sein.',
invalidLength: 'Der für das Feld "%1" angegebene Wert muss eine positive Zahl mit oder ohne gültige Maßeinheit (%2) sein. ',
invalidCssLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
invalidHtmlLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).',
invalidInlineStyle: 'Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format "Name : Wert" getrennt mit Semikolons.',
cssLengthTooltip: 'Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, nicht verfügbar</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Rücktaste',
13: 'Eingabe',
16: 'Umschalt',
17: 'Strg',
18: 'Alt',
32: 'Leer',
35: 'Ende',
36: 'Pos1',
46: 'Entfernen',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Befehl'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Tastaturkürzel',
optionDefault: 'Standard'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* Greek language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'el' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Επεξεργαστής Πλούσιου Κειμένου',
editorPanel: 'Πίνακας Επεξεργαστή Πλούσιου Κειμένου',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Πατήστε το ALT 0 για βοήθεια',
browseServer: 'Εξερεύνηση Διακομιστή',
url: 'URL',
protocol: 'Πρωτόκολλο',
upload: 'Αποστολή',
uploadSubmit: 'Αποστολή στον Διακομιστή',
image: 'Εικόνα',
form: 'Φόρμα',
checkbox: 'Κουτί Επιλογής',
radio: 'Κουμπί Επιλογής',
textField: 'Πεδίο Κειμένου',
textarea: 'Περιοχή Κειμένου',
hiddenField: 'Κρυφό Πεδίο',
button: 'Κουμπί',
select: 'Πεδίο Επιλογής',
imageButton: 'Κουμπί Εικόνας',
notSet: '<δεν έχει ρυθμιστεί>',
id: 'Id',
name: 'Όνομα',
langDir: 'Κατεύθυνση Κειμένου',
langDirLtr: 'Αριστερά προς Δεξιά (LTR)',
langDirRtl: 'Δεξιά προς Αριστερά (RTL)',
langCode: 'Κωδικός Γλώσσας',
longDescr: 'Αναλυτική Περιγραφή URL',
cssClass: 'Κλάσεις Φύλλων Στυλ',
advisoryTitle: 'Ενδεικτικός Τίτλος',
cssStyle: 'Μορφή Κειμένου',
ok: 'OK',
cancel: 'Ακύρωση',
close: 'Κλείσιμο',
preview: 'Προεπισκόπηση',
resize: 'Αλλαγή Μεγέθους',
generalTab: 'Γενικά',
advancedTab: 'Για Προχωρημένους',
validateNumberFailed: 'Αυτή η τιμή δεν είναι αριθμός.',
confirmNewPage: 'Οι όποιες αλλαγές στο περιεχόμενο θα χαθούν. Είσαστε σίγουροι ότι θέλετε να φορτώσετε μια νέα σελίδα;',
confirmCancel: 'Μερικές επιλογές έχουν αλλάξει. Είσαστε σίγουροι ότι θέλετε να κλείσετε το παράθυρο διαλόγου;',
options: 'Επιλογές',
target: 'Προορισμός',
targetNew: 'Νέο Παράθυρο (_blank)',
targetTop: 'Αρχική Περιοχή (_top)',
targetSelf: 'Ίδιο Παράθυρο (_self)',
targetParent: 'Γονεϊκό Παράθυρο (_parent)',
langDirLTR: 'Αριστερά προς Δεξιά (LTR)',
langDirRTL: 'Δεξιά προς Αριστερά (RTL)',
styles: 'Μορφή',
cssClasses: 'Κλάσεις Φύλλων Στυλ',
width: 'Πλάτος',
height: 'Ύψος',
align: 'Στοίχιση',
left: 'Αριστερά',
right: 'Δεξιά',
center: 'Κέντρο',
justify: 'Πλήρης Στοίχιση',
alignLeft: 'Στοίχιση Αριστερά',
alignRight: 'Στοίχιση Δεξιά',
alignCenter: 'Στοίχιση στο κέντρο',
alignTop: 'Πάνω',
alignMiddle: 'Μέση',
alignBottom: 'Κάτω',
alignNone: 'Χωρίς',
invalidValue: 'Μη έγκυρη τιμή.',
invalidHeight: 'Το ύψος πρέπει να είναι ένας αριθμός.',
invalidWidth: 'Το πλάτος πρέπει να είναι ένας αριθμός.',
invalidLength: 'Η τιμή που ορίζεται στο πεδίο «%1» πρέπει να είναι θετικός αριθμός με ή χωρίς μονάδα μέτρησης (%2).',
invalidCssLength: 'Η τιμή που ορίζεται για το πεδίο "%1" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).',
invalidHtmlLength: 'Η τιμή που ορίζεται για το πεδίο "%1" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης HTML (px ή %).',
invalidInlineStyle: 'Η τιμή για το εν σειρά στυλ πρέπει να περιέχει ένα ή περισσότερα ζεύγη με την μορφή "όνομα: τιμή" διαχωρισμένα με Ελληνικό ερωτηματικό.',
cssLengthTooltip: 'Εισάγεται μια τιμή σε pixel ή έναν αριθμό μαζί με μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, δεν είναι διαθέσιμο</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Κενό',
35: 'End',
36: 'Home',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Εντολή'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Συντόμευση πληκτρολογίου',
optionDefault: 'Προεπιλογή'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* English (Australia) language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'en-au' ] = {
// ARIA description.
application: 'Rich Text Editor',
editor: 'Editor',
editorPanel: 'Rich Text Editor panel',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help',
browseServer: 'Browse Server',
url: 'URL',
protocol: 'Protocol',
upload: 'Upload',
uploadSubmit: 'Send it to the Server',
image: 'Image',
form: 'Form',
checkbox: 'Checkbox',
radio: 'Radio Button',
textField: 'Text Field',
textarea: 'Textarea',
hiddenField: 'Hidden Field',
button: 'Button',
select: 'Selection Field',
imageButton: 'Image Button',
notSet: '<not set>',
id: 'Id',
name: 'Name',
langDir: 'Language Direction',
langDirLtr: 'Left to Right (LTR)',
langDirRtl: 'Right to Left (RTL)',
langCode: 'Language Code',
longDescr: 'Long Description URL',
cssClass: 'Stylesheet Classes',
advisoryTitle: 'Advisory Title',
cssStyle: 'Style',
ok: 'OK',
cancel: 'Cancel',
close: 'Close',
preview: 'Preview',
resize: 'Resize',
generalTab: 'General',
advancedTab: 'Advanced',
validateNumberFailed: 'This value is not a number.',
confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
options: 'Options',
target: 'Target',
targetNew: 'New Window (_blank)',
targetTop: 'Topmost Window (_top)',
targetSelf: 'Same Window (_self)',
targetParent: 'Parent Window (_parent)',
langDirLTR: 'Left to Right (LTR)',
langDirRTL: 'Right to Left (RTL)',
styles: 'Style',
cssClasses: 'Stylesheet Classes',
width: 'Width',
height: 'Height',
align: 'Align',
left: 'Left',
right: 'Right',
center: 'Centre',
justify: 'Justify',
alignLeft: 'Align Left',
alignRight: 'Align Right',
alignCenter: 'Align Centre',
alignTop: 'Top',
alignMiddle: 'Middle',
alignBottom: 'Bottom',
alignNone: 'None',
invalidValue: 'Invalid value.',
invalidHeight: 'Height must be a number.',
invalidWidth: 'Width must be a number.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).',
invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).',
invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).',
invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.',
cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, unavailable</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Space',
35: 'End',
36: 'Home',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Command'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut',
optionDefault: 'Default'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* English (Canadian) language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'en-ca' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Editor', // MISSING
editorPanel: 'Rich Text Editor panel', // MISSING
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help', // MISSING
browseServer: 'Browse Server',
url: 'URL',
protocol: 'Protocol',
upload: 'Upload',
uploadSubmit: 'Send it to the Server',
image: 'Image',
form: 'Form',
checkbox: 'Checkbox',
radio: 'Radio Button',
textField: 'Text Field',
textarea: 'Textarea',
hiddenField: 'Hidden Field',
button: 'Button',
select: 'Selection Field',
imageButton: 'Image Button',
notSet: '<not set>',
id: 'Id',
name: 'Name',
langDir: 'Language Direction',
langDirLtr: 'Left to Right (LTR)',
langDirRtl: 'Right to Left (RTL)',
langCode: 'Language Code',
longDescr: 'Long Description URL',
cssClass: 'Stylesheet Classes',
advisoryTitle: 'Advisory Title',
cssStyle: 'Style',
ok: 'OK',
cancel: 'Cancel',
close: 'Close', // MISSING
preview: 'Preview',
resize: 'Resize', // MISSING
generalTab: 'General',
advancedTab: 'Advanced',
validateNumberFailed: 'This value is not a number.',
confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
options: 'Options', // MISSING
target: 'Target',
targetNew: 'New Window (_blank)', // MISSING
targetTop: 'Topmost Window (_top)', // MISSING
targetSelf: 'Same Window (_self)', // MISSING
targetParent: 'Parent Window (_parent)', // MISSING
langDirLTR: 'Left to Right (LTR)',
langDirRTL: 'Right to Left (RTL)',
styles: 'Style',
cssClasses: 'Stylesheet Classes',
width: 'Width', // MISSING
height: 'Height', // MISSING
align: 'Align',
left: 'Left', // MISSING
right: 'Right', // MISSING
center: 'Centre',
justify: 'Justify',
alignLeft: 'Align Left',
alignRight: 'Align Right',
alignCenter: 'Align Center', // MISSING
alignTop: 'Top', // MISSING
alignMiddle: 'Middle', // MISSING
alignBottom: 'Bottom', // MISSING
alignNone: 'None', // MISSING
invalidValue: 'Invalid value.', // MISSING
invalidHeight: 'Height must be a number.', // MISSING
invalidWidth: 'Width must be a number.', // MISSING
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object, for the
* English (United Kingdom) language.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'en-gb' ] = {
// ARIA description.
application: 'Rich Text Editor', // MISSING
editor: 'Rich Text Editor',
editorPanel: 'Rich Text Editor panel',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help',
browseServer: 'Browse Server',
url: 'URL',
protocol: 'Protocol',
upload: 'Upload',
uploadSubmit: 'Send it to the Server',
image: 'Image',
form: 'Form',
checkbox: 'Checkbox',
radio: 'Radio Button',
textField: 'Text Field',
textarea: 'Textarea',
hiddenField: 'Hidden Field',
button: 'Button',
select: 'Selection Field',
imageButton: 'Image Button',
notSet: '<not set>',
id: 'Id',
name: 'Name',
langDir: 'Language Direction',
langDirLtr: 'Left to Right (LTR)',
langDirRtl: 'Right to Left (RTL)',
langCode: 'Language Code',
longDescr: 'Long Description URL',
cssClass: 'Stylesheet Classes',
advisoryTitle: 'Advisory Title',
cssStyle: 'Style',
ok: 'OK',
cancel: 'Cancel',
close: 'Close',
preview: 'Preview',
resize: 'Drag to resize',
generalTab: 'General',
advancedTab: 'Advanced',
validateNumberFailed: 'This value is not a number.',
confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
confirmCancel: 'You have changed some options. Are you sure you want to close the dialogue window?',
options: 'Options',
target: 'Target',
targetNew: 'New Window (_blank)',
targetTop: 'Topmost Window (_top)',
targetSelf: 'Same Window (_self)',
targetParent: 'Parent Window (_parent)',
langDirLTR: 'Left to Right (LTR)',
langDirRTL: 'Right to Left (RTL)',
styles: 'Style',
cssClasses: 'Stylesheet Classes',
width: 'Width',
height: 'Height',
align: 'Align',
left: 'Left', // MISSING
right: 'Right', // MISSING
center: 'Centre',
justify: 'Justify', // MISSING
alignLeft: 'Align Left', // MISSING
alignRight: 'Align Right', // MISSING
alignCenter: 'Align Centre',
alignTop: 'Top',
alignMiddle: 'Middle',
alignBottom: 'Bottom',
alignNone: 'None',
invalidValue: 'Invalid value.',
invalidHeight: 'Height must be a number.',
invalidWidth: 'Width must be a number.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).', // MISSING
invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).',
invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).',
invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.',
cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, unavailable</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace', // MISSING
13: 'Enter', // MISSING
16: 'Shift', // MISSING
17: 'Ctrl', // MISSING
18: 'Alt', // MISSING
32: 'Space', // MISSING
35: 'End', // MISSING
36: 'Home', // MISSING
46: 'Delete', // MISSING
112: 'F1', // MISSING
113: 'F2', // MISSING
114: 'F3', // MISSING
115: 'F4', // MISSING
116: 'F5', // MISSING
117: 'F6', // MISSING
118: 'F7', // MISSING
119: 'F8', // MISSING
120: 'F9', // MISSING
121: 'F10', // MISSING
122: 'F11', // MISSING
123: 'F12', // MISSING
124: 'F13', // MISSING
125: 'F14', // MISSING
126: 'F15', // MISSING
127: 'F16', // MISSING
128: 'F17', // MISSING
129: 'F18', // MISSING
130: 'F19', // MISSING
131: 'F20', // MISSING
132: 'F21', // MISSING
133: 'F22', // MISSING
134: 'F23', // MISSING
135: 'F24', // MISSING
224: 'Command' // MISSING
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut', // MISSING
optionDefault: 'Default' // MISSING
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.', // MISSING
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link', // MISSING
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>', // MISSING
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>' // MISSING
}
};

View file

@ -1,154 +0,0 @@
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @fileOverview Defines the {@link CKEDITOR.lang} object for the English
* language. This is the base file for all translations.
*/
/**#@+
@type String
@example
*/
/**
* Contains the dictionary of language entries.
* @namespace
*/
CKEDITOR.lang[ 'en' ] = {
// ARIA description.
application: 'Rich Text Editor',
editor: 'Editor',
editorPanel: 'Rich Text Editor panel',
// Common messages and labels.
common: {
// Screenreader titles. Please note that screenreaders are not always capable
// of reading non-English words. So be careful while translating it.
editorHelp: 'Press ALT 0 for help',
browseServer: 'Browse Server',
url: 'URL',
protocol: 'Protocol',
upload: 'Upload',
uploadSubmit: 'Send it to the Server',
image: 'Image',
form: 'Form',
checkbox: 'Checkbox',
radio: 'Radio Button',
textField: 'Text Field',
textarea: 'Textarea',
hiddenField: 'Hidden Field',
button: 'Button',
select: 'Selection Field',
imageButton: 'Image Button',
notSet: '<not set>',
id: 'Id',
name: 'Name',
langDir: 'Language Direction',
langDirLtr: 'Left to Right (LTR)',
langDirRtl: 'Right to Left (RTL)',
langCode: 'Language Code',
longDescr: 'Long Description URL',
cssClass: 'Stylesheet Classes',
advisoryTitle: 'Advisory Title',
cssStyle: 'Style',
ok: 'OK',
cancel: 'Cancel',
close: 'Close',
preview: 'Preview',
resize: 'Resize',
generalTab: 'General',
advancedTab: 'Advanced',
validateNumberFailed: 'This value is not a number.',
confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
options: 'Options',
target: 'Target',
targetNew: 'New Window (_blank)',
targetTop: 'Topmost Window (_top)',
targetSelf: 'Same Window (_self)',
targetParent: 'Parent Window (_parent)',
langDirLTR: 'Left to Right (LTR)',
langDirRTL: 'Right to Left (RTL)',
styles: 'Style',
cssClasses: 'Stylesheet Classes',
width: 'Width',
height: 'Height',
align: 'Alignment',
left: 'Left',
right: 'Right',
center: 'Center',
justify: 'Justify',
alignLeft: 'Align Left',
alignRight: 'Align Right',
alignCenter: 'Align Center',
alignTop: 'Top',
alignMiddle: 'Middle',
alignBottom: 'Bottom',
alignNone: 'None',
invalidValue: 'Invalid value.',
invalidHeight: 'Height must be a number.',
invalidWidth: 'Width must be a number.',
invalidLength: 'Value specified for the "%1" field must be a positive number with or without a valid measurement unit (%2).',
invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).',
invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).',
invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.',
cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).',
// Put the voice-only part of the label in the span.
unavailable: '%1<span class="cke_accessibility">, unavailable</span>',
// Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
keyboard: {
8: 'Backspace',
13: 'Enter',
16: 'Shift',
17: 'Ctrl',
18: 'Alt',
32: 'Space',
35: 'End',
36: 'Home',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
124: 'F13',
125: 'F14',
126: 'F15',
127: 'F16',
128: 'F17',
129: 'F18',
130: 'F19',
131: 'F20',
132: 'F21',
133: 'F22',
134: 'F23',
135: 'F24',
224: 'Command'
},
// Prepended to ARIA labels with shortcuts.
keyboardShortcut: 'Keyboard shortcut',
optionDefault: 'Default'
},
versionCheck: {
notificationMessage: 'This CKEditor %current version is not secure. Consider <a target="_blank" href="%link">upgrading to the latest one</a>, %latest.',
consoleMessage: 'This CKEditor %current version is not secure. Consider upgrading to the latest one, %latest: %link',
aboutDialogInsecureMessage: 'This CKEditor %current version is not secure.<br>Consider upgrading to the latest one, %latest:<br><a target="_blank" href="%link">%link</a>',
aboutDialogUpgradeMessage: 'Consider upgrading to the latest editor version, %latest:<br><a target="_blank" href="%link">%link</a>'
}
};

Some files were not shown because too many files have changed in this diff Show more