diff --git a/COPYRIGHT b/COPYRIGHT index f7edb08cae8..c38873a2f07 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -13,8 +13,9 @@ Component Version License GPL Compatible ------------------------------------------------------------------------------------- PHP libraries: AdoDb-Date 0.33 Modified BSD License Yes Date convertion (not into rpm package) -ChromePHP 4.3.3 Apache Software License 2.0 Yes Return server log to chrome browser console +ChromePHP 4.1.0 Apache Software License 2.0 Yes Return server log to chrome browser console CKEditor 4.3.3 LGPL-2.1+ Yes Editor WYSIWYG +EvalMath 1.0 BSD Yes Safe math expressions evaluation FPDI 1.5.2 Apache Software License 2.0 Yes PDF templates management GeoIP 1.4 LGPL-2.1+ Yes Sample code to make geoip convert (not into deb package) Mobiledetect 2.8.3 MIT License Yes Detect mobile devices browsers @@ -24,9 +25,10 @@ odtPHP 1.0.1 GPL-2+ b Yes PHPExcel 1.8.0 LGPL-2.1+ Yes Read/Write XLS files, read ODS files php-iban 1.4.7 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP PHPPrintIPP 1.3 GPL-2+ Yes Library to send print IPP requests +Raven-php 0.12.1 MIT License Yes Used for server-side error logging with Sentry logger Restler 3.0 LGPL-3+ Yes Library to develop REST Web services TCPDF 6.2.6 LGPL-3+ Yes PDF generation -EvalMath 1.0 BSD Yes Safe math expressions evaluation +TCPDI 1.0.0 LGPL-3+ / Apache 2.0 Yes FPDI replacement JS libraries: jQuery 1.11.3 MIT License Yes JS library @@ -49,7 +51,8 @@ jQuery TableDnD 0.6 GPL and MIT License Yes jQuery Timepicker 1.1.0 GPL and MIT License Yes JS library Timepicker addon for Datepicker jQuery Tiptip 1.3 GPL and MIT License Yes JS library for tooltips jsGantt 1.2 BSD License Yes JS library (to build Gantt reports) -JsTimezoneDetect 1.0.4 MIT Licence Yes JS library to detect user timezone +JsTimezoneDetect 1.0.4 MIT License Yes JS library to detect user timezone +Raven.js 1.1.19 MIT License Yes Used for client-side error logging with Sentry logger For licenses compatibility informations: http://www.fsf.org/licensing/licenses/index_html diff --git a/composer.json b/composer.json index ed75d3ca61d..d5e2d7f411e 100644 --- a/composer.json +++ b/composer.json @@ -12,21 +12,31 @@ }, "require": { "php": ">=5.3.0", - "ext-gd": "*", "ext-curl": "*", - "restler/framework": "3.0.*" + "ccampbell/chromephp": "^4.1", + "ckeditor/ckeditor": "4.3.3", + "mobiledetect/mobiledetectlib": "2.8.3", + "phpoffice/phpexcel": "1.8.0", + "restler/framework": "^3.0", + "tecnick.com/tcpdf": "6.2.6", + "raven/raven": "^0.12.0" }, "suggest": { - "ext-mysqli": "*", - "ext-pgsql": "*", - "ext-mssql": "*", - "ext-pdo_sqlite": "*", - "ext-imagick": "*", - "ext-mcrypt": "*", - "ext-openssl": "*", - "ext-mbstring": "*", - "ext-soap": "*", - "ext-zip": "*", - "ext-xml": "*" + "ext-mysqlnd": "To use with MySQL or MariaDB", + "ext-mysqli": "To use with MySQL or MariaDB", + "ext-pgsql": "To use with PostgreSQL", + "ext-mssql": "To use with MSSQL (experimental)", + "ext-pdo_sqlite": "To use with SQLite (experimental)", + "ext-gd": "Image manipulation (Required but maybe built-in PHP)", + "ext-imagick": "Image manipulation (TCPDF)", + "ext-mcrypt": "(Required but maybe built-in PHP)", + "ext-openssl": "Secure connections (Emails, SOAP…)", + "ext-mbstring": "Handle non UTF-8 databases", + "ext-soap": "Native SOAP", + "ext-zip": "ODT and Excel support", + "ext-xml": "Excel support" + }, + "config": { + "vendor-dir": "htdocs/includes" } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000000..2856ef0b749 --- /dev/null +++ b/composer.lock @@ -0,0 +1,405 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "32e1fa78cc95c32b154a38e07706874c", + "packages": [ + { + "name": "ccampbell/chromephp", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/ccampbell/chromephp.git", + "reference": "c3c297615d48ae5b2a86a82311152d1ed095fcef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ccampbell/chromephp/zipball/c3c297615d48ae5b2a86a82311152d1ed095fcef", + "reference": "c3c297615d48ae5b2a86a82311152d1ed095fcef", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ChromePhp": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Craig Campbell", + "email": "iamcraigcampbell@gmail.com", + "homepage": "http://craig.is", + "role": "Developer" + } + ], + "description": "Log variables to the Chrome console (via Chrome Logger Google Chrome extension).", + "homepage": "http://github.com/ccampbell/chromephp", + "keywords": [ + "log", + "logging" + ], + "time": "2013-06-26 03:44:33" + }, + { + "name": "ckeditor/ckeditor", + "version": "4.3.3", + "source": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor-releases.git", + "reference": "0068dd540ce8bf1815abb7b5455c55354bc56334" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ckeditor/ckeditor-releases/zipball/0068dd540ce8bf1815abb7b5455c55354bc56334", + "reference": "0068dd540ce8bf1815abb7b5455c55354bc56334", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+", + "LGPL-2.1+", + "MPL-1.1+" + ], + "authors": [ + { + "name": "CKSource - Frederico Knabben", + "homepage": "http://cksource.com" + } + ], + "description": "JavaScript WYSIWYG web text editor.", + "homepage": "http://ckeditor.com", + "keywords": [ + "CKEditor", + "editor", + "fckeditor", + "html", + "javascript", + "richtext", + "text", + "wysiwyg" + ], + "time": "2014-02-26 15:34:37" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.3", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "f5753e4b90daffe50c902e99df5ce3c58fca3fee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/f5753e4b90daffe50c902e99df5ce3c58fca3fee", + "reference": "f5753e4b90daffe50c902e99df5ce3c58fca3fee", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "Mobile_Detect.php" + ], + "psr-0": { + "Detection": "namespaced/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://ghita.org", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "time": "2014-07-10 20:00:25" + }, + { + "name": "phpoffice/phpexcel", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PHPExcel.git", + "reference": "e69a5e4d0ffa7fb6f171859e0a04346e580df30b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/e69a5e4d0ffa7fb6f171859e0a04346e580df30b", + "reference": "e69a5e4d0ffa7fb6f171859e0a04346e580df30b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "ext-xmlwriter": "*", + "php": ">=5.2.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "PHPExcel": "Classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "http://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker" + }, + { + "name": "Franck Lefevre", + "homepage": "http://blog.rootslabs.net" + }, + { + "name": "Erik Tilt" + } + ], + "description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "http://phpexcel.codeplex.com", + "keywords": [ + "OpenXML", + "excel", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "time": "2014-03-02 15:22:49" + }, + { + "name": "raven/raven", + "version": "0.12.1", + "source": { + "type": "git", + "url": "https://github.com/getsentry/raven-php.git", + "reference": "b325984c792ff89f985b73da9a3ad8ed8b520bca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/raven-php/zipball/b325984c792ff89f985b73da9a3ad8ed8b520bca", + "reference": "b325984c792ff89f985b73da9a3ad8ed8b520bca", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.2.4" + }, + "require-dev": { + "fabpot/php-cs-fixer": "^1.8.0", + "phpunit/phpunit": "^4.6.6" + }, + "bin": [ + "bin/raven" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.12.x-dev" + } + }, + "autoload": { + "psr-0": { + "Raven_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "authors": [ + { + "name": "David Cramer", + "email": "dcramer@gmail.com" + } + ], + "description": "A PHP client for Sentry (http://getsentry.com)", + "homepage": "http://getsentry.com", + "keywords": [ + "log", + "logging" + ], + "time": "2015-08-25 22:38:46" + }, + { + "name": "restler/framework", + "version": "3.0.0", + "target-dir": "Luracast/Restler", + "source": { + "type": "git", + "url": "https://github.com/Luracast/Restler-Framework.git", + "reference": "6ee10b3e5dbc6376916fed55ec2340a37cce436b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Luracast/Restler-Framework/zipball/6ee10b3e5dbc6376916fed55ec2340a37cce436b", + "reference": "6ee10b3e5dbc6376916fed55ec2340a37cce436b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "replace": { + "luracast/restler": "3.*" + }, + "require-dev": { + "bshaffer/oauth2-server-php": "v1.0", + "luracast/explorer": "*", + "mustache/mustache": "dev-master", + "rodneyrehm/plist": "dev-master", + "symfony/yaml": "*", + "twig/twig": "v1.13.0", + "zendframework/zendamf": "dev-master" + }, + "suggest": { + "bshaffer/oauth2-server-php": "Restler can provide OAuth2 authentication using this library (see require-dev for details)", + "luracast/explorer": "Restler's very own api explorer (see require-dev for details)", + "mustache/mustache": "Restler can render HtmlView using mustache/handlebar templates (see require-dev for details)", + "rodneyrehm/plist": "Restler supports tho Apple plist xml format (see require-dev for details)", + "symfony/yaml": "Restler can produce content in yaml format as well (see require-dev for details)", + "twig/twig": "Restler can render HtmlView using twig templates (see require-dev for details)", + "zendframework/zendamf": "Support for the amf document format (see require-dev for details)" + }, + "type": "library", + "extra": { + "branch-alias": { + "master": "v3.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Luracast\\Restler": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Luracast", + "email": "arul@luracast.com" + }, + { + "name": "Nick nickl- Lombard", + "email": "github@jigsoft.co.za" + } + ], + "description": "Just the Restler Framework without the tests and examples", + "homepage": "http://luracast.com/products/restler/", + "keywords": [ + "api", + "framework", + "rest", + "server" + ], + "time": "2015-08-04 07:52:49" + }, + { + "name": "tecnick.com/tcpdf", + "version": "6.2.6", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/TCPDF.git", + "reference": "a2e8f5b505a7a14a4ed960313c4baf699fd1f4bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/a2e8f5b505a7a14a4ed960313c4baf699fd1f4bb", + "reference": "a2e8f5b505a7a14a4ed960313c4baf699fd1f4bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "fonts", + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPLv3" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "time": "2015-01-28 18:51:40" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.0", + "ext-curl": "*" + }, + "platform-dev": [] +} diff --git a/dev/dolibarr_changes.txt b/dev/dolibarr_changes.txt index bf68293d369..9d449070a5f 100644 --- a/dev/dolibarr_changes.txt +++ b/dev/dolibarr_changes.txt @@ -69,7 +69,7 @@ Add tcpdi.php Add tcpdi_parser.php and replace: require_once(dirname(__FILE__).'/include/tcpdf_filters.php'); with: -require_once(dirname(__FILE__).'/../tcpdf/include/tcpdf_filters.php'); +require_once(dirname(__FILE__).'/../tecnick.com/tcpdf/include/tcpdf_filters.php'); diff --git a/dev/test/testtcpdf.php b/dev/test/testtcpdf.php index 4b8b6f36d53..6b600c630d3 100755 --- a/dev/test/testtcpdf.php +++ b/dev/test/testtcpdf.php @@ -27,8 +27,8 @@ * @since 2008-03-04 */ -require_once('../../htdocs/includes/tcpdf/config/lang/eng.php'); -require_once('../../htdocs/includes/tcpdf/tcpdf.php'); +require_once('../../htdocs/includes/tecnick.com/tcpdf/config/tcpdf_config.php'); +require_once('../../htdocs/includes/tecnick.com/tcpdf/tcpdf.php'); // create new PDF document $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); diff --git a/dev/test/testutf.php b/dev/test/testutf.php index 5812b0c8639..f60f9d195a3 100644 --- a/dev/test/testutf.php +++ b/dev/test/testutf.php @@ -47,8 +47,8 @@ print 'Files has been created. Check its name from your explorer'."\n"; * @since 2008-09-15 */ -require_once('../../htdocs/includes/tcpdf/config/lang/eng.php'); -require_once('../../htdocs/includes/tcpdf/tcpdf.php'); +require_once('../../htdocs/includes/tecnick.com/tcpdf/config/tcpdf_config.php'); +require_once('../../htdocs/includes/tecnick.com/tcpdf/tcpdf.php'); // create new PDF document $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); diff --git a/htdocs/admin/syslog.php b/htdocs/admin/syslog.php index 3eebfebb37b..7d713760382 100644 --- a/htdocs/admin/syslog.php +++ b/htdocs/admin/syslog.php @@ -106,8 +106,17 @@ if ($action == 'set') $activeModules = $newActiveModules; dolibarr_set_const($db, 'SYSLOG_HANDLERS', json_encode($activeModules), 'chaine',0,'',0); + // Check configuration + foreach ($activeModules as $modulename) { + /** + * @var LogHandler + */ + $module = new $modulename; + $error = $module->checkConfiguration(); + } - if (! $error) + + if (! $error) { $db->commit(); setEventMessage($langs->trans("SetupSaved")); @@ -115,7 +124,8 @@ if ($action == 'set') else { $db->rollback(); - setEventMessage($langs->trans("Error"),'errors'); + setEventMessage($error, 'errors'); + } } diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php index d27e6e59fb4..67458fd401d 100644 --- a/htdocs/core/actions_sendmails.inc.php +++ b/htdocs/core/actions_sendmails.inc.php @@ -47,7 +47,7 @@ if (GETPOST('addfile')) /* * Remove file in email form */ -if (! empty($_POST['removedfile'])) +if (! empty($_POST['removedfile']) && empty($_POST['removAll'])) { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; @@ -60,11 +60,41 @@ if (! empty($_POST['removedfile'])) $action='presend'; } +/* + * Remove all files in email form + */ + +if(! empty($_POST['removAll'])) +{ + $listofpaths=array(); + $listofnames=array(); + $listofmimes=array(); + if (! empty($_SESSION["listofpaths"])) $listofpaths=explode(';',$_SESSION["listofpaths"]); + if (! empty($_SESSION["listofnames"])) $listofnames=explode(';',$_SESSION["listofnames"]); + if (! empty($_SESSION["listofmimes"])) $listofmimes=explode(';',$_SESSION["listofmimes"]); + + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + foreach($listofpaths as $key => $value) + { + $pathtodelete = $value; + $filetodelete = $listofnames[$key]; + $result = dol_delete_file($pathtodelete,1); // Delete uploded Files + + $langs->load("other"); + setEventMessage($langs->trans("FileWasRemoved",$filetodelete)); + + $formmail->remove_attached_files($key); // Update Session + } +} + /* * Send mail */ -if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_POST['removedfile'] && ! $_POST['cancel'] && !$_POST['modelselected']) +if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_POST['removAll'] && ! $_POST['removedfile'] && ! $_POST['cancel'] && !$_POST['modelselected']) { + if($conf->dolimail->enabled) $langs->load("dolimail@dolimail"); $langs->load('mails'); $subject='';$actionmsg='';$actionmsg2=''; @@ -81,7 +111,37 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO else if ($object->element == 'societe') { $thirdparty=$object; - $sendtosocid=$thirdparty->id; + if ($thirdparty->id > 0) $sendtosocid=$thirdparty->id; + elseif($conf->dolimail->enabled) + { + $dolimail = new Dolimail($db); + $possibleaccounts=$dolimail->get_societe_by_email($_POST['sendto'],"1"); + $possibleuser=$dolimail->get_from_user_by_mail($_POST['sendto'],"1"); // suche in llx_societe and socpeople + if (!$possibleaccounts && !$possibleuser) + { + setEventMessage($langs->trans('ErrorFailedToFindSocieteRecord',$_POST['sendto']),'errors'); + } + elseif (count($possibleaccounts)>1) + { + $sendtosocid=$possibleaccounts[1]['id']; + $result=$object->fetch($sendtosocid); + + setEventMessage($langs->trans('ErrorFoundMoreThanOneRecordWithEmail',$_POST['sendto'],$object->name)); + } + else + { + if($possibleaccounts){ + $sendtosocid=$possibleaccounts[1]['id']; + $result=$object->fetch($sendtosocid); + }elseif($possibleuser){ + $sendtosocid=$possibleuser[0]['id']; + + $result=$uobject->fetch($sendtosocid); + $object=$uobject; + } + + } + } } else dol_print_error('','Use actions_sendmails.in.php for a type that is not supported'); @@ -163,6 +223,46 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO $trackid = GETPOST('trackid','aZ'); + if($conf->dolimail->enabled) + { + $mailfromid = explode ("#", $_POST['frommail'],3); + if (count($mailfromid)==0) $from = $_POST['fromname'] . ' <' . $_POST['frommail'] .'>'; + else + { + $mbid = $mailfromid[1]; + + /*IMAP Postbox*/ + $mailboxconfig = new IMAP($db); + $mailboxconfig->fetch($mbid); + if ($mailboxconfig->mailbox_imap_host) $ref=$mailboxconfig->get_ref(); + + $mailboxconfig->folder_id=$mailboxconfig->mailbox_imap_outbox; + $mailboxconfig->userfolder_fetch(); + + if ($mailboxconfig->mailbox_save_sent_mails == 1) + { + + $folder=str_replace($ref, '', $mailboxconfig->folder_cache_key); + if (!$folder) $folder = "Sent"; + + $mailboxconfig->mbox = imap_open($mailboxconfig->get_connector_url().$folder, $mailboxconfig->mailbox_imap_login, $mailboxconfig->mailbox_imap_password); + if (FALSE === $mailboxconfig->mbox) + { + $info = FALSE; + $err = $langs->trans('Error3_Imap_Connection_Error'); + setEventMessage($err,$mailboxconfig->element,'errors'); + } + else + { + $mailboxconfig->mailboxid=$_POST['frommail']; + $mailboxconfig->foldername=$folder; + $from = $mailfromid[0] . $mailfromid[2]; + $imap=1; + } + + } + } + } // Send mail require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,$sendtobcc,$deliveryreceipt,-1,'','',$trackid); @@ -176,7 +276,26 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO if ($result) { $error=0; - + if($conf->dolimail->enabled) + { + $mid = (GETPOST('mid','int') ? GETPOST('mid','int') : 0); + if ($mid) + { + // set imap flag answered if it is a answered mail + + $dolimail=new DoliMail($db); + $dolimail->id = $mid; + $res=$dolimail->set_prop($user, 'answered',1); + } + if ($imap==1) + { + // write mail to IMAP Server + $movemail = $mailboxconfig->putMail($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,$folder,$deliveryreceipt,$mailfile); + if ($movemail) setEventMessage($langs->trans("MailMovedToImapFolder",$folder),'mesgs'); + else setEventMessage($langs->trans("MailMovedToImapFolder_Warning",$folder),'warnings'); + } + } + // Initialisation donnees $object->socid = $sendtosocid; // To link to a company $object->sendtoid = $sendtoid; // To link to a contact/address @@ -205,24 +324,27 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO // This avoid sending mail twice if going out and then back to page $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); setEventMessage($mesg); - header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.$object->id); + if($conf->dolimail->enabled) header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.$object->id.'&'.($paramname2?$paramname2:'mid').'='.$parm2val); + else header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.$object->id); exit; } } else { $langs->load("other"); + $mesg='
'; if ($mailfile->error) { - $mesg=''; $mesg.=$langs->trans('ErrorFailedToSendMail',$from,$sendto); $mesg.='
'.$mailfile->error; - setEventMessage($mesg,'errors'); } else { - setEventMessage('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', 'warnings'); + $mesg.='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS'; } + $mesg.='
'; + + setEventMessage($mesg,'warnings'); $action = 'presend'; } } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 2f197d8b645..8f6471f4af0 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -202,6 +202,329 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil } } +/** + * Scan a directory and return a array of files/directories from a selection. + * Content for string is UTF8 and dir separator is "/". + * + * @param int $fk_soc select socid - for your selection in array + * @param string $module_get Starting path from which to search + * @param string $sortorder SORT_ASC or SORT_DESC + * @param array $excludefiles Array of Regex for exclude filter (example: array('(\.meta|_preview\.png)$','^\.')) + * @return array Array of array( filefolder=> array( filelabel=> array( file=> array('name'=>'xxx','date'=>'yyy','size'=>99,'type'=>'dir|file')))) + */ +function get_soc_file_array($fk_soc, $module_get = false, $sortorder = false, $excludefiles = false) +{ + global $user, $conf, $db; + + $sortfield = "date"; + + if(!$sortorder){ + $sorting = SORT_DESC; + }else{ + $sorting = $sortorder; + } + + $ar_modules_get = array(); + if (is_array($module_get)) $ar_modules_get = $module_get; + elseif (strlen($module_get) > 0) $ar_modules_get[$module_get] = $module_get; + else + { + $ar_modules_get['company'] = 'company'; + $ar_modules_get['dolimail'] = 'dolimail'; + $ar_modules_get['actions'] = 'actions'; + $ar_modules_get['invoice'] = 'invoice'; + $ar_modules_get['order'] = 'order'; + $ar_modules_get['propal'] = 'propal'; + $ar_modules_get['contract'] = 'contract'; + $ar_modules_get['project'] = 'project'; + $ar_modules_get['invoice_supplier'] = 'invoice_supplier'; + $ar_modules_get['order_supplier'] = 'order_supplier'; + } + + + // rights + if (count($ar_modules_get) > 0) + foreach($ar_modules_get as $curmodule) + { + switch($curmodule) + { + case 'company': + if (! empty($conf->societe->enabled)) // Recht Alle oder nur die Vertriebspartneradressen + $ar_modules_secure['company']['outputdir'] = $conf->societe->dir_output; + break; + case 'dolimail': + if (! empty($conf->dolimail->enabled) && ($user->rights->dolimail->read || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->dolimail->dir_output.'/attachments'; + break; + case 'actions': + if (! empty($conf->agenda->enabled) || ($user->rights->agenda->allactions->read || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->agenda->dir_output; + break; + case 'invoice': + if (! empty($conf->facture->enabled) && ($user->rights->facture->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->facture->dir_output; + break; + case 'order': + if (!empty($conf->commande->enabled) && ($user->rights->commande->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->commande->dir_output; + break; + case 'propal': + if (!empty($conf->propal->enabled) && ($user->rights->propale->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->propal->dir_output; + break; + case 'project': + if (! empty($conf->projet->enabled) && ($user->rights->projet->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->projet->dir_output; + break; + case 'invoice_supplier': + if (! empty($conf->fournisseur->enabled) && ($user->rights->fournisseur->facture->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->fournisseur->dir_output.'/facture'; + break; + case 'order_supplier': + if (! empty($conf->fournisseur->enabled) && ($user->rights->fournisseur->commande->lire || $user->admin)) + $ar_modules_secure[$curmodule]['outputdir']=$conf->fournisseur->dir_output.'/commande'; + break; + } + } + /* TODO make a outputdir*/ + //unset($ar_modules_secure['dolimail']); + unset($ar_modules_secure['project']); // project (list with project) is "ref" + unset($ar_modules_secure['actions']); + unset($ar_modules_secure['contract']); + /* TODO make a outputdir*/ + unset($curmodule); + + if($fk_soc > 0) + $ar_modules_get = $ar_modules_secure; + + $xy=0; + if (count($ar_modules_get)>0) + foreach($ar_modules_get as $curmodule => $myarray) + { + if($fk_soc > 0 && $curmodule != "company") + { + + // SQL to find documents (ref number) + + if($curmodule == "invoice") $sql = "SELECT facnumber as refstr FROM ".MAIN_DB_PREFIX."facture"; + elseif($curmodule == "order") $sql = "SELECT ref as refstr FROM ".MAIN_DB_PREFIX."commande"; + elseif($curmodule == "invoice_supplier") $sql = "SELECT rowid as refstr FROM ".MAIN_DB_PREFIX."facture_fourn"; + elseif($curmodule == "order_supplier") $sql = "SELECT ref as refstr FROM ".MAIN_DB_PREFIX."commande_fournisseur"; + elseif($curmodule == "propal") $sql = "SELECT ref as refstr FROM ".MAIN_DB_PREFIX."propal"; + elseif($curmodule == "contract") $sql = "SELECT ref as refstr FROM ".MAIN_DB_PREFIX."contrat"; + elseif($curmodule == "dolimail") $sql = "SELECT uid as refstr, subject FROM ".MAIN_DB_PREFIX."mails"; + + $sql.= ' WHERE entity IN ('.getEntity('societe', 1).')'; + $sql.= " AND fk_soc = '".$fk_soc."'"; + + + $res = $db->query($sql); + if ($res && $db->num_rows($res) > 0) + { + while($obj = $db->fetch_object($res)) + { + $ar_modules_secure[$curmodule]['socref'][] = $obj->refstr; + if($curmodule == "dolimail") $ar_modules_secure['dolimail']['subject'][$obj->refstr] = $obj->subject; + } + } + else + { + unset($ar_modules_secure[$curmodule]); + continue; + $errors[]="SQL Error: ".$sql; + $error++; + } + + + }else{ + if($curmodule == "dolimail") $sql = "SELECT uid as refstr, subject FROM ".MAIN_DB_PREFIX."mails"; + + $res = $db->query($sql); + if ($res && $db->num_rows($res) > 0) + { + while($obj = $db->fetch_object($res)) + { + if($curmodule == "dolimail") $ar_modules_secure['dolimail']['subject'][$obj->refstr] = $obj->subject; + } + } + } + + // Data in Array + // Get Array from ar_module + + $output[$curmodule]=dol_dir_list($myarray['outputdir'],"files",1,'', $excludefiles, $sortfield, $sorting,1); + if($fk_soc > 0) + { + if($curmodule == "company") + { + foreach($output["company"] as $label => $filedata) + { + if($filedata['level1name'] != $fk_soc) + { + unset($output['company'][$label]); + } + } + } + + elseif($curmodule == "invoice") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // wenn no file exsit + foreach($output["invoice"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) + { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($fac_supp_N_arr) array + } + + } + } + elseif($curmodule == "invoice_supplier") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["invoice_supplier"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($fac_supp_N_arr) array + } + } + } + elseif($curmodule == "order") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["order"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($ref_order_arr) array + } + } + } + elseif($curmodule == "order_supplier") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["order_supplier"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($ref_order_supp_arr) array + } + } + } + elseif($curmodule == "propal") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["propal"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($ref_propal_arr) array + } + } + } + elseif($curmodule == "contract") + { + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["contract"] as $label => $filedata) + { + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($ref_contract_arr) array + } + } + } + elseif($curmodule == "dolimail") + { + + if (! is_array($ar_modules_secure[$curmodule]['socref'])) { unset($output[$curmodule]); continue; } // throw all ref number who are not in ($fac_invoice_arr) array + foreach($output["dolimail"] as $label => $filedata) + { + if($filedata['name'] == "winmail.dat" || $filedata['name'] == "smime.p7s") unset($output[$curmodule][$label]); + else + if (! in_array($filedata['level1name'], $ar_modules_secure[$curmodule]['socref'])) { + unset($output[$curmodule][$label]); // throw all ref number who are not in ($ref_propal_arr) array + } + } + } + // Error if ther isn't any File + if(count($output[$curmodule]) == 0) + { + $error++; + $errors[]="Error [404]: No File found for User: ".$fk_soc." in module: ".$curmodule; + unset($output[$curmodule]); + } + } + + // Extra for Mail attachments + if($curmodule == "dolimail" && count($output["dolimail"])>0) + { + foreach($output["dolimail"] as $label => $filedata) + { + $output[$curmodule][$label]['subject'] = $ar_modules_secure['dolimail']['subject'][$filedata['level1name']]; + } + } + + // Extra for Mail attachments + if($curmodule == "invoice" && count($output["invoice"])>0) + { + foreach($output["invoice"] as $label => $filedata) + { + $output[$curmodule][$label]['subject'] = $filedata['level1name']; + } + } + + // Extra for Mail attachments + if($curmodule == "invoice_supplier" && count($output["invoice_supplier"])>0) + { + foreach($output["invoice_supplier"] as $label => $filedata) + { + $output[$curmodule][$label]['subject'] = $filedata['level1name']; + } + } + + // Extra for Mail attachments + if($curmodule == "contract" && count($output["contract"])>0) + { + foreach($output["contract"] as $label => $filedata) + { + $output[$curmodule][$label]['subject'] = $filedata['level1name']; + } + } + + $xy++; + } + + if(count($output) > 0) + { + return $output; + } + else + { + return -1; + } +} + +/** + * Calculate Bytes to kb, mb and translate it to current language + * + * @param int $byt Bytes + * @return string calculated string + */ +function calculate_byte($byt) +{ + global $langs; + + if ($byt < 1024) { + $unit = ' '.$langs->trans("b"); + $mailsize=$byt; + } else if ($byt / 1024 > 1024) { + $mailsize = $byt / 1024 / 1024; + $unit = ' '.$langs->trans("Mb"); + } else { + $mailsize = $byt / 1024; + $unit = ' '.$langs->trans("Kb"); + } + + $val = number_format($mailsize, 2).$unit; + + return $val; +} + /** * Fast compare of 2 files identified by their properties ->name, ->date and ->size * diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 62170e7d277..8ac512856e4 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -142,14 +142,14 @@ function getEntity($element=false, $shared=0) */ function getBrowserInfo($user_agent) { - include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetect.class.php'; + include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php'; $name='unknown'; $version=''; $os='unknown'; $phone = ''; - $detectmobile = new MobileDetect(null, $user_agent); + $detectmobile = new Mobile_Detect(null, $user_agent); $tablet = $detectmobile->isTablet(); if ($detectmobile->isMobile()) { diff --git a/htdocs/core/modules/syslog/mod_syslog_chromephp.php b/htdocs/core/modules/syslog/mod_syslog_chromephp.php index 4093b89d434..e47a0059828 100644 --- a/htdocs/core/modules/syslog/mod_syslog_chromephp.php +++ b/htdocs/core/modules/syslog/mod_syslog_chromephp.php @@ -52,11 +52,10 @@ class mod_syslog_chromephp extends LogHandler implements LogHandlerInterface try { if (empty($conf->global->SYSLOG_CHROMEPHP_INCLUDEPATH)) { - $conf->global->SYSLOG_CHROMEPHP_INCLUDEPATH=DOL_DOCUMENT_ROOT . '/includes/chromephp/'; + $conf->global->SYSLOG_CHROMEPHP_INCLUDEPATH = DOL_DOCUMENT_ROOT . '/includes/ccampbell/chromephp/'; } set_include_path($conf->global->SYSLOG_CHROMEPHP_INCLUDEPATH); - //print 'rrrrr'.get_include_path(); $res = @include_once('ChromePhp.php'); if (! $res) $res=@include_once('ChromePhp.class.php'); @@ -88,7 +87,7 @@ class mod_syslog_chromephp extends LogHandler implements LogHandlerInterface array( 'name' => $langs->trans('IncludePath','SYSLOG_CHROMEPHP_INCLUDEPATH'), 'constant' => 'SYSLOG_CHROMEPHP_INCLUDEPATH', - 'default' => DOL_DOCUMENT_ROOT . '/includes/chromephp/', + 'default' => DOL_DOCUMENT_ROOT . '/includes/ccampbell/chromephp/', 'attr' => 'size="60"', 'example' =>'/usr/share/php' ) diff --git a/htdocs/core/modules/syslog/mod_syslog_sentry.php b/htdocs/core/modules/syslog/mod_syslog_sentry.php new file mode 100644 index 00000000000..3625405aeaa --- /dev/null +++ b/htdocs/core/modules/syslog/mod_syslog_sentry.php @@ -0,0 +1,187 @@ + + * Copyright (C) 2004-2009 Laurent Destailleur + * Copyright (C) 2015 Raphaël Doursenaud + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +require_once DOL_DOCUMENT_ROOT . '/includes/autoload.php'; +require_once DOL_DOCUMENT_ROOT . '/core/modules/syslog/logHandler.php'; + +/** + * Class to manage logging to Sentry + * + * @see https://docs.getsentry.com/on-premise/clients/php/ + */ +class mod_syslog_sentry extends LogHandler implements LogHandlerInterface +{ + /** + * @var string Log handler code + */ + public $code = 'sentry'; + + /** + * Return name of logger + * + * @return string Name of logger + */ + public function getName() + { + return 'Sentry'; + } + + /** + * Version of the module ('x.y.z' or 'dolibarr' or 'experimental' or 'development') + * + * @return string + */ + public function getVersion() + { + return 'dolibarr'; + } + + /** + * Content of the info tooltip. + * + * @return false|string + */ + public function getInfo() + { + global $langs; + return $langs->trans('SyslogSentryFromProject'); + } + + /** + * Is the module active ? + * + * @return int + */ + public function isActive() + { + return 1; + } + + /** + * Return array of configuration data + * + * @return array Return array of configuration data + */ + public function configure() + { + global $langs; + return array( + array( + 'constant' => 'SYSLOG_SENTRY_DSN', + 'name' => $langs->trans('SyslogSentryDSN'), + 'default' => '', + 'attr' => 'size="100" placeholder="https://:@app.getsentry.com/"' + ) + ); + } + + /** + * Return if configuration is valid + * + * @return array Array of errors. Empty array if ok. + */ + public function checkConfiguration() + { + global $conf; + + $errors = array(); + + $dsn = $conf->global->SYSLOG_SENTRY_DSN; + + try { + $client = new Raven_Client( + $dsn, + array('curl_method' => 'sync') + ); + } catch (InvalidArgumentException $ex) { + $errors[] = "ERROR: There was an error parsing your DSN:\n " . $ex->getMessage(); + } + + if (!$errors) { + // Send test event and check for errors + $client->captureMessage('TEST: Sentry syslog configuration check', null, Raven_Client::DEBUG); + $last_error = $client->getLastError(); + if ($last_error) { + $errors[] = $last_error; + } + } + + if (!$errors) { + // Install handlers + $error_handler = new Raven_ErrorHandler($client); + $error_handler->registerExceptionHandler(); + $error_handler->registerErrorHandler(); + $error_handler->registerShutdownFunction(); + } + + return $errors; + } + + /** + * Export the message + * + * @param array $content Array containing the info about the message + * @return void + */ + public function export($content) + { + global $conf; + $dsn = $conf->global->SYSLOG_SENTRY_DSN; + $client = new Raven_Client( + $dsn, + array('curl_method' => 'exec') + ); + + $client->user_context(array( + 'username' => ($content['user'] ? $content['user'] : ''), + 'ip_address' => $content['ip'] + )); + + $client->tags_context(array( + 'version' => DOL_VERSION + )); + + $client->registerSeverityMap(array( + LOG_EMERG => Raven_Client::FATAL, + LOG_ALERT => Raven_Client::FATAL, + LOG_CRIT => Raven_Client::ERROR, + LOG_ERR => Raven_Client::ERROR, + LOG_WARNING => Raven_Client::WARNING, + LOG_NOTICE => Raven_Client::WARNING, + LOG_INFO => Raven_Client::INFO, + LOG_DEBUG => Raven_Client::DEBUG, + )); + + if (substr($content['message'], 0, 3) === 'sql') { + global $db; + $query = substr($content['message'], 4, strlen($content['message'])); + $client->captureQuery( + $query, + $client->translateSeverity($content['level']), + $db->type + ); + } else { + $client->captureMessage( + $content['message'], + null, + $client->translateSeverity($content['level']) + ); + } + } +} diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php index beead03469c..c591359f424 100644 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -205,11 +205,11 @@ define('MAIN_DB_PREFIX',$dolibarr_main_db_prefix); // Path to root libraries if (! defined('ADODB_PATH')) { define('ADODB_PATH', (!isset($dolibarr_lib_ADODB_PATH))?DOL_DOCUMENT_ROOT.'/includes/adodbtime/':(empty($dolibarr_lib_ADODB_PATH)?'':$dolibarr_lib_ADODB_PATH.'/')); } if (! defined('FPDF_PATH')) { define('FPDF_PATH', (empty($dolibarr_lib_FPDF_PATH))?DOL_DOCUMENT_ROOT.'/includes/fpdf/':$dolibarr_lib_FPDF_PATH.'/'); } // Used only for package that can't include tcpdf -if (! defined('TCPDF_PATH')) { define('TCPDF_PATH', (empty($dolibarr_lib_TCPDF_PATH))?DOL_DOCUMENT_ROOT.'/includes/tcpdf/':$dolibarr_lib_TCPDF_PATH.'/'); } +if (! defined('TCPDF_PATH')) { define('TCPDF_PATH', (empty($dolibarr_lib_TCPDF_PATH))?DOL_DOCUMENT_ROOT.'/includes/tecnick.com/tcpdf/':$dolibarr_lib_TCPDF_PATH.'/'); } if (! defined('FPDI_PATH')) { define('FPDI_PATH', (empty($dolibarr_lib_FPDI_PATH))?DOL_DOCUMENT_ROOT.'/includes/fpdfi/':$dolibarr_lib_FPDI_PATH.'/'); } if (! defined('TCPDI_PATH')) { define('TCPDI_PATH', (empty($dolibarr_lib_TCPDI_PATH))?DOL_DOCUMENT_ROOT.'/includes/tcpdi/':$dolibarr_lib_TCPDI_PATH.'/'); } if (! defined('NUSOAP_PATH')) { define('NUSOAP_PATH', (!isset($dolibarr_lib_NUSOAP_PATH))?DOL_DOCUMENT_ROOT.'/includes/nusoap/lib/':(empty($dolibarr_lib_NUSOAP_PATH)?'':$dolibarr_lib_NUSOAP_PATH.'/')); } -if (! defined('PHPEXCEL_PATH')) { define('PHPEXCEL_PATH', (!isset($dolibarr_lib_PHPEXCEL_PATH))?DOL_DOCUMENT_ROOT.'/includes/phpexcel/':(empty($dolibarr_lib_PHPEXCEL_PATH)?'':$dolibarr_lib_PHPEXCEL_PATH.'/')); } +if (! defined('PHPEXCEL_PATH')) { define('PHPEXCEL_PATH', (!isset($dolibarr_lib_PHPEXCEL_PATH))?DOL_DOCUMENT_ROOT.'/includes/phpoffice/phpexcel/Classes/':(empty($dolibarr_lib_PHPEXCEL_PATH)?'':$dolibarr_lib_PHPEXCEL_PATH.'/')); } if (! defined('GEOIP_PATH')) { define('GEOIP_PATH', (!isset($dolibarr_lib_GEOIP_PATH))?DOL_DOCUMENT_ROOT.'/includes/geoip/':(empty($dolibarr_lib_GEOIP_PATH)?'':$dolibarr_lib_GEOIP_PATH.'/')); } if (! defined('ODTPHP_PATH')) { define('ODTPHP_PATH', (!isset($dolibarr_lib_ODTPHP_PATH))?DOL_DOCUMENT_ROOT.'/includes/odtphp/':(empty($dolibarr_lib_ODTPHP_PATH)?'':$dolibarr_lib_ODTPHP_PATH.'/')); } if (! defined('ODTPHP_PATHTOPCLZIP')) { define('ODTPHP_PATHTOPCLZIP', (!isset($dolibarr_lib_ODTPHP_PATHTOPCLZIP))?DOL_DOCUMENT_ROOT.'/includes/odtphp/zip/pclzip/':(empty($dolibarr_lib_ODTPHP_PATHTOPCLZIP)?'':$dolibarr_lib_ODTPHP_PATHTOPCLZIP.'/')); } diff --git a/htdocs/includes/autoload.php b/htdocs/includes/autoload.php new file mode 100644 index 00000000000..be5223ff062 --- /dev/null +++ b/htdocs/includes/autoload.php @@ -0,0 +1,7 @@ +//samples/index.html - -For example: - - http://www.example.com/ckeditor/samples/index.html diff --git a/htdocs/includes/ckeditor/_source/CHANGES.md b/htdocs/includes/ckeditor/_source/CHANGES.md deleted file mode 100644 index a5bec2ba830..00000000000 --- a/htdocs/includes/ckeditor/_source/CHANGES.md +++ /dev/null @@ -1,442 +0,0 @@ -CKEditor 4 Changelog -==================== - -## CKEditor 4.3.3 - -Fixed Issues: - -* [#11500](http://dev.ckeditor.com/ticket/11500): [Webkit/Blink] Fixed: Selection lost when setting data in another inline editor. Additionally, [`selection.removeAllRanges()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-removeAllRanges) is now scoped to selection's [root](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-property-root). -* [#11104](http://dev.ckeditor.com/ticket/11104): [IE] Fixed: Various issues with scrolling and selection when focusing widgets. -* [#11487](http://dev.ckeditor.com/ticket/11487): Moving mouse over the [Enhanced Image](http://ckeditor.com/addon/image2) widget will no longer change the value returned by the [`editor.checkDirty()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-checkDirty) method. -* [#8673](http://dev.ckeditor.com/ticket/8673): [WebKit] Fixed: Cannot select and remove the [Page Break](http://ckeditor.com/addon/pagebreak). -* [#11413](http://dev.ckeditor.com/ticket/11413): Fixed: Incorrect [`editor.execCommand()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-execCommand) behavior. -* [#11438](http://dev.ckeditor.com/ticket/11438): Splitting table cells vertically is no longer changing table structure. -* [#8899](http://dev.ckeditor.com/ticket/8899): Fixed: Links in the [About CKEditor](http://ckeditor.com/addon/about) dialog window now open in a new browser window or tab. -* [#11490](http://dev.ckeditor.com/ticket/11490): Fixed: [Menu button](http://ckeditor.com/addon/menubutton) panel not showing in the source mode. -* [#11417](http://dev.ckeditor.com/ticket/11417): The [`widget.doubleclick`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-event-doubleclick) event is not canceled anymore after editing was triggered. -* [#11253](http://dev.ckeditor.com/ticket/11253): [IE] Fixed: Clipped upload button in the [Enhanced Image](http://ckeditor.com/addon/image2) dialog window. -* [#11359](http://dev.ckeditor.com/ticket/11359): Standardized the way anchors are discovered by the [Link](http://ckeditor.com/addon/link) plugin. -* [#11058](http://dev.ckeditor.com/ticket/11058): [IE8] Fixed: Error when deleting a table row. -* [#11508](http://dev.ckeditor.com/ticket/11508): Fixed: [`htmlDataProcessor`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor) discovering protected attributes within other attributes' values. -* [#11533](http://dev.ckeditor.com/ticket/11533): Widgets: Avoid recurring upcasts if the DOM structure was modified during an upcast. -* [#11400](http://dev.ckeditor.com/ticket/11400): Fixed: The [`domObject.removeAllListeners()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.domObject-method-removeAllListeners) method does not remove custom listeners completely. -* [#11493](http://dev.ckeditor.com/ticket/11493): Fixed: The [`selection.getRanges()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-getRanges) method does not override cached ranges when used with the `onlyEditables` argument. -* [#11390](http://dev.ckeditor.com/ticket/11390): [IE] All [XML](http://ckeditor.com/addon/xml) plugin [methods](http://docs.ckeditor.com/#!/api/CKEDITOR.xml) now work in IE10+. -* [#11542](http://dev.ckeditor.com/ticket/11542): [IE11] Fixed: Blurry toolbar icons when Right-to-Left UI language is set. -* [#11504](http://dev.ckeditor.com/ticket/11504): Fixed: When [`config.fullPage`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fullPage) is set to `true`, entities are not encoded in editor output. -* [#11004](http://dev.ckeditor.com/ticket/11004): Integrated [Enhanced Image](http://ckeditor.com/addon/image2) dialog window with [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter). -* [#11439](http://dev.ckeditor.com/ticket/11439): Fixed: Properties get cloned in the Cell Properties dialog window if multiple cells are selected. - -## CKEditor 4.3.2 - -Fixed Issues: - -* [#11331](http://dev.ckeditor.com/ticket/11331): A menu button will have a changed label when selected instead of using the `aria-pressed` attribute. -* [#11177](http://dev.ckeditor.com/ticket/11177): Widget drag handler improvements: - * [#11176](http://dev.ckeditor.com/ticket/11176): Fixed: Initial position is not updated when the widget data object is empty. - * [#11001](http://dev.ckeditor.com/ticket/11001): Fixed: Multiple synchronous layout recalculations are caused by initial drag handler positioning causing performance issues. - * [#11161](http://dev.ckeditor.com/ticket/11161): Fixed: Drag handler is not repositioned in various situations. - * [#11281](http://dev.ckeditor.com/ticket/11281): Fixed: Drag handler and mask are duplicated after widget reinitialization. -* [#11207](http://dev.ckeditor.com/ticket/11207): [Firefox] Fixed: Misplaced [Enhanced Image](http://ckeditor.com/addon/image2) resizer in the inline editor. -* [#11102](http://dev.ckeditor.com/ticket/11102): `CKEDITOR.template` improvements: - * [#11102](http://dev.ckeditor.com/ticket/11102): Added newline character support. - * [#11216](http://dev.ckeditor.com/ticket/11216): Added "\\'" substring support. -* [#11121](http://dev.ckeditor.com/ticket/11121): [Firefox] Fixed: High Contrast mode is enabled when the editor is loaded in a hidden iframe. -* [#11350](http://dev.ckeditor.com/ticket/11350): The default value of [`config.contentsCss`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-contentsCss) is affected by [`CKEDITOR.getUrl()`](http://docs.ckeditor.com/#!/api/CKEDITOR-method-getUrl). -* [#11097](http://dev.ckeditor.com/ticket/11097): Improved the [Autogrow](http://ckeditor.com/addon/autogrow) plugin performance when dealing with very big tables. -* [#11290](http://dev.ckeditor.com/ticket/11290): Removed redundant code in the [Source Dialog](http://ckeditor.com/addon/sourcedialog) plugin. -* [#11133](http://dev.ckeditor.com/ticket/11133): [Page Break](http://ckeditor.com/addon/pagebreak) becomes editable if pasted. -* [#11126](http://dev.ckeditor.com/ticket/11126): Fixed: Native Undo executed once the bottom of the snapshot stack is reached. -* [#11131](http://dev.ckeditor.com/ticket/11131): [Div Editing Area](http://ckeditor.com/addon/divarea): Fixed: Error thrown when switching to source mode if the selection was in widget's nested editable. -* [#11139](http://dev.ckeditor.com/ticket/11139): [Div Editing Area](http://ckeditor.com/addon/divarea): Fixed: Elements Path is not cleared after switching to source mode. -* [#10778](http://dev.ckeditor.com/ticket/10778): Fixed a bug with range enlargement. The range no longer expands to visible whitespace. -* [#11146](http://dev.ckeditor.com/ticket/11146): [IE] Fixed: Preview window switches Internet Explorer to Quirks Mode. -* [#10762](http://dev.ckeditor.com/ticket/10762): [IE] Fixed: JavaScript code displayed in preview window's URL bar. -* [#11186](http://dev.ckeditor.com/ticket/11186): Introduced the [`widgets.repository.addUpcastCallback()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-addUpcastCallback) method that allows to block upcasting given element to a widget. -* [#11307](http://dev.ckeditor.com/ticket/11307): Fixed: Paste as Plain Text conflict with the [MooTools](http://mootools.net) library. -* [#11140](http://dev.ckeditor.com/ticket/11140): [IE11] Fixed: Anchors are not draggable. -* [#11379](http://dev.ckeditor.com/ticket/11379): Changed default contents `line-height` to unitless values to avoid huge text overlapping (like in [#9696](http://dev.ckeditor.com/ticket/9696)). -* [#10787](http://dev.ckeditor.com/ticket/10787): [Firefox] Fixed: Broken replacement of text while pasting into `div`-based editor. -* [#10884](http://dev.ckeditor.com/ticket/10884): Widgets integration with the [Show Blocks](http://ckeditor.com/addon/showblocks) plugin. -* [#11021](http://dev.ckeditor.com/ticket/11021): Fixed: An error thrown when selecting entire editable contents while fake selection is on. -* [#11086](http://dev.ckeditor.com/ticket/11086): [IE8] Re-enable inline widgets drag&drop in Internet Explorer 8. -* [#11372](http://dev.ckeditor.com/ticket/11372): Widgets: Special characters encoded twice in nested editables. -* [#10068](http://dev.ckeditor.com/ticket/10068): Fixed: Support for protocol-relative URLs. -* [#11283](http://dev.ckeditor.com/ticket/11283): [Enhanced Image](http://ckeditor.com/addon/image2): A `
` element with `text-align: center` and an image inside is not recognised correctly. -* [#11196](http://dev.ckeditor.com/ticket/11196): [Accessibility Instructions](http://ckeditor.com/addon/a11yhelp): Allowed additional keyboard button labels to be translated in the dialog window. - -## CKEditor 4.3.1 - -**Important Notes:** - -* To match the naming convention, the `language` button is now `Language` ([#11201](http://dev.ckeditor.com/ticket/11201)). -* [Enhanced Image](http://ckeditor.com/addon/image2) button, context menu, command, and icon names match those of the [Image](http://ckeditor.com/addon/image) plugin ([#11222](http://dev.ckeditor.com/ticket/11222)). - -Fixed Issues: - -* [#11244](http://dev.ckeditor.com/ticket/11244): Changed: The [`widget.repository.checkWidgets()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-checkWidgets) method now fires the [`widget.repository.checkWidgets`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-event-checkWidgets) event, so from CKEditor 4.3.1 it is preferred to use the method rather than fire the event. -* [#11171](http://dev.ckeditor.com/ticket/11171): Fixed: [`editor.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) and [`editor.insertText()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertText) methods do not call the [`widget.repository.checkWidgets()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-checkWidgets) method. -* [#11085](http://dev.ckeditor.com/ticket/11085): [IE8] Replaced preview generated by the [Mathematical Formulas](http://ckeditor.com/addon/mathjax) widget with a placeholder. -* [#11044](http://dev.ckeditor.com/ticket/11044): Enhanced WAI-ARIA support for the [Language](http://ckeditor.com/addon/language) plugin drop-down menu. -* [#11075](http://dev.ckeditor.com/ticket/11075): With drop-down menu button focused, pressing the *Down Arrow* key will now open the menu and focus its first option. -* [#11165](http://dev.ckeditor.com/ticket/11165): Fixed: The [File Browser](http://ckeditor.com/addon/filebrowser) plugin cannot be removed from the editor. -* [#11159](http://dev.ckeditor.com/ticket/11159): [IE9-10] [Enhanced Image](http://ckeditor.com/addon/image2): Fixed buggy discovery of image dimensions. -* [#11101](http://dev.ckeditor.com/ticket/11101): Drop-down lists no longer break when given double quotes. -* [#11077](http://dev.ckeditor.com/ticket/11077): [Enhanced Image](http://ckeditor.com/addon/image2): Empty undo step recorded when resizing the image. -* [#10853](http://dev.ckeditor.com/ticket/10853): [Enhanced Image](http://ckeditor.com/addon/image2): Widget has paragraph wrapper when de-captioning unaligned image. -* [#11198](http://dev.ckeditor.com/ticket/11198): Widgets: Drag handler is not fully visible when an inline widget is in a heading. -* [#11132](http://dev.ckeditor.com/ticket/11132): [Firefox] Fixed: Caret is lost after drag and drop of an inline widget. -* [#11182](http://dev.ckeditor.com/ticket/11182): [IE10-11] Fixed: Editor crashes (IE11) or works with minor issues (IE10) if a page is loaded in Quirks Mode. See [`env.quirks`](http://docs.ckeditor.com/#!/api/CKEDITOR.env-property-quirks) for more details. -* [#11204](http://dev.ckeditor.com/ticket/11204): Added `figure` and `figcaption` styles to the `contents.css` file so [Enhanced Image](http://ckeditor.com/addon/image2) looks nicer. -* [#11202](http://dev.ckeditor.com/ticket/11202): Fixed: No newline in [BBCode](http://ckeditor.com/addon/bbcode) mode. -* [#10890](http://dev.ckeditor.com/ticket/10890): Fixed: Error thrown when pressing the *Delete* key in a list item. -* [#10055](http://dev.ckeditor.com/ticket/10055): [IE8-10] Fixed: *Delete* pressed on a selected image causes the browser to go back. -* [#11183](http://dev.ckeditor.com/ticket/11183): Fixed: Inserting a horizontal rule or a table in multiple row selection causes a browser crash. Additionally, the [`editor.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) method does not insert the element into every range of a selection any more. -* [#11042](http://dev.ckeditor.com/ticket/11042): Fixed: Selection made on an element containing a non-editable element was not auto faked. -* [#11125](http://dev.ckeditor.com/ticket/11125): Fixed: Keyboard navigation through menu and drop-down items will now cycle. -* [#11011](http://dev.ckeditor.com/ticket/11011): Fixed: The [`editor.applyStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-applyStyle) method removes attributes from nested elements. -* [#11179](http://dev.ckeditor.com/ticket/11179): Fixed: [`editor.destroy()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-destroy) does not cleanup content generated by the [Table Resize](http://ckeditor.com/addon/tableresize) plugin for inline editors. -* [#11237](http://dev.ckeditor.com/ticket/11237): Fixed: Table border attribute value is deleted when pasting content from Microsoft Word. -* [#11250](http://dev.ckeditor.com/ticket/11250): Fixed: HTML entities inside the ` - * ... - * CKEDITOR.replace( 'myfield' ); - * - * var textarea = document.body.appendChild( document.createElement( 'textarea' ) ); - * CKEDITOR.replace( textarea ); - * - * @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} The editor instance created. - */ - 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. - * - *
- * ... - * CKEDITOR.appendTo( 'editorSpace' ); - * - * @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} The editor instance created. - */ - CKEDITOR.appendTo = function( element, config, data ) - { - return createInstance( element, config, data, CKEDITOR.ELEMENT_MODE_APPENDTO ); - }; - - /** - * Replaces all ` - data = protectElements( data, protectTextareaRegex ); - - // Before anything, we must protect the URL attributes as the - // browser may changing them when setting the innerHTML later in - // the code. - data = protectAttributes( data ); - - // Protect elements than can't be set inside a DIV. E.g. IE removes - // style tags from innerHTML. (#3710) - data = protectElements( data, protectElementsRegex ); - - // Certain elements has problem to go through DOM operation, protect - // them by prefixing 'cke' namespace. (#3591) - data = protectElementsNames( data ); - - // All none-IE browsers ignore self-closed custom elements, - // protecting them into open-close. (#3591) - data = protectSelfClosingElements( data ); - - // Compensate one leading line break after
 open as browsers
-			// eat it up. (#5789)
-			data = protectPreFormatted( data );
-
-			var fixBin = evtData.context || editor.editable().getName(),
-				isPre;
-
-			// Old IEs loose formats when load html into 
.
-			if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && fixBin == 'pre' ) {
-				fixBin = 'div';
-				data = '
' + data + '
'; - isPre = 1; - } - - // Call the browser to help us fixing a possibly invalid HTML - // structure. - var el = editor.document.createElement( fixBin ); - // Add fake character to workaround IE comments bug. (#3801) - el.setHtml( 'a' + data ); - data = el.getHtml().substr( 1 ); - - // Restore shortly protected attribute names. - data = data.replace( new RegExp( ' data-cke-' + CKEDITOR.rnd + '-', 'ig' ), ' ' ); - - isPre && ( data = data.replace( /^
|<\/pre>$/gi, '' ) );
-
-			// Unprotect "some" of the protected elements at this point.
-			data = unprotectElementNames( data );
-
-			data = unprotectElements( data );
-
-			// Restore the comments that have been protected, in this way they
-			// can be properly filtered.
-			data = unprotectRealComments( data );
-
-			// Now use our parser to make further fixes to the structure, as
-			// well as apply the filter.
-			evtData.dataValue = CKEDITOR.htmlParser.fragment.fromHtml(
-				data, evtData.context, evtData.fixForBody === false ? false : getFixBodyTag( evtData.enterMode, editor.config.autoParagraph ) );
-		}, null, null, 5 );
-
-		// Filter incoming "data".
-		// Add element filter before htmlDataProcessor.dataFilter when purifying input data to correct html.
-		editor.on( 'toHtml', function( evt ) {
-			if ( evt.data.filter.applyTo( evt.data.dataValue, true, evt.data.dontFilter, evt.data.enterMode ) )
-				editor.fire( 'dataFiltered' );
-		}, null, null, 6 );
-
-		editor.on( 'toHtml', function( evt ) {
-			evt.data.dataValue.filterChildren( that.dataFilter, true );
-		}, null, null, 10 );
-
-		editor.on( 'toHtml', function( evt ) {
-			var evtData = evt.data,
-				data = evtData.dataValue,
-				writer = new CKEDITOR.htmlParser.basicWriter();
-
-			data.writeChildrenHtml( writer );
-			data = writer.getHtml( true );
-
-			// Protect the real comments again.
-			evtData.dataValue = protectRealComments( data );
-		}, null, null, 15 );
-
-
-		editor.on( 'toDataFormat', function( evt ) {
-			var data = evt.data.dataValue;
-
-			// #10854 - we need to strip leading blockless 
which FF adds - // automatically when editable contains only non-editable content. - // We do that for every browser (so it's a constant behavior) and - // not in BR mode, in which chance of valid leading blockless
is higher. - if ( evt.data.enterMode != CKEDITOR.ENTER_BR ) - data = data.replace( /^
/i, '' ); - - evt.data.dataValue = CKEDITOR.htmlParser.fragment.fromHtml( - data, evt.data.context, getFixBodyTag( evt.data.enterMode, editor.config.autoParagraph ) ); - }, null, null, 5 ); - - editor.on( 'toDataFormat', function( evt ) { - evt.data.dataValue.filterChildren( that.htmlFilter, true ); - }, null, null, 10 ); - - // Transform outcoming "data". - // Add element filter after htmlDataProcessor.htmlFilter when preparing output data HTML. - editor.on( 'toDataFormat', function( evt ) { - evt.data.filter.applyTo( evt.data.dataValue, false, true ); - }, null, null, 11 ); - - editor.on( 'toDataFormat', function( evt ) { - var data = evt.data.dataValue, - writer = that.writer; - - writer.reset(); - data.writeChildrenHtml( writer ); - data = writer.getHtml( true ); - - // Restore those non-HTML protected source. (#4475,#4880) - data = unprotectRealComments( data ); - data = unprotectSource( data, editor ); - - evt.data.dataValue = data; - }, null, null, 15 ); - }; - - CKEDITOR.htmlDataProcessor.prototype = { - /** - * Processes the input (potentially malformed) HTML to a purified form which - * is suitable for using in the WYSIWYG editable. - * - * This method fires the {@link CKEDITOR.editor#toHtml} event which makes it possible - * to hook into the process at various stages. - * - * **Note:** Since CKEditor 4.3 the signature of this method changed and all options - * are now grouped in one `options` object. Previously `context`, `fixForBody` and `dontFilter` - * were passed separately. - * - * @param {String} data The raw data. - * @param {Object} [options] The options object. - * @param {String} [options.context] The tag name of a context element within which - * the input is to be processed, default to be the editable element. - * If `null` is passed, then data will be parsed without context (as children of {@link CKEDITOR.htmlParser.fragment}). - * See {@link CKEDITOR.htmlParser.fragment#fromHtml} for more details. - * @param {Boolean} [options.fixForBody=true] Whether to trigger the auto paragraph for non-block contents. - * @param {CKEDITOR.filter} [options.filter] When specified, instead of using the {@link CKEDITOR.editor#filter main filter}, - * passed instance will be used to filter the content. - * @param {Boolean} [options.dontFilter] Do not filter data with {@link CKEDITOR.filter} (note: transformations - * will be still applied). - * @param {Number} [options.enterMode] When specified it will be used instead of the {@link CKEDITOR.editor#enterMode main enterMode}. - * @returns {String} - */ - toHtml: function( data, options, fixForBody, dontFilter ) { - var editor = this.editor, - context, filter, enterMode; - - // Typeof null == 'object', so check truthiness of options too. - if ( options && typeof options == 'object' ) { - context = options.context; - fixForBody = options.fixForBody; - dontFilter = options.dontFilter; - filter = options.filter; - enterMode = options.enterMode; - } - // Backward compatibility. Since CKEDITOR 4.3 every option was a separate argument. - else - context = options; - - // Fall back to the editable as context if not specified. - if ( !context && context !== null ) - context = editor.editable().getName(); - - return editor.fire( 'toHtml', { - dataValue: data, - context: context, - fixForBody: fixForBody, - dontFilter: dontFilter, - filter: filter || editor.filter, - enterMode: enterMode || editor.enterMode - } ).dataValue; - }, - - /** - * See {@link CKEDITOR.dataProcessor#toDataFormat}. - * - * This method fires the {@link CKEDITOR.editor#toDataFormat} event which makes it possible - * to hook into the process at various steps. - * - * @param {String} html - * @param {Object} [options] The options object. - * @param {String} [options.context] The tag name of a context element within which - * the input is to be processed, default to be the editable element. - * @param {CKEDITOR.filter} [options.filter] When specified, instead of using the {@link CKEDITOR.editor#filter main filter}, - * passed instance will be used to apply content transformations to the content. - * @param {Number} [options.enterMode] When specified it will be used instead of the {@link CKEDITOR.editor#enterMode main enterMode}. - * @returns {String} - */ - toDataFormat: function( html, options ) { - var context, filter, enterMode; - - // Do not shorten this to `options && options.xxx`, because - // falsy `options` will be passed instead of undefined. - if ( options ) { - context = options.context; - filter = options.filter; - enterMode = options.enterMode; - } - - // Fall back to the editable as context if not specified. - if ( !context && context !== null ) - context = this.editor.editable().getName(); - - return this.editor.fire( 'toDataFormat', { - dataValue: html, - filter: filter || this.editor.filter, - context: context, - enterMode: enterMode || this.editor.enterMode - } ).dataValue; - } - }; - - // Produce a set of filtering rules that handles bogus and filler node at the - // end of block/pseudo block, in the following consequence: - // 1. elements: - this filter removes any bogus node, then check - // if it's an empty block that requires a filler. - // 2. elements:
- After cleaned with bogus, this filter checks the real - // line-break BR to compensate a filler after it. - // - // Terms definitions: - // filler: An element that's either
or &NBSP; at the end of block that established line height. - // bogus: Whenever a filler is proceeded with inline content, it becomes a bogus which is subjected to be removed. - // - // Various forms of the filler: - // In output HTML: Filler should be consistently &NBSP;
at the end of block is always considered as bogus. - // In Wysiwyg HTML: Browser dependent - see env.needsBrFiller. Either BR for when needsBrFiller is true, or &NBSP; otherwise. - //
is NEVER considered as bogus when needsBrFiller is true. - function createBogusAndFillerRules( editor, type ) { - function createFiller( isOutput ) { - return isOutput || CKEDITOR.env.needsNbspFiller ? - new CKEDITOR.htmlParser.text( '\xa0' ) : - new CKEDITOR.htmlParser.element( 'br', { 'data-cke-bogus': 1 } ); - } - - // This text block filter, remove any bogus and create the filler on demand. - function blockFilter( isOutput, fillEmptyBlock ) { - - return function( block ) { - - // DO NOT apply the filer if it's a fragment node. - if ( block.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) - return; - - cleanBogus( block ); - - // [Opera] it's mandatory for the filler to present inside of empty block when in WYSIWYG. - if ( ( ( CKEDITOR.env.opera && !isOutput ) || - ( typeof fillEmptyBlock == 'function' ? fillEmptyBlock( block ) !== false : fillEmptyBlock ) ) && - isEmptyBlockNeedFiller( block ) ) - { - block.add( createFiller( isOutput ) ); - } - }; - } - - // Append a filler right after the last line-break BR, found at the end of block. - function brFilter( isOutput ) { - return function( br ) { - - // DO NOT apply the filer if parent's a fragment node. - if ( br.parent.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) - return; - - var attrs = br.attributes; - // Dismiss BRs that are either bogus or eol marker. - if ( 'data-cke-bogus' in attrs || - 'data-cke-eol' in attrs ) { - delete attrs [ 'data-cke-bogus' ]; - return; - } - - // Judge the tail line-break BR, and to insert bogus after it. - var next = getNext( br ), previous = getPrevious( br ); - - if ( !next && isBlockBoundary( br.parent ) ) - append( br.parent, createFiller( isOutput ) ); - else if ( isBlockBoundary( next ) && previous && !isBlockBoundary( previous ) ) - createFiller( isOutput ).insertBefore( next ); - }; - } - - // Determinate whether this node is potentially a bogus node. - function maybeBogus( node, atBlockEnd ) { - - // BR that's not from IE<11 DOM, except for a EOL marker. - if ( !( isOutput && !CKEDITOR.env.needsBrFiller ) && - node.type == CKEDITOR.NODE_ELEMENT && node.name == 'br' && - !node.attributes[ 'data-cke-eol' ] ) - return true; - - var match; - // NBSP, possibly. - if ( node.type == CKEDITOR.NODE_TEXT && - ( match = node.value.match( tailNbspRegex ) ) ) - { - // We need to separate tail NBSP out of a text node, for later removal. - if ( match.index ) { - ( new CKEDITOR.htmlParser.text( node.value.substring( 0, match.index ) ) ).insertBefore( node ); - node.value = match[ 0 ]; - } - - // From IE<11 DOM, at the end of a text block, or before block boundary. - if ( !CKEDITOR.env.needsBrFiller && isOutput && ( !atBlockEnd || node.parent.name in textBlockTags ) ) - return true; - - // From the output. - if ( !isOutput ) { - var previous = node.previous; - - // Following a line-break at the end of block. - if ( previous && previous.name == 'br' ) - return true; - - // Or a single NBSP between two blocks. - if ( !previous || isBlockBoundary( previous ) ) - return true; - } - } - - return false; - } - - // Removes all bogus inside of this block, and to convert fillers into the proper form. - function cleanBogus( block ) { - var bogus = []; - var last = getLast( block ), node, previous; - if ( last ) { - - // Check for bogus at the end of this block. - // e.g.

foo

- maybeBogus( last, 1 ) && bogus.push( last ); - - while ( last ) { - - // Check for bogus at the end of any pseudo block contained. - if ( isBlockBoundary( last ) && - ( node = getPrevious( last ) ) && - maybeBogus( node ) ) - { - // Bogus must have inline proceeding, instead single BR between two blocks, - // is considered as filler, e.g.


- if ( ( previous = getPrevious( node ) ) && !isBlockBoundary( previous ) ) - bogus.push( node ); - // Convert the filler into appropriate form. - else { - createFiller( isOutput ).insertAfter( node ); - node.remove(); - } - } - - last = last.previous; - } - } - - // Now remove all bogus collected from above. - for ( var i = 0 ; i < bogus.length ; i++ ) - bogus[ i ].remove(); - } - - // Judge whether it's an empty block that requires a filler node. - function isEmptyBlockNeedFiller( block ) { - - // DO NOT fill empty editable in IE<11. - if ( !isOutput && !CKEDITOR.env.needsBrFiller && block.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) - return false; - - // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg; - // 2. For the rest, at least table cell and list item need no filler space. (#6248) - if ( !isOutput && !CKEDITOR.env.needsBrFiller && - ( document.documentMode > 7 || - block.name in CKEDITOR.dtd.tr || - block.name in CKEDITOR.dtd.$listItem ) ) { - return false; - } - - var last = getLast( block ); - return !last || block.name == 'form' && last.name == 'input' ; - } - - var rules = { elements: {} }; - var isOutput = type == 'html'; - - // Build the list of text blocks. - var textBlockTags = CKEDITOR.tools.extend( {}, blockLikeTags ); - for ( var i in textBlockTags ) { - if ( !( '#' in dtd[ i ] ) ) - delete textBlockTags[ i ]; - } - - for ( i in textBlockTags ) - rules.elements[ i ] = blockFilter( isOutput, editor.config.fillEmptyBlocks !== false ); - - // Editable element is to be checked separately. - rules.root = blockFilter( isOutput ); - rules.elements.br = brFilter( isOutput ); - return rules; - } - - function getFixBodyTag( enterMode, autoParagraph ) { - return ( enterMode != CKEDITOR.ENTER_BR && autoParagraph !== false ) ? enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' : false; - } - - // Regex to scan for   at the end of blocks, which are actually placeholders. - // Safari transforms the   to \xa0. (#4172) - var tailNbspRegex = /(?: |\xa0)$/; - - var protectedSourceMarker = '{cke_protected}'; - - function getLast( node ) { - var last = node.children[ node.children.length - 1 ]; - while ( last && isEmpty( last ) ) - last = last.previous; - return last; - } - - function getNext( node ) { - var next = node.next; - while ( next && isEmpty( next ) ) - next = next.next; - return next; - } - - function getPrevious( node ) { - var previous = node.previous; - while ( previous && isEmpty( previous ) ) - previous = previous.previous; - return previous; - } - - // Judge whether the node is an ghost node to be ignored, when traversing. - function isEmpty( node ) { - return node.type == CKEDITOR.NODE_TEXT && - !CKEDITOR.tools.trim( node.value ) || - node.type == CKEDITOR.NODE_ELEMENT && - node.attributes[ 'data-cke-bookmark' ]; - } - - // Judge whether the node is a block-like element. - function isBlockBoundary( node ) { - return node && - ( node.type == CKEDITOR.NODE_ELEMENT && node.name in blockLikeTags || - node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ); - } - - function append( parent, node ) { - var last = parent.children[ parent.children.length -1 ]; - parent.children.push( node ); - node.parent = parent; - if ( last ) { - last.next = node; - node.previous = last; - } - } - - function getNodeIndex( node ) { - return node.parent ? node.getIndex() : -1; - } - - var dtd = CKEDITOR.dtd, - // Define orders of table elements. - tableOrder = [ 'caption', 'colgroup', 'col', 'thead', 'tfoot', 'tbody' ], - // List of all block elements. - blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$blockLimit, dtd.$block ); - - // - // DATA filter rules ------------------------------------------------------ - // - - var defaultDataFilterRulesEditableOnly = { - elements: { - input: protectReadOnly, - textarea: protectReadOnly - } - }; - - // These rules will also be applied to non-editable content. - var defaultDataFilterRulesForAll = { - attributeNames: [ - // Event attributes (onXYZ) must not be directly set. They can become - // active in the editing area (IE|WebKit). - [ ( /^on/ ), 'data-cke-pa-on' ], - - // Don't let some old expando enter editor. Concerns only IE8, - // but for consistency remove on all browsers. - [ ( /^data-cke-expando$/ ), '' ] - ] - }; - - // Disable form elements editing mode provided by some browsers. (#5746) - function protectReadOnly( element ) { - var attrs = element.attributes; - - // We should flag that the element was locked by our code so - // it'll be editable by the editor functions (#6046). - if ( attrs.contenteditable != 'false' ) - attrs[ 'data-cke-editable' ] = attrs.contenteditable ? 'true' : 1; - - attrs.contenteditable = 'false'; - } - - // - // HTML filter rules ------------------------------------------------------ - // - - var defaultHtmlFilterRulesEditableOnly = { - elements: { - embed: function( element ) { - var parent = element.parent; - - // If the is child of a , copy the width - // and height attributes from it. - if ( parent && parent.name == 'object' ) { - var parentWidth = parent.attributes.width, - parentHeight = parent.attributes.height; - if ( parentWidth ) - element.attributes.width = parentWidth; - if ( parentHeight ) - element.attributes.height = parentHeight; - } - }, - - // Remove empty link but not empty anchor. (#3829) - a: function( element ) { - if ( !( element.children.length || element.attributes.name || element.attributes[ 'data-cke-saved-name' ] ) ) - return false; - } - } - }; - - // These rules will also be applied to non-editable content. - var defaultHtmlFilterRulesForAll = { - elementNames: [ - // Remove the "cke:" namespace prefix. - [ ( /^cke:/ ), '' ], - - // Ignore tags. - [ ( /^\?xml:namespace$/ ), '' ] - ], - - attributeNames: [ - // Attributes saved for changes and protected attributes. - [ ( /^data-cke-(saved|pa)-/ ), '' ], - - // All "data-cke-" attributes are to be ignored. - [ ( /^data-cke-.*/ ), '' ], - - [ 'hidefocus', '' ] - ], - - elements: { - $: function( element ) { - var attribs = element.attributes; - - if ( attribs ) { - // Elements marked as temporary are to be ignored. - if ( attribs[ 'data-cke-temp' ] ) - return false; - - // Remove duplicated attributes - #3789. - var attributeNames = [ 'name', 'href', 'src' ], - savedAttributeName; - for ( var i = 0; i < attributeNames.length; i++ ) { - savedAttributeName = 'data-cke-saved-' + attributeNames[ i ]; - savedAttributeName in attribs && ( delete attribs[ attributeNames[ i ] ] ); - } - } - - return element; - }, - - // The contents of table should be in correct order (#4809). - table: function( element ) { - // Clone the array as it would become empty during the sort call. - var children = element.children.slice( 0 ); - children.sort( function( node1, node2 ) { - var index1, index2; - - // Compare in the predefined order. - if ( node1.type == CKEDITOR.NODE_ELEMENT && - node2.type == node1.type ) { - index1 = CKEDITOR.tools.indexOf( tableOrder, node1.name ); - index2 = CKEDITOR.tools.indexOf( tableOrder, node2.name ); - } - - // Make sure the sort is stable, if no order can be established above. - if ( !( index1 > -1 && index2 > -1 && index1 != index2 ) ) { - index1 = getNodeIndex( node1 ); - index2 = getNodeIndex( node2 ); - } - - return index1 > index2 ? 1 : -1; - } ); - }, - - // Restore param elements into self-closing. - param: function( param ) { - param.children = []; - param.isEmpty = true; - return param; - }, - - // Remove dummy span in webkit. - span: function( element ) { - if ( element.attributes[ 'class' ] == 'Apple-style-span' ) - delete element.name; - }, - - html: function( element ) { - delete element.attributes.contenteditable; - delete element.attributes[ 'class' ]; - }, - - body: function( element ) { - delete element.attributes.spellcheck; - delete element.attributes.contenteditable; - }, - - style: function( element ) { - var child = element.children[ 0 ]; - if ( child && child.value ) - child.value = CKEDITOR.tools.trim( child.value ); - - if ( !element.attributes.type ) - element.attributes.type = 'text/css'; - }, - - title: function( element ) { - var titleText = element.children[ 0 ]; - - // Append text-node to title tag if not present (i.e. non-IEs) (#9882). - !titleText && append( element, titleText = new CKEDITOR.htmlParser.text() ); - - // Transfer data-saved title to title tag. - titleText.value = element.attributes[ 'data-cke-title' ] || ''; - }, - - input: unprotectReadyOnly, - textarea: unprotectReadyOnly - }, - - attributes: { - 'class': function( value, element ) { - // Remove all class names starting with "cke_". - return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false; - } - } - }; - - if ( CKEDITOR.env.ie ) { - // IE outputs style attribute in capital letters. We should convert - // them back to lower case, while not hurting the values (#5930) - defaultHtmlFilterRulesForAll.attributes.style = function( value, element ) { - return value.replace( /(^|;)([^\:]+)/g, function( match ) { - return match.toLowerCase(); - } ); - }; - } - - // Disable form elements editing mode provided by some browsers. (#5746) - function unprotectReadyOnly( element ) { - var attrs = element.attributes; - switch ( attrs[ 'data-cke-editable' ] ) { - case 'true': - attrs.contenteditable = 'true'; - break; - case '1': - delete attrs.contenteditable; - break; - } - } - - // - // Preprocessor filters --------------------------------------------------- - // - - var protectElementRegex = /<(a|area|img|input|source)\b([^>]*)>/gi, - // Be greedy while looking for protected attributes. This will let us avoid an unfortunate - // situation when "nested attributes", which may appear valid, are also protected. - // I.e. if we consider the following HTML: - // - // - // - // then the "non-greedy match" returns: - // - // 'href' => '"X"' // It's wrong! Href is not an attribute of . - // - // while greedy match returns: - // - // 'data-x' => '<a href="X"' - // - // which, can be easily filtered out (#11508). - protectAttributeRegex = /([\w-]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi, - protectAttributeNameRegex = /^(href|src|name)$/i; - - // Note: we use lazy star '*?' to prevent eating everything up to the last occurrence of or . - var protectElementsRegex = /(?:])[^>]*>[\s\S]*?<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi, - protectTextareaRegex = /(])[^>]*>)([\s\S]*?)(?:<\/textarea>)/gi, - encodedElementsRegex = /([^<]*)<\/cke:encoded>/gi; - - var protectElementNamesRegex = /(<\/?)((?:object|embed|param|html|body|head|title)[^>]*>)/gi, - unprotectElementNamesRegex = /(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi; - - var protectSelfClosingRegex = /]*?)\/?>(?!\s*<\/cke:\1)/gi; - - function protectAttributes( html ) { - return html.replace( protectElementRegex, function( element, tag, attributes ) { - return '<' + tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName ) { - // Avoid corrupting the inline event attributes (#7243). - // We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (#5218) - if ( protectAttributeNameRegex.test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 ) - return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr; - - return fullAttr; - } ) + '>'; - } ); - } - - function protectElements( html, regex ) { - return html.replace( regex, function( match, tag, content ) { - // Encode < and > in textarea because this won't be done by a browser, since - // textarea will be protected during passing data through fix bin. - if ( match.indexOf( '/g, '>' ) + ''; - - return '' + encodeURIComponent( match ) + ''; - } ); - } - - function unprotectElements( html ) { - return html.replace( encodedElementsRegex, function( match, encoded ) { - return decodeURIComponent( encoded ); - } ); - } - - function protectElementsNames( html ) { - return html.replace( protectElementNamesRegex, '$1cke:$2' ); - } - - function unprotectElementNames( html ) { - return html.replace( unprotectElementNamesRegex, '$1$2' ); - } - - function protectSelfClosingElements( html ) { - return html.replace( protectSelfClosingRegex, '' ); - } - - function protectPreFormatted( html ) { - return CKEDITOR.env.opera ? html : html.replace( /(]*>)(\r\n|\n)/g, '$1$2$2' ); - } - - function protectRealComments( html ) { - return html.replace( //g, function( match ) { - return ''; - } ); - } - - function unprotectRealComments( html ) { - return html.replace( //g, function( match, data ) { - return decodeURIComponent( data ); - } ); - } - - function unprotectSource( html, editor ) { - var store = editor._.dataStore; - - return html.replace( //g, function( match, data ) { - return decodeURIComponent( data ); - } ).replace( /\{cke_protected_(\d+)\}/g, function( match, id ) { - return store && store[ id ] || ''; - } ); - } - - function protectSource( data, editor ) { - var protectedHtml = [], - protectRegexes = editor.config.protectedSource, - store = editor._.dataStore || ( editor._.dataStore = { id: 1 } ), - tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g; - - var regexes = [ - // Script tags will also be forced to be protected, otherwise - // IE will execute them. - ( //gi ), - - //