ckeditor.module 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <?php
  2. /**
  3. * CKEditor - The text editor for the Internet - http://ckeditor.com
  4. * Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
  5. *
  6. * == BEGIN LICENSE ==
  7. *
  8. * Licensed under the terms of any of the following licenses of your
  9. * choice:
  10. *
  11. * - GNU General Public License Version 2 or later (the "GPL")
  12. * http://www.gnu.org/licenses/gpl.html
  13. *
  14. * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
  15. * http://www.gnu.org/licenses/lgpl.html
  16. *
  17. * - Mozilla Public License Version 1.1 or later (the "MPL")
  18. * http://www.mozilla.org/MPL/MPL-1.1.html
  19. *
  20. * == END LICENSE ==
  21. *
  22. * @file
  23. * CKEditor Module for Drupal 7.x
  24. *
  25. * This module allows Drupal to replace textarea fields with CKEditor.
  26. *
  27. * CKEditor is an online rich text editor that can be embedded inside web pages.
  28. * It is a WYSIWYG (What You See Is What You Get) editor which means that the
  29. * text edited in it looks as similar as possible to the results end users will
  30. * see after the document gets published. It brings to the Web popular editing
  31. * features found in desktop word processors such as Microsoft Word and
  32. * OpenOffice.org Writer. CKEditor is truly lightweight and does not require any
  33. * kind of installation on the client computer.
  34. */
  35. /**
  36. * The name of the simplified toolbar that should be forced.
  37. * Make sure that this toolbar is defined in ckeditor.config.js or fckconfig.js.
  38. */
  39. define('CKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic');
  40. define('CKEDITOR_ENTERMODE_P', 1);
  41. define('CKEDITOR_ENTERMODE_BR', 2);
  42. define('CKEDITOR_ENTERMODE_DIV', 3);
  43. define('CKEDITOR_LATEST', '4.5.4');
  44. global $_ckeditor_configuration;
  45. global $_ckeditor_ids;
  46. module_load_include('inc', 'ckeditor', 'includes/ckeditor.user');
  47. $_ckeditor_configuration = array();
  48. $_ckeditor_ids = array();
  49. /**
  50. * Implements hook_hook_info().
  51. */
  52. function ckeditor_hook_info() {
  53. $hooks = array(
  54. 'ckeditor_plugin',
  55. 'ckeditor_plugin_alter',
  56. 'ckeditor_security_filter',
  57. 'ckeditor_security_filter_alter',
  58. 'ckeditor_settings_alter',
  59. );
  60. return array_fill_keys($hooks, array('group' => 'ckeditor'));
  61. }
  62. /**
  63. * Implementation of hook_menu().
  64. */
  65. function ckeditor_menu() {
  66. $items = array();
  67. $items['ckeditor/xss'] = array(
  68. 'title' => 'XSS Filter',
  69. 'description' => 'XSS Filter.',
  70. 'page callback' => 'ckeditor_filter_xss',
  71. 'file' => 'includes/ckeditor.page.inc',
  72. 'access callback' => TRUE,
  73. 'type' => MENU_CALLBACK,
  74. );
  75. $items['ckeditor/disable/wysiwyg/%'] = array(
  76. 'title' => 'Disable the WYSIWYG module',
  77. 'description' => 'Disable WYSIWYG module.',
  78. 'page callback' => 'ckeditor_disable_wysiwyg',
  79. 'page arguments' => array(3),
  80. 'file' => 'includes/ckeditor.admin.inc',
  81. 'access arguments' => array('administer ckeditor'),
  82. 'access callback' => TRUE,
  83. 'type' => MENU_CALLBACK,
  84. );
  85. $items['admin/config/content/ckeditor'] = array(
  86. 'title' => 'CKEditor',
  87. 'description' => 'Configure the rich text editor.',
  88. 'page callback' => 'ckeditor_admin_main',
  89. 'file' => 'includes/ckeditor.admin.inc',
  90. 'access arguments' => array('administer ckeditor'),
  91. 'type' => MENU_NORMAL_ITEM,
  92. );
  93. $items['admin/config/content/ckeditor/skinframe'] = array(
  94. 'title' => 'Change skin of CKEditor',
  95. 'description' => 'Configure skin for CKEditor.',
  96. 'page callback' => 'ckeditor_skinframe',
  97. 'file' => 'includes/ckeditor.admin.inc',
  98. 'access arguments' => array('administer ckeditor'),
  99. 'type' => MENU_CALLBACK,
  100. );
  101. $items['admin/config/content/ckeditor/add'] = array(
  102. 'title' => 'Add a new CKEditor profile',
  103. 'description' => 'Configure the rich text editor.',
  104. 'page callback' => 'drupal_get_form',
  105. 'page arguments' => array('ckeditor_admin_profile_form', 'add'),
  106. 'file' => 'includes/ckeditor.admin.inc',
  107. 'access arguments' => array('administer ckeditor'),
  108. 'type' => MENU_CALLBACK,
  109. );
  110. $items['admin/config/content/ckeditor/clone/%ckeditor_profile'] = array(
  111. 'title' => 'Clone the CKEditor profile',
  112. 'description' => 'Configure the rich text editor.',
  113. 'page callback' => 'drupal_get_form',
  114. 'page arguments' => array('ckeditor_admin_profile_clone_form', 'clone', 5),
  115. 'file' => 'includes/ckeditor.admin.inc',
  116. 'access arguments' => array('administer ckeditor'),
  117. 'type' => MENU_CALLBACK,
  118. );
  119. $items['admin/config/content/ckeditor/edit/%ckeditor_profile'] = array(
  120. 'title' => 'Edit the CKEditor profile',
  121. 'description' => 'Configure the rich text editor.',
  122. 'page callback' => 'drupal_get_form',
  123. 'page arguments' => array('ckeditor_admin_profile_form', 'edit', 5),
  124. 'file' => 'includes/ckeditor.admin.inc',
  125. 'access arguments' => array('administer ckeditor'),
  126. 'type' => MENU_CALLBACK,
  127. );
  128. $items['admin/config/content/ckeditor/delete/%ckeditor_profile'] = array(
  129. 'title' => 'Delete the CKEditor profile',
  130. 'description' => 'Configure the rich text editor.',
  131. 'page callback' => 'drupal_get_form',
  132. 'page arguments' => array('ckeditor_admin_profile_delete_form', 5),
  133. 'file' => 'includes/ckeditor.admin.inc',
  134. 'access arguments' => array('administer ckeditor'),
  135. 'type' => MENU_CALLBACK,
  136. );
  137. $items['admin/config/content/ckeditor/addg'] = array(
  138. 'title' => 'Add the CKEditor Global profile',
  139. 'description' => 'Configure the rich text editor.',
  140. 'page callback' => 'drupal_get_form',
  141. 'page arguments' => array('ckeditor_admin_global_profile_form', 'add'),
  142. 'file' => 'includes/ckeditor.admin.inc',
  143. 'access arguments' => array('administer ckeditor'),
  144. 'type' => MENU_CALLBACK,
  145. );
  146. $items['admin/config/content/ckeditor/editg'] = array(
  147. 'title' => 'Edit the CKEditor Global profile',
  148. 'description' => 'Configure the rich text editor.',
  149. 'page callback' => 'drupal_get_form',
  150. 'page arguments' => array('ckeditor_admin_global_profile_form', 'edit'),
  151. 'file' => 'includes/ckeditor.admin.inc',
  152. 'access arguments' => array('administer ckeditor'),
  153. 'type' => MENU_CALLBACK,
  154. );
  155. return $items;
  156. }
  157. /**
  158. * Implementation of hook_permission().
  159. *
  160. * People -> Permissions
  161. */
  162. function ckeditor_permission() {
  163. $arr = array();
  164. $arr['administer ckeditor'] = array(
  165. 'title' => t('Administer CKEditor access'),
  166. 'description' => t('Allow users to change CKEditor settings.')
  167. );
  168. $arr['customize ckeditor'] = array(
  169. 'title' => t('Customize CKEditor appearance'),
  170. 'description' => t('Allow users to customize CKEditor appearance.')
  171. );
  172. if (file_exists(ckfinder_path('local'))) {
  173. $arr['allow CKFinder file uploads'] = array(
  174. 'title' => t('CKFinder access'),
  175. 'description' => t('Allow users to use CKFinder.')
  176. );
  177. }
  178. return $arr;
  179. }
  180. /**
  181. * Implementation of hook_help().
  182. *
  183. * This function delegates the execution to ckeditor_help_delegate() in includes/ckeditor.page.inc to
  184. * lower the amount of code in ckeditor.module.
  185. */
  186. function ckeditor_help($path, $arg) {
  187. module_load_include('inc', 'ckeditor', 'includes/ckeditor.page');
  188. return module_invoke('ckeditor', 'help_delegate', $path, $arg);
  189. }
  190. /**
  191. * Check CKEditor version
  192. */
  193. function ckeditor_get_version($main_version = FALSE) {
  194. static $ckeditor_version = FALSE;
  195. if ($ckeditor_version !== FALSE) {
  196. if (!$main_version) {
  197. return $ckeditor_version;
  198. }
  199. $version = explode('.', $ckeditor_version);
  200. return trim($version[0]);
  201. }
  202. $editor_path = ckeditor_path('local', TRUE);
  203. if ($editor_path == '<URL>') {
  204. $url = ckeditor_path('url', TRUE);
  205. $matches = array();
  206. if (preg_match("|cdn.ckeditor.com/(\d(\.\d+)+.*)/|i", $url, $matches)) {
  207. $ckeditor_version = $matches[1];
  208. return $matches[1];
  209. }
  210. return $ckeditor_version = NULL;
  211. }
  212. $jspath = $editor_path . '/ckeditor.js';
  213. $configcontents = @file_get_contents($jspath);
  214. if (!$configcontents) {
  215. return $ckeditor_version = NULL;
  216. }
  217. $matches = array();
  218. if (preg_match('#,version:[\'\"]{1}(.*?)[\'\"]{1},#', $configcontents, $matches)) {
  219. $ckeditor_version = $matches[1];
  220. if ($ckeditor_version == '%VERSION%') {
  221. $ckeditor_version = '4.0.0';
  222. }
  223. if (!$main_version) {
  224. return $ckeditor_version;
  225. }
  226. $version = explode('.', $ckeditor_version);
  227. return trim($version[0]);
  228. }
  229. return $ckeditor_version = NULL;
  230. }
  231. /**
  232. * Implements hook_page_build().
  233. */
  234. function ckeditor_page_build(&$page) {
  235. // Add our CSS file that adds common needed classes, such as align-left,
  236. // align-right, underline, indent, etc.
  237. $page['page_bottom']['ckeditor']['#attached']['css'] = array(
  238. drupal_get_path('module', 'ckeditor') . '/css/ckeditor.css' => array(
  239. 'every_page' => TRUE,
  240. ),
  241. );
  242. }
  243. /**
  244. * Implements hook_form_FORM_ID_alter() for user_profile_form().
  245. */
  246. function ckeditor_form_user_profile_form_alter(&$form, &$form_state) {
  247. if ($form['#user_category'] == 'account') {
  248. ckeditor_user_customize($form, $form_state, 'user_profile_form');
  249. }
  250. }
  251. /**
  252. * Implementation of hook_element_info_alter().
  253. *
  254. * Replace the textarea with CKEditor using a callback function (ckeditor_pre_render_text_format).
  255. */
  256. function ckeditor_element_info_alter(&$types) {
  257. $types['text_format']['#pre_render'][] = 'ckeditor_pre_render_text_format';
  258. }
  259. /**
  260. * This function creates the HTML objects required for CKEditor.
  261. *
  262. * @param $element
  263. * A fully populated form element to add the editor to.
  264. * @return
  265. * The same $element with extra CKEditor markup and initialization.
  266. */
  267. function ckeditor_pre_render_text_format($element) {
  268. static $init = FALSE;
  269. if (!isset($element['#format'])) {
  270. return $element;
  271. }
  272. module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
  273. if ($init === FALSE) {
  274. $input_formats = ckeditor_profiles_compile();
  275. drupal_add_js(array('ckeditor' => array('input_formats' => $input_formats, 'plugins' => array())), 'setting');
  276. $init = TRUE;
  277. }
  278. if (isset($element['value'])) {
  279. if (!isset($element['format'])) {
  280. return $element;
  281. }
  282. if (isset($element['summary'])) {
  283. $element['value'] = ckeditor_load_by_field($element['value'], $element['format']['format'], TRUE, $element['summary']['#id']);
  284. $element['summary'] = ckeditor_load_by_field($element['summary'], $element['format']['format'], FALSE);
  285. }
  286. else {
  287. $element['value'] = ckeditor_load_by_field($element['value'], $element['format']['format']);
  288. }
  289. }
  290. else {
  291. $element = ckeditor_load_by_field($element, $element['#format']);
  292. }
  293. return $element;
  294. }
  295. /**
  296. * Load all profiles. Just load one profile if $name is passed in.
  297. */
  298. function ckeditor_profile_load($name = '', $clear = FALSE, $check_access = TRUE) {
  299. static $profiles = array();
  300. global $user;
  301. if (empty($profiles) || $clear === TRUE) {
  302. $result = db_select('ckeditor_settings', 's')->fields('s')->execute();
  303. foreach ($result as $data) {
  304. $data->settings = unserialize($data->settings);
  305. $data->input_formats = array();
  306. $profiles[$data->name] = $data;
  307. }
  308. if ($check_access === FALSE) {
  309. // don't check if user has access to filter formats, needed for exporting as feature with drush
  310. $input_formats = filter_formats();
  311. } else {
  312. $input_formats = filter_formats($user);
  313. }
  314. $result = db_select('ckeditor_input_format', 'f')->fields('f')->execute();
  315. foreach ($result as $data) {
  316. if (isset($input_formats[$data->format])) {
  317. $profiles[$data->name]->input_formats[$data->format] = $input_formats[$data->format]->name;
  318. }
  319. }
  320. }
  321. return ($name ? (isset($profiles[urldecode($name)]) ? $profiles[urldecode($name)] : FALSE) : $profiles);
  322. }
  323. /**
  324. * Generate base path of the Drupal installation.
  325. *
  326. * @return
  327. * Path of the Drupal installation.
  328. */
  329. function ckeditor_base_path($mode = 'relative') {
  330. if ($mode == 'local') {
  331. return $cke_base_local_path = '.';
  332. }
  333. return rtrim(base_path(), '/');
  334. }
  335. /**
  336. * Generate module path of the CKEditor module.
  337. *
  338. * @return
  339. * Path of CKEditor module.
  340. */
  341. function ckeditor_module_path($mode = 'relative') {
  342. switch ($mode) {
  343. default:
  344. case 'relative':
  345. return ckeditor_base_path('relative') . '/' . drupal_get_path('module', 'ckeditor');
  346. case 'local':
  347. return ckeditor_base_path('local') . '/' . drupal_get_path('module', 'ckeditor');
  348. case 'url':
  349. return drupal_get_path('module', 'ckeditor');
  350. }
  351. }
  352. /**
  353. * Generate library path of the Drupal installation.
  354. *
  355. * @return
  356. * Path of library in the Drupal installation.
  357. */
  358. function ckeditor_library_path($mode = 'relative') {
  359. $lib_path = 'sites/all/libraries';
  360. if (function_exists('libraries_get_path')) {
  361. $path = libraries_get_path('ckeditor');
  362. if ($path !== FALSE) {
  363. $lib_path = drupal_substr($path, 0, strlen($path) - 9);
  364. }
  365. }
  366. switch ($mode) {
  367. default:
  368. case 'relative':
  369. return ckeditor_base_path('relative') . '/' . $lib_path;
  370. case 'local':
  371. return ckeditor_base_path('local') . '/' . $lib_path;
  372. case 'url':
  373. return $lib_path;
  374. }
  375. }
  376. /**
  377. * Read the CKEditor path from the Global profile.
  378. *
  379. * @return
  380. * Path to CKEditor folder.
  381. */
  382. function ckeditor_path($mode = 'relative', $refresh = FALSE) {
  383. static $cke_static;
  384. if (!isset($cke_static)) {
  385. $cke_static = array();
  386. }
  387. if ($refresh || !isset($cke_static[$mode])) {
  388. $global_profile = ckeditor_profile_load('CKEditor Global Profile', $refresh);
  389. switch ($mode) {
  390. default:
  391. case 'relative':
  392. if ($global_profile && isset($global_profile->settings['ckeditor_path'])) {
  393. // http:// OR https:// OR //
  394. if (preg_match("|^(http(s)?:)?//|i", $global_profile->settings['ckeditor_path'])) {
  395. return '<URL>';
  396. }
  397. $cke_path = $global_profile->settings['ckeditor_path'];
  398. $cke_path = strtr($cke_path, array("%b" => ckeditor_base_path('relative'), "%m" => ckeditor_module_path('relative'), "%l" => ckeditor_library_path('relative')));
  399. $cke_path = str_replace('\\', '/', $cke_path);
  400. $cke_path = str_replace('//', '/', $cke_path);
  401. return $cke_static[$mode] = $cke_path;
  402. }
  403. return $cke_static[$mode] = ckeditor_module_path('relative') . '/ckeditor';
  404. case 'local':
  405. if ($global_profile) {
  406. if (!empty($global_profile->settings['ckeditor_local_path'])) {
  407. return $cke_static[$mode] = $global_profile->settings['ckeditor_local_path'];
  408. }
  409. if (isset($global_profile->settings['ckeditor_path'])) {
  410. // http:// OR https:// OR //
  411. if (preg_match("|^(http(s)?:)?//|i", $global_profile->settings['ckeditor_path'])) {
  412. return '<URL>';
  413. }
  414. $cke_local_path = $global_profile->settings['ckeditor_path'];
  415. $cke_local_path = strtr($cke_local_path, array("%b" => ckeditor_base_path('local'), "%m" => ckeditor_module_path('local'), "%l" => ckeditor_library_path('local')));
  416. return $cke_static[$mode] = $cke_local_path;
  417. }
  418. }
  419. return $cke_static[$mode] = ckeditor_module_path('local') . '/ckeditor';
  420. case 'url':
  421. if ($global_profile && isset($global_profile->settings['ckeditor_path'])) {
  422. // http:// OR https:// OR //
  423. if (preg_match("|^(http(s)?:)?//|i", $global_profile->settings['ckeditor_path'])) {
  424. $cke_path = $global_profile->settings['ckeditor_path'];
  425. }
  426. else {
  427. $cke_path = $global_profile->settings['ckeditor_path'];
  428. $cke_path = strtr($cke_path, array("%m" => ckeditor_module_path('url'), "%l" => ckeditor_library_path('url')));
  429. $cke_path = str_replace('\\', '/', $cke_path);
  430. $cke_path = str_replace('//', '/', $cke_path);
  431. //In D7 base path in URL mode is not needed, so we need to remove it with trailing slash (if exists)
  432. $cke_path = str_replace(array("%b/", "%b"), '', $cke_path);
  433. }
  434. return $cke_static[$mode] = $cke_path;
  435. }
  436. return $cke_static[$mode] = ckeditor_module_path('url') . '/ckeditor';
  437. }
  438. }
  439. return $cke_static[$mode];
  440. }
  441. /**
  442. * Read the CKEditor plugins path from the Global profile.
  443. *
  444. * @return
  445. * Path to CKEditor plugins folder.
  446. */
  447. function ckeditor_plugins_path($mode = 'relative', $refresh = FALSE) {
  448. static $cke_static;
  449. if (!isset($cke_static)) {
  450. $cke_static = array();
  451. }
  452. if ($refresh || !isset($cke_static[$mode])) {
  453. $global_profile = ckeditor_profile_load('CKEditor Global Profile', $refresh);
  454. switch ($mode) {
  455. default:
  456. case 'relative':
  457. if ($global_profile && isset($global_profile->settings['ckeditor_plugins_path'])) {
  458. $cke_plugins_path = $global_profile->settings['ckeditor_plugins_path'];
  459. $cke_plugins_path = strtr($cke_plugins_path, array("%b" => ckeditor_base_path('relative'), "%m" => ckeditor_module_path('relative'), "%l" => ckeditor_library_path('relative')));
  460. $cke_plugins_path = str_replace('\\', '/', $cke_plugins_path);
  461. $cke_plugins_path = str_replace('//', '/', $cke_plugins_path);
  462. $cke_plugins_path = rtrim($cke_plugins_path, ' \/');
  463. return $cke_static[$mode] = $cke_plugins_path;
  464. }
  465. return $cke_static[$mode] = ckeditor_module_path('relative') . '/plugins';
  466. case 'local':
  467. if ($global_profile) {
  468. if (!empty($global_profile->settings['ckeditor_plugins_local_path'])) {
  469. return $cke_static[$mode] = $global_profile->settings['ckeditor_plugins_local_path'];
  470. }
  471. if (isset($global_profile->settings['ckeditor_plugins_path'])) {
  472. $cke_plugins_local_path = $global_profile->settings['ckeditor_plugins_path'];
  473. $cke_plugins_local_path = strtr($cke_plugins_local_path, array("%b" => ckeditor_base_path('local'), "%m" => ckeditor_module_path('local'), "%l" => ckeditor_library_path('local')));
  474. return $cke_static[$mode] = $cke_plugins_local_path;
  475. }
  476. }
  477. return $cke_static[$mode] = ckeditor_module_path('local') . '/plugins';
  478. case 'url':
  479. if ($global_profile && isset($global_profile->settings['ckeditor_plugins_path'])) {
  480. $cke_plugins_path = $global_profile->settings['ckeditor_plugins_path'];
  481. $cke_plugins_path = strtr($cke_plugins_path, array("%m" => ckeditor_module_path('url'), "%l" => ckeditor_library_path('url')));
  482. $cke_plugins_path = str_replace('\\', '/', $cke_plugins_path);
  483. $cke_plugins_path = str_replace('//', '/', $cke_plugins_path);
  484. $cke_plugins_path = rtrim($cke_plugins_path, ' \/');
  485. //In D7 base path in URL mode is not needed, so we need to remove it with trailing slash (if exists)
  486. $cke_plugins_path = str_replace(array("%b/", "%b"), '', $cke_plugins_path);
  487. return $cke_static[$mode] = $cke_plugins_path;
  488. }
  489. return $cke_static[$mode] = ckeditor_module_path('url') . '/plugins';
  490. }
  491. }
  492. return $cke_static[$mode];
  493. }
  494. /**
  495. * Read the CKFinder path from the Global profile.
  496. *
  497. * @return
  498. * Path to CKFinder folder.
  499. */
  500. function ckfinder_path($mode = 'relative', $refresh = FALSE) {
  501. static $cke_static;
  502. if (!isset($cke_static)) {
  503. $cke_static = array();
  504. }
  505. if ($refresh || !isset($cke_static[$mode])) {
  506. $global_profile = ckeditor_profile_load('CKEditor Global Profile', $refresh);
  507. switch ($mode) {
  508. default:
  509. case 'relative':
  510. if ($global_profile && isset($global_profile->settings['ckfinder_path'])) {
  511. $ckfinder_path = $global_profile->settings['ckfinder_path'];
  512. $ckfinder_path = strtr($ckfinder_path, array("%b" => ckeditor_base_path('relative'), "%m" => ckeditor_module_path('relative'), "%l" => ckeditor_library_path('relative')));
  513. $ckfinder_path = str_replace('\\', '/', $ckfinder_path);
  514. $ckfinder_path = str_replace('//', '/', $ckfinder_path);
  515. return $cke_static[$mode] = $ckfinder_path;
  516. }
  517. return $cke_static[$mode] = ckeditor_module_path('relative') . '/ckfinder';
  518. case 'local':
  519. if ($global_profile) {
  520. if (!empty($global_profile->settings['ckfinder_local_path'])) {
  521. return $cke_static[$mode] = $global_profile->settings['ckfinder_local_path'];
  522. }
  523. if (isset($global_profile->settings['ckfinder_path'])) {
  524. $ckfinder_path = $global_profile->settings['ckfinder_path'];
  525. $ckfinder_path = strtr($ckfinder_path, array("%b" => ckeditor_base_path('local'), "%m" => ckeditor_module_path('local'), "%l" => ckeditor_library_path('local')));
  526. return $cke_static[$mode] = $ckfinder_path;
  527. }
  528. }
  529. return $cke_static[$mode] = ckeditor_module_path('local') . '/ckfinder';
  530. case 'url':
  531. if ($global_profile && isset($global_profile->settings['ckfinder_path'])) {
  532. $ckfinder_path = $global_profile->settings['ckfinder_path'];
  533. $ckfinder_path = strtr($ckfinder_path, array("%m" => ckeditor_module_path('url'), "%l" => ckeditor_library_path('url')));
  534. $ckfinder_path = str_replace('\\', '/', $cke_plugins_path);
  535. $ckfinder_path = str_replace('//', '/', $cke_plugins_path);
  536. //In D7 base path in URL mode is not needed, so we need to remove it with trailing slash (if exists)
  537. $ckfinder_path = str_replace(array("%b/", "%b"), '', $ckfinder_path);
  538. return $cke_static[$mode] = $ckfinder_path;
  539. }
  540. return $cke_static[$mode] = ckeditor_module_path('url') . '/ckfinder';
  541. }
  542. }
  543. return $cke_static[$mode];
  544. }
  545. /**
  546. * Implementation of hook_features_api().
  547. *
  548. * Allow exporting of CKEditor profiles by the Features module.
  549. */
  550. function ckeditor_features_api() {
  551. return array(
  552. 'ckeditor_profile' => array(
  553. 'name' => t('CKEditor profiles'),
  554. 'feature_source' => TRUE,
  555. 'default_hook' => 'ckeditor_profile_defaults',
  556. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  557. 'file' => drupal_get_path('module', 'ckeditor') . '/includes/ckeditor.features.inc',
  558. )
  559. );
  560. }
  561. /**
  562. * Implementation of hook_file_download().
  563. * Support for private downloads.
  564. * CKEditor does not implement any kind of potection on private files.
  565. */
  566. function ckeditor_file_download($uri) {
  567. $result = db_query("SELECT f.* FROM {file_managed} f WHERE uri = :uri", array(':uri' => $uri));
  568. foreach ($result as $record) {
  569. return NULL;
  570. }
  571. if ($path = file_create_url($uri)) {
  572. //No info in DB? Probably a file uploaded with FCKeditor / CKFinder
  573. $global_profile = ckeditor_profile_load("CKEditor Global Profile");
  574. //Assume that files inside of ckeditor directory belong to the CKEditor. If private directory is set, let the decision about protection to the user.
  575. $private_dir_db = $private_dir = isset($global_profile->settings['private_dir']) ? trim($global_profile->settings['private_dir'], '\/') : '';
  576. $private_dir_db = str_replace(array('\\%u', '\\%n'), array('', ''), $private_dir_db);
  577. $private_dir = preg_quote($private_dir, '#');
  578. $private_dir = strtr($private_dir, array('%u' => '(\d+)', '%n' => '([\x80-\xF7 \w@.-]+)')); // regex for %n taken from user_validate_name() in user.module
  579. $private_dir = trim($private_dir, '\/');
  580. $regex = '#^' . preg_quote('private://', '#') . $private_dir . '#';
  581. if (!strstr($uri, 'private://') && !strstr($uri, 'public://')) {
  582. $path = 'private://' . $uri;
  583. }
  584. else {
  585. $path = $uri;
  586. }
  587. //check if CKEditor's "Enable access to files located in the private folder" option is disabled or enabled
  588. $allow_download_private_files = FALSE;
  589. if (isset($global_profile->settings['ckeditor_allow_download_private_files']) && $global_profile->settings['ckeditor_allow_download_private_files'] === 't') {
  590. $allow_download_private_files = TRUE;
  591. }
  592. //denied access to file if private upload is set and CKEditor's "Enable access to files located in the private folder" option is disabled
  593. if ($allow_download_private_files == FALSE)
  594. return NULL;
  595. //check if file can be served by comparing regex and path to file
  596. if (preg_match($regex, $path)) {
  597. $info = image_get_info($uri);
  598. return array('Content-Type' => $info['mime_type']);
  599. }
  600. }
  601. }
  602. /**
  603. * Implementation of hook_modules_uninstalled().
  604. *
  605. * Remove enabled plugins in CKEditor profiles added by uninstalled modules.
  606. */
  607. function ckeditor_modules_uninstalled($modules) {
  608. module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
  609. $profiles_list = ckeditor_profile_input_formats();
  610. $plugins_list = ckeditor_load_plugins();
  611. foreach ($profiles_list as $_profile => $_inputs) {
  612. $changed = FALSE;
  613. $profile = ckeditor_profile_load($_profile);
  614. if (!isset($profile->settings['loadPlugins'])) continue;
  615. foreach (array_keys((array) $profile->settings['loadPlugins']) as $plugin_name) {
  616. if (!array_key_exists($plugin_name, $plugins_list)) {
  617. unset($profile->settings['loadPlugins'][$plugin_name]);
  618. $changed = TRUE;
  619. }
  620. }
  621. if ($changed) {
  622. db_update('ckeditor_settings')
  623. ->fields(array(
  624. 'settings' => serialize($profile->settings)
  625. ))
  626. ->condition('name', $profile->name, '=')
  627. ->execute();
  628. }
  629. }
  630. }
  631. /**
  632. * Implements hook_field_extra_fields().
  633. */
  634. function ckeditor_field_extra_fields() {
  635. $fields['user']['user']['form']['ckeditor'] = array(
  636. 'label' => t('Rich text editor settings'),
  637. 'description' => t('Rich text editor settings'),
  638. 'weight' => 10,
  639. );
  640. return $fields;
  641. }