Projet

Général

Profil

Paste
Télécharger (83 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ckeditor / includes / ckeditor.admin.inc @ 651307cd

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * CKEditor - The text editor for the Internet - http://ckeditor.com
5
 * Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
6
 *
7
 * == BEGIN LICENSE ==
8
 *
9
 * Licensed under the terms of any of the following licenses of your
10
 * choice:
11
 *
12
 *  - GNU General Public License Version 2 or later (the "GPL")
13
 *    http://www.gnu.org/licenses/gpl.html
14
 *
15
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
16
 *    http://www.gnu.org/licenses/lgpl.html
17
 *
18
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
19
 *    http://www.mozilla.org/MPL/MPL-1.1.html
20
 *
21
 * == END LICENSE ==
22
 *
23
 * @file
24
 * CKEditor Module for Drupal 7.x
25
 *
26
 * This module allows Drupal to replace textarea fields with CKEditor.
27
 *
28
 * CKEditor is an online rich text editor that can be embedded inside web pages.
29
 * It is a WYSIWYG (What You See Is What You Get) editor which means that the
30
 * text edited in it looks as similar as possible to the results end users will
31
 * see after the document gets published. It brings to the Web popular editing
32
 * features found in desktop word processors such as Microsoft Word and
33
 * OpenOffice.org Writer. CKEditor is truly lightweight and does not require any
34
 * kind of installation on the client computer.
35
 */
36
37
/**
38
 * Main administrative page
39
 */
40
function ckeditor_admin_main() {
41
  global $base_url;
42
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
43
  $editor_path = ckeditor_path('local');
44
  $ckconfig_file = $editor_path . '/config.js';
45
46
  //check if CKEditor plugin is installed
47 6fd71452 Julien Enselme
  if ($editor_path != '<URL>' && !_ckeditor_requirements_isinstalled()) {
48 85ad3d82 Assos Assos
    drupal_set_message(t(
49
            'Checking for !filename or !file.', array(
50
          '!filename' => '<code>' . $ckconfig_file . '</code>',
51
          '!file' => '<code>sites/all/libraries/ckeditor/ckeditor.js</code>'
52
            )
53
        ));
54
    drupal_set_message(t(
55
            'The CKEditor component is not installed correctly. Please go to the !ckeditorlink in order to download the latest version. After that you must extract the files to the !ckeditorpath or !librarypath directory and make sure that the !ckeditorfile or !ckeditorlibrary file exists. Refer to the !readme file for more information.', array(
56
          '!ckeditorlink' => l(t('CKEditor homepage'), 'http://ckeditor.com/download'),
57
          '!readme' => l(t('README.txt'), $base_url . '/' . drupal_get_path('module', 'ckeditor') . '/README.txt', array('absolute' => TRUE)),
58
          '!ckeditorpath' => '<code>sites/all/modules/ckeditor/ckeditor</code>',
59
          '!ckeditorfile' => '<code>sites/all/modules/ckeditor/ckeditor/ckeditor.js</code>',
60
          '!ckeditorlibrary' => '<code>sites/all/libraries/ckeditor/ckeditor.js</code>',
61
          '!librarypath' => '<code>sites/all/libraries/ckeditor</code>'
62
            )
63
        ), 'error');
64
    drupal_set_message(t(
65
            'If you have CKEditor already installed, edit the <strong>!editg</strong> and update the CKEditor path.', array(
66
          '!editg' => l(t('CKEditor Global Profile'), 'admin/config/content/ckeditor/editg')
67
            )
68
        ), 'warning');
69
70
    return '';
71
  }
72
73
  if (module_exists('wysiwyg')) {
74
    drupal_set_message(t(
75
            'The WYSIWYG module was detected. Using both modules at the same time may cause problems. It is recommended to turn the WYSIWYG module off (!wysiwygdisablelink).', array(
76
          '!wysiwygdisablelink' => l(t('click here to disable'), 'ckeditor/disable/wysiwyg/' . drupal_get_token('ckeditorDisableWysiwyg'))
77
            )
78
        ), 'warning');
79
  }
80
81
  //find profile other than Global
82
  $result = db_select('ckeditor_settings', 's')->fields('s', array('name'))->condition('name', 'CKEditor Global Profile', '<>')->range(0, 1)->execute()->fetchAssoc();
83
  if (!$result) {
84
    drupal_set_message(t('No CKEditor profiles found. Right now nobody is able to use CKEditor. Create a new profile below.'), 'error');
85
  }
86
87
  return ckeditor_profile_overview();
88
}
89
90
/**
91
 * Controller for CKEditor profiles.
92
 */
93
function ckeditor_profile_overview() {
94
  $output = '';
95
  $skins = ckeditor_load_skin_options();
96
  $global_profile = ckeditor_profile_load('CKEditor Global Profile');
97
  if (isset($global_profile->settings['skin']) && !array_key_exists($global_profile->settings['skin'], $skins)) {
98
    drupal_set_message(t('The <em>CKEditor Global Profile</em> profile is using %skin skin which cannot be found. Please <a href="@profile_settings">update your settings</a>.', array('%skin' => $global_profile->settings['skin'], '@profile_settings' => url('admin/config/content/ckeditor/editg'))), 'warning');
99
  }
100
  $profiles = ckeditor_profile_load();
101
  if ($profiles) {
102 4b706e38 Assos Assos
    // @todo The following variable is never used. Remove it?
103 85ad3d82 Assos Assos
    $access_ckeditor_roles = user_roles(FALSE, 'access ckeditor');
104
    $header = array(t('Profile'), t('Input format'), t('Operations'));
105
    $disabled_plugins = array();
106
    foreach ($profiles as $p) {
107
      if ($p->name !== "CKEditor Global Profile") {
108
        $rows[] = array(
109
          array('data' => $p->name, 'valign' => 'top'),
110
          array('data' => implode("<br />\n", $p->input_formats)),
111
          array(
112
            'data' =>
113
            l(t('edit'), 'admin/config/content/ckeditor/edit/' . urlencode($p->name)) . ' ' .
114
            l(t('clone'), 'admin/config/content/ckeditor/clone/' . urlencode($p->name)) . ' ' .
115
            l(t('delete'), 'admin/config/content/ckeditor/delete/' . urlencode($p->name)),
116
            'valign' => 'top'
117
          )
118
        );
119
      }
120
    }
121
122
    if (count($disabled_plugins) > 0) {
123
      $msg = t("The following plugins could not be found and were automatically disabled in CKEditor profiles:");
124
      foreach ($disabled_plugins as $profile_name => $profile_plugins) {
125
        $msg .= "<br/><br/>";
126
        $msg .= t("<b>Profile</b>: %profile_name", array("%profile_name" => $profile_name));
127
        $msg .= "<br/>";
128
        $msg .= t("<b>Plugins</b>: %profile_plugins", array("%profile_plugins" => implode(', ', $profile_plugins)));
129
      }
130
      drupal_set_message($msg, 'warning');
131
    }
132
133
    $output .= '<h3>' . t('Profiles') . '</h3>';
134
    $output .= theme('table', array("header" => $header, "rows" => $rows));
135
    $output .= '<p>' . l(t('Create a new profile'), 'admin/config/content/ckeditor/add') . '</p>';
136
  }
137
  else {
138
    drupal_set_message(t(
139
            'No profiles found. Click here to !create.', array(
140
          '!create' => l(t('create a new profile'), 'admin/config/content/ckeditor/add')
141
            )
142
        ), 'warning');
143
  }
144
145
  $rows = array();
146
  if (!isset($profiles['CKEditor Global Profile'])) {
147
    drupal_set_message(t(
148
            'The global profile can not be found. Click here to !create.', array(
149
          '!create' => l(t('create the global profile'), 'admin/config/content/ckeditor/addg')
150
            )
151
        ), 'warning');
152
  }
153
  else {
154
    $output .= "<h3>" . t("Global settings") . "</h3>";
155
    $rows[] = array(
156
      array('data' => t('CKEditor Global Profile')),
157
      array('data' => l(t('edit'), 'admin/config/content/ckeditor/editg'), 'valign' => 'top')
158
    );
159
    $output .= theme('table', array("header" => array(t('Profile'), t('Operations')), "rows" => $rows));
160
  }
161
  return $output;
162
}
163
164
/**
165
 * Form builder for a global profile
166
 */
167
function ckeditor_admin_global_profile_form($form, $form_state, $mode = 'add') {
168
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
169
  if ($mode == 'edit') {
170
    $profile = ckeditor_profile_load('CKEditor Global Profile');
171
172
    $form['_profile'] = array(
173
      '#type' => 'value',
174
      '#value' => $profile,
175
    );
176
  }
177
  else {
178
    $profile = new stdClass();
179
  }
180
181
  if ($mode == 'add') {
182
    $data = ckeditor_profile_load('CKEditor Global Profile');
183
    if (!empty($data)) {
184
      drupal_set_message(t('The global profile already exists. Only one global profile is allowed.'), 'error');
185
      drupal_not_found();
186
    }
187
188
    $btn = t('Create a global profile');
189
  }
190
  else {
191
    $btn = t('Update the global profile');
192
  }
193
194
  $orig_formats = filter_formats();
195
  $formats = array();
196
  foreach ($orig_formats AS $format) {
197
    $formats[$format->format] = $format->name;
198
  }
199
200
  $drupal_base_path = ckeditor_base_path('relative');
201
  $drupal_library_path = ckeditor_library_path('relative');
202
  $module_drupal_path = ckeditor_module_path('relative');
203
  $skin_options = ckeditor_load_skin_options();
204
205
  $form['appearance'] = array(
206
    '#type' => 'fieldset',
207
    '#title' => t('Editor appearance'),
208
    '#collapsible' => TRUE,
209
    '#collapsed' => FALSE,
210
  );
211
212
  //if skin is not set or not exists select default skin (moono or skin) or first on the skin list
213
  if (empty($profile->settings['skin']) || (!empty($profile->settings['skin']) && !array_key_exists($profile->settings['skin'], $skin_options))) {
214
    $profile->settings['skin'] = ckeditor_default_skin();
215
  }
216
217
  $form['appearance']['skin'] = array(
218
    '#type' => 'select',
219
    '#title' => t('Skin'),
220
    '#default_value' => $profile->settings['skin'],
221
    '#options' => $skin_options,
222
    '#description' => t('Choose a CKEditor skin.'),
223
  );
224
225
  $form['ckeditor_advanced_settings'] = array(
226
    '#type' => 'fieldset',
227
    '#title' => t('Advanced settings'),
228
    '#collapsible' => TRUE,
229
    '#collapsed' => FALSE,
230
  );
231
232 6fd71452 Julien Enselme
  $current_path = ckeditor_path('relative');
233
  if ($current_path == '<URL>') {
234
    $current_path = ckeditor_path('url');
235
  }
236 85ad3d82 Assos Assos
  $form['ckeditor_advanced_settings']['ckeditor_path'] = array(
237
    '#type' => 'textfield',
238
    '#title' => t('Path to CKEditor'),
239
    '#default_value' => !empty($profile->settings['ckeditor_path']) ? $profile->settings['ckeditor_path'] : '%m/ckeditor',
240
    '#size' => 40,
241
    '#maxlength' => 128,
242
    '#description' => t(
243 6fd71452 Julien Enselme
        'The path to CKEditor (the WYSIWYG rich text editor downloaded from !ckeditorcom). Provide a path relative to the document root, unless CKEditor is located on an external URL. In such case enter the full URL to a folder with CKEditor.<br />The simplest way to have the editor running is to use CDN, to use it set: !cdn', array(
244
      '!ckeditorcom' => l(t('ckeditor.com'), 'http://ckeditor.com/download'),
245 4b706e38 Assos Assos
      '!cdn' => '<strong>//cdn.ckeditor.com/' . CKEDITOR_LATEST . '/full-all</strong>'
246 85ad3d82 Assos Assos
        )
247
    ) .
248 6fd71452 Julien Enselme
    '<br /><br /> ' .
249
    t('Available placeholders:!b &ndash; path of the Drupal installation (!base) !m &ndash; path where the CKEditor module is stored (!module).!l &ndash; path to the libraries directory (!library).', array(
250 85ad3d82 Assos Assos
      '!b' => '<br /><code>%b</code>',
251
      '!m' => '<br /><code>%m</code>',
252
      '!l' => '<br /><code>%l</code>',
253
      '!base' => '<code>' . $drupal_base_path . '</code>',
254
      '!module' => '<code>' . $module_drupal_path . '</code>',
255
      '!library' => '<code>' . $drupal_library_path . '</code>',
256
        )
257
    ) .
258
    '<br /> ' .
259
    t('Current path: !path', array(
260 6fd71452 Julien Enselme
      '!path' => '<code>' . $current_path . '</code>'
261 85ad3d82 Assos Assos
        )
262
    ),
263
    '#required' => TRUE
264
  );
265
266 6fd71452 Julien Enselme
  $local_path = ckeditor_path('local');
267
  if ($local_path == '<URL>') {
268
    $local_path = t('CKEditor is loaded from URL. Local path is not available.');
269
  }
270 85ad3d82 Assos Assos
  $form['ckeditor_advanced_settings']['ckeditor_local_path'] = array(
271
    '#type' => 'textfield',
272
    '#title' => t('Local path to CKEditor'),
273
    '#default_value' => isset($profile->settings['ckeditor_local_path']) ? $profile->settings['ckeditor_local_path'] : '',
274
    '#size' => 40,
275
    '#maxlength' => 128,
276
    '#description' => t(
277
        'The path to the local directory (on the server) that points to the path defined above. Enter either an absolute server path or a path relative to the !indexphp file. If left empty, the CKEditor module will try to find the right path.', array(
278
      '!indexphp' => '<code>index.php</code>'
279
        )
280
    ) .
281
    '<br /> ' .
282
    t('Current path: !path', array(
283 6fd71452 Julien Enselme
      '!path' => '<code>' . $local_path . '</code>'
284 85ad3d82 Assos Assos
        )
285
    )
286
  );
287
288
  $form['ckeditor_advanced_settings']['ckeditor_plugins_path'] = array(
289
    '#type' => 'textfield',
290
    '#title' => t('Path to the CKEditor plugins directory'),
291
    '#default_value' => !empty($profile->settings['ckeditor_plugins_path']) ? $profile->settings['ckeditor_plugins_path'] : '%m/plugins',
292
    '#size' => 40,
293
    '#maxlength' => 128,
294
    '#description' => t('Path to the CKEditor plugins directory relative to the document root.') .
295
    '<br />' .
296
    t('Available placeholders:!b &ndash; path of the Drupal installation (!base) !m &ndash; the base URL path where the CKEditor module is stored (!module).!l &ndash; the base URL path to the libraries directory (!library)', array(
297
      '!b' => '<br /><code>%b</code>',
298
      '!m' => '<br /><code>%m</code>',
299
      '!l' => '<br /><code>%l</code>',
300
      '!base' => '<code>' . $drupal_base_path . '</code>',
301
      '!module' => '<code>' . $module_drupal_path . '</code>',
302
      '!library' => '<code>' . $drupal_library_path . '</code>',
303
        )
304
    ) .
305
    '<br /> ' .
306
    t('Current path: !path', array(
307
      '!path' => '<code>' . ckeditor_plugins_path('relative') . '</code>'
308
        )
309
    )
310
  );
311
312
  $form['ckeditor_advanced_settings']['ckeditor_plugins_local_path'] = array(
313
    '#type' => 'textfield',
314
    '#title' => t('Local path to the CKEditor plugins directory'),
315
    '#default_value' => isset($profile->settings['ckeditor_plugins_local_path']) ? $profile->settings['ckeditor_plugins_local_path'] : '',
316
    '#size' => 40,
317
    '#maxlength' => 128,
318
    '#description' => t(
319
        'The path to the local directory (on the server) that points to the path defined above. Enter either an absolute server path or a path relative to the !indexphp file. If left empty, the CKEditor module will try to find the right path.', array(
320
      '!indexphp' => '<code>index.php</code>'
321
        )
322
    ) .
323
    '<br /> ' .
324
    t('Current path: !path', array(
325
      '!path' => '<code>' . ckeditor_plugins_path('local') . '</code>'
326
        )
327
    )
328
  );
329
330
  $form['ckeditor_advanced_settings']['ckfinder_path'] = array(
331
    '#type' => 'textfield',
332
    '#title' => t('Path to CKFinder'),
333
    '#default_value' => !empty($profile->settings['ckfinder_path']) ? $profile->settings['ckfinder_path'] : '%m/ckfinder',
334
    '#size' => 40,
335
    '#maxlength' => 128,
336
    '#description' => t(
337
        'The path to CKFinder (AJAX based file manager downloaded from !ckfindercom) relative to the document root.', array(
338
      '!ckfindercom' => l(t('ckfinder.com'), 'http://cksource.com/ckfinder')
339
        )
340
    ) .
341
    '<br />' .
342
    t('Available placeholders:!b &ndash; path of the Drupal installation (!base) !m &ndash; path where the CKEditor module is stored (!module).!l &ndash; path to the libraries directory (!library)', array(
343
      '!b' => '<br /><code>%b</code>',
344
      '!m' => '<br /><code>%m</code>',
345
      '!l' => '<br /><code>%l</code>',
346
      '!base' => '<code>' . $drupal_base_path . '</code>',
347
      '!module' => '<code>' . $module_drupal_path . '</code>',
348
      '!library' => '<code>' . $drupal_library_path . '</code>'
349
        )
350
    ) .
351
    '<br /> ' .
352
    t('Current path: !path', array(
353
      '!path' => '<code>' . ckfinder_path('relative') . '</code>'
354
        )
355
    )
356
  );
357
358
  $form['ckeditor_advanced_settings']['ckfinder_local_path'] = array(
359
    '#type' => 'textfield',
360
    '#title' => t('Local path to CKFinder'),
361
    '#default_value' => isset($profile->settings['ckfinder_local_path']) ? $profile->settings['ckfinder_local_path'] : '',
362
    '#size' => 40,
363
    '#maxlength' => 128,
364
    '#description' => t(
365
        'The path to the local directory (on the server) that points to the path defined above. Enter either an absolute server path or a path relative to the !indexphp file. If left empty, the CKEditor module will try to find the right path.', array(
366
      '!indexphp' => '<code>index.php</code>'
367
        )
368
    ) .
369
    '<br /> ' .
370
    t('Current path: !path', array(
371
      '!path' => '<code>' . ckfinder_path('local') . '</code>'
372
        )
373
    )
374
  );
375
376
  //@todo DOWNLOAD API
377
  if (variable_get('file_default_scheme', '') == 'private') {
378
    $form['ckeditor_advanced_settings']['ckeditor_allow_download_private_files'] = array(
379
      '#type' => 'checkbox',
380
      '#title' => t('Enable access to files located in the private folder'),
381
      '#default_value' => !empty($profile->settings['ckeditor_allow_download_private_files']),
382
      '#return_value' => 't',
383
      '#description' => t(
384
          '<strong>Use this option with care.</strong> If checked, CKEditor will allow anyone knowing the URL to view a file located inside of the private path (!private_path), but only if there is no information about the file in the Drupal database. If the path below is specified, anyone will have access only to that location.', array(
385
        '!private_path' => '<code>' . variable_get('file_private_path', '') . '</code>'
386
          )
387
      ),
388
      '#required' => FALSE
389
    );
390
    $current_private_dir = !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '';
391
    $form['ckeditor_advanced_settings']['private_dir'] = array(
392
      '#type' => 'textfield',
393
      '#title' => t('Location of files uploaded with CKEditor to the private folder'),
394
      '#default_value' => !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '',
395
      '#size' => 40,
396
      '#maxlength' => 255,
397
      '#description' => t('The path relative to the location of the private directory where CKEditor should store uploaded files.') .
398
      '<br />' .
399
      t('Available wildcard characters:!u &ndash; User ID.!n &ndash; Username', array(
400
        '!u' => '<br/><code>%u</code>',
401
        '!n' => '<br /><code>%n</code>'
402
          )
403
      ) .
404
      '<br />' .
405
      t('System path to the private folder is: !system_path.', array(
406
        '!system_path' => '<code>' . realpath(variable_get('file_private_path', conf_path() . '/files')) . DIRECTORY_SEPARATOR . '</code>'
407
          )
408
      )
409
    );
410
  }
411
412
  if (function_exists('linktocontent_node_menu') && function_exists('pathfilter_filter')) {
413
    $form['ckeditor_advanced_settings']['linktoc'] = array(
414
      '#type' => 'select',
415
      '#options' => array('p' => t('Link to paths only'), 'n' => t('Link using internal: links'), 'pn' => t('Allow the user to select between paths and internal links')),
416
      '#title' => t('Path Filter & Link To Content integration'),
417
      '#default_value' => empty($profile->settings['linktoc']) ? 'p' : $profile->settings['linktoc'],
418
      '#description' => t(
419
          'With the !plink extension it is possible to use internal: links. By default the !link extension is linking to nodes using paths.', array(
420
        '!plink' => l(t('Path Filter'), 'http://drupal.org/project/pathfilter'),
421
        '!link' => l(t('Link To Content'), 'http://drupal.org/project/linktocontent')
422
          )
423
      )
424
    );
425
  }
426
427
  $form['ckeditor_advanced_settings']['ckeditor_aggregate'] = array(
428
    '#type' => 'radios',
429
    '#title' => t('Aggregate <code>ckeditor.js</code>'),
430
    '#default_value' => !empty($profile->settings['ckeditor_aggregate']) ? $profile->settings['ckeditor_aggregate'] : 'f',
431
    '#options' => array(
432
      't' => t('Enabled'),
433
      'f' => t('Disabled')
434
    ),
435
    '#description' => t('When enabled, <code>ckeditor.js</code> will be aggregated if JavaScript aggregation is enabled. <strong>Not recommended</strong>.'),
436
  );
437
438
  $form['ckeditor_advanced_settings']['toolbar_wizard'] = array(
439
    '#type' => 'radios',
440
    '#title' => t('Use toolbar Drag&Drop feature'),
441
    '#default_value' => !empty($profile->settings['toolbar_wizard']) ? $profile->settings['toolbar_wizard'] : 't',
442
    '#options' => array(
443
      't' => t('Enabled'),
444
      'f' => t('Disabled')
445
    ),
446
    '#description' => t('When enabled, the toolbar can be built by using the drag-and-drop feature. Otherwise you will need to enter the toolbar configuration manually to the text box.'),
447
  );
448
449
  $form['submit'] = array(
450
    '#type' => 'submit',
451
    '#value' => $btn
452
  );
453
454
  return $form;
455
}
456
457
/**
458
 * Form validation for a global profile
459
 */
460
function ckeditor_admin_global_profile_form_validate($form, &$form_state) {
461
462
}
463
464
/**
465
 * Submit form for a global profile
466
 */
467
function ckeditor_admin_global_profile_form_submit($form, &$form_state) {
468
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
469
  $edit = & $form_state['values'];
470
  $edit['name'] = 'CKEditor Global Profile';
471
472
  if (isset($edit['_profile'])) {
473
    ckeditor_profile_delete($edit['_profile']->name);
474
  }
475
476
  //strip whitespaces
477
  if (empty($edit['ckeditor_local_path'])) {
478
    $edit['ckeditor_local_path'] = '';
479
  }
480
  else {
481
    $edit['ckeditor_local_path'] = trim($edit['ckeditor_local_path']);
482
  }
483
484
  //strip slash from the end
485
  if (empty($edit['ckeditor_path'])) {
486
    $edit['ckeditor_path'] = '';
487
  }
488
  $edit['ckeditor_path'] = trim(rtrim($edit['ckeditor_path'], "/"));
489 6fd71452 Julien Enselme
  if ($edit['ckeditor_path'] && 0 !== strpos($edit['ckeditor_path'], "/") && 0 !== strpos($edit['ckeditor_path'], "%") && !preg_match("|^http(s)?://|i", $edit['ckeditor_path'])) {
490 85ad3d82 Assos Assos
    //ensure that slash is at the beginning
491
    $edit['ckeditor_path'] = "/" . $edit['ckeditor_path'];
492
  }
493
  //no slash at the end
494
  $edit['ckeditor_local_path'] = trim(rtrim($edit['ckeditor_local_path'], "/"));
495
496
  //strip whitespaces
497
  if (empty($edit['ckeditor_plugins_local_path'])) {
498
    $edit['ckeditor_plugins_local_path'] = '';
499
  }
500
  else {
501
    $edit['ckeditor_plugins_local_path'] = trim($edit['ckeditor_plugins_local_path']);
502
  }
503
504
  //strip slash from the end
505
  if (empty($edit['ckeditor_plugins_path'])) {
506
    $edit['ckeditor_plugins_path'] = '';
507
  }
508
  $edit['ckeditor_plugins_path'] = trim(rtrim($edit['ckeditor_plugins_path'], "/"));
509
  if ($edit['ckeditor_plugins_path'] && 0 !== strpos($edit['ckeditor_plugins_path'], "/") && 0 !== strpos($edit['ckeditor_plugins_path'], "%")) {
510
    //ensure that slash is at the beginning
511
    $edit['ckeditor_plugins_path'] = "/" . $edit['ckeditor_plugins_path'];
512
  }
513
  //no slash at the end
514
  $edit['ckeditor_plugins_path'] = trim(rtrim($edit['ckeditor_plugins_path'], "/"));
515
516
  //strip slash from the end
517
  if (empty($edit['ckfinder_path'])) {
518
    $edit['ckfinder_path'] = '';
519
  }
520
  $edit['ckfinder_path'] = trim(rtrim($edit['ckfinder_path'], "/"));
521
  if ($edit['ckfinder_path'] && 0 !== strpos($edit['ckfinder_path'], "/") && 0 !== strpos($edit['ckfinder_path'], "%")) {
522
    //ensure that slash is at the beginning
523
    $edit['ckfinder_path'] = "/" . $edit['ckfinder_path'];
524
  }
525
526
  //no slash at the end
527
  $edit['ckfinder_local_path'] = trim(rtrim($edit['ckfinder_local_path'], "/"));
528
529
  $settings = ckeditor_admin_values_to_settings($edit);
530
  db_insert('ckeditor_settings')
531
      ->fields(array(
532
        "name" => $edit["name"],
533
        "settings" => $settings
534
      ))
535
      ->execute();
536
537
  drupal_set_message(t('The CKEditor global profile was saved.'));
538
  $form_state['redirect'] = 'admin/config/content/ckeditor';
539
}
540
541
/**
542
 * Form builder for a profile
543
 */
544 6fd71452 Julien Enselme
function ckeditor_admin_profile_form($form, $form_state, $task, $profile = NULL) {
545 85ad3d82 Assos Assos
  global $theme;
546
547
  if ($profile != NULL) {
548
    $form['_profile'] = array(
549
      '#type' => 'value',
550
      '#value' => $profile,
551
    );
552
  }
553
  else {
554
    $profile = new stdClass();
555
  }
556
557
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
558
559
  $editor_path = ckeditor_path('relative');
560
  $editor_local_path = ckeditor_path('local');
561
  $editor_url_path = ckeditor_path('url');
562
  $module_drupal_path = ckeditor_module_path('relative');
563
  $module_drupal_url_path = ckeditor_module_path('url');
564
565
  drupal_add_js(array('ckeditor_version' => ckeditor_get_version()), 'setting');
566
567
  $lang_options = ckeditor_load_lang_options();
568
569 6fd71452 Julien Enselme
  // Attach the administration CSS.
570
  $form['#attached'] = array(
571
    'css' => array(
572
      drupal_get_path('module', 'ckeditor') . '/css/ckeditor.admin.css',
573
    ),
574
  );
575
576 85ad3d82 Assos Assos
  $form['basic'] = array(
577
    '#type' => 'fieldset',
578
    '#title' => t('Basic setup'),
579
    '#collapsible' => TRUE,
580
    '#collapsed' => TRUE
581
  );
582
583 6fd71452 Julien Enselme
  switch ($task) {
584 85ad3d82 Assos Assos
    case 'clone':
585
      //load all profiles to check their names
586
      $profiles = ckeditor_profile_load();
587
      $oldname = $profile->name;
588
      $maxsize = 128;   //default max name length
589
590
      $res = array();
591
      $pat = "/^(.*?)_([0-9]+)$/";
592
      if (preg_match($pat, $oldname, $res)) {     // oldname like 'name_nr'
593
        $name = $res[1];
594
        $num = $res[2] + 1;
595
      }
596
      else {
597
        $name = $oldname;
598
        $num = 2;
599
      }
600
601
      $newname = substr($name, 0, $maxsize - 3) . '_' . $num;   // +limit
602
      while (isset($profiles[$newname])) {            //find next free number
603
        $num++;
604
        $newname = substr($name, 0, $maxsize - 3) . '_' . $num;
605
      }
606
      break;
607
    case 'edit':
608
      $newname = $profile->name;
609
      break;
610
  }
611
612
  $global_profile = ckeditor_profile_load('CKEditor Global Profile');
613
  $toolbar_wizard = !empty($global_profile->settings['toolbar_wizard']) ? $global_profile->settings['toolbar_wizard'] : 't';
614
  drupal_add_js(array('ckeditor_toolbar_wizard' => $toolbar_wizard), 'setting');
615
616
  $form['basic']['name'] = array(
617
    '#type' => 'textfield',
618
    '#title' => t('Profile name'),
619
    '#default_value' => !empty($profile->name) ? $newname : '',
620
    '#size' => 40,
621
    '#maxlength' => 128,
622
    '#description' => t('Enter a name for this profile. This name is only visible within the CKEditor administration page.'),
623
    '#required' => TRUE
624
  );
625
626
  $orig_formats = filter_formats();
627
628 6fd71452 Julien Enselme
  if ($task == 'edit' && !empty($profile->name)) {
629 85ad3d82 Assos Assos
    $used_formats = db_select('ckeditor_input_format', 'f')->fields('f', array("format"))->distinct()->condition("f.name", array($profile->name), 'NOT IN')->execute()->fetchAllAssoc('format');
630
  }
631
  else {
632
    $profile->input_formats = array();
633
    $used_formats = db_select('ckeditor_input_format', 'f')->fields('f', array("format"))->distinct()->execute()->fetchAllAssoc('format');
634
  }
635
636
  $formats = array();
637
  $input_format_config_links = array();
638
  foreach ($orig_formats AS $format) {
639 6fd71452 Julien Enselme
    if (($task == 'edit' && !empty($profile->input_formats) && array_key_exists($format->format, $profile->input_formats)) || !array_key_exists($format->format, $used_formats)) {
640 85ad3d82 Assos Assos
      $formats[$format->format] = $format->name;
641
      $input_format_config_links[$format->format] = array("name" => $format->name, "config_url" => url("admin/config/content/formats/" . $format->format));
642
    }
643
  }
644
645
  $form['basic']['input_formats'] = array(
646
    '#id' => 'input-formats',
647
    '#type' => 'checkboxes',
648
    '#title' => t('Text formats'),
649
    '#default_value' => !empty($profile->input_formats) ? array_keys((array) $profile->input_formats) : array(),
650
    '#options' => $formats,
651
    '#description' => t('Choose the text formats where you want to load CKEditor.')
652
  );
653
654
  $form['security'] = array(
655
    '#type' => 'fieldset',
656
    '#title' => t('Security'),
657
    '#description' => '<p>' . t('The CKEditor security system protects you from executing malicious code that is already in your database. In plain textareas database content is harmless because it is not executed, but the CKEditor WYSIWYG editor interprets HTML like a web browser and thus the content needs to be filtered before it is loaded.') . '</p>',
658
    '#collapsible' => TRUE,
659
    '#collapsed' => TRUE
660
  );
661
662
  $form['security']['filters'] = array(
663
    '#id' => 'security-filters',
664
    '#type' => 'container'
665
  );
666
667
  $form['security']['filters']['__header'] = array(
668
    '#type' => 'item',
669
    '#title' => t('Security filters'),
670
    '#description' => t(
671
      'Below is a list of security filters along with their status for each text format.<br /><br />The following statuses are available: !img_enabled - the filter is configured for a given text format and will be run on the content during the filtering process. !img_disabled - the filter is disabled for a given text format and will not be run on the content during the filtering process.<br /><br />In order to modify the security filters settings for each of the text formats, you need to visit the text format configuration sections as listed below: !elem_format_config', array(
672
      '!img_enabled' => '</br><img src="' . $module_drupal_path . '/images/tick.png"/>',
673
      '!img_disabled' => '</br><img src="' . $module_drupal_path . '/images/delete.png"/>',
674
      '!elem_format_config' => '<ul class="text-formats-config"></ul>'
675
        )
676
    ),
677
    '#weight' => -10
678
  );
679
680
  //get text formats filters
681
  $input_format_filters = array();
682
  foreach ($formats AS $key => $value) {
683
    $input_format_filters[$key] = array();
684
    $filters = filter_list_format($key);
685
    foreach ($filters as $filter_name => $filter_settings) {
686
      if ($filter_settings->status == 1) {
687
        $input_format_filters[$key][$filter_name] = TRUE;
688
      }
689
    }
690
  }
691
  drupal_add_js(array('text_format_filters' => $input_format_filters, 'text_formats_config_links' => $input_format_config_links), 'setting');
692
693
  $security_filters = ckeditor_security_filters();
694
  _ckeditor_admin_profile_form_security_filters($form, $profile, $security_filters);
695
696
  $form['security']['ss'] = array(
697
    '#type' => 'radios',
698
    '#title' => t('Security settings'),
699
    '#default_value' => isset($profile->settings['ss']) ? $profile->settings['ss'] : '2',
700
    '#options' => array(
701
      '2' => t('Always run security filters for CKEditor.'),
702
      '1' => t('Run security filters only when CKEditor is set to start automatically.'),
703
    ),
704
    '#description' => t('There are two ways of starting CKEditor: automatically and manually (via toggle). If you decide to apply security filters only when CKEditor starts automatically, you will not be protected when toggling manually from plain textarea to CKEditor. Choose this option only if you can detect various attacks (mainly XSS) by yourself just by looking at the HTML code.'),
705
  );
706
707
  $form['appearance'] = array(
708
    '#type' => 'fieldset',
709
    '#title' => t('Editor appearance'),
710
    '#collapsible' => TRUE,
711
    '#collapsed' => TRUE,
712
  );
713
714
  $ui_colors = array(
715
    "default" => t('CKEditor default'),
716
    "custom" => t('Select manually')
717
  );
718
  if (function_exists('color_get_palette')) {
719
    // apparently $theme is not initialized (?)
720
    if (empty($theme)) {
721
      init_theme();
722
    }
723
    $palette = @color_get_palette($theme, FALSE); //[#652274]
724
    $color_palette['default'] = '#D3D3D3';
725
    if (!empty($palette)) {
726
      if (!empty($palette['base'])) {
727
        $color_palette['color_base'] = $palette['base'];
728
        $ui_colors["color_base"] = t('Color module: base');
729
      }
730
      if (!empty($palette['top'])) {
731
        $color_palette['color_top'] = $palette['top'];
732
        $ui_colors["color_top"] = t('Color module: top');
733
      }
734
      if (!empty($palette['bottom'])) {
735
        $color_palette['color_bottom'] = $palette['bottom'];
736
        $ui_colors["color_bottom"] = t('Color module: bottom');
737
      }
738
    }
739
    drupal_add_js(array('ckeditor_uicolor' => $color_palette), 'setting');
740
  }
741
742 6fd71452 Julien Enselme
  if ($editor_path == '<URL>') {
743
    drupal_add_js($editor_url_path . '/ckeditor.js', 'external');
744
  }
745
  else {
746
    drupal_add_js('window.CKEDITOR_BASEPATH = "' . $editor_path . '/"', array('type' => 'inline', 'weight' => -100));
747
    drupal_add_js($editor_url_path . '/ckeditor.js', array('type' => 'file', 'preprocess' => FALSE));
748
  }
749 85ad3d82 Assos Assos
  drupal_add_js($module_drupal_url_path . '/ckeditor.config.js', 'file');
750
  drupal_add_js($module_drupal_url_path . '/includes/ckeditor.admin.js', 'file');
751
752
  if ($toolbar_wizard == 't') {
753 6fd71452 Julien Enselme
    drupal_add_library('system', 'ui.widget');
754
    drupal_add_library('system', 'ui.sortable');
755 85ad3d82 Assos Assos
    drupal_add_js($module_drupal_url_path . '/includes/jqueryUI/sort.js', 'file');
756
  }
757
758 6fd71452 Julien Enselme
  $form['appearance']['toolbar'] = array(
759
    '#type' => 'textarea',
760
    '#title' => t('Toolbar'),
761
    '#default_value' => !empty($profile->settings['toolbar']) ? $profile->settings['toolbar'] : '',
762
    '#description' => t('Load sample toolbar: !toolbars', array("!toolbars" => '<a href="#" id="cke_toolbar_DrupalBasic" class="cke_load_toolbar">' . t('Basic') . '</a> | <a href="#" id="cke_toolbar_DrupalAdvanced" class="cke_load_toolbar">' . t('Advanced') . '</a> | <a href="#" id="cke_toolbar_DrupalFull" class="cke_load_toolbar">' . t('Full') . '</a>')),
763
    '#wysiwyg' => FALSE,
764
    '#rows' => 15
765
  );
766
767
  if ($toolbar_wizard == 't') {
768
    $form['appearance']['toolbar_wizzard_used'] = array(
769
      '#markup' => '<div>' . t('Current toolbar') . '</div><div class="sortableList" id="groupLayout"></div><br/>',
770
      '#description' => t('Currently used buttons'),
771
    );
772
773
    drupal_add_js(array('cke_toolbar_buttons_all' => ckeditor_toolbar_buttons_all()), 'setting');
774
775
    $form['appearance']['toolbar_wizzard_all'] = array(
776
      '#markup' => '<div>' . t('Available buttons') . '</div><div id="allButtons" class="sortableList"></div><br/>',
777
      '#description' => t('All available buttons'),
778
    );
779
  }
780
781
  $form['appearance']['expand'] = array(
782
    '#type' => 'radios',
783
    '#title' => t('Toolbar state on startup'),
784
    '#default_value' => !empty($profile->settings['expand']) ? $profile->settings['expand'] : 't',
785
    '#options' => array(
786
      't' => t('Expanded'),
787
      'f' => t('Collapsed')
788
    ),
789
    '#description' => t('The toolbar will start in an expanded or collapsed state.'),
790
  );
791
792
  $form['appearance']['default'] = array(
793
    '#type' => 'radios',
794
    '#title' => t('Default editor state'),
795
    '#default_value' => !empty($profile->settings['default']) ? $profile->settings['default'] : 't',
796
    '#options' => array(
797
      't' => t('Enabled'),
798
      'f' => t('Disabled')
799
    ),
800
    '#description' => t('Default editor state. If disabled, the rich text editor may still be enabled by using toggle.'),
801
  );
802
803
  $form['appearance']['show_toggle'] = array(
804
    '#type' => 'radios',
805
    '#title' => t('Show the disable/enable rich text editor toggle'),
806
    '#default_value' => !empty($profile->settings['show_toggle']) ? $profile->settings['show_toggle'] : 't',
807
    '#options' => array(
808
      't' => t('Show'),
809
      'f' => t('Hide')
810
    ),
811
    '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea.'),
812
  );
813
814 85ad3d82 Assos Assos
  $form['appearance']['uicolor'] = array(
815
    '#type' => 'select',
816
    '#title' => t('User interface color'),
817
    '#default_value' => !empty($profile->settings['uicolor']) ? $profile->settings['uicolor'] : 'default',
818
    '#options' => $ui_colors,
819
  );
820
821
  if (!isset($global_profile->settings['skin']) || !file_exists($editor_local_path . '/skins/' . $global_profile->settings['skin'])) {
822
    $global_profile->settings['skin'] = ckeditor_default_skin();
823
  }
824
  $skinframe_url = url('admin/config/content/ckeditor/skinframe', array(
825
    'query' => array(
826
      'token' => drupal_get_token('ckeditorSkinframeCall'),
827
      'skin' => $global_profile->settings['skin'],
828
      'uicolor' => (!empty($profile->settings['uicolor_user']) && $profile->settings['uicolor'] == 'custom') ? ltrim($profile->settings['uicolor_user'], '#') : 'D3D3D3'
829
    )
830
  ));
831
  $form['appearance']['skinframe'] = array(
832 6fd71452 Julien Enselme
    '#markup' => '<iframe frameborder="0" id="skinframe" marginheight="0" marginwidth="0" src="' . $skinframe_url . '" style="height:430px;width:700px;"></iframe><br/>',
833 85ad3d82 Assos Assos
    '#description' => '',
834
  );
835
  $form['appearance']['uicolor_user'] = array(
836
    '#type' => 'hidden',
837
    '#default_value' => !empty($profile->settings['uicolor_user']) ? $profile->settings['uicolor_user'] : 'default',
838
  );
839
840
  $plugin_list = ckeditor_load_plugins();
841
  $plugins = array();
842
  if (isset($profile->settings['loadPlugins'])) {
843
    foreach ($plugin_list AS $key => $val) {
844
      $plugins[$key] = $val['desc'];
845
    }
846
  }
847
  else {
848
    $default_plugins = array();
849
    foreach ($plugin_list AS $key => $val) {
850
      $plugins[$key] = $val['desc'];
851
      if (isset($val['default']) && $val['default'] == 't') {
852
        $default_plugins[] = $key;
853
      }
854
    }
855
  }
856
857
  $form['appearance']['loadPlugins'] = array(
858
    '#type' => 'checkboxes',
859
    '#title' => t('Plugins'),
860
    '#default_value' => isset($profile->settings['loadPlugins']) ? array_keys((array) $profile->settings['loadPlugins']) : $default_plugins,
861
    '#options' => $plugins,
862
    '#description' => t('Choose the plugins that you want to enable in CKEditor.')
863
  );
864
865 6fd71452 Julien Enselme
  if ($editor_local_path != '<URL>' && file_exists($editor_local_path . '/plugins/divarea/plugin.js')) {
866 85ad3d82 Assos Assos
    $form['appearance']['use_divarea'] = array(
867
      '#type' => 'radios',
868
      '#title' => t('"Div-based" editor'),
869
      '#default_value' => !empty($profile->settings['use_divarea']) ? $profile->settings['use_divarea'] : 'f',
870
      '#options' => array(
871
        't' => t('Enabled'),
872
        'f' => t('Disabled')
873
      ),
874
      '#description' => t("Loading editor into <code>div</code> instead of <code>iframe</code>.")
875
    );
876
  }
877
878
  $form['appearance']['width'] = array(
879
    '#type' => 'textfield',
880
    '#title' => t('Editor width'),
881
    '#default_value' => !empty($profile->settings['width']) ? $profile->settings['width'] : '100%',
882
    '#description' => t("Editor interface width in pixels or percent. Examples: 400, 100%."),
883
    '#size' => 40,
884
    '#maxlength' => 128,
885
  );
886
887
  $form['appearance']['lang'] = array(
888
    '#type' => 'select',
889
    '#title' => t('Language'),
890
    '#default_value' => !empty($profile->settings['lang']) ? $profile->settings['lang'] : 'en',
891
    '#options' => $lang_options,
892
    '#description' => t('The language for the CKEditor user interface.')
893
  );
894
895
  $form['appearance']['auto_lang'] = array(
896
    '#type' => 'radios',
897
    '#title' => t('Auto-detect language'),
898
    '#default_value' => !empty($profile->settings['auto_lang']) ? $profile->settings['auto_lang'] : 't',
899
    '#options' => array(
900
      't' => t('Enabled'),
901
      'f' => t('Disabled')
902
    ),
903
    '#description' => t('Automatically detect the user language.')
904
  );
905
906
  $form['appearance']['language_direction'] = array(
907
    '#type' => 'select',
908
    '#title' => t('Language direction'),
909
    '#default_value' => !empty($profile->settings['language_direction']) ? $profile->settings['language_direction'] : 'default',
910
    '#options' => array(
911
      'default' => t('Get from current locale (default)'),
912
      'ltr' => t('Left-To-Right'), // language like English
913
      'rtl' => t('Right-To-Left') // languages like Arabic
914
    ),
915
    '#description' => t(
916
        'Choose the language direction used in the editing area. Even when CKEditor automatically detects the user language and adjusts its user interface, the editing area is not automatically changed into the LTR or RTL mode. To be able to type LTR (like English) and RTL (like Arabic, Hebrew, Persian) content at the same time, please make sure that the <strong>!bidiltr</strong> and <strong>!bidirtl</strong> buttons are enabled in the toolbar.', array(
917
      '!bidiltr' => 'BidiLtr',
918
      '!bidirtl' => 'BidiRtl'
919
        )
920
    )
921
  );
922
923 6fd71452 Julien Enselme
  $form['acf'] = array(
924
    '#type' => 'fieldset',
925
    '#title' => t('Advanced content filter'),
926
    '#description' => t('Configure input data filtering in CKEditor. See !link for more information about ACF.', array(
927
        '!link' => l(t('this blog post'), 'http://ckeditor.com/blog/Upgrading-to-CKEditor-4.1')
928
      )),
929
    '#collapsible' => TRUE,
930
    '#collapsed' => TRUE
931
  );
932
933
  $form['acf']['allowed_content'] = array(
934
    '#type' => 'radios',
935
    '#title' => t('Advanced content filter'),
936
    '#description' => t('<strong>Example:</strong> if only Bold and Link buttons are enabled, only !strong and !a tags will be allowed. Any !b tags will automatically be converted into !strong. The !img tag will not be allowed, unless the Image button is added to the toolbar.', array(
937
    '!strong' => '<code>&lt;strong&gt;</code>',
938
    '!a' => '<code>&lt;a&gt;</code>',
939
    '!img' => '<code>&lt;img&gt;</code>',
940
    '!b' => '<code>&lt;b&gt;</code>'
941
  )).'<br /><br />'.
942
    t('<strong>Warning:</strong> CKEditor will not use the set of tags associated with text format. Only the buttons enabled in the toolbar and optional plugins will determine which tags/attributes/styles are handled by CKEditor. Enabling ACF in CKEditor does not affect server-side filtering done by Drupal in any way.'),
943
944
    '#default_value' => !empty($profile->settings['allowed_content']) ? $profile->settings['allowed_content'] : 't',
945
    '#options' => array(
946
      't' => t('Enabled'),
947
      'f' => t('Disabled'),
948
    ),
949
  );
950
  $form['acf']['allowed_content']['t']['#description'] = t('CKEditor will only allow tags/attributes/styles provided by CKEditor features. Disallowed content will be removed directly by CKEditor. When configured properly, it helps to ensure a true WYSIWYG experience.');
951
  $form['acf']['allowed_content']['f']['#description'] = t('CKEditor will not filter any tags and as a result, the user will be able to insert any content into the editor. The content will only be filtered by server-side filters associated with input formats.');
952
953
  $form['acf']['extraAllowedContent'] = array(
954
    '#type' => 'textarea',
955
    '#title' => t('Extra allowed content'),
956
    '#default_value' => !empty($profile->settings['extraAllowedContent']) ? $profile->settings['extraAllowedContent'] : "",
957
    '#cols' => 60,
958
    '#rows' => 5,
959
    '#description' => t(
960
      'Set additional allowed content rules for CKEditor. Separate rules with a semicolon. See !docs for more information.', array(
961
        '!docs' => l(t('CKEditor documentation'), 'http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent')
962
       )).'<p>'.
963
       t('<strong>Example:</strong> !rules', array(
964
         '!rules' => "<code>object[width,height];param[name,value];embed[*];</code>"
965
       )).'</p>',
966
    '#wysiwyg' => FALSE,
967
  );
968
969 85ad3d82 Assos Assos
  $form['output'] = array(
970
    '#type' => 'fieldset',
971
    '#title' => t('Cleanup and output'),
972
    '#collapsible' => TRUE,
973
    '#collapsed' => TRUE,
974
  );
975
976
  $form['output']['enter_mode'] = array(
977
    '#type' => 'select',
978
    '#title' => t('Enter mode'),
979
    '#default_value' => !empty($profile->settings['enter_mode']) ? $profile->settings['enter_mode'] : 'p',
980
    '#options' => array(
981
      'p' => '<p>',
982
      'br' => '<br>',
983
      'div' => '<div>'
984
    ),
985
    '#description' => t('Set which tag should be used by CKEditor when the <em>Enter</em> key is pressed.')
986
  );
987
988
  $form['output']['shift_enter_mode'] = array(
989
    '#type' => 'select',
990
    '#title' => t('Shift+Enter mode'),
991
    '#default_value' => !empty($profile->settings['shift_enter_mode']) ? $profile->settings['shift_enter_mode'] : 'br',
992
    '#options' => array(
993
      'p' => '<p>',
994
      'br' => '<br>',
995
      'div' => '<div>'
996
    ),
997
    '#description' => t('Set which tag should be used by CKEditor when the <em>Shift+Enter</em> key combination is pressed.')
998
  );
999
1000
  $form['output']['font_format'] = array(
1001
    '#type' => 'textfield',
1002
    '#title' => t('Font formats'),
1003
    '#default_value' => !empty($profile->settings['font_format']) ? $profile->settings['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6',
1004
    '#size' => 40,
1005
    '#maxlength' => 250,
1006
    '#description' => t(
1007
        'Semicolon-separated list of HTML font formats. Allowed values are: !allowed_values', array(
1008
      '!allowed_values' => '<code>p;div;pre;address;h1;h2;h3;h4;h5;h6</code>'
1009
        )
1010
    )
1011
  );
1012
1013
  if (!empty($profile->settings['formatting']['custom_formatting_options'])) {
1014
    foreach ($profile->settings['formatting']['custom_formatting_options'] as $k => $v) {
1015
      if ($v === 0) {
1016
        unset($profile->settings['formatting']['custom_formatting_options'][$k]);
1017
      }
1018
    }
1019
  }
1020
1021
  $form['output']['custom_formatting'] = array(
1022
    '#type' => 'radios',
1023
    '#title' => t('Use custom formatting options'),
1024
    '#default_value' => !empty($profile->settings['custom_formatting']) ? $profile->settings['custom_formatting'] : 'f',
1025
    '#options' => array(
1026
      't' => t('Yes'),
1027
      'f' => t('No'),
1028
    ),
1029
  );
1030
1031
  $form['output']['formatting'] = array(
1032
    '#type' => 'fieldset',
1033
    '#title' => t('Custom formatting options'),
1034
    '#tree' => TRUE,
1035
  );
1036
1037
  $form['output']['formatting']['custom_formatting_options'] = array(
1038
    '#type' => 'checkboxes',
1039
    '#default_value' => isset($profile->settings['formatting']['custom_formatting_options']) ? array_keys((array) $profile->settings['formatting']['custom_formatting_options']) : array('indent' => 'indent', 'breakBeforeOpen' => 'breakBeforeOpen', 'breakAfterOpen' => 'breakAfterOpen', 'breakAfterClose' => 'breakAfterClose'),
1040
    '#options' => array(
1041
      'indent' => t('Indent the element contents.'),
1042
      'breakBeforeOpen' => t('Break line before the opening tag.'),
1043
      'breakAfterOpen' => t('Break line after the opening tag.'),
1044
      'breakBeforeClose' => t('Break line before the closing tag.'),
1045
      'breakAfterClose' => t('Break line after the closing tag.'),
1046
      'pre_indent' => t('Indent the <code>&lt;pre&gt;</code> element contents.'),
1047
    ),
1048
  );
1049
1050
  $form['css'] = array(
1051
    '#type' => 'fieldset',
1052
    '#title' => t('CSS'),
1053
    '#collapsible' => TRUE,
1054
    '#collapsed' => TRUE
1055
  );
1056
1057 6fd71452 Julien Enselme
  $current_theme = variable_get('theme_default', $theme);
1058
  $theme_path = drupal_get_path('theme', $current_theme);
1059
1060 85ad3d82 Assos Assos
  $form['css']['css_mode'] = array(
1061
    '#type' => 'select',
1062
    '#title' => t('Editor CSS'),
1063
    '#default_value' => !empty($profile->settings['css_mode']) ? $profile->settings['css_mode'] : 'theme',
1064
    '#options' => array(
1065
      'theme' => t('Use theme CSS'),
1066
      'self' => t('Define CSS'),
1067
      'none' => t('CKEditor default')
1068
    ),
1069
    '#description' => t(
1070
        'Defines the CSS to be used in the editor area.!title_theme_css &ndash; load the !style_css file from the current site theme.!title_define_css &ndash; enter the CSS file path below.!title_ckeditor_default &ndash; use the default editor CSS.', array(
1071
      '!title_theme_css' => '<br /><strong>' . t('Use theme CSS') . '</strong>',
1072
      '!title_define_css' => '<br /><strong>' . t('Define CSS') . '</strong>',
1073
      '!title_ckeditor_default' => '<br /><strong>' . t('CKEditor default') . '</strong>',
1074
      '!style_css' => '<code>style.css</code>'
1075
        )
1076
    )
1077
  );
1078
1079
  $form['css']['css_path'] = array(
1080
    '#type' => 'textfield',
1081
    '#title' => t('CSS file path'),
1082
    '#default_value' => !empty($profile->settings['css_path']) ? $profile->settings['css_path'] : "",
1083
    '#size' => 40,
1084
    '#maxlength' => 255,
1085
    '#description' => t(
1086
        'Enter the path to the CSS file (Example: !example1) or a list of CSS files separated with a comma (Example: !example2). Make sure you select the !title_define_css option above.', array(
1087
      '!example1' => '<code>"css/editor.css"</code>',
1088
      '!example2' => '<code>"/themes/garland/style.css,http://example.com/style.css"</code>',
1089
      '!title_define_css' => '<strong>' . t('Define CSS') . '</strong>'
1090
        )
1091
    ) .
1092
    '<br />' .
1093
    t('Available placeholders:!h &ndash; host name (!host).!t &ndash; path to theme (!theme).', array(
1094
      '!h' => '<br /><code>%h</code>',
1095
      '!t' => '<br /><code>%t</code>',
1096
      '!host' => '<code>' . base_path() . '</code>',
1097 6fd71452 Julien Enselme
      '!theme' => '<code>' . base_path() . $theme_path . '/</code>'
1098 85ad3d82 Assos Assos
        )
1099
    )
1100
  );
1101
1102
  $form['css']['css_style'] = array(
1103
    '#type' => 'select',
1104
    '#title' => t('Predefined styles'),
1105
    '#default_value' => !empty($profile->settings['css_style']) ? $profile->settings['css_style'] : 'theme',
1106
    '#options' => array(
1107
      'theme' => t('Use theme ckeditor.styles.js'),
1108
      'self' => t('Define path to ckeditor.styles.js'),
1109
      'default' => t('CKEditor default')
1110
    ),
1111
    '#description' => t(
1112
        'Define the location of the !ckeditor_styles_js_file file. It is used by the <strong>Style</strong> drop-down list available in the default toolbar. Copy the !ckeditor_styles_js_path file into your theme directory (!theme) and adjust it to your needs.', array(
1113
      '!ckeditor_styles_js_file' => '<code>ckeditor.styles.js</code>',
1114
      '!ckeditor_styles_js_path' => '<code>' . drupal_get_path('module', 'ckeditor') . '/ckeditor.styles.js</code>',
1115 6fd71452 Julien Enselme
      '!theme' => '<code>' . $theme_path . '/ckeditor.styles.js' . '</code>'
1116 85ad3d82 Assos Assos
        )
1117
    )
1118
  );
1119
1120
  $form['css']['styles_path'] = array(
1121
    '#type' => 'textfield',
1122
    '#title' => t('Predefined styles path'),
1123
    '#default_value' => !empty($profile->settings['styles_path']) ? $profile->settings['styles_path'] : "",
1124
    '#size' => 40,
1125
    '#maxlength' => 255,
1126
    '#description' => t(
1127
        'Enter the path to a file with predefined styles (Example: !example1). Make sure you select the !style_define_path option above.', array(
1128
      '!style_define_path' => '<strong>' . t('Define path to ckeditor.styles.js') . '</strong>',
1129
      '!ckeditor_styles_js_file' => '<code>ckeditor.styles.js</code>',
1130
      '!example1' => '<code>/ckeditor.styles.js</code>'
1131
        )
1132
    ) .
1133
    '<br />' .
1134
    t('Available placeholders:!h &ndash; host name (!host).!t &ndash; path to theme (!theme).!m &ndash; path to the CKEditor module (!module).', array(
1135
      '!h' => '<br /><code>%h</code>',
1136
      '!t' => '<br /><code>%t</code>',
1137
      '!m' => '<br /><code>%m</code>',
1138
      '!host' => '<code>' . base_path() . '</code>',
1139 6fd71452 Julien Enselme
      '!theme' => '<code>' . base_path() . $theme_path . '/</code>',
1140 85ad3d82 Assos Assos
      '!module' => '<code>' . drupal_get_path('module', 'ckeditor') . '</code>'
1141
        )
1142
    )
1143
  );
1144
1145
  $form['ckeditor_upload_settings'] = array(
1146
    '#type' => 'fieldset',
1147
    '#title' => t('File browser settings'),
1148
    '#collapsible' => TRUE,
1149
    '#collapsed' => TRUE,
1150
    '#description' => t(
1151
        'Set the file browser settings. A file browser will allow you to browse the files stored on the server and embed them as links, images, or Flash movies. CKEditor is compatible with such Drupal modules as !imce or !elfinder. CKEditor can be also integrated with !ckfinder, an advanced Ajax file manager.', array(
1152
      '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce'),
1153
      '!elfinder' => l(t('elFinder'), 'http://drupal.org/project/elfinder'),
1154
      '!ckfinder' => l(t('CKFinder'), 'http://cksource.com/ckfinder')
1155
        )
1156
    )
1157
  );
1158
1159
  $filebrowsers = array(
1160
    'none' => t('None'),
1161
    'ckfinder' => t('CKFinder'),
1162
  );
1163
1164
  $filebrowsers_dialogs = array(
1165
    '' => t('Same as in the Link dialog window'),
1166
    'ckfinder' => t('CKFinder'),
1167
  );
1168
1169
  if (module_exists('imce')) {
1170
    $filebrowsers['imce'] = t('IMCE');
1171
    $filebrowsers_dialogs['imce'] = t('IMCE');
1172
  }
1173
1174
  if (module_exists('elfinder')) {
1175
    $filebrowsers['elfinder'] = t('elFinder');
1176
    $filebrowsers_dialogs['elfinder'] = t('elFinder');
1177
  }
1178
1179
  /* MODULES NOT PORTED TO D7
1180
    if (module_exists('tinybrowser')) {
1181
    $filebrowsers['tinybrowser'] = t('TinyBrowser');
1182
    $filebrowsers_dialogs['tinybrowser'] = t('TinyBrowser');
1183
    }
1184
1185
    if (module_exists('imagebrowser')) {
1186
    $filebrowsers['ib'] = t('Image Browser');
1187
    $filebrowsers_dialogs['ib'] = t('Image Browser');
1188
    }
1189
1190
    if (module_exists('webfm_popup')) {
1191
    $filebrowsers['webfm'] = t('Web File Manager');
1192
    $filebrowsers_dialogs['webfm'] = t('Web File Manager');
1193
    }
1194
   */
1195
  $form['ckeditor_upload_settings']['filebrowser'] = array(
1196
    '#type' => 'select',
1197
    '#title' => t('File browser type (Link dialog window)'),
1198
    '#default_value' => !empty($profile->settings['filebrowser']) ? $profile->settings['filebrowser'] : 'none',
1199
    '#options' => $filebrowsers,
1200
    '#description' => t('Select the file browser that you would like to use to upload files.'),
1201
  );
1202
1203
  $form['ckeditor_upload_settings']['filebrowser_image'] = array(
1204
    '#type' => 'select',
1205
    '#title' => t('File browser type (Image dialog window)'),
1206
    '#default_value' => !empty($profile->settings['filebrowser_image']) ? $profile->settings['filebrowser_image'] : 'none',
1207
    '#options' => $filebrowsers_dialogs,
1208
    '#description' => t('Select the file browser that you would like to use to upload images.'),
1209
  );
1210
1211
  $form['ckeditor_upload_settings']['filebrowser_flash'] = array(
1212
    '#type' => 'select',
1213
    '#title' => t('File browser type (Flash dialog window)'),
1214
    '#default_value' => !empty($profile->settings['filebrowser_flash']) ? $profile->settings['filebrowser_flash'] : 'none',
1215
    '#options' => $filebrowsers_dialogs,
1216
    '#description' => t('Select the file browser that you would like to use to upload Flash movies.'),
1217
  );
1218
1219
  if (variable_get('file_default_scheme', '') != 'private') {
1220
    $current_user_files_path = empty($profile->settings['UserFilesPath']) ? "%b%f/" : $profile->settings['UserFilesPath'];
1221
    $current_user_files_path = strtr($current_user_files_path, array("%f" => variable_get('file_public_path', conf_path() . '/files'), "%u" => "UID", "%b" => base_path(), "%n" => "UNAME"));
1222
1223
    $current_user_files_absolute_path = empty($profile->settings['UserFilesAbsolutePath']) ? "%d%b%f/" : $profile->settings['UserFilesAbsolutePath'];
1224
    $current_user_files_absolute_path = strtr($current_user_files_absolute_path, array("%f" => variable_get('file_public_path', conf_path() . '/files'), "%u" => "UID", "%b" => base_path(), "%d" => ckeditor_get_document_root_full_path(), "%n" => "UNAME"));
1225
1226
1227
    $form['ckeditor_upload_settings']['UserFilesPath'] = array(
1228
      '#type' => 'textfield',
1229
      '#prefix' => '<fieldset><legend>' . t('CKFinder settings') . '</legend>',
1230
      '#title' => t('Path to uploaded files'),
1231
      '#default_value' => !empty($profile->settings['UserFilesPath']) ? $profile->settings['UserFilesPath'] : "%b%f/",
1232
      '#size' => 40,
1233
      '#maxlength' => 255,
1234
      '#description' => t('Path to uploaded files relative to the document root.') .
1235
      '<br />' .
1236
      t('Available placeholders:!b &ndash; the base URL path of the Drupal installation (!base).!f &ndash; the Drupal file system path where the files are stored (!files).!u &ndash; User ID.!n &ndash; Username.', array(
1237
        '!n' => '<br /><code>%n</code>',
1238
        '!u' => '<br /><code>%u</code>',
1239
        '!f' => '<br/><code>%f</code>',
1240
        '!b' => '<br/><code>%b</code>',
1241
        '!files' => '<code>' . variable_get('file_public_path', conf_path() . '/files') . '</code>',
1242
        '!base' => '<code>' . base_path() . '</code>'
1243
          )
1244
      ) .
1245
      '<br />' .
1246
      t('Current path: !path', array(
1247
        '!path' => '<code>' . $current_user_files_path . '</code>'
1248
          )
1249
      )
1250
    );
1251
1252
    $form['ckeditor_upload_settings']['UserFilesAbsolutePath'] = array(
1253
      '#type' => 'textfield',
1254
      '#title' => t('Absolute path to uploaded files'),
1255
      '#default_value' => !empty($profile->settings['UserFilesAbsolutePath']) ? $profile->settings['UserFilesAbsolutePath'] : "%d%b%f/",
1256
      '#size' => 40,
1257
      '#maxlength' => 255,
1258
      '#suffix' => '</fieldset>',
1259
      '#description' => t('The path to the local directory (on the server) which points to the path defined above. If left empty, CKEditor will try to discover the right path.') .
1260
      '<br />' .
1261
      t('Available placeholders:!d &ndash; the server path to the document root (!root).!b &ndash; the base URL path of the Drupal installation (!base).!f &ndash; the Drupal file system path where the files are stored (!files).!u &ndash; User ID.!n &ndash; Username.', array(
1262
        '!u' => '<br /><code>%u</code>',
1263
        '!n' => '<br /><code>%n</code>',
1264
        '!d' => '<br/><code>%d</code>',
1265
        '!b' => '<br /><code>%b</code>',
1266
        '!f' => '<br/><code>%f</code>',
1267
        '!files' => '<code>' . variable_get('file_public_path', conf_path() . '/files') . '</code>',
1268
        '!base' => '<code>' . base_path() . '</code>',
1269
        '!root' => '<code>' . ckeditor_get_document_root_full_path() . '</code>'
1270
          )
1271
      ) .
1272
      '<br />' .
1273
      t('Current path: !path', array(
1274
        '!path' => '<code>' . $current_user_files_absolute_path . '</code>'
1275
          )
1276
      )
1277
    );
1278
  }
1279
  if (variable_get('file_default_scheme', '') == 'private') {
1280
    $form['ckeditor_upload_settings']['private_path_descrption'] = array(
1281
      '#markup' => '<div>' . t(
1282
          'Setting a relative path to uploaded files was disabled because private downloads are enabled and thus this path is calculated automatically. To change the location of uploaded files in the private file system, edit the <strong>!url</strong>.', array(
1283
        '!url' => l(t('CKEditor Global Profile'), 'admin/config/content/ckeditor/editg')
1284
          )
1285
      ) . '</div>',
1286
    );
1287
  }
1288
1289
  $form['advanced'] = array(
1290
    '#type' => 'fieldset',
1291
    '#title' => t('Advanced options'),
1292
    '#collapsible' => TRUE,
1293
    '#collapsed' => TRUE,
1294
  );
1295
  if (ckeditor_get_version(TRUE) == 3) {
1296
    $form['advanced']['ckeditor_load_method'] = array(
1297
      '#type' => 'select',
1298
      '#title' => t('Loading method'),
1299
      '#default_value' => !empty($profile->settings['ckeditor_load_method']) ? $profile->settings['ckeditor_load_method'] : 'ckeditor.js',
1300
      '#options' => _ckeditor_load_methods(),
1301
      '#description' => t('Select the loading method of CKEditor. If the !ckeditor_basic_js file is used, only a small file is loaded initially and the rest of the editor is loaded later (see <strong>Loading timeout</strong>). This might be useful if CKEditor is disabled by default.', array(
1302
        '!ckeditor_basic_js' => '<code>ckeditor_basic.js</code>'
1303
          )
1304
      )
1305
    );
1306
    $form['advanced']['ckeditor_load_time_out'] = array(
1307
      '#type' => 'textfield',
1308
      '#title' => t('Loading timeout'),
1309
      '#default_value' => !empty($profile->settings['ckeditor_load_time_out']) ? $profile->settings['ckeditor_load_time_out'] : "0",
1310
      '#size' => 40,
1311
      '#maxlength' => 255,
1312
      '#description' => t('The time to wait (in seconds) to load the full editor code after the page is loaded, if the !ckeditor_basic_js file is used. If set to zero, the editor is loaded on demand.', array(
1313
        '!ckeditor_basic_js' => '<code>ckeditor_basic.js</code>'
1314
          )
1315
      )
1316
    );
1317
  }
1318
1319
  $form['advanced']['forcePasteAsPlainText'] = array(
1320
    '#type' => 'select',
1321
    '#title' => t('Force pasting as plain text'),
1322
    '#default_value' => !empty($profile->settings['forcePasteAsPlainText']) ? $profile->settings['forcePasteAsPlainText'] : "f",
1323
    '#options' => array(
1324
      't' => t('Enabled'),
1325
      'f' => t('Disabled')
1326
    ),
1327
    '#description' => t('If enabled, HTML content will be automatically changed to plain text when pasting.'),
1328
  );
1329
  $form['advanced']['html_entities'] = array(
1330
    '#type' => 'radios',
1331
    '#title' => t('HTML Entities'),
1332
    '#default_value' => !empty($profile->settings['html_entities']) ? $profile->settings['html_entities'] : 'f',
1333
    '#description' => t('Convert all applicable characters to HTML entities.'),
1334
    '#options' => array(
1335
      'f' => t('No'),
1336
      't' => t('Yes')
1337
    ),
1338
  );
1339
  $form['advanced']['scayt_autoStartup'] = array(
1340
    '#type' => 'radios',
1341
    '#title' => t('Spellchecker'),
1342
    '#default_value' => !empty($profile->settings['scayt_autoStartup']) ? $profile->settings['scayt_autoStartup'] : 'f',
1343
    '#description' => t('If enabled, turns on SCAYT (Spell Check As You Type) automatically after loading the editor.'),
1344
    '#options' => array(
1345
      'f' => t('No'),
1346
      't' => t('Yes')
1347
    ),
1348
  );
1349
  $form['advanced']['theme_config_js'] = array(
1350
    '#type' => 'radios',
1351
    '#title' => t('Load !ckeditor_config_js from the theme path', array(
1352
      '!ckeditor_config_js' => '<code>ckeditor.config.js</code>'
1353
        )
1354
    ),
1355
    '#default_value' => !empty($profile->settings['theme_config_js']) ? $profile->settings['theme_config_js'] : 'f',
1356
    '#options' => array(
1357
      't' => t('Yes'),
1358
      'f' => t('No')
1359
    ),
1360
    '#description' => t('When enabled, the editor will try to load the !ckeditor_config_js file from the theme directory.', array(
1361
      '!ckeditor_config_js' => '<code>ckeditor.config.js</code>'
1362
        )
1363
    )
1364
  );
1365
  $form['advanced']['js_conf'] = array(
1366
    '#type' => 'textarea',
1367
    '#title' => t('Custom JavaScript configuration'),
1368
    '#default_value' => !empty($profile->settings['js_conf']) ? $profile->settings['js_conf'] : "",
1369
    '#cols' => 60,
1370
    '#rows' => 5,
1371
    '#description' => t(
1372
        'In order to change CKEditor configuration globally, you should modify the !ckeditor_config configuration file. Sometimes it is required to change the CKEditor configuration for a single profile only. Use this box to define settings that are unique for this profile. Available options are listed in the !docs. Add the following code snippet to change the fonts available in the CKEditor <strong>Font</strong> and <strong>Size</strong> drop-down lists: <pre>@code</pre><strong>Warning</strong>: If you make a mistake here, CKEditor may not load correctly.', array(
1373
      '!ckeditor_config' => '<code>' . drupal_get_path('module', 'ckeditor') . "/ckeditor.config.js</code>",
1374
      '!docs' => l(t('CKEditor documentation'), 'http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html'),
1375
      '@code' => "config.font_names = 'Arial;Times New Roman;Verdana';\nconfig.fontSize_sizes = '16/16px;24/24px;48/48px;';"
1376
        )
1377
    ),
1378
    '#wysiwyg' => FALSE,
1379
  );
1380
1381
  $form['submit'] = array(
1382
    '#type' => 'submit',
1383
    '#value' => t('Save')
1384
  );
1385
1386
  return $form;
1387
}
1388
1389
/**
1390
 * Form validation for a profile.
1391
 */
1392
function ckeditor_admin_profile_form_validate($form, &$form_state) {
1393
  $edit = & $form_state['values'];
1394
  /*
1395
    if ($edit['default'] == 't' && $edit['popup'] == 't') {
1396
    form_set_error('popup', t('If CKEditor is enabled by default, the popup window must be disabled.'));
1397
    }
1398
1399
    if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') {
1400
    form_set_error('popup', t('If toggle is enabled, the popup window must be disabled.'));
1401
    }
1402
   */
1403
  if (!$edit['name']) {
1404
    form_set_error('name', t('You must give a profile name.'));
1405
  }
1406
  elseif (!preg_match('/^[A-Za-z0-9_]+$/', $edit['name'])) {
1407
    form_set_error('name', t('Enter a valid profile name. Only alphanumeric and underscore characters are allowed.'));
1408
  }
1409
  elseif ($edit['name'] == 'CKEditor Global Profile') {
1410
    form_set_error('name', t('This profile name is reserved. Please choose a different name.'));
1411
  }
1412
  elseif (!isset($edit['_profile']) || ($edit['_profile']->name != $edit['name'])) {
1413
    $result = ckeditor_profile_load($edit['name']);
1414
    if (!empty($result)) {
1415
      form_set_error('name', t('The profile name must be unique. A profile with this name already exists.'));
1416
    }
1417
  }
1418
1419
  if (!preg_match('/^\d+%?$/', $edit['width'])) {
1420
    form_set_error('width', t('Enter a valid width value. Examples: 400, 100%.'));
1421
  }
1422
1423
  if (!empty($edit['css_path'])) {
1424
    if ($edit['css_mode'] != 'self') {
1425
      form_set_error('css_path', t('The CSS path is not empty. Please set the <strong>Editor CSS</strong> option to the <strong>Define CSS</strong> mode.'));
1426
    }
1427
    elseif (FALSE !== strpos($edit['css_path'], '"')) {
1428
      form_set_error('css_path', t('Double quotes are not allowed in the CSS path.'));
1429
    }
1430
    elseif (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") {
1431
      form_set_error('css_path', t('Enter a valid CSS path, do not surround it with quotes.'));
1432
    }
1433
  }
1434
1435
  if (!empty($edit['styles_path'])) {
1436
    if ($edit['css_style'] != 'self') {
1437
      form_set_error('styles_path', t('The path to predefined styles is not empty. Please set the <strong>Predefined styles</strong> option to the <strong>Define path to ckeditor.styles.js</strong> mode.'));
1438
    }
1439
    elseif (FALSE !== strpos($edit['styles_path'], '"')) {
1440
      form_set_error('styles_path', t('Double quotes are not allowed in the styles path.'));
1441
    }
1442
    elseif (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") {
1443
      form_set_error('styles_path', t('Enter a valid styles path, do not surround it with quotes.'));
1444
    }
1445
  }
1446
1447
  if (!empty($edit['font_format'])) {
1448
    if (!preg_match("/^((p|div|pre|address|h1|h2|h3|h4|h5|h6);)*(p|div|pre|address|h1|h2|h3|h4|h5|h6)$/", $edit['font_format'])) {
1449
      form_set_error('font_format', t('Enter a valid, semicolon-separated list of HTML font formats (no semicolon at the end of the list is expected).'));
1450
    }
1451
  }
1452
  // @todo DOWNLOAD API
1453
  if (!empty($edit['UserFilesAbsolutePath']) && empty($edit['UserFilesPath'])) {
1454
    form_set_error('UserFilesPath', t('The path to uploaded files is required.'));
1455
  }
1456
  if (!empty($edit['UserFilesPath']) && empty($edit['UserFilesAbsolutePath'])) {
1457
    form_set_error('UserFilesPath', t('An absolute path to uploaded files is required.'));
1458
  }
1459
1460
  if (ckeditor_get_version(TRUE) == 3) {
1461
    $load_methods = _ckeditor_load_methods();
1462
    if (!isset($load_methods[$edit['ckeditor_load_method']])) {
1463
      form_set_error('ckeditor_load_method', t('Set a valid loading method.'));
1464
    }
1465
    if (!preg_match('#\d+#', $edit['ckeditor_load_time_out'])) {
1466
      form_set_error('ckeditor_load_time_out', t('Enter a valid loading timeout in seconds.'));
1467
    }
1468
  }
1469
  $toolbar = $edit['toolbar'];
1470
  $toolbar = str_replace("'", '"', $toolbar);
1471
  $toolbar = preg_replace('/(\w*)\s*\:/', '"${1}":', $toolbar);
1472 6fd71452 Julien Enselme
1473
  if (strpos($toolbar, 'CodeSnippet') !== false && empty($edit['loadPlugins']['codesnippet'])) {
1474
    form_set_error('loadPlugins][codesnippet', t('The Code Snippet plugin must be enabled if the CodeSnippet button is enabled in the toolbar.'));
1475
  }
1476
  if (strpos($toolbar, 'Mathjax') !== false && empty($edit['loadPlugins']['mathjax'])) {
1477
    form_set_error('loadPlugins][mathjax', t('The Mathjax plugin must be enabled if the Mathjax button is enabled in the toolbar.'));
1478
  }
1479 85ad3d82 Assos Assos
  if (!json_decode($toolbar)) {
1480
    form_set_error('toolbar', t('Enter a valid toolbar configuration.'));
1481
  }
1482
}
1483
1484
/**
1485
 * Form submit for a profile
1486
 */
1487
function ckeditor_admin_profile_form_submit($form, &$form_state) {
1488
  $edit = & $form_state['values'];
1489
1490
  if (isset($edit['_profile'])) {
1491
    ckeditor_profile_delete($edit['_profile']->name);
1492
    drupal_set_message(t('Your CKEditor profile was updated.'));
1493
  }
1494
  else {
1495
    drupal_set_message(t('Your CKEditor profile was created.'));
1496
  }
1497
1498
  $settings = ckeditor_admin_values_to_settings($edit);
1499
  db_insert('ckeditor_settings')
1500
      ->fields(array(
1501
        "name" => $edit['name'],
1502
        "settings" => $settings
1503
      ))
1504
      ->execute();
1505
1506
  if (!empty($edit['input_formats'])) {
1507
    foreach (array_keys($edit['input_formats']) as $format) {
1508
      if ($edit['input_formats'][$format] != '0') {
1509
        db_insert('ckeditor_input_format')->fields(array("name" => $edit['name'], "format" => $format))->execute();
1510
      }
1511
    }
1512
  }
1513
1514
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1515
}
1516
1517
/**
1518
 * Form builder for a clone profile
1519
 */
1520 6fd71452 Julien Enselme
function ckeditor_admin_profile_clone_form($form, $form_state, $task, $oldprofile) {
1521
  return ckeditor_admin_profile_form($form, $form_state, $task, $oldprofile);
1522 85ad3d82 Assos Assos
}
1523
1524
/**
1525
 * Form validation for a clone profile
1526
 */
1527
function ckeditor_admin_profile_clone_form_validate($form_state, $oldprofile) {
1528
  ckeditor_admin_profile_form_validate($form_state, $oldprofile);
1529
}
1530
1531
/**
1532
 * Form submit for a clone profile
1533
 */
1534
function ckeditor_admin_profile_clone_form_submit($form, &$form_state) {
1535
  $edit = & $form_state['values'];
1536
  drupal_set_message(t('Your CKEditor profile was created.'));
1537
  $settings = ckeditor_admin_values_to_settings($edit);
1538
  db_insert('ckeditor_settings')
1539
      ->fields(array(
1540
        "name" => $edit['name'],
1541
        "settings" => $settings
1542
      ))
1543
      ->execute();
1544
1545
  if (!empty($edit['input_formats'])) {
1546
    foreach (array_keys($edit['input_formats']) as $format) {
1547
      if ($edit['input_formats'][$format] != 0) {
1548
        db_insert('ckeditor_input_format')->fields(array("name" => $edit['name'], "format" => $format))->execute();
1549
      }
1550
    }
1551
  }
1552
1553
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1554
}
1555
1556
/**
1557
 * Form builder for a profile delete
1558
 */
1559
function ckeditor_admin_profile_delete_form($form, $form_state, $profile) {
1560
  $form = array();
1561
1562
  $form['_profile'] = array(
1563
    '#type' => 'value',
1564
    '#value' => $profile,
1565
  );
1566
1567
  $form['question'] = array(
1568
    '#type' => 'item',
1569
    '#markup' => t(
1570
        'Are you sure that you want to delete the CKEditor profile <strong>%profile</strong>?', array(
1571
      '%profile' => $profile->name
1572
        )
1573
    ),
1574
  );
1575
1576
  $form['delete'] = array(
1577
    '#type' => 'submit',
1578
    '#id' => 'delete',
1579
    '#value' => t('Delete'),
1580
  );
1581
1582
  $form['back'] = array(
1583
    '#type' => 'submit',
1584
    '#id' => 'back',
1585
    '#value' => t('Cancel'),
1586
  );
1587
1588
  return $form;
1589
}
1590
1591
/**
1592
 * Submit form for a profile delete
1593
 */
1594
function ckeditor_admin_profile_delete_form_submit($form, &$form_state) {
1595
  $v = & $form_state['values'];
1596
1597
  if ($form_state['clicked_button']['#id'] == 'delete') {
1598
    ckeditor_profile_delete($v['_profile']->name);
1599
    drupal_set_message(t('The CKEditor profile was deleted.'));
1600
  }
1601
1602
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1603
}
1604
1605
/**
1606
 * Converts an array of form values to a serialized array that does not
1607
 * contain Drupal Form API values
1608
 */
1609
function ckeditor_admin_values_to_settings($values) {
1610
  $plugins = array();
1611
  if (isset($values['loadPlugins'])) {
1612
    $plugins = $values['loadPlugins'];
1613
  }
1614
  unset($values['name'], $values['input_formats'], $values['_profile'], $values['op'], $values['submit'], $values['form_build_id'], $values['form_token'], $values['form_id'], $values['loadPlugins']);
1615
1616 6fd71452 Julien Enselme
  // Replace CRLF with LF in toolbar settings
1617
  if(isset($values['toolbar'])){
1618
    $values['toolbar'] = str_replace("\r\n", "\n", $values['toolbar']);
1619
  }
1620
1621 85ad3d82 Assos Assos
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
1622
  $plugin_list = ckeditor_load_plugins();
1623
  $values['loadPlugins'] = array();
1624
  if (!empty($plugins)) {
1625
    foreach (array_keys($plugins) as $plugin) {
1626
      if ($plugins[$plugin] != '0') {
1627
        $values['loadPlugins'][$plugin] = $plugin_list[$plugin];
1628
      }
1629
    }
1630
  }
1631
1632
  return serialize($values);
1633
}
1634
1635
/**
1636
 * Remove a profile from the database.
1637
 */
1638
function ckeditor_profile_delete($name) {
1639
  db_delete('ckeditor_settings')
1640
      ->condition('name', $name)
1641
      ->execute();
1642
  db_delete('ckeditor_input_format')
1643
      ->condition('name', $name)
1644
      ->execute();
1645
}
1646
1647
/*
1648
 * List of CKEditor librares to load
1649
 */
1650
1651
function _ckeditor_load_methods() {
1652
  $result = array('ckeditor.js' => 'ckeditor.js');
1653 6fd71452 Julien Enselme
  $ckeditor_local_path = ckeditor_path('local');
1654
  if ($ckeditor_local_path == '<URL>') {
1655
    return $result;
1656
  }
1657
  if (file_exists($ckeditor_local_path . '/ckeditor_basic.js')) {
1658 85ad3d82 Assos Assos
    $result['ckeditor_basic.js'] = 'ckeditor_basic.js';
1659
  }
1660 6fd71452 Julien Enselme
  if (file_exists($ckeditor_local_path . '/ckeditor_source.js')) {
1661 85ad3d82 Assos Assos
    $result['ckeditor_source.js'] = 'ckeditor_source.js (' . t('for developers only') . ')';
1662
  }
1663
  return $result;
1664
}
1665
1666
/*
1667
 * Disable WYSIWYG module
1668
 */
1669
1670
function ckeditor_disable_wysiwyg($token) {
1671
  if (!drupal_valid_token($token, 'ckeditorDisableWysiwyg')) {
1672
    exit();
1673
  }
1674
  module_disable(array('wysiwyg'));
1675
  drupal_set_message(t('The WYSIWYG module is disabled.'));
1676
1677
  drupal_goto('admin/config/content/ckeditor');
1678
}
1679
1680
/*
1681
 * Get all available toolbar buttons
1682
 */
1683
1684
function ckeditor_toolbar_buttons_all() {
1685
  $path = base_path() . drupal_get_path('module', 'ckeditor');
1686
1687
  //CKEditor default buttons
1688
  $buttons = array(
1689
    'Source' => array('name' => 'Source', 'icon' => $path . '/images/buttons/source.png', 'title' => 'Source', 'row' => 1),
1690
    'Save' => array('name' => 'Save', 'icon' => $path . '/images/buttons/save.png', 'title' => 'Save', 'row' => 1),
1691 6fd71452 Julien Enselme
    'NewPage' => array('name' => 'NewPage', 'icon' => $path . '/images/buttons/newpage.png', 'title' => 'New Page', 'row' => 1),
1692 85ad3d82 Assos Assos
    'Preview' => array('name' => 'Preview', 'icon' => $path . '/images/buttons/preview.png', 'title' => 'Preview', 'row' => 1),
1693
    'Templates' => array('name' => 'Templates', 'icon' => $path . '/images/buttons/templates.png', 'title' => 'Templates', 'row' => 1),
1694
    'Cut' => array('name' => 'Cut', 'icon' => $path . '/images/buttons/cut.png', 'title' => 'Cut', 'row' => 1),
1695
    'Copy' => array('name' => 'Copy', 'icon' => $path . '/images/buttons/copy.png', 'title' => 'Copy', 'row' => 1),
1696
    'Paste' => array('name' => 'Paste', 'icon' => $path . '/images/buttons/paste.png', 'title' => 'Paste', 'row' => 1),
1697 6fd71452 Julien Enselme
    'PasteText' => array('name' => 'PasteText', 'icon' => $path . '/images/buttons/pastetext.png', 'title' => 'Paste as plain text', 'row' => 1),
1698
    'PasteFromWord' => array('name' => 'PasteFromWord', 'icon' => $path . '/images/buttons/pastefromword.png', 'title' => 'Paste from Word', 'row' => 1),
1699 85ad3d82 Assos Assos
    'Print' => array('name' => 'Print', 'icon' => $path . '/images/buttons/print.png', 'title' => 'Print', 'row' => 1),
1700 6fd71452 Julien Enselme
    'SpellChecker' => array('name' => 'SpellChecker', 'icon' => $path . '/images/buttons/spellchecker.png', 'title' => 'Check Spelling', 'row' => 1),
1701
    'Scayt' => array('name' => 'Scayt', 'icon' => $path . '/images/buttons/scayt.png', 'title' => 'Spell Check As you Type', 'row' => 1), //TODO sprawdzic ta opcje
1702 85ad3d82 Assos Assos
    'Undo' => array('name' => 'Undo', 'icon' => $path . '/images/buttons/undo.png', 'title' => 'Undo', 'row' => 1),
1703
    'Redo' => array('name' => 'Redo', 'icon' => $path . '/images/buttons/redo.png', 'title' => 'Redo', 'row' => 1),
1704
    'Find' => array('name' => 'Find', 'icon' => $path . '/images/buttons/find.png', 'title' => 'Find', 'row' => 1),
1705
    'Replace' => array('name' => 'Replace', 'icon' => $path . '/images/buttons/replace.png', 'title' => 'Replace', 'row' => 1),
1706 6fd71452 Julien Enselme
    'SelectAll' => array('name' => 'SelectAll', 'icon' => $path . '/images/buttons/selectall.png', 'title' => 'Select All', 'row' => 1),
1707
    'RemoveFormat' => array('name' => 'RemoveFormat', 'icon' => $path . '/images/buttons/removeformat.png', 'title' => 'Remove Format', 'row' => 1),
1708 85ad3d82 Assos Assos
    'Form' => array('name' => 'Form', 'icon' => $path . '/images/buttons/form.png', 'title' => 'Form', 'row' => 1),
1709
    'Checkbox' => array('name' => 'Checkbox', 'icon' => $path . '/images/buttons/checkbox.png', 'title' => 'Checkbox', 'row' => 1),
1710 6fd71452 Julien Enselme
    'Radio' => array('name' => 'Radio', 'icon' => $path . '/images/buttons/radio.png', 'title' => 'Radio Button', 'row' => 1),
1711
    'TextField' => array('name' => 'TextField', 'icon' => $path . '/images/buttons/textfield.png', 'title' => 'Text Field', 'row' => 1),
1712 85ad3d82 Assos Assos
    'Textarea' => array('name' => 'Textarea', 'icon' => $path . '/images/buttons/textarea.png', 'title' => 'Textarea', 'row' => 1),
1713 6fd71452 Julien Enselme
    'Select' => array('name' => 'Select', 'icon' => $path . '/images/buttons/select.png', 'title' => 'Selection Field', 'row' => 1),
1714 85ad3d82 Assos Assos
    'Button' => array('name' => 'Button', 'icon' => $path . '/images/buttons/button.png', 'title' => 'Button', 'row' => 1),
1715 6fd71452 Julien Enselme
    'ImageButton' => array('name' => 'ImageButton', 'icon' => $path . '/images/buttons/imagebutton.png', 'title' => 'Image Button', 'row' => 1),
1716
    'HiddenField' => array('name' => 'HiddenField', 'icon' => $path . '/images/buttons/hiddenfield.png', 'title' => 'Hidden Field', 'row' => 1),
1717 85ad3d82 Assos Assos
    'Bold' => array('name' => 'Bold', 'icon' => $path . '/images/buttons/bold.png', 'title' => 'Bold', 'row' => 2),
1718
    'Italic' => array('name' => 'Italic', 'icon' => $path . '/images/buttons/italic.png', 'type' => 'command', 'title' => 'Italic', 'row' => 2),
1719
    'Underline' => array('name' => 'Underline', 'icon' => $path . '/images/buttons/underline.png', 'title' => 'Underline', 'row' => 2),
1720
    'Strike' => array('name' => 'Strike', 'icon' => $path . '/images/buttons/strike.png', 'title' => 'Strike Through', 'row' => 2),
1721
    'Subscript' => array('name' => 'Subscript', 'icon' => $path . '/images/buttons/subscript.png', 'title' => 'Subscript', 'row' => 2),
1722
    'Superscript' => array('name' => 'Superscript', 'icon' => $path . '/images/buttons/superscript.png', 'title' => 'Superscript', 'row' => 2),
1723 6fd71452 Julien Enselme
    'NumberedList' => array('name' => 'NumberedList', 'icon' => $path . '/images/buttons/numberedlist.png', 'title' => 'Insert/Remove Numbered List', 'row' => 2),
1724
    'BulletedList' => array('name' => 'BulletedList', 'icon' => $path . '/images/buttons/bulletedlist.png', 'title' => 'Insert/Remove Bulleted List', 'row' => 2),
1725
    'Outdent' => array('name' => 'Outdent', 'icon' => $path . '/images/buttons/outdent.png', 'title' => 'Decrease Indent', 'row' => 2),
1726
    'Indent' => array('name' => 'Indent', 'icon' => $path . '/images/buttons/indent.png', 'title' => 'Increase Indent', 'row' => 2),
1727
    'Blockquote' => array('name' => 'Blockquote', 'icon' => $path . '/images/buttons/blockquote.png', 'title' => 'Block Quote', 'row' => 2),
1728
    'CreateDiv' => array('name' => 'CreateDiv', 'icon' => $path . '/images/buttons/creatediv.png', 'title' => 'Create Div Container', 'row' => 2),
1729
    'JustifyLeft' => array('name' => 'JustifyLeft', 'icon' => $path . '/images/buttons/justifyleft.png', 'title' => 'Left Justify', 'row' => 2),
1730
    'JustifyCenter' => array('name' => 'JustifyCenter', 'icon' => $path . '/images/buttons/justifycenter.png', 'title' => 'Center Justify', 'row' => 2),
1731
    'JustifyRight' => array('name' => 'JustifyRight', 'icon' => $path . '/images/buttons/justifyright.png', 'title' => 'Right Justify', 'row' => 2),
1732
    'JustifyBlock' => array('name' => 'JustifyBlock', 'icon' => $path . '/images/buttons/justifyblock.png', 'title' => 'Block Justify', 'row' => 2),
1733
    'BidiLtr' => array('name' => 'BidiLtr', 'icon' => $path . '/images/buttons/bidiltr.png', 'title' => 'Text direction from left to right', 'row' => 2),
1734
    'BidiRtl' => array('name' => 'BidiRtl', 'icon' => $path . '/images/buttons/bidirtl.png', 'title' => 'Text direction from right to left', 'row' => 2),
1735
    'Language' => array('name' => 'Language', 'icon' => $path . '/images/buttons/language.png', 'title' => 'Set Language', 'row' => 2),
1736 85ad3d82 Assos Assos
    'Link' => array('name' => 'Link', 'icon' => $path . '/images/buttons/link.png', 'title' => 'Link', 'row' => 2),
1737
    'Unlink' => array('name' => 'Unlink', 'icon' => $path . '/images/buttons/unlink.png', 'title' => 'Unlink', 'row' => 2),
1738
    'Anchor' => array('name' => 'Anchor', 'icon' => $path . '/images/buttons/anchor.png', 'title' => 'Anchor', 'row' => 2),
1739
    'Image' => array('name' => 'Image', 'icon' => $path . '/images/buttons/image.png', 'title' => 'Image', 'row' => 2),
1740
    'Flash' => array('name' => 'Flash', 'icon' => $path . '/images/buttons/flash.png', 'title' => 'Flash', 'row' => 2),
1741
    'Table' => array('name' => 'Table', 'icon' => $path . '/images/buttons/table.png', 'title' => 'Table', 'row' => 2),
1742 6fd71452 Julien Enselme
    'HorizontalRule' => array('name' => 'HorizontalRule', 'icon' => $path . '/images/buttons/horizontalrule.png', 'title' => 'Insert Horizontal Line', 'row' => 2),
1743 85ad3d82 Assos Assos
    'Smiley' => array('name' => 'Smiley', 'icon' => $path . '/images/buttons/smiley.png', 'title' => 'Smiley', 'row' => 2),
1744 6fd71452 Julien Enselme
    'SpecialChar' => array('name' => 'SpecialChar', 'icon' => $path . '/images/buttons/specialchar.png', 'title' => 'Insert Special Character', 'row' => 2),
1745
    'PageBreak' => array('name' => 'PageBreak', 'icon' => $path . '/images/buttons/pagebreak.png', 'title' => 'Insert Page Break for Printing', 'row' => 2),
1746 85ad3d82 Assos Assos
    'Styles' => array('name' => 'Styles', 'icon' => $path . '/images/buttons/styles.png', 'title' => 'Formatting Styles', 'row' => 3),
1747
    'Format' => array('name' => 'Format', 'icon' => $path . '/images/buttons/format.png', 'title' => 'Paragraph Format', 'row' => 3),
1748
    'Font' => array('name' => 'Font', 'icon' => $path . '/images/buttons/font.png', 'title' => 'Font Name', 'row' => 3),
1749 6fd71452 Julien Enselme
    'FontSize' => array('name' => 'FontSize', 'icon' => $path . '/images/buttons/size.png', 'title' => 'Font Size', 'row' => 3),
1750
    'TextColor' => array('name' => 'TextColor', 'icon' => $path . '/images/buttons/textcolor.png', 'title' => 'Text Color', 'row' => 3),
1751
    'BGColor' => array('name' => 'BGColor', 'icon' => $path . '/images/buttons/bgcolor.png', 'title' => 'Background Color', 'row' => 3),
1752 85ad3d82 Assos Assos
    'Maximize' => array('name' => 'Maximize', 'icon' => $path . '/images/buttons/maximize.png', 'title' => 'Maximize', 'row' => 3),
1753 6fd71452 Julien Enselme
    'ShowBlocks' => array('name' => 'ShowBlocks', 'icon' => $path . '/images/buttons/showblocks.png', 'title' => 'Show Blocks', 'row' => 3),
1754 85ad3d82 Assos Assos
    'Iframe' => array('name' => 'Iframe', 'icon' => $path . '/images/buttons/iframe.png', 'title' => 'IFrame', 'row' => 3),
1755
    'About' => array('name' => 'About', 'icon' => $path . '/images/buttons/about.png', 'title' => 'About', 'row' => 3),
1756
    '__spacer' => array('name' => FALSE, 'icon' => $path . '/images/buttons/spacer.png', 'title' => 'Spacer', 'row' => 4),
1757
    '__group' => array('name' => FALSE, 'icon' => $path . '/images/buttons/group.png', 'title' => 'Group', 'row' => 4)
1758
  );
1759
1760
  $plugins = ckeditor_load_plugins(TRUE);
1761
  foreach ($plugins as $plugin_name => $plugin) {
1762
    if (!isset($plugin['buttons']) || $plugin['buttons'] == FALSE)
1763
      continue;
1764
    foreach ((array) $plugin['buttons'] as $button_name => $button) {
1765
      $buttons[$button_name] = array('name' => $button_name, 'icon' => $plugin['path'] . $button['icon'], 'title' => t($button['label']), 'row' => 4);
1766
    }
1767
  }
1768
1769
  return $buttons;
1770
}
1771
1772
/**
1773
 * Add security filters to the configuration panel available in the CKEditor profile administration section
1774
 */
1775
function _ckeditor_admin_profile_form_security_filters(&$form, $profile, $security_filters) {
1776
  foreach ((array) $security_filters['modules'] as $module_name => $module_conf) {
1777
    if (isset($module_conf['project_page']) && strlen($module_conf['project_page']) > 0) {
1778
      $form['security']['filters'][$module_name] = array(
1779
        '#type' => 'fieldset',
1780
        '#title' => t(
1781
            "!title <a href=\"!link\" target=\"_blank\">project page</a>", array(
1782
          "!title" => $module_conf['title'],
1783
          "!link" => $module_conf['project_page']
1784
            )
1785
        ),
1786
        '#weight' => $module_conf['weight']
1787
      );
1788
    }
1789
    else {
1790
      $form['security']['filters'][$module_name] = array(
1791
        '#type' => 'fieldset',
1792
        '#title' => t("!title", array("!title" => $module_conf['title'])),
1793
        '#weight' => $module_conf['weight']
1794
      );
1795
    }
1796
1797
    if ($module_conf['installed'] == TRUE) {
1798
      foreach ((array) $module_conf['filters'] as $filter_name => $filter_conf) {
1799
        $filter_text_formats = '<div class="filter-text-formats" filter="' . $filter_name . '"></div><div class="filter-info">';
1800
        $form['security']['filters'][$module_name][$filter_name] = array(
1801
          '#type' => 'item',
1802
          '#title' => t("@data", array('@data' => $filter_conf['title'])),
1803
          '#description' => t("!data", array('!data' => $filter_conf['description'])),
1804
          '#prefix' => "<div class=\"filter-wrapper\"></div>" . $filter_text_formats,
1805
          '#suffix' => "</div>"
1806
        );
1807
      }
1808
    }
1809
    else {
1810
      $form['security']['filters'][$module_name]['not_installed'] = array(
1811
        '#markup' => t("<i>Not installed</i>")
1812
      );
1813
    }
1814
  }
1815
}
1816
1817
function ckeditor_skinframe() {
1818
  header('Content-Type: text/html; charset=utf-8');
1819
1820
  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'ckeditorSkinframeCall')) {
1821
    exit;
1822
  }
1823
1824
  $editor_path = ckeditor_path('relative');
1825 6fd71452 Julien Enselme
  if ($editor_path == '<URL>')
1826
    $editor_path = ckeditor_path('url');
1827 85ad3d82 Assos Assos
  $module_drupal_path = ckeditor_module_path('relative');
1828
1829
  $html = "<!DOCTYPE html>";
1830
  $html .= "<html>";
1831
  $html .= "<head>";
1832
  $html .= '<title>CKEditor UI Color Picker</title>';
1833
  $html .= "<script type=\"text/javascript\" src=\"{$editor_path}/ckeditor.js\"></script>";
1834
  $html .= "</head>";
1835
  $html .= "<body>";
1836
  $html .= "<input type=\"hidden\" name=\"uicolor_user\"/>";
1837
  $html .= "<div id=\"editor\" style=\"height: 200px;\">Click the <strong>UI Color Picker</strong> button to set your color preferences.</div>";
1838
  $html .= "<script type=\"text/javascript\">
1839
var skin = window.location.search.match(/skin=([^&]*)/)[1];
1840
var uicolor = window.location.search.match(/uicolor=([^&]*)/)[1];
1841
var ckeditorUiColorOnChange = function() {
1842
  var color = CKEDITOR.instances['editor'].getUiColor();
1843
  if (typeof(color) != 'undefined') {
1844
    document.getElementsByName('uicolor_user').value = parent.document.getElementsByName('uicolor_user')[0].value = color;
1845
    var edit_uicolor = parent.document.getElementById('edit-uicolor');
1846
    for (i=0; i<edit_uicolor.options.length; i++) {
1847
      if (edit_uicolor[i].value == 'custom') {
1848
        edit_uicolor.selectedIndex = i;
1849
        edit_uicolor[i].selected = 'selected';
1850
        break;
1851
      }
1852
    }
1853
  }
1854
};
1855
CKEDITOR.on('dialogDefinition', function( ev ) {
1856
  var dialogName = ev.data.name;
1857
  var dialogDefinition = ev.data.definition;
1858
1859
  if (dialogName == 'uicolor') {
1860
    dialogDefinition.getContents('tab1').get('configBox').style = 'display:none';
1861
  }
1862
});
1863
CKEDITOR.replace('editor', {
1864
  extraPlugins : 'uicolor',
1865 6fd71452 Julien Enselme
  height: 330,
1866 85ad3d82 Assos Assos
  uiColor: '#' + uicolor,
1867
  toolbar : [[ 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList'],[ 'UIColor' ]],
1868
  skin: skin,
1869
  on: {
1870
    configLoaded: function(ev) {
1871
      var ckeditor_ver = CKEDITOR.version.split('.')[0];
1872
      if (ckeditor_ver == 3) {
1873
        if (skin != 'kama') {
1874
          ev.editor.config.toolbar = [[ 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList']];
1875
        }
1876
      }
1877
      else {
1878
        CKEDITOR.plugins.addExternal('uicolor', '{$module_drupal_path}/includes/uicolor/', 'plugin.js');
1879
        if (uicolor.length == 0 || uicolor == 'default') {
1880
          delete ev.editor.config.uiColor;
1881
        }
1882
      }
1883
    },
1884
    blur: ckeditorUiColorOnChange,
1885
    focus: ckeditorUiColorOnChange
1886
  }
1887
});
1888
</script>";
1889
  $html .= "</body>";
1890
  $html .= "</html>";
1891
  echo $html;
1892
}