2018-10-19 16:35:18 +02:00
/ * *
* EGroupware eTemplate2 - JS widget for HTML editing
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Nathan Gray
* @ copyright Nathan Gray 2012
* @ version $Id$
* /
/ * e g w : u s e s
jsapi . jsapi ; // Needed for egw_seperateJavaScript
/ v e n d o r / b o w e r - a s s e t / j q u e r y / d i s t / j q u e r y . j s ;
et2 _core _baseWidget ;
* /
/ * *
* @ augments et2 _inputWidget
* /
var et2 _ckeditor = ( function ( ) { "use strict" ; return et2 _inputWidget . extend ( [ et2 _IResizeable ] ,
{
modes : [ 'ascii' , 'simple' , 'extended' , 'advanced' ] ,
attributes : {
'mode' : {
'name' : 'Mode' ,
'description' : 'One of {ascii|simple|extended|advanced}' ,
'default' : 'simple' ,
'type' : 'string'
} ,
'height' : {
'name' : 'Height' ,
'default' : et2 _no _init ,
'type' : 'string'
} ,
'width' : {
'name' : 'Width' ,
'default' : et2 _no _init ,
'type' : 'string'
} ,
'expand_toolbar' : {
'name' : 'Expand Toolbar' ,
'default' : true ,
'type' : 'boolean' ,
'description' : 'Have the toolbar expanded (visible)'
} ,
'base_href' : { // seems not to be used anymore
'name' : 'Image base path' ,
'default' : et2 _no _init ,
'type' : 'string' ,
'description' : 'activates the browser for images at the path (relative to the docroot)'
} ,
'config' : {
// internal default configuration
'name' : 'Internal configuration' ,
'type' : 'any' ,
'default' : et2 _no _init ,
'description' : 'Internal configuration - managed by preferences & framework, passed in here' ,
'translate' : 'no_lang'
} ,
value : {
name : "Value" ,
description : "The value of the widget" ,
type : "html" , // "string" would remove html tags by running html_entity_decode
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
}
} ,
legacyOptions : [ 'mode' , 'height' , 'width' , 'expand_toolbar' , 'base_href' ] ,
/ * *
* Constructor
*
* @ param _parent
* @ param _attrs
* @ memberOf et2 _ckeditor
* /
init : function ( _parent , _attrs ) {
// _super.apply is responsible for the actual setting of the params (some magic)
this . _super . apply ( this , arguments ) ;
// CK instance
this . ckeditor = null ;
// Allow no child widgets
this . supportedWidgetClasses = [ ] ;
this . htmlNode = jQuery ( document . createElement ( "textarea" ) )
. css ( 'height' , this . options . height )
. addClass ( 'et2_textbox_ro' ) ;
this . setDOMNode ( this . htmlNode [ 0 ] ) ;
} ,
transformAttributes : function ( _attrs ) {
// Check mode, some apps jammed everything in there
if ( _attrs [ 'mode' ] && jQuery . inArray ( _attrs [ 'mode' ] , this . modes ) < 0 )
{
this . egw ( ) . debug ( "warn" , "'%s' is an invalid mode for et2_ckeditor '%s'. Valid options:" , _attrs [ 'mode' ] , _attrs [ 'id' ] , this . modes ) ;
var list = _attrs [ 'mode' ] . split ( ',' ) ;
for ( var i = 0 ; i < list . length && i < this . legacyOptions . length ; i ++ )
{
_attrs [ this . legacyOptions [ i ] ] = list [ i ] ;
}
}
this . _super . apply ( this , arguments ) ;
} ,
doLoadingFinished : function ( ) {
this . _super . apply ( this , arguments ) ;
if ( this . mode == 'ascii' || this . ckeditor != null ) return ;
var self = this ;
if ( ! this . options . imageUpload )
{
delete self . options . config . imageUploadUrl ;
}
else if ( this . options . imageUpload [ 0 ] !== '/' && this . options . imageUpload . substr ( 0 , 4 ) != 'http' )
{
self . options . config . imageUploadUrl = egw . ajaxUrl ( "EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_htmlarea_upload" ) +
'&request_id=' + self . getInstanceManager ( ) . etemplate _exec _id + '&widget_id=' + this . options . imageUpload ;
self . options . config . imageUploadUrl = self . options . config . imageUploadUrl . substr ( egw . webserverUrl . length + 1 ) ;
}
else
{
self . options . config . imageUploadUrl = this . options . imageUpload . substr ( egw . webserverUrl . length + 1 ) ;
}
try
{
this . ckeditor = CKEDITOR . replace ( this . dom _id , jQuery . extend ( { } , this . options . config , this . options ) ) ;
this . ckeditor . setData ( self . value ) ;
delete self . value ;
}
catch ( e )
{
if ( CKEDITOR . instances [ this . dom _id ] )
{
CKEDITOR . instances [ this . dom _id ] . destroy ( ) ;
}
if ( this . htmlNode . ckeditor )
{
this . ckeditor = CKEDITOR . replace ( this . dom _id , this . options . config ) ;
this . ckeditor . setData ( self . value ) ;
delete self . value ;
}
}
if ( this . ckeditor && this . options . config . preference _style )
{
var editor = this . ckeditor ;
this . ckeditor . on ( 'instanceReady' , function ( e ) {
// Add in user font preferences
if ( self . options . config . preference _style && ! e . editor . getData ( ) )
{
e . editor . document . getBody ( ) . setHtml ( self . options . config . preference _style ) ;
delete self . options . config . preference _style ;
}
} ) ;
// Drag & drop of images inline won't work, because of database
// field sizes. For some reason FF ignored just changing the cursor
// when dragging, so we replace dropped images with error icon.
var replaceImgText = function ( html ) {
var ret = html . replace ( /<img[^>]*src="(data:.*;base64,.*?)"[^>]*>/gi , function ( img , src ) {
return '' ;
} ) ;
return ret ;
} ;
var chkImg = function ( e ) {
// don't execute code if the editor is readOnly
if ( editor . readOnly )
return ;
// allow data-URL, returning false to stop regular upload
if ( ! self . options . imageUpload )
{
// Remove the image from the text
setTimeout ( function ( ) {
editor . document . $ . body . innerHTML = replaceImgText ( editor . document . $ . body . innerHTML ) ;
} , 200 ) ;
}
// Supported file types for dropping on CKEditor imageUpload plugin
var supportedTypesByCKEditor = /image\/(jpeg|png|gif)/ ;
// Try to pass the image into the first et2_file that will accept it
if ( e . data . $ . dataTransfer && ! CKEDITOR . fileTools . isTypeSupported ( e . data . $ . dataTransfer . files [ 0 ] , supportedTypesByCKEditor ) )
{
self . getRoot ( ) . iterateOver ( function ( widget ) {
if ( widget . options . drop _target )
{
widget . set _value ( e . data . $ . dataTransfer . files , e . data . $ ) ;
return ;
}
} , e . data . $ , et2 _file ) ;
}
} ;
editor . on ( 'contentDom' , function ( ) {
editor . document . on ( 'drop' , chkImg ) ;
} ) ;
}
} ,
destroy : function ( ) {
try
{
//this.htmlNode.ckeditorGet().destroy(true);
if ( this . ckeditor ) this . ckeditor . destroy ( true ) ;
this . ckeditor = null ;
}
catch ( e )
{
this . egw ( ) . debug ( "warn" , "Removing CKEDITOR: " + e . message , this , e ) ;
// Finish it
delete CKEDITOR . instances [ this . dom _id ] ;
}
this . htmlNode . remove ( ) ;
this . htmlNode = null ;
this . _super . apply ( this , arguments ) ;
} ,
set _value : function ( _value ) {
this . _oldValue = _value ;
try {
//this.htmlNode.ckeditorGet().setData(_value);
var ckeditor = CKEDITOR . instances [ this . dom _id ] ;
if ( ckeditor )
{
ckeditor . setData ( _value ) ;
}
else
{
this . htmlNode . val ( _value ) ;
this . value = _value ;
}
} catch ( e ) {
// CK editor not ready - callback will do it
this . value = _value ;
}
} ,
getValue : function ( ) {
try
{
//return this.htmlNode.ckeditorGet().getData();
var ckeditor = CKEDITOR . instances [ this . dom _id ] ;
return ckeditor ? ckeditor . getData ( ) : this . htmlNode . val ( ) ;
}
catch ( e )
{
// CK Error
this . egw ( ) . debug ( "error" , e ) ;
return null ;
}
} ,
/ * *
* Resize htmlNode tag according to window size
* @ param { type } _height excess height which comes from window resize
* /
resize : function ( _height )
{
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 . ckeditor ) // CKEDITOR HTML
{
var h = 0 ;
if ( typeof this . ckeditor . container != 'undefined' && this . ckeditor . container . $ . clientHeight > 0 )
{
h = ( this . ckeditor . container . $ . clientHeight + _height ) > 0 ?
this . ckeditor . container . $ . clientHeight + _height : this . ckeditor . config . height ;
}
else if ( this . ckeditor . ui . space ( 'contents' ) )
{
h = parseInt ( this . ckeditor . ui . space ( 'contents' ) . getStyle ( 'height' ) ) + _height ;
}
else // fallback height size
{
h = this . ckeditor . config . height + _height ;
}
this . ckeditor . resize ( '' , h ) ;
}
else // No CKEDITOR
{
this . htmlNode . height ( this . htmlNode . height ( ) + _height ) ;
}
}
}
}
} ) ; } ) . call ( this ) ;
et2 _register _widget ( et2 _ckeditor , [ "ckeditor" ] ) ;
jQuery . extend ( et2 _ckeditor ,
{
/ * *
* Build VfsSelect widget for CKEditor Browse Server button
* @ param { array } _data
* /
buildVfsSelectForCKEditor : function ( _data )
{
if ( ! _data ) return ;
// 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.
var etemplate = jQuery ( 'form' ) . data ( 'etemplate' ) ;
var et2 = { } ;
if ( etemplate && etemplate . name && ! app [ egw ( window ) . app _name ( ) ] )
{
et2 = etemplate2 . getByTemplate ( etemplate . name ) [ 0 ] [ 'widgetContainer' ] ;
}
else
{
et2 = app [ egw ( window ) . app _name ( ) ] . et2 ;
}
var vfsSelect = et2 _createWidget ( 'vfs-select' , {
id : 'upload' ,
mode : 'open' ,
name : '' ,
button _caption : "Link" ,
button _label : "Link" ,
dialog _title : "Link file" ,
2018-10-23 13:04:20 +02:00
method : "download"
2018-10-19 16:35:18 +02:00
} , et2 ) ;
jQuery ( vfsSelect . getDOMNode ( ) ) . on ( 'change' , function ( ) {
CKEDITOR . tools . callFunction ( _data . funcNum , vfsSelect . get _value ( ) ) ;
} ) ;
// start the file selector dialog
vfsSelect . click ( ) ;
}
} ) ;