ckeditor.module 27 KB

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