2012-06-06 06:13:19 +02:00
/ * *
2013-04-13 21:00:13 +02:00
* EGroupware eTemplate2 - JS widget for HTML editing
2012-06-06 06:13:19 +02:00
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
2021-06-07 17:33:53 +02:00
* @ link https : //www.egroupware.org
2018-10-19 16:35:18 +02:00
* @ author Hadi Nategh < hn @ egroupware . org >
* @ copyright Hadi Nategh < hn @ egroupware . org >
2012-06-06 06:13:19 +02:00
* @ version $Id$
* /
/ * e g w : u s e s
2020-02-06 14:30:22 +01:00
jsapi . jsapi ; // Needed for egw_seperateJavaScript
/ v e n d o r / t i n y m c e / t i n y m c e / t i n y m c e . m i n . j s ;
et2 _core _editableWidget ;
2012-06-06 06:13:19 +02:00
* /
2021-06-07 17:33:53 +02:00
import { et2 _editableWidget } from "./et2_core_editableWidget" ;
import { ClassWithAttributes } from "./et2_core_inheritance" ;
import { et2 _register _widget , et2 _createWidget } from "./et2_core_widget" ;
import { et2 _no _init } from "./et2_core_common" ;
2021-06-08 14:11:59 +02:00
import { egw } from "../jsapi/egw_global" ;
2021-06-10 15:53:31 +02:00
import "../../../vendor/tinymce/tinymce/tinymce.min.js" ;
2021-06-10 11:38:54 +02:00
import { etemplate2 } from "./etemplate2" ;
2013-04-13 21:00:13 +02:00
/ * *
* @ augments et2 _inputWidget
* /
2021-06-07 17:33:53 +02:00
export class et2 _htmlarea extends et2 _editableWidget {
2020-02-06 14:30:22 +01:00
/ * *
* Constructor
* /
2021-06-07 17:33:53 +02:00
constructor ( _parent , _attrs , _child ) {
2020-02-06 14:30:22 +01:00
// Call the inherited constructor
2021-06-07 17:33:53 +02:00
super ( _parent , _attrs , ClassWithAttributes . extendAttributes ( et2 _htmlarea . _attributes , _child || { } ) ) ;
this . editor = null ;
this . htmlNode = null ;
this . editor = null ; // TinyMce editor instance
this . supportedWidgetClasses = [ ] ; // Allow no child widgets
this . htmlNode = jQuery ( document . createElement ( this . options . readonly ? "div" : "textarea" ) )
2020-02-06 14:30:22 +01:00
. addClass ( 'et2_textbox_ro' ) ;
2021-06-07 17:33:53 +02:00
if ( this . options . height ) {
this . htmlNode . css ( 'height' , this . options . height ) ;
2020-02-06 14:30:22 +01:00
}
2021-06-07 17:33:53 +02:00
this . setDOMNode ( this . htmlNode [ 0 ] ) ;
2020-02-06 14:30:22 +01:00
}
/ * *
*
* @ returns { undefined }
* /
2021-06-07 17:33:53 +02:00
doLoadingFinished ( ) {
super . doLoadingFinished ( ) ;
2020-02-06 14:30:22 +01:00
this . init _editor ( ) ;
return true ;
2021-06-07 17:33:53 +02:00
}
init _editor ( ) {
2020-02-06 14:30:22 +01:00
if ( this . mode == 'ascii' || this . editor != null || this . options . readonly )
return ;
2021-06-07 17:33:53 +02:00
let imageUpload ;
let self = this ;
2020-02-06 14:30:22 +01:00
if ( this . options . imageUpload && this . options . imageUpload [ 0 ] !== '/' && this . options . imageUpload . substr ( 0 , 4 ) != 'http' ) {
imageUpload = egw . ajaxUrl ( "EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_htmlarea_upload" ) +
'&request_id=' + this . getInstanceManager ( ) . etemplate _exec _id + '&widget_id=' + this . options . imageUpload + '&type=htmlarea' ;
imageUpload = imageUpload . substr ( egw . webserverUrl . length + 1 ) ;
}
else if ( imageUpload ) {
imageUpload = this . options . imageUpload . substr ( egw . webserverUrl . length + 1 ) ;
}
else {
imageUpload = egw . ajaxUrl ( "EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_htmlarea_upload" ) +
'&request_id=' + this . getInstanceManager ( ) . etemplate _exec _id + '&type=htmlarea' ;
}
// default settings for initialization
2021-06-07 17:33:53 +02:00
let settings = {
2021-06-10 15:53:31 +02:00
base _url : egw . webserverUrl + '/vendor/tinymce/tinymce' ,
2020-02-06 14:30:22 +01:00
target : this . htmlNode [ 0 ] ,
body _id : this . dom _id + '_htmlarea' ,
menubar : false ,
statusbar : this . options . statusbar ,
2020-10-14 10:40:35 +02:00
toolbar _mode : this . options . toolbar _mode ,
2020-02-06 14:30:22 +01:00
branding : false ,
resize : false ,
height : this . options . height ,
width : this . options . width ,
2021-01-06 14:06:21 +01:00
end _container _on _empty _block : true ,
2020-02-06 14:30:22 +01:00
mobile : {
theme : 'silver'
} ,
formats : {
customparagraph : { block : 'p' , styles : { "margin-block-start" : "0px" , "margin-block-end" : "0px" } }
} ,
min _height : 100 ,
convert _urls : false ,
language : et2 _htmlarea . LANGUAGE _CODE [ egw . preference ( 'lang' , 'common' ) ] ,
language _url : egw . webserverUrl + '/api/js/tinymce/langs/' + et2 _htmlarea . LANGUAGE _CODE [ egw . preference ( 'lang' , 'common' ) ] + '.js' ,
paste _data _images : true ,
paste _filter _drop : true ,
browser _spellcheck : true ,
contextmenu : false ,
images _upload _url : imageUpload ,
file _picker _callback : jQuery . proxy ( this . _file _picker _callback , this ) ,
images _upload _handler : this . options . images _upload _handler ,
init _instance _callback : jQuery . proxy ( this . _instanceIsReady , this ) ,
auto _focus : false ,
valid _children : this . options . valid _children ,
plugins : [
"print searchreplace autolink directionality " ,
2020-03-05 14:45:25 +01:00
"visualblocks visualchars image link media template fullscreen" ,
2020-02-06 14:30:22 +01:00
"codesample table charmap hr pagebreak nonbreaking anchor toc " ,
"insertdatetime advlist lists textcolor wordcount imagetools " ,
"colorpicker textpattern help paste code searchreplace tabfocus"
] ,
toolbar : et2 _htmlarea . TOOLBAR _SIMPLE ,
block _formats : "Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;" +
"Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre;Custom Paragraph=customparagraph" ,
font _formats : "Andale Mono=andale mono,times;Arial=arial,helvetica," +
"sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book " +
"antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;" +
"Courier New=courier new,courier;Georgia=georgia,palatino;" +
2020-12-09 13:17:37 +01:00
"Helvetica=helvetica;Impact=impact,chicago;Segoe=segoe,segoe ui;Symbol=symbol;" +
2020-02-06 14:30:22 +01:00
"Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal," +
"monaco;Times New Roman=times new roman,times;Trebuchet " +
"MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;" +
"Wingdings=wingdings,zapf dingbats" ,
fontsize _formats : '8pt 10pt 12pt 14pt 18pt 24pt 36pt' ,
setup : function ( ed ) {
ed . on ( 'init' , function ( ) {
2019-01-14 10:37:07 +01:00
this . getDoc ( ) . body . style . fontSize = egw . preference ( 'rte_font_size' , 'common' )
2020-02-06 14:30:22 +01:00
+ egw . preference ( 'rte_font_unit' , 'common' ) ;
2019-01-14 10:37:07 +01:00
this . getDoc ( ) . body . style . fontFamily = egw . preference ( 'rte_font' , 'common' ) ;
} ) ;
}
2020-02-06 14:30:22 +01:00
} ;
// extend default settings with configured options and preferences
jQuery . extend ( settings , this . _extendedSettings ( ) ) ;
this . tinymce = tinymce . init ( settings ) ;
// make sure value gets set in case of widget gets loaded by delay like
// inside an inactive tabs
this . tinymce . then ( function ( ) {
self . set _value ( self . htmlNode . val ( ) ) ;
2020-06-24 17:58:18 +02:00
self . resetDirty ( ) ;
2020-02-06 14:30:22 +01:00
if ( self . editor && self . editor . editorContainer ) {
self . editor . formatter . toggle ( egw . preference ( 'rte_formatblock' , 'common' ) ) ;
jQuery ( self . editor . editorContainer ) . height ( self . options . height ) ;
jQuery ( self . editor . iframeElement . contentWindow . document ) . on ( 'dragenter' , function ( ) {
if ( jQuery ( '#dragover-tinymce' ) . length < 1 )
jQuery ( "<style id='dragover-tinymce'>.dragover:after {height:calc(100% - " + jQuery ( this ) . height ( ) + "px) !important;}</style>" ) . appendTo ( 'head' ) ;
} ) ;
}
} ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-06 14:30:22 +01:00
/ * *
* set disabled
*
* @ param { type } _value
* @ returns { undefined }
* /
2021-06-07 17:33:53 +02:00
set _disabled ( _value ) {
super . set _disabled ( _value ) ;
2020-02-06 14:30:22 +01:00
if ( _value ) {
jQuery ( this . tinymce _container ) . css ( 'display' , 'none' ) ;
}
else {
jQuery ( this . tinymce _container ) . css ( 'display' , 'flex' ) ;
}
2021-06-07 17:33:53 +02:00
}
set _readonly ( _value ) {
2020-02-06 14:30:22 +01:00
if ( this . options . readonly === _value )
return ;
2021-06-07 17:33:53 +02:00
let value = this . get _value ( ) ;
2020-02-06 14:30:22 +01:00
this . options . readonly = _value ;
if ( this . options . readonly ) {
if ( this . editor )
this . editor . remove ( ) ;
this . htmlNode = jQuery ( document . createElement ( this . options . readonly ? "div" : "textarea" ) )
. addClass ( 'et2_textbox_ro' ) ;
if ( this . options . height ) {
this . htmlNode . css ( 'height' , this . options . height ) ;
}
this . editor = null ;
this . setDOMNode ( this . htmlNode [ 0 ] ) ;
this . set _value ( value ) ;
}
else {
if ( ! this . editor ) {
this . htmlNode = jQuery ( document . createElement ( "textarea" ) )
. val ( value ) ;
if ( this . options . height || this . options . editable _height ) {
this . htmlNode . css ( 'height' , ( this . options . editable _height ? this . options . editable _height : this . options . height ) ) ;
}
this . setDOMNode ( this . htmlNode [ 0 ] ) ;
this . init _editor ( ) ;
}
}
2021-06-07 17:33:53 +02:00
}
2020-02-06 14:30:22 +01:00
/ * *
* Callback function runs when the filepicker in image dialog is clicked
*
* @ param { type } _callback
* @ param { type } _value
* @ param { type } _meta
* /
2021-06-07 17:33:53 +02:00
_file _picker _callback ( _callback , _value , _meta ) {
2020-02-06 14:30:22 +01:00
if ( typeof this . file _picker _callback == 'function' )
return this . file _picker _callback . call ( arguments , this ) ;
2021-06-07 17:33:53 +02:00
let callback = _callback ;
2020-02-06 14:30:22 +01:00
// Don't rely only on app_name to fetch et2 object as app_name may not
// always represent current app of the window, e.g.: mail admin account.
// Try to fetch et2 from its template name.
2021-06-07 17:33:53 +02:00
let etemplate = jQuery ( 'form' ) . data ( 'etemplate' ) ;
let et2 ;
2020-02-06 14:30:22 +01:00
if ( etemplate && etemplate . name && ! app [ egw ( window ) . app _name ( ) ] ) {
et2 = etemplate2 . getByTemplate ( etemplate . name ) [ 0 ] [ 'widgetContainer' ] ;
}
else {
et2 = app [ egw ( window ) . app _name ( ) ] . et2 ;
}
2021-06-07 17:33:53 +02:00
let vfsSelect = et2 _createWidget ( 'vfs-select' , {
2020-02-06 14:30:22 +01:00
id : 'upload' ,
mode : 'open' ,
name : '' ,
button _caption : "Link" ,
button _label : "Link" ,
dialog _title : "Link file" ,
method : "download"
} , et2 ) ;
jQuery ( vfsSelect . getDOMNode ( ) ) . on ( 'change' , function ( ) {
callback ( vfsSelect . get _value ( ) , { alt : vfsSelect . get _value ( ) } ) ;
} ) ;
// start the file selector dialog
vfsSelect . click ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-06 14:30:22 +01:00
/ * *
* Callback when instance is ready
*
* @ param { type } _editor
* /
2021-06-07 17:33:53 +02:00
_instanceIsReady ( _editor ) {
2020-02-06 14:30:22 +01:00
console . log ( "Editor: " + _editor . id + " is now initialized." ) ;
// try to reserve focus state as running command on editor may steal the
// current focus.
2021-06-07 17:33:53 +02:00
let focusedEl = jQuery ( ':focus' ) ;
2020-02-06 14:30:22 +01:00
this . editor = _editor ;
this . editor . on ( 'drop' , function ( e ) {
e . preventDefault ( ) ;
} ) ;
if ( ! this . disabled )
jQuery ( this . editor . editorContainer ) . css ( 'display' , 'flex' ) ;
this . tinymce _container = this . editor . editorContainer ;
// go back to reserved focused element
focusedEl . focus ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-06 14:30:22 +01:00
/ * *
* Takes all relevant preferences into account and set settings accordingly
*
* @ returns { object } returns a object including all settings
* /
2021-06-07 17:33:53 +02:00
_extendedSettings ( ) {
let rte _menubar = egw . preference ( 'rte_menubar' , 'common' ) ;
let rte _toolbar = egw . preference ( 'rte_toolbar' , 'common' ) ;
2020-02-06 14:30:22 +01:00
// we need to have rte_toolbar values as an array
2020-09-25 14:17:29 +02:00
if ( rte _toolbar && typeof rte _toolbar == "object" && this . toolbar == '' ) {
2020-02-06 14:30:22 +01:00
rte _toolbar = Object . keys ( rte _toolbar ) . map ( function ( key ) { return rte _toolbar [ key ] ; } ) ;
}
2020-09-25 14:17:29 +02:00
else if ( this . toolbar != '' ) {
rte _toolbar = this . toolbar . split ( ',' ) ;
}
2021-06-07 17:33:53 +02:00
let settings = {
2020-02-06 14:30:22 +01:00
fontsize _formats : et2 _htmlarea . FONT _SIZE _FORMATS [ egw . preference ( 'rte_font_unit' , 'common' ) ] ,
menubar : parseInt ( rte _menubar ) && this . menubar ? true : typeof rte _menubar != 'undefined' ? false : this . menubar
} ;
switch ( this . mode ) {
case 'simple' :
settings [ 'toolbar' ] = et2 _htmlarea . TOOLBAR _SIMPLE ;
break ;
case 'extended' :
settings [ 'toolbar' ] = et2 _htmlarea . TOOLBAR _EXTENDED ;
break ;
case 'advanced' :
settings [ 'toolbar' ] = et2 _htmlarea . TOOLBAR _ADVANCED ;
break ;
default :
this . mode = '' ;
}
// take rte_toolbar into account if no mode restrictly set from template
if ( rte _toolbar && ! this . mode ) {
2021-06-07 17:33:53 +02:00
let toolbar _diff = et2 _htmlarea . TOOLBAR _LIST . filter ( function ( i ) { return ! ( rte _toolbar . indexOf ( i ) > - 1 ) ; } ) ;
2020-02-06 14:30:22 +01:00
settings [ 'toolbar' ] = et2 _htmlarea . TOOLBAR _ADVANCED ;
toolbar _diff . forEach ( function ( a ) {
2021-06-07 17:33:53 +02:00
let r = new RegExp ( a ) ;
2020-02-06 14:30:22 +01:00
settings [ 'toolbar' ] = settings [ 'toolbar' ] . replace ( r , '' ) ;
} ) ;
}
return settings ;
2021-06-07 17:33:53 +02:00
}
destroy ( ) {
2020-02-06 14:30:22 +01:00
if ( this . editor ) {
2021-04-21 23:38:10 +02:00
try {
this . editor . destroy ( ) ;
}
catch ( e ) {
egw ( ) . debug ( "Error destroying editor" , e ) ;
}
2020-02-06 14:30:22 +01:00
}
this . editor = null ;
this . tinymce = null ;
this . tinymce _container = null ;
this . htmlNode . remove ( ) ;
this . htmlNode = null ;
2021-06-07 17:33:53 +02:00
super . destroy ( ) ;
}
set _value ( _value ) {
2020-02-06 14:30:22 +01:00
this . _oldValue = _value ;
if ( this . editor ) {
this . editor . setContent ( _value ) ;
}
else {
if ( this . options . readonly ) {
this . htmlNode . empty ( ) . append ( _value ) ;
}
else {
this . htmlNode . val ( _value ) ;
}
}
this . value = _value ;
2021-06-07 17:33:53 +02:00
}
getValue ( ) {
2020-02-06 14:30:22 +01:00
return this . editor ? this . editor . getContent ( ) : ( this . options . readonly ? this . value : this . htmlNode . val ( ) ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-06 14:30:22 +01:00
/ * *
* Resize htmlNode tag according to window size
* @ param { type } _height excess height which comes from window resize
* /
2021-06-07 17:33:53 +02:00
resize ( _height ) {
2021-01-07 11:45:57 +01:00
var _a , _b ;
2020-02-06 14:30:22 +01:00
if ( _height && this . options . resize _ratio !== '0' ) {
// apply the ratio
_height = ( this . options . resize _ratio != '' ) ? _height * this . options . resize _ratio : _height ;
if ( _height != 0 ) {
if ( this . editor ) // TinyMCE HTML
{
2021-06-07 17:33:53 +02:00
let h ;
2020-02-06 14:30:22 +01:00
if ( typeof this . editor . iframeElement != 'undefined' && this . editor . editorContainer . clientHeight > 0 ) {
h = ( this . editor . editorContainer . clientHeight + _height ) > 0 ?
( this . editor . editorContainer . clientHeight ) + _height : this . editor . settings . min _height ;
}
else // fallback height size
{
h = this . editor . settings . min _height + _height ;
}
jQuery ( this . editor . editorContainer ) . height ( h ) ;
2021-01-07 11:45:57 +01:00
jQuery ( this . editor . iframeElement ) . height ( h - ( ( ( _a = this . editor . editorContainer . getElementsByClassName ( 'tox-editor-header' ) [ 0 ] ) === null || _a === void 0 ? void 0 : _a . clientHeight ) + ( ( _b = this . editor . editorContainer . getElementsByClassName ( 'tox-statusbar' ) [ 0 ] ) === null || _b === void 0 ? void 0 : _b . clientHeight ) ) ) ;
2020-02-06 14:30:22 +01:00
}
else // No TinyMCE
{
this . htmlNode . height ( this . htmlNode . height ( ) + _height ) ;
}
}
}
2021-06-07 17:33:53 +02:00
}
}
et2 _htmlarea . _attributes = {
mode : {
'name' : 'Mode' ,
'description' : 'One of {ascii|simple|extended|advanced}' ,
'default' : '' ,
'type' : 'string'
} ,
height : {
'name' : 'Height' ,
'default' : et2 _no _init ,
'type' : 'string'
} ,
width : {
'name' : 'Width' ,
'default' : et2 _no _init ,
'type' : 'string'
} ,
value : {
name : "Value" ,
description : "The value of the widget" ,
type : "html" ,
default : et2 _no _init
} ,
imageUpload : {
name : "imageUpload" ,
description : "Url to upload images dragged in or id of link_to widget to it's vfs upload. Can also be just a name for which content array contains a path to upload the picture." ,
type : "string" ,
default : null
} ,
file _picker _callback : {
name : "File picker callback" ,
description : "Callback function to get called when file picker is clicked" ,
type : 'js' ,
default : et2 _no _init
} ,
images _upload _handler : {
name : "Images upload handler" ,
description : "Callback function for handling image upload" ,
type : 'js' ,
default : et2 _no _init
} ,
menubar : {
name : "Menubar" ,
description : "Display menubar at the top of the editor" ,
type : "boolean" ,
default : true
} ,
statusbar : {
name : "Status bar" ,
description : "Enable/disable status bar on the bottom of editor" ,
type : "boolean" ,
default : true
} ,
valid _children : {
name : "Valid children" ,
description : "Enables to control what child tag is allowed or not allowed of the present tag. For instance: +body[style], makes style tag allowed inside body" ,
type : "string" ,
default : "+body[style]"
} ,
toolbar : {
'name' : 'Toolbar' ,
'description' : 'Comma separated string of toolbar actions. It will only be considered if no Mode is restricted.' ,
'default' : '' ,
'type' : 'string'
} ,
toolbar _mode : {
'name' : 'toolbar mode' ,
'type' : 'string' ,
'default' : 'floating' ,
'description' : 'It allows to extend the toolbar to accommodate the overflowing toolbar buttons. {floating, sliding, scrolling, wrap}'
}
} ;
/ * *
* Array of toolbars
* @ constant
* /
et2 _htmlarea . TOOLBAR _LIST = [ 'undo' , 'redo' , 'formatselect' , 'fontselect' , 'fontsizeselect' ,
'bold' , 'italic' , 'strikethrough' , 'forecolor' , 'backcolor' , 'link' ,
'alignleft' , 'aligncenter' , 'alignright' , 'alignjustify' , 'numlist' ,
'bullist' , 'outdent' , 'indent' , 'ltr' , 'rtl' , 'removeformat' , 'code' , 'image' , 'searchreplace' , 'fullscreen' , 'table'
] ;
/ * *
* arranged toolbars as simple mode
* @ constant
* /
et2 _htmlarea . TOOLBAR _SIMPLE = "undo redo|formatselect fontselect fontsizeselect | bold italic removeformat forecolor backcolor | " +
"alignleft aligncenter alignright alignjustify | bullist " +
"numlist outdent indent| link image pastetext | table" ;
/ * *
* arranged toolbars as extended mode
* @ constant
* /
et2 _htmlarea . TOOLBAR _EXTENDED = "fontselect fontsizeselect | bold italic strikethrough forecolor backcolor | " +
"link | alignleft aligncenter alignright alignjustify | numlist " +
"bullist outdent indent | removeformat | image | fullscreen | table" ;
/ * *
* arranged toolbars as advanced mode
* @ constant
* /
et2 _htmlarea . TOOLBAR _ADVANCED = "undo redo| formatselect | fontselect fontsizeselect | bold italic strikethrough forecolor backcolor | " +
"alignleft aligncenter alignright alignjustify | bullist " +
"numlist outdent indent ltr rtl | removeformat code| link image pastetext | searchreplace | fullscreen | table" ;
/ * *
* font size formats
* @ constant
* /
et2 _htmlarea . FONT _SIZE _FORMATS = {
pt : "8pt 9pt 10pt 11pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 28pt 36pt 48pt 72pt" ,
px : "8px 9px 10px 11px 12px 14px 16px 18px 20px 22px 24px 26px 28px 36px 48px 72px"
} ;
/ * *
* language code represention for TinyMCE lang code
* /
et2 _htmlarea . LANGUAGE _CODE = {
bg : "bg_BG" , ca : "ca" , cs : "cs" , da : "da" , de : "de" , en : "en_CA" ,
el : "el" , "es-es" : "es" , et : "et" , eu : "eu" , fa : "fa_IR" , fi : "fi" ,
fr : "fr_FR" , hi : "" , hr : "hr" , hu : "hu_HU" , id : "id" , it : "it" , iw : "" ,
ja : "ja" , ko : "ko_KR" , lo : "" , lt : "lt" , lv : "lv" , nl : "nl" , no : "nb_NO" ,
pl : "pl" , pt : "pt_PT" , "pt-br" : "pt_BR" , ru : "ru" , sk : "sk" , sl : "sl_SI" ,
sv : "sv_SE" , th : "th_TH" , tr : "tr_TR" , uk : "en_GB" , vi : "vi_VN" , zh : "zh_CN" ,
"zh-tw" : "zh_TW"
} ;
et2 _register _widget ( et2 _htmlarea , [ "htmlarea" ] ) ;
2020-02-12 11:33:20 +01:00
//# sourceMappingURL=et2_widget_htmlarea.js.map