Projet

Général

Profil

Paste
Télécharger (79,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ckeditor / includes / ckeditor.admin.inc @ 5a7e6170

1
<?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
  if (!_ckeditor_requirements_isinstalled()) {
48
    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
    $access_ckeditor_roles = user_roles(FALSE, 'access ckeditor');
103
    $header = array(t('Profile'), t('Input format'), t('Operations'));
104
    $plugins = ckeditor_load_plugins();
105
    $disabled_plugins = array();
106
    foreach ($profiles as $p) {
107
      if ($p->name !== "CKEditor Global Profile") {
108
        if (isset($p->settings['loadPlugins']) && is_array($p->settings['loadPlugins']) && count($p->settings['loadPlugins']) > 0) {
109
          $changed = FALSE;
110
          foreach ($p->settings['loadPlugins'] as $plugin_name => $plugin_settings) {
111
            if (!array_key_exists($plugin_name, $plugins)) {
112
              if (isset($plugin_settings['active']) && $plugin_settings['active'] == 0) {
113
                continue;
114
              }
115
              if (!isset($disabled_plugins[$p->name])) {
116
                $disabled_plugins[$p->name] = array();
117
              }
118
              $p->settings['loadPlugins'][$plugin_name]['active'] = 0;
119
              $disabled_plugins[$p->name][] = $plugin_name;
120
              $changed = TRUE;
121
            }
122
          }
123
          if ($changed === TRUE) {
124
            db_update('ckeditor_settings')
125
                ->fields(array(
126
                  'settings' => serialize($p->settings)
127
                ))
128
                ->condition('name', $p->name, '=')
129
                ->execute();
130
          }
131
        }
132
        $rows[] = array(
133
          array('data' => $p->name, 'valign' => 'top'),
134
          array('data' => implode("<br />\n", $p->input_formats)),
135
          array(
136
            'data' =>
137
            l(t('edit'), 'admin/config/content/ckeditor/edit/' . urlencode($p->name)) . ' ' .
138
            l(t('clone'), 'admin/config/content/ckeditor/clone/' . urlencode($p->name)) . ' ' .
139
            l(t('delete'), 'admin/config/content/ckeditor/delete/' . urlencode($p->name)),
140
            'valign' => 'top'
141
          )
142
        );
143
      }
144
    }
145

    
146
    if (count($disabled_plugins) > 0) {
147
      $msg = t("The following plugins could not be found and were automatically disabled in CKEditor profiles:");
148
      foreach ($disabled_plugins as $profile_name => $profile_plugins) {
149
        $msg .= "<br/><br/>";
150
        $msg .= t("<b>Profile</b>: %profile_name", array("%profile_name" => $profile_name));
151
        $msg .= "<br/>";
152
        $msg .= t("<b>Plugins</b>: %profile_plugins", array("%profile_plugins" => implode(', ', $profile_plugins)));
153
      }
154
      drupal_set_message($msg, 'warning');
155
    }
156

    
157
    $output .= '<h3>' . t('Profiles') . '</h3>';
158
    $output .= theme('table', array("header" => $header, "rows" => $rows));
159
    $output .= '<p>' . l(t('Create a new profile'), 'admin/config/content/ckeditor/add') . '</p>';
160
  }
161
  else {
162
    drupal_set_message(t(
163
            'No profiles found. Click here to !create.', array(
164
          '!create' => l(t('create a new profile'), 'admin/config/content/ckeditor/add')
165
            )
166
        ), 'warning');
167
  }
168

    
169
  $rows = array();
170
  if (!isset($profiles['CKEditor Global Profile'])) {
171
    drupal_set_message(t(
172
            'The global profile can not be found. Click here to !create.', array(
173
          '!create' => l(t('create the global profile'), 'admin/config/content/ckeditor/addg')
174
            )
175
        ), 'warning');
176
  }
177
  else {
178
    $output .= "<h3>" . t("Global settings") . "</h3>";
179
    $rows[] = array(
180
      array('data' => t('CKEditor Global Profile')),
181
      array('data' => l(t('edit'), 'admin/config/content/ckeditor/editg'), 'valign' => 'top')
182
    );
183
    $output .= theme('table', array("header" => array(t('Profile'), t('Operations')), "rows" => $rows));
184
  }
185
  return $output;
186
}
187

    
188
/**
189
 * Form builder for a global profile
190
 */
191
function ckeditor_admin_global_profile_form($form, $form_state, $mode = 'add') {
192
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
193
  if ($mode == 'edit') {
194
    $profile = ckeditor_profile_load('CKEditor Global Profile');
195

    
196
    $form['_profile'] = array(
197
      '#type' => 'value',
198
      '#value' => $profile,
199
    );
200
  }
201
  else {
202
    $profile = new stdClass();
203
  }
204

    
205
  if ($mode == 'add') {
206
    $data = ckeditor_profile_load('CKEditor Global Profile');
207
    if (!empty($data)) {
208
      drupal_set_message(t('The global profile already exists. Only one global profile is allowed.'), 'error');
209
      drupal_not_found();
210
    }
211

    
212
    $btn = t('Create a global profile');
213
  }
214
  else {
215
    $btn = t('Update the global profile');
216
  }
217

    
218
  $orig_formats = filter_formats();
219
  $formats = array();
220
  foreach ($orig_formats AS $format) {
221
    $formats[$format->format] = $format->name;
222
  }
223

    
224
  $drupal_base_path = ckeditor_base_path('relative');
225
  $drupal_library_path = ckeditor_library_path('relative');
226
  $module_drupal_path = ckeditor_module_path('relative');
227
  $skin_options = ckeditor_load_skin_options();
228

    
229
  $form['appearance'] = array(
230
    '#type' => 'fieldset',
231
    '#title' => t('Editor appearance'),
232
    '#collapsible' => TRUE,
233
    '#collapsed' => FALSE,
234
  );
235

    
236
  //if skin is not set or not exists select default skin (moono or skin) or first on the skin list
237
  if (empty($profile->settings['skin']) || (!empty($profile->settings['skin']) && !array_key_exists($profile->settings['skin'], $skin_options))) {
238
    $profile->settings['skin'] = ckeditor_default_skin();
239
  }
240

    
241
  $form['appearance']['skin'] = array(
242
    '#type' => 'select',
243
    '#title' => t('Skin'),
244
    '#default_value' => $profile->settings['skin'],
245
    '#options' => $skin_options,
246
    '#description' => t('Choose a CKEditor skin.'),
247
  );
248

    
249
  $form['ckeditor_advanced_settings'] = array(
250
    '#type' => 'fieldset',
251
    '#title' => t('Advanced settings'),
252
    '#collapsible' => TRUE,
253
    '#collapsed' => FALSE,
254
  );
255

    
256
  $form['ckeditor_advanced_settings']['ckeditor_path'] = array(
257
    '#type' => 'textfield',
258
    '#title' => t('Path to CKEditor'),
259
    '#default_value' => !empty($profile->settings['ckeditor_path']) ? $profile->settings['ckeditor_path'] : '%m/ckeditor',
260
    '#size' => 40,
261
    '#maxlength' => 128,
262
    '#description' => t(
263
        'The path to CKEditor (the WYSIWYG rich text editor downloaded from !ckeditorcom) relative to the document root.', array(
264
      '!ckeditorcom' => l(t('ckeditor.com'), 'http://ckeditor.com/download')
265
        )
266
    ) .
267
    '<br /> ' .
268
    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(
269
      '!b' => '<br /><code>%b</code>',
270
      '!m' => '<br /><code>%m</code>',
271
      '!l' => '<br /><code>%l</code>',
272
      '!base' => '<code>' . $drupal_base_path . '</code>',
273
      '!module' => '<code>' . $module_drupal_path . '</code>',
274
      '!library' => '<code>' . $drupal_library_path . '</code>',
275
        )
276
    ) .
277
    '<br /> ' .
278
    t('Current path: !path', array(
279
      '!path' => '<code>' . ckeditor_path('relative') . '</code>'
280
        )
281
    ),
282
    '#required' => TRUE
283
  );
284

    
285
  $form['ckeditor_advanced_settings']['ckeditor_local_path'] = array(
286
    '#type' => 'textfield',
287
    '#title' => t('Local path to CKEditor'),
288
    '#default_value' => isset($profile->settings['ckeditor_local_path']) ? $profile->settings['ckeditor_local_path'] : '',
289
    '#size' => 40,
290
    '#maxlength' => 128,
291
    '#description' => t(
292
        '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(
293
      '!indexphp' => '<code>index.php</code>'
294
        )
295
    ) .
296
    '<br /> ' .
297
    t('Current path: !path', array(
298
      '!path' => '<code>' . ckeditor_path('local') . '</code>'
299
        )
300
    )
301
  );
302

    
303
  $form['ckeditor_advanced_settings']['ckeditor_plugins_path'] = array(
304
    '#type' => 'textfield',
305
    '#title' => t('Path to the CKEditor plugins directory'),
306
    '#default_value' => !empty($profile->settings['ckeditor_plugins_path']) ? $profile->settings['ckeditor_plugins_path'] : '%m/plugins',
307
    '#size' => 40,
308
    '#maxlength' => 128,
309
    '#description' => t('Path to the CKEditor plugins directory relative to the document root.') .
310
    '<br />' .
311
    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(
312
      '!b' => '<br /><code>%b</code>',
313
      '!m' => '<br /><code>%m</code>',
314
      '!l' => '<br /><code>%l</code>',
315
      '!base' => '<code>' . $drupal_base_path . '</code>',
316
      '!module' => '<code>' . $module_drupal_path . '</code>',
317
      '!library' => '<code>' . $drupal_library_path . '</code>',
318
        )
319
    ) .
320
    '<br /> ' .
321
    t('Current path: !path', array(
322
      '!path' => '<code>' . ckeditor_plugins_path('relative') . '</code>'
323
        )
324
    )
325
  );
326

    
327
  $form['ckeditor_advanced_settings']['ckeditor_plugins_local_path'] = array(
328
    '#type' => 'textfield',
329
    '#title' => t('Local path to the CKEditor plugins directory'),
330
    '#default_value' => isset($profile->settings['ckeditor_plugins_local_path']) ? $profile->settings['ckeditor_plugins_local_path'] : '',
331
    '#size' => 40,
332
    '#maxlength' => 128,
333
    '#description' => t(
334
        '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(
335
      '!indexphp' => '<code>index.php</code>'
336
        )
337
    ) .
338
    '<br /> ' .
339
    t('Current path: !path', array(
340
      '!path' => '<code>' . ckeditor_plugins_path('local') . '</code>'
341
        )
342
    )
343
  );
344

    
345
  $form['ckeditor_advanced_settings']['ckfinder_path'] = array(
346
    '#type' => 'textfield',
347
    '#title' => t('Path to CKFinder'),
348
    '#default_value' => !empty($profile->settings['ckfinder_path']) ? $profile->settings['ckfinder_path'] : '%m/ckfinder',
349
    '#size' => 40,
350
    '#maxlength' => 128,
351
    '#description' => t(
352
        'The path to CKFinder (AJAX based file manager downloaded from !ckfindercom) relative to the document root.', array(
353
      '!ckfindercom' => l(t('ckfinder.com'), 'http://cksource.com/ckfinder')
354
        )
355
    ) .
356
    '<br />' .
357
    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(
358
      '!b' => '<br /><code>%b</code>',
359
      '!m' => '<br /><code>%m</code>',
360
      '!l' => '<br /><code>%l</code>',
361
      '!base' => '<code>' . $drupal_base_path . '</code>',
362
      '!module' => '<code>' . $module_drupal_path . '</code>',
363
      '!library' => '<code>' . $drupal_library_path . '</code>'
364
        )
365
    ) .
366
    '<br /> ' .
367
    t('Current path: !path', array(
368
      '!path' => '<code>' . ckfinder_path('relative') . '</code>'
369
        )
370
    )
371
  );
372

    
373
  $form['ckeditor_advanced_settings']['ckfinder_local_path'] = array(
374
    '#type' => 'textfield',
375
    '#title' => t('Local path to CKFinder'),
376
    '#default_value' => isset($profile->settings['ckfinder_local_path']) ? $profile->settings['ckfinder_local_path'] : '',
377
    '#size' => 40,
378
    '#maxlength' => 128,
379
    '#description' => t(
380
        '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(
381
      '!indexphp' => '<code>index.php</code>'
382
        )
383
    ) .
384
    '<br /> ' .
385
    t('Current path: !path', array(
386
      '!path' => '<code>' . ckfinder_path('local') . '</code>'
387
        )
388
    )
389
  );
390

    
391
  //@todo DOWNLOAD API
392
  if (variable_get('file_default_scheme', '') == 'private') {
393
    $form['ckeditor_advanced_settings']['ckeditor_allow_download_private_files'] = array(
394
      '#type' => 'checkbox',
395
      '#title' => t('Enable access to files located in the private folder'),
396
      '#default_value' => !empty($profile->settings['ckeditor_allow_download_private_files']),
397
      '#return_value' => 't',
398
      '#description' => t(
399
          '<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(
400
        '!private_path' => '<code>' . variable_get('file_private_path', '') . '</code>'
401
          )
402
      ),
403
      '#required' => FALSE
404
    );
405
    $current_private_dir = !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '';
406
    $form['ckeditor_advanced_settings']['private_dir'] = array(
407
      '#type' => 'textfield',
408
      '#title' => t('Location of files uploaded with CKEditor to the private folder'),
409
      '#default_value' => !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '',
410
      '#size' => 40,
411
      '#maxlength' => 255,
412
      '#description' => t('The path relative to the location of the private directory where CKEditor should store uploaded files.') .
413
      '<br />' .
414
      t('Available wildcard characters:!u &ndash; User ID.!n &ndash; Username', array(
415
        '!u' => '<br/><code>%u</code>',
416
        '!n' => '<br /><code>%n</code>'
417
          )
418
      ) .
419
      '<br />' .
420
      t('System path to the private folder is: !system_path.', array(
421
        '!system_path' => '<code>' . realpath(variable_get('file_private_path', conf_path() . '/files')) . DIRECTORY_SEPARATOR . '</code>'
422
          )
423
      )
424
    );
425
  }
426

    
427
  if (function_exists('linktocontent_node_menu') && function_exists('pathfilter_filter')) {
428
    $form['ckeditor_advanced_settings']['linktoc'] = array(
429
      '#type' => 'select',
430
      '#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')),
431
      '#title' => t('Path Filter & Link To Content integration'),
432
      '#default_value' => empty($profile->settings['linktoc']) ? 'p' : $profile->settings['linktoc'],
433
      '#description' => t(
434
          'With the !plink extension it is possible to use internal: links. By default the !link extension is linking to nodes using paths.', array(
435
        '!plink' => l(t('Path Filter'), 'http://drupal.org/project/pathfilter'),
436
        '!link' => l(t('Link To Content'), 'http://drupal.org/project/linktocontent')
437
          )
438
      )
439
    );
440
  }
441

    
442
  $form['ckeditor_advanced_settings']['ckeditor_aggregate'] = array(
443
    '#type' => 'radios',
444
    '#title' => t('Aggregate <code>ckeditor.js</code>'),
445
    '#default_value' => !empty($profile->settings['ckeditor_aggregate']) ? $profile->settings['ckeditor_aggregate'] : 'f',
446
    '#options' => array(
447
      't' => t('Enabled'),
448
      'f' => t('Disabled')
449
    ),
450
    '#description' => t('When enabled, <code>ckeditor.js</code> will be aggregated if JavaScript aggregation is enabled. <strong>Not recommended</strong>.'),
451
  );
452

    
453
  $form['ckeditor_advanced_settings']['toolbar_wizard'] = array(
454
    '#type' => 'radios',
455
    '#title' => t('Use toolbar Drag&Drop feature'),
456
    '#default_value' => !empty($profile->settings['toolbar_wizard']) ? $profile->settings['toolbar_wizard'] : 't',
457
    '#options' => array(
458
      't' => t('Enabled'),
459
      'f' => t('Disabled')
460
    ),
461
    '#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.'),
462
  );
463

    
464
  $form['submit'] = array(
465
    '#type' => 'submit',
466
    '#value' => $btn
467
  );
468

    
469
  return $form;
470
}
471

    
472
/**
473
 * Form validation for a global profile
474
 */
475
function ckeditor_admin_global_profile_form_validate($form, &$form_state) {
476

    
477
}
478

    
479
/**
480
 * Submit form for a global profile
481
 */
482
function ckeditor_admin_global_profile_form_submit($form, &$form_state) {
483
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
484
  $edit = & $form_state['values'];
485
  $edit['name'] = 'CKEditor Global Profile';
486

    
487
  if (isset($edit['_profile'])) {
488
    ckeditor_profile_delete($edit['_profile']->name);
489
  }
490

    
491
  //strip whitespaces
492
  if (empty($edit['ckeditor_local_path'])) {
493
    $edit['ckeditor_local_path'] = '';
494
  }
495
  else {
496
    $edit['ckeditor_local_path'] = trim($edit['ckeditor_local_path']);
497
  }
498

    
499
  //strip slash from the end
500
  if (empty($edit['ckeditor_path'])) {
501
    $edit['ckeditor_path'] = '';
502
  }
503
  $edit['ckeditor_path'] = trim(rtrim($edit['ckeditor_path'], "/"));
504
  if ($edit['ckeditor_path'] && 0 !== strpos($edit['ckeditor_path'], "/") && 0 !== strpos($edit['ckeditor_path'], "%")) {
505
    //ensure that slash is at the beginning
506
    $edit['ckeditor_path'] = "/" . $edit['ckeditor_path'];
507
  }
508
  //no slash at the end
509
  $edit['ckeditor_local_path'] = trim(rtrim($edit['ckeditor_local_path'], "/"));
510

    
511
  //strip whitespaces
512
  if (empty($edit['ckeditor_plugins_local_path'])) {
513
    $edit['ckeditor_plugins_local_path'] = '';
514
  }
515
  else {
516
    $edit['ckeditor_plugins_local_path'] = trim($edit['ckeditor_plugins_local_path']);
517
  }
518

    
519
  //strip slash from the end
520
  if (empty($edit['ckeditor_plugins_path'])) {
521
    $edit['ckeditor_plugins_path'] = '';
522
  }
523
  $edit['ckeditor_plugins_path'] = trim(rtrim($edit['ckeditor_plugins_path'], "/"));
524
  if ($edit['ckeditor_plugins_path'] && 0 !== strpos($edit['ckeditor_plugins_path'], "/") && 0 !== strpos($edit['ckeditor_plugins_path'], "%")) {
525
    //ensure that slash is at the beginning
526
    $edit['ckeditor_plugins_path'] = "/" . $edit['ckeditor_plugins_path'];
527
  }
528
  //no slash at the end
529
  $edit['ckeditor_plugins_path'] = trim(rtrim($edit['ckeditor_plugins_path'], "/"));
530

    
531
  //strip slash from the end
532
  if (empty($edit['ckfinder_path'])) {
533
    $edit['ckfinder_path'] = '';
534
  }
535
  $edit['ckfinder_path'] = trim(rtrim($edit['ckfinder_path'], "/"));
536
  if ($edit['ckfinder_path'] && 0 !== strpos($edit['ckfinder_path'], "/") && 0 !== strpos($edit['ckfinder_path'], "%")) {
537
    //ensure that slash is at the beginning
538
    $edit['ckfinder_path'] = "/" . $edit['ckfinder_path'];
539
  }
540

    
541
  //no slash at the end
542
  $edit['ckfinder_local_path'] = trim(rtrim($edit['ckfinder_local_path'], "/"));
543

    
544
  $settings = ckeditor_admin_values_to_settings($edit);
545
  db_insert('ckeditor_settings')
546
      ->fields(array(
547
        "name" => $edit["name"],
548
        "settings" => $settings
549
      ))
550
      ->execute();
551

    
552
  drupal_set_message(t('The CKEditor global profile was saved.'));
553
  $form_state['redirect'] = 'admin/config/content/ckeditor';
554
}
555

    
556
/**
557
 * Form builder for a profile
558
 */
559
function ckeditor_admin_profile_form($form, $form_state, $profile = NULL) {
560
  global $theme;
561

    
562
  if ($profile != NULL) {
563
    $form['_profile'] = array(
564
      '#type' => 'value',
565
      '#value' => $profile,
566
    );
567
  }
568
  else {
569
    $profile = new stdClass();
570
  }
571

    
572
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
573

    
574
  $editor_path = ckeditor_path('relative');
575
  $editor_local_path = ckeditor_path('local');
576
  $editor_url_path = ckeditor_path('url');
577
  $module_drupal_path = ckeditor_module_path('relative');
578
  $module_drupal_url_path = ckeditor_module_path('url');
579

    
580
  drupal_add_js(array('ckeditor_version' => ckeditor_get_version()), 'setting');
581

    
582
  $lang_options = ckeditor_load_lang_options();
583

    
584
  $form['basic'] = array(
585
    '#type' => 'fieldset',
586
    '#title' => t('Basic setup'),
587
    '#collapsible' => TRUE,
588
    '#collapsed' => TRUE
589
  );
590

    
591
  switch (arg(4)) {
592
    case 'clone':
593
      //load all profiles to check their names
594
      $profiles = ckeditor_profile_load();
595
      $oldname = $profile->name;
596
      $maxsize = 128;   //default max name length
597

    
598
      $res = array();
599
      $pat = "/^(.*?)_([0-9]+)$/";
600
      if (preg_match($pat, $oldname, $res)) {     // oldname like 'name_nr'
601
        $name = $res[1];
602
        $num = $res[2] + 1;
603
      }
604
      else {
605
        $name = $oldname;
606
        $num = 2;
607
      }
608

    
609
      $newname = substr($name, 0, $maxsize - 3) . '_' . $num;   // +limit
610
      while (isset($profiles[$newname])) {            //find next free number
611
        $num++;
612
        $newname = substr($name, 0, $maxsize - 3) . '_' . $num;
613
      }
614
      break;
615
    case 'edit':
616
      $newname = $profile->name;
617
      break;
618
  }
619

    
620
  $global_profile = ckeditor_profile_load('CKEditor Global Profile');
621
  $toolbar_wizard = !empty($global_profile->settings['toolbar_wizard']) ? $global_profile->settings['toolbar_wizard'] : 't';
622
  drupal_add_js(array('ckeditor_toolbar_wizard' => $toolbar_wizard), 'setting');
623

    
624
  $form['basic']['name'] = array(
625
    '#type' => 'textfield',
626
    '#title' => t('Profile name'),
627
    '#default_value' => !empty($profile->name) ? $newname : '',
628
    '#size' => 40,
629
    '#maxlength' => 128,
630
    '#description' => t('Enter a name for this profile. This name is only visible within the CKEditor administration page.'),
631
    '#required' => TRUE
632
  );
633

    
634
  $orig_formats = filter_formats();
635

    
636
  if (arg(4) == 'edit' && !empty($profile->name)) {
637
    $used_formats = db_select('ckeditor_input_format', 'f')->fields('f', array("format"))->distinct()->condition("f.name", array($profile->name), 'NOT IN')->execute()->fetchAllAssoc('format');
638
  }
639
  else {
640
    $profile->input_formats = array();
641
    $used_formats = db_select('ckeditor_input_format', 'f')->fields('f', array("format"))->distinct()->execute()->fetchAllAssoc('format');
642
  }
643

    
644
  $formats = array();
645
  $input_format_config_links = array();
646
  foreach ($orig_formats AS $format) {
647
    if ((arg(4) == 'edit' && !empty($profile->input_formats) && array_key_exists($format->format, $profile->input_formats)) || !array_key_exists($format->format, $used_formats)) {
648
      $formats[$format->format] = $format->name;
649
      $input_format_config_links[$format->format] = array("name" => $format->name, "config_url" => url("admin/config/content/formats/" . $format->format));
650
    }
651
  }
652

    
653
  $form['basic']['input_formats'] = array(
654
    '#id' => 'input-formats',
655
    '#type' => 'checkboxes',
656
    '#title' => t('Text formats'),
657
    '#default_value' => !empty($profile->input_formats) ? array_keys((array) $profile->input_formats) : array(),
658
    '#options' => $formats,
659
    '#description' => t('Choose the text formats where you want to load CKEditor.')
660
  );
661

    
662
  $form['security'] = array(
663
    '#type' => 'fieldset',
664
    '#title' => t('Security'),
665
    '#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>',
666
    '#collapsible' => TRUE,
667
    '#collapsed' => TRUE
668
  );
669

    
670
  $form['security']['filters'] = array(
671
    '#id' => 'security-filters',
672
    '#type' => 'container'
673
  );
674

    
675
  $form['security']['filters']['__header'] = array(
676
    '#type' => 'item',
677
    '#title' => t('Security filters'),
678
    '#description' => t(
679
      '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(
680
      '!img_enabled' => '</br><img src="' . $module_drupal_path . '/images/tick.png"/>',
681
      '!img_disabled' => '</br><img src="' . $module_drupal_path . '/images/delete.png"/>',
682
      '!elem_format_config' => '<ul class="text-formats-config"></ul>'
683
        )
684
    ),
685
    '#weight' => -10
686
  );
687

    
688
  //get text formats filters
689
  $input_format_filters = array();
690
  foreach ($formats AS $key => $value) {
691
    $input_format_filters[$key] = array();
692
    $filters = filter_list_format($key);
693
    foreach ($filters as $filter_name => $filter_settings) {
694
      if ($filter_settings->status == 1) {
695
        $input_format_filters[$key][$filter_name] = TRUE;
696
      }
697
    }
698
  }
699
  drupal_add_js(array('text_format_filters' => $input_format_filters, 'text_formats_config_links' => $input_format_config_links), 'setting');
700

    
701
  $security_filters = ckeditor_security_filters();
702
  _ckeditor_admin_profile_form_security_filters($form, $profile, $security_filters);
703

    
704
  $form['security']['ss'] = array(
705
    '#type' => 'radios',
706
    '#title' => t('Security settings'),
707
    '#default_value' => isset($profile->settings['ss']) ? $profile->settings['ss'] : '2',
708
    '#options' => array(
709
      '2' => t('Always run security filters for CKEditor.'),
710
      '1' => t('Run security filters only when CKEditor is set to start automatically.'),
711
    ),
712
    '#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.'),
713
  );
714

    
715
  $form['appearance'] = array(
716
    '#type' => 'fieldset',
717
    '#title' => t('Editor appearance'),
718
    '#collapsible' => TRUE,
719
    '#collapsed' => TRUE,
720
  );
721

    
722
  $form['appearance']['default'] = array(
723
    '#type' => 'radios',
724
    '#title' => t('Default state'),
725
    '#default_value' => !empty($profile->settings['default']) ? $profile->settings['default'] : 't',
726
    '#options' => array(
727
      't' => t('Enabled'),
728
      'f' => t('Disabled')
729
    ),
730
    '#description' => t('Default editor state. If disabled, the rich text editor may still be enabled by using toggle.'),
731
  );
732

    
733
  $form['appearance']['show_toggle'] = array(
734
    '#type' => 'radios',
735
    '#title' => t('Show the disable/enable rich text editor toggle'),
736
    '#default_value' => !empty($profile->settings['show_toggle']) ? $profile->settings['show_toggle'] : 't',
737
    '#options' => array(
738
      't' => t('Show'),
739
      'f' => t('Hide')
740
    ),
741
    '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea.'),
742
  );
743

    
744
  $ui_colors = array(
745
    "default" => t('CKEditor default'),
746
    "custom" => t('Select manually')
747
  );
748
  if (function_exists('color_get_palette')) {
749
    // apparently $theme is not initialized (?)
750
    if (empty($theme)) {
751
      init_theme();
752
    }
753
    $palette = @color_get_palette($theme, FALSE); //[#652274]
754
    $color_palette['default'] = '#D3D3D3';
755
    if (!empty($palette)) {
756
      if (!empty($palette['base'])) {
757
        $color_palette['color_base'] = $palette['base'];
758
        $ui_colors["color_base"] = t('Color module: base');
759
      }
760
      if (!empty($palette['top'])) {
761
        $color_palette['color_top'] = $palette['top'];
762
        $ui_colors["color_top"] = t('Color module: top');
763
      }
764
      if (!empty($palette['bottom'])) {
765
        $color_palette['color_bottom'] = $palette['bottom'];
766
        $ui_colors["color_bottom"] = t('Color module: bottom');
767
      }
768
    }
769
    drupal_add_js(array('ckeditor_uicolor' => $color_palette), 'setting');
770
  }
771

    
772
  drupal_add_js('window.CKEDITOR_BASEPATH = "' . $editor_path . '/"', array('type' => 'inline', 'weight' => -100));
773
  drupal_add_js($editor_url_path . '/ckeditor.js', array('type' => 'file', 'preprocess' => FALSE));
774
  drupal_add_js($module_drupal_url_path . '/ckeditor.config.js', 'file');
775
  drupal_add_js($module_drupal_url_path . '/includes/ckeditor.admin.js', 'file');
776

    
777
  if ($toolbar_wizard == 't') {
778
    if (module_exists('jquery_ui')) {
779
      jquery_ui_add(array('jquery.ui.widget.min.js', 'jquery.ui.sortable.min.js'));
780
    }
781
    else {
782
      drupal_add_js($module_drupal_url_path . '/includes/jqueryUI/jquery-ui.min.js', 'file');
783
      drupal_add_js($module_drupal_url_path . '/includes/jqueryUI/jquery.ui.widget.min.js', 'file');
784
      drupal_add_js($module_drupal_url_path . '/includes/jqueryUI/jquery.ui.sortable.min.js', 'file');
785
    }
786
    drupal_add_js($module_drupal_url_path . '/includes/jqueryUI/sort.js', 'file');
787
  }
788

    
789
  $form['appearance']['uicolor'] = array(
790
    '#type' => 'select',
791
    '#title' => t('User interface color'),
792
    '#default_value' => !empty($profile->settings['uicolor']) ? $profile->settings['uicolor'] : 'default',
793
    '#options' => $ui_colors,
794
  );
795

    
796
  if (!isset($global_profile->settings['skin']) || !file_exists($editor_local_path . '/skins/' . $global_profile->settings['skin'])) {
797
    $global_profile->settings['skin'] = ckeditor_default_skin();
798
  }
799
  $skinframe_url = url('admin/config/content/ckeditor/skinframe', array(
800
    'query' => array(
801
      'token' => drupal_get_token('ckeditorSkinframeCall'),
802
      'skin' => $global_profile->settings['skin'],
803
      'uicolor' => (!empty($profile->settings['uicolor_user']) && $profile->settings['uicolor'] == 'custom') ? ltrim($profile->settings['uicolor_user'], '#') : 'D3D3D3'
804
    )
805
  ));
806
  $form['appearance']['skinframe'] = array(
807
    '#markup' => '<iframe frameborder="0" id="skinframe" marginheight="0" marginwidth="0" src="' . $skinframe_url . '" style="height:500px;width:700px;"></iframe><br/>',
808
    '#description' => '',
809
  );
810
  $form['appearance']['uicolor_user'] = array(
811
    '#type' => 'hidden',
812
    '#default_value' => !empty($profile->settings['uicolor_user']) ? $profile->settings['uicolor_user'] : 'default',
813
  );
814

    
815
  $form['appearance']['toolbar'] = array(
816
    '#type' => 'textarea',
817
    '#title' => t('Toolbar'),
818
    '#default_value' => !empty($profile->settings['toolbar']) ? $profile->settings['toolbar'] : '',
819
    '#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>')),
820
    '#wysiwyg' => FALSE,
821
    '#rows' => 15
822
  );
823

    
824
  if ($toolbar_wizard == 't') {
825
    $form['appearance']['toolbar_wizzard_used'] = array(
826
      '#markup' => '<div>' . t('Used buttons') . '</div><div class="sortableList" id="groupLayout"></div><br/>',
827
      '#description' => t('Currently used buttons'),
828
    );
829

    
830
    drupal_add_js(array('cke_toolbar_buttons_all' => ckeditor_toolbar_buttons_all()), 'setting');
831

    
832
    $form['appearance']['toolbar_wizzard_all'] = array(
833
      '#markup' => '<div>' . t('All buttons') . '</div><div id="allButtons" class="sortableList"></div><br/>',
834
      '#description' => t('All available buttons'),
835
    );
836
  }
837

    
838
  $plugin_list = ckeditor_load_plugins();
839
  $plugins = array();
840
  if (isset($profile->settings['loadPlugins'])) {
841
    foreach ($plugin_list AS $key => $val) {
842
      $plugins[$key] = $val['desc'];
843
    }
844
  }
845
  else {
846
    $default_plugins = array();
847
    foreach ($plugin_list AS $key => $val) {
848
      $plugins[$key] = $val['desc'];
849
      if (isset($val['default']) && $val['default'] == 't') {
850
        $default_plugins[] = $key;
851
      }
852
    }
853
  }
854

    
855
  $form['appearance']['loadPlugins'] = array(
856
    '#type' => 'checkboxes',
857
    '#title' => t('Plugins'),
858
    '#default_value' => isset($profile->settings['loadPlugins']) ? array_keys((array) $profile->settings['loadPlugins']) : $default_plugins,
859
    '#options' => $plugins,
860
    '#description' => t('Choose the plugins that you want to enable in CKEditor.')
861
  );
862

    
863
  $form['appearance']['expand'] = array(
864
    '#type' => 'radios',
865
    '#title' => t('Toolbar state on startup'),
866
    '#default_value' => !empty($profile->settings['expand']) ? $profile->settings['expand'] : 't',
867
    '#options' => array(
868
      't' => t('Expanded'),
869
      'f' => t('Collapsed')
870
    ),
871
    '#description' => t('The toolbar will start in an expanded or collapsed state.'),
872
  );
873

    
874
  if (file_exists(ckeditor_path('local') . '/plugins/divarea/plugin.js')) {
875
    $form['appearance']['use_divarea'] = array(
876
      '#type' => 'radios',
877
      '#title' => t('"Div-based" editor'),
878
      '#default_value' => !empty($profile->settings['use_divarea']) ? $profile->settings['use_divarea'] : 'f',
879
      '#options' => array(
880
        't' => t('Enabled'),
881
        'f' => t('Disabled')
882
      ),
883
      '#description' => t("Loading editor into <code>div</code> instead of <code>iframe</code>.")
884
    );
885
  }
886

    
887
  $form['appearance']['width'] = array(
888
    '#type' => 'textfield',
889
    '#title' => t('Editor width'),
890
    '#default_value' => !empty($profile->settings['width']) ? $profile->settings['width'] : '100%',
891
    '#description' => t("Editor interface width in pixels or percent. Examples: 400, 100%."),
892
    '#size' => 40,
893
    '#maxlength' => 128,
894
  );
895

    
896
  $form['appearance']['lang'] = array(
897
    '#type' => 'select',
898
    '#title' => t('Language'),
899
    '#default_value' => !empty($profile->settings['lang']) ? $profile->settings['lang'] : 'en',
900
    '#options' => $lang_options,
901
    '#description' => t('The language for the CKEditor user interface.')
902
  );
903

    
904
  $form['appearance']['auto_lang'] = array(
905
    '#type' => 'radios',
906
    '#title' => t('Auto-detect language'),
907
    '#default_value' => !empty($profile->settings['auto_lang']) ? $profile->settings['auto_lang'] : 't',
908
    '#options' => array(
909
      't' => t('Enabled'),
910
      'f' => t('Disabled')
911
    ),
912
    '#description' => t('Automatically detect the user language.')
913
  );
914

    
915
  $form['appearance']['language_direction'] = array(
916
    '#type' => 'select',
917
    '#title' => t('Language direction'),
918
    '#default_value' => !empty($profile->settings['language_direction']) ? $profile->settings['language_direction'] : 'default',
919
    '#options' => array(
920
      'default' => t('Get from current locale (default)'),
921
      'ltr' => t('Left-To-Right'), // language like English
922
      'rtl' => t('Right-To-Left') // languages like Arabic
923
    ),
924
    '#description' => t(
925
        '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(
926
      '!bidiltr' => 'BidiLtr',
927
      '!bidirtl' => 'BidiRtl'
928
        )
929
    )
930
  );
931

    
932
  $form['output'] = array(
933
    '#type' => 'fieldset',
934
    '#title' => t('Cleanup and output'),
935
    '#collapsible' => TRUE,
936
    '#collapsed' => TRUE,
937
  );
938

    
939
  $form['output']['enter_mode'] = array(
940
    '#type' => 'select',
941
    '#title' => t('Enter mode'),
942
    '#default_value' => !empty($profile->settings['enter_mode']) ? $profile->settings['enter_mode'] : 'p',
943
    '#options' => array(
944
      'p' => '<p>',
945
      'br' => '<br>',
946
      'div' => '<div>'
947
    ),
948
    '#description' => t('Set which tag should be used by CKEditor when the <em>Enter</em> key is pressed.')
949
  );
950

    
951
  $form['output']['shift_enter_mode'] = array(
952
    '#type' => 'select',
953
    '#title' => t('Shift+Enter mode'),
954
    '#default_value' => !empty($profile->settings['shift_enter_mode']) ? $profile->settings['shift_enter_mode'] : 'br',
955
    '#options' => array(
956
      'p' => '<p>',
957
      'br' => '<br>',
958
      'div' => '<div>'
959
    ),
960
    '#description' => t('Set which tag should be used by CKEditor when the <em>Shift+Enter</em> key combination is pressed.')
961
  );
962

    
963
  $form['output']['font_format'] = array(
964
    '#type' => 'textfield',
965
    '#title' => t('Font formats'),
966
    '#default_value' => !empty($profile->settings['font_format']) ? $profile->settings['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6',
967
    '#size' => 40,
968
    '#maxlength' => 250,
969
    '#description' => t(
970
        'Semicolon-separated list of HTML font formats. Allowed values are: !allowed_values', array(
971
      '!allowed_values' => '<code>p;div;pre;address;h1;h2;h3;h4;h5;h6</code>'
972
        )
973
    )
974
  );
975

    
976
  if (!empty($profile->settings['formatting']['custom_formatting_options'])) {
977
    foreach ($profile->settings['formatting']['custom_formatting_options'] as $k => $v) {
978
      if ($v === 0) {
979
        unset($profile->settings['formatting']['custom_formatting_options'][$k]);
980
      }
981
    }
982
  }
983

    
984
  $form['output']['custom_formatting'] = array(
985
    '#type' => 'radios',
986
    '#title' => t('Use custom formatting options'),
987
    '#default_value' => !empty($profile->settings['custom_formatting']) ? $profile->settings['custom_formatting'] : 'f',
988
    '#options' => array(
989
      't' => t('Yes'),
990
      'f' => t('No'),
991
    ),
992
  );
993

    
994
  $form['output']['formatting'] = array(
995
    '#type' => 'fieldset',
996
    '#title' => t('Custom formatting options'),
997
    '#tree' => TRUE,
998
  );
999

    
1000
  $form['output']['formatting']['custom_formatting_options'] = array(
1001
    '#type' => 'checkboxes',
1002
    '#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'),
1003
    '#options' => array(
1004
      'indent' => t('Indent the element contents.'),
1005
      'breakBeforeOpen' => t('Break line before the opening tag.'),
1006
      'breakAfterOpen' => t('Break line after the opening tag.'),
1007
      'breakBeforeClose' => t('Break line before the closing tag.'),
1008
      'breakAfterClose' => t('Break line after the closing tag.'),
1009
      'pre_indent' => t('Indent the <code>&lt;pre&gt;</code> element contents.'),
1010
    ),
1011
  );
1012

    
1013
  $form['css'] = array(
1014
    '#type' => 'fieldset',
1015
    '#title' => t('CSS'),
1016
    '#collapsible' => TRUE,
1017
    '#collapsed' => TRUE
1018
  );
1019

    
1020
  $form['css']['css_mode'] = array(
1021
    '#type' => 'select',
1022
    '#title' => t('Editor CSS'),
1023
    '#default_value' => !empty($profile->settings['css_mode']) ? $profile->settings['css_mode'] : 'theme',
1024
    '#options' => array(
1025
      'theme' => t('Use theme CSS'),
1026
      'self' => t('Define CSS'),
1027
      'none' => t('CKEditor default')
1028
    ),
1029
    '#description' => t(
1030
        '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(
1031
      '!title_theme_css' => '<br /><strong>' . t('Use theme CSS') . '</strong>',
1032
      '!title_define_css' => '<br /><strong>' . t('Define CSS') . '</strong>',
1033
      '!title_ckeditor_default' => '<br /><strong>' . t('CKEditor default') . '</strong>',
1034
      '!style_css' => '<code>style.css</code>'
1035
        )
1036
    )
1037
  );
1038

    
1039
  $form['css']['css_path'] = array(
1040
    '#type' => 'textfield',
1041
    '#title' => t('CSS file path'),
1042
    '#default_value' => !empty($profile->settings['css_path']) ? $profile->settings['css_path'] : "",
1043
    '#size' => 40,
1044
    '#maxlength' => 255,
1045
    '#description' => t(
1046
        '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(
1047
      '!example1' => '<code>"css/editor.css"</code>',
1048
      '!example2' => '<code>"/themes/garland/style.css,http://example.com/style.css"</code>',
1049
      '!title_define_css' => '<strong>' . t('Define CSS') . '</strong>'
1050
        )
1051
    ) .
1052
    '<br />' .
1053
    t('Available placeholders:!h &ndash; host name (!host).!t &ndash; path to theme (!theme).', array(
1054
      '!h' => '<br /><code>%h</code>',
1055
      '!t' => '<br /><code>%t</code>',
1056
      '!host' => '<code>' . base_path() . '</code>',
1057
      '!theme' => '<code>' . base_path() . path_to_theme() . '/</code>'
1058
        )
1059
    )
1060
  );
1061

    
1062
  $form['css']['css_style'] = array(
1063
    '#type' => 'select',
1064
    '#title' => t('Predefined styles'),
1065
    '#default_value' => !empty($profile->settings['css_style']) ? $profile->settings['css_style'] : 'theme',
1066
    '#options' => array(
1067
      'theme' => t('Use theme ckeditor.styles.js'),
1068
      'self' => t('Define path to ckeditor.styles.js'),
1069
      'default' => t('CKEditor default')
1070
    ),
1071
    '#description' => t(
1072
        '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(
1073
      '!ckeditor_styles_js_file' => '<code>ckeditor.styles.js</code>',
1074
      '!ckeditor_styles_js_path' => '<code>' . drupal_get_path('module', 'ckeditor') . '/ckeditor.styles.js</code>',
1075
      '!theme' => '<code>' . path_to_theme() . '/ckeditor.styles.js' . '</code>'
1076
        )
1077
    )
1078
  );
1079

    
1080
  $form['css']['styles_path'] = array(
1081
    '#type' => 'textfield',
1082
    '#title' => t('Predefined styles path'),
1083
    '#default_value' => !empty($profile->settings['styles_path']) ? $profile->settings['styles_path'] : "",
1084
    '#size' => 40,
1085
    '#maxlength' => 255,
1086
    '#description' => t(
1087
        'Enter the path to a file with predefined styles (Example: !example1). Make sure you select the !style_define_path option above.', array(
1088
      '!style_define_path' => '<strong>' . t('Define path to ckeditor.styles.js') . '</strong>',
1089
      '!ckeditor_styles_js_file' => '<code>ckeditor.styles.js</code>',
1090
      '!example1' => '<code>/ckeditor.styles.js</code>'
1091
        )
1092
    ) .
1093
    '<br />' .
1094
    t('Available placeholders:!h &ndash; host name (!host).!t &ndash; path to theme (!theme).!m &ndash; path to the CKEditor module (!module).', array(
1095
      '!h' => '<br /><code>%h</code>',
1096
      '!t' => '<br /><code>%t</code>',
1097
      '!m' => '<br /><code>%m</code>',
1098
      '!host' => '<code>' . base_path() . '</code>',
1099
      '!theme' => '<code>' . base_path() . path_to_theme() . '/</code>',
1100
      '!module' => '<code>' . drupal_get_path('module', 'ckeditor') . '</code>'
1101
        )
1102
    )
1103
  );
1104

    
1105
  $form['ckeditor_upload_settings'] = array(
1106
    '#type' => 'fieldset',
1107
    '#title' => t('File browser settings'),
1108
    '#collapsible' => TRUE,
1109
    '#collapsed' => TRUE,
1110
    '#description' => t(
1111
        '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(
1112
      '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce'),
1113
      '!elfinder' => l(t('elFinder'), 'http://drupal.org/project/elfinder'),
1114
      '!ckfinder' => l(t('CKFinder'), 'http://cksource.com/ckfinder')
1115
        )
1116
    )
1117
  );
1118

    
1119
  $filebrowsers = array(
1120
    'none' => t('None'),
1121
    'ckfinder' => t('CKFinder'),
1122
  );
1123

    
1124
  $filebrowsers_dialogs = array(
1125
    '' => t('Same as in the Link dialog window'),
1126
    'ckfinder' => t('CKFinder'),
1127
  );
1128

    
1129
  if (module_exists('imce')) {
1130
    $filebrowsers['imce'] = t('IMCE');
1131
    $filebrowsers_dialogs['imce'] = t('IMCE');
1132
  }
1133

    
1134
  if (module_exists('elfinder')) {
1135
    $filebrowsers['elfinder'] = t('elFinder');
1136
    $filebrowsers_dialogs['elfinder'] = t('elFinder');
1137
  }
1138

    
1139
  /* MODULES NOT PORTED TO D7
1140
    if (module_exists('tinybrowser')) {
1141
    $filebrowsers['tinybrowser'] = t('TinyBrowser');
1142
    $filebrowsers_dialogs['tinybrowser'] = t('TinyBrowser');
1143
    }
1144

    
1145
    if (module_exists('imagebrowser')) {
1146
    $filebrowsers['ib'] = t('Image Browser');
1147
    $filebrowsers_dialogs['ib'] = t('Image Browser');
1148
    }
1149

    
1150
    if (module_exists('webfm_popup')) {
1151
    $filebrowsers['webfm'] = t('Web File Manager');
1152
    $filebrowsers_dialogs['webfm'] = t('Web File Manager');
1153
    }
1154
   */
1155
  $form['ckeditor_upload_settings']['filebrowser'] = array(
1156
    '#type' => 'select',
1157
    '#title' => t('File browser type (Link dialog window)'),
1158
    '#default_value' => !empty($profile->settings['filebrowser']) ? $profile->settings['filebrowser'] : 'none',
1159
    '#options' => $filebrowsers,
1160
    '#description' => t('Select the file browser that you would like to use to upload files.'),
1161
  );
1162

    
1163
  $form['ckeditor_upload_settings']['filebrowser_image'] = array(
1164
    '#type' => 'select',
1165
    '#title' => t('File browser type (Image dialog window)'),
1166
    '#default_value' => !empty($profile->settings['filebrowser_image']) ? $profile->settings['filebrowser_image'] : 'none',
1167
    '#options' => $filebrowsers_dialogs,
1168
    '#description' => t('Select the file browser that you would like to use to upload images.'),
1169
  );
1170

    
1171
  $form['ckeditor_upload_settings']['filebrowser_flash'] = array(
1172
    '#type' => 'select',
1173
    '#title' => t('File browser type (Flash dialog window)'),
1174
    '#default_value' => !empty($profile->settings['filebrowser_flash']) ? $profile->settings['filebrowser_flash'] : 'none',
1175
    '#options' => $filebrowsers_dialogs,
1176
    '#description' => t('Select the file browser that you would like to use to upload Flash movies.'),
1177
  );
1178

    
1179
  if (variable_get('file_default_scheme', '') != 'private') {
1180
    $current_user_files_path = empty($profile->settings['UserFilesPath']) ? "%b%f/" : $profile->settings['UserFilesPath'];
1181
    $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"));
1182

    
1183
    $current_user_files_absolute_path = empty($profile->settings['UserFilesAbsolutePath']) ? "%d%b%f/" : $profile->settings['UserFilesAbsolutePath'];
1184
    $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"));
1185

    
1186

    
1187
    $form['ckeditor_upload_settings']['UserFilesPath'] = array(
1188
      '#type' => 'textfield',
1189
      '#prefix' => '<fieldset><legend>' . t('CKFinder settings') . '</legend>',
1190
      '#title' => t('Path to uploaded files'),
1191
      '#default_value' => !empty($profile->settings['UserFilesPath']) ? $profile->settings['UserFilesPath'] : "%b%f/",
1192
      '#size' => 40,
1193
      '#maxlength' => 255,
1194
      '#description' => t('Path to uploaded files relative to the document root.') .
1195
      '<br />' .
1196
      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(
1197
        '!n' => '<br /><code>%n</code>',
1198
        '!u' => '<br /><code>%u</code>',
1199
        '!f' => '<br/><code>%f</code>',
1200
        '!b' => '<br/><code>%b</code>',
1201
        '!files' => '<code>' . variable_get('file_public_path', conf_path() . '/files') . '</code>',
1202
        '!base' => '<code>' . base_path() . '</code>'
1203
          )
1204
      ) .
1205
      '<br />' .
1206
      t('Current path: !path', array(
1207
        '!path' => '<code>' . $current_user_files_path . '</code>'
1208
          )
1209
      )
1210
    );
1211

    
1212
    $form['ckeditor_upload_settings']['UserFilesAbsolutePath'] = array(
1213
      '#type' => 'textfield',
1214
      '#title' => t('Absolute path to uploaded files'),
1215
      '#default_value' => !empty($profile->settings['UserFilesAbsolutePath']) ? $profile->settings['UserFilesAbsolutePath'] : "%d%b%f/",
1216
      '#size' => 40,
1217
      '#maxlength' => 255,
1218
      '#suffix' => '</fieldset>',
1219
      '#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.') .
1220
      '<br />' .
1221
      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(
1222
        '!u' => '<br /><code>%u</code>',
1223
        '!n' => '<br /><code>%n</code>',
1224
        '!d' => '<br/><code>%d</code>',
1225
        '!b' => '<br /><code>%b</code>',
1226
        '!f' => '<br/><code>%f</code>',
1227
        '!files' => '<code>' . variable_get('file_public_path', conf_path() . '/files') . '</code>',
1228
        '!base' => '<code>' . base_path() . '</code>',
1229
        '!root' => '<code>' . ckeditor_get_document_root_full_path() . '</code>'
1230
          )
1231
      ) .
1232
      '<br />' .
1233
      t('Current path: !path', array(
1234
        '!path' => '<code>' . $current_user_files_absolute_path . '</code>'
1235
          )
1236
      )
1237
    );
1238
  }
1239
  if (variable_get('file_default_scheme', '') == 'private') {
1240
    $form['ckeditor_upload_settings']['private_path_descrption'] = array(
1241
      '#markup' => '<div>' . t(
1242
          '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(
1243
        '!url' => l(t('CKEditor Global Profile'), 'admin/config/content/ckeditor/editg')
1244
          )
1245
      ) . '</div>',
1246
    );
1247
  }
1248

    
1249
  $form['advanced'] = array(
1250
    '#type' => 'fieldset',
1251
    '#title' => t('Advanced options'),
1252
    '#collapsible' => TRUE,
1253
    '#collapsed' => TRUE,
1254
  );
1255
  if (ckeditor_get_version(TRUE) == 3) {
1256
    $form['advanced']['ckeditor_load_method'] = array(
1257
      '#type' => 'select',
1258
      '#title' => t('Loading method'),
1259
      '#default_value' => !empty($profile->settings['ckeditor_load_method']) ? $profile->settings['ckeditor_load_method'] : 'ckeditor.js',
1260
      '#options' => _ckeditor_load_methods(),
1261
      '#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(
1262
        '!ckeditor_basic_js' => '<code>ckeditor_basic.js</code>'
1263
          )
1264
      )
1265
    );
1266
    $form['advanced']['ckeditor_load_time_out'] = array(
1267
      '#type' => 'textfield',
1268
      '#title' => t('Loading timeout'),
1269
      '#default_value' => !empty($profile->settings['ckeditor_load_time_out']) ? $profile->settings['ckeditor_load_time_out'] : "0",
1270
      '#size' => 40,
1271
      '#maxlength' => 255,
1272
      '#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(
1273
        '!ckeditor_basic_js' => '<code>ckeditor_basic.js</code>'
1274
          )
1275
      )
1276
    );
1277
  }
1278

    
1279
  $form['advanced']['forcePasteAsPlainText'] = array(
1280
    '#type' => 'select',
1281
    '#title' => t('Force pasting as plain text'),
1282
    '#default_value' => !empty($profile->settings['forcePasteAsPlainText']) ? $profile->settings['forcePasteAsPlainText'] : "f",
1283
    '#options' => array(
1284
      't' => t('Enabled'),
1285
      'f' => t('Disabled')
1286
    ),
1287
    '#description' => t('If enabled, HTML content will be automatically changed to plain text when pasting.'),
1288
  );
1289
  $form['advanced']['html_entities'] = array(
1290
    '#type' => 'radios',
1291
    '#title' => t('HTML Entities'),
1292
    '#default_value' => !empty($profile->settings['html_entities']) ? $profile->settings['html_entities'] : 'f',
1293
    '#description' => t('Convert all applicable characters to HTML entities.'),
1294
    '#options' => array(
1295
      'f' => t('No'),
1296
      't' => t('Yes')
1297
    ),
1298
  );
1299
  $form['advanced']['scayt_autoStartup'] = array(
1300
    '#type' => 'radios',
1301
    '#title' => t('Spellchecker'),
1302
    '#default_value' => !empty($profile->settings['scayt_autoStartup']) ? $profile->settings['scayt_autoStartup'] : 'f',
1303
    '#description' => t('If enabled, turns on SCAYT (Spell Check As You Type) automatically after loading the editor.'),
1304
    '#options' => array(
1305
      'f' => t('No'),
1306
      't' => t('Yes')
1307
    ),
1308
  );
1309
  $form['advanced']['theme_config_js'] = array(
1310
    '#type' => 'radios',
1311
    '#title' => t('Load !ckeditor_config_js from the theme path', array(
1312
      '!ckeditor_config_js' => '<code>ckeditor.config.js</code>'
1313
        )
1314
    ),
1315
    '#default_value' => !empty($profile->settings['theme_config_js']) ? $profile->settings['theme_config_js'] : 'f',
1316
    '#options' => array(
1317
      't' => t('Yes'),
1318
      'f' => t('No')
1319
    ),
1320
    '#description' => t('When enabled, the editor will try to load the !ckeditor_config_js file from the theme directory.', array(
1321
      '!ckeditor_config_js' => '<code>ckeditor.config.js</code>'
1322
        )
1323
    )
1324
  );
1325
  $form['advanced']['js_conf'] = array(
1326
    '#type' => 'textarea',
1327
    '#title' => t('Custom JavaScript configuration'),
1328
    '#default_value' => !empty($profile->settings['js_conf']) ? $profile->settings['js_conf'] : "",
1329
    '#cols' => 60,
1330
    '#rows' => 5,
1331
    '#description' => t(
1332
        '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(
1333
      '!ckeditor_config' => '<code>' . drupal_get_path('module', 'ckeditor') . "/ckeditor.config.js</code>",
1334
      '!docs' => l(t('CKEditor documentation'), 'http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html'),
1335
      '@code' => "config.font_names = 'Arial;Times New Roman;Verdana';\nconfig.fontSize_sizes = '16/16px;24/24px;48/48px;';"
1336
        )
1337
    ),
1338
    '#wysiwyg' => FALSE,
1339
  );
1340

    
1341
  $form['submit'] = array(
1342
    '#type' => 'submit',
1343
    '#value' => t('Save')
1344
  );
1345

    
1346
  return $form;
1347
}
1348

    
1349
/**
1350
 * Form validation for a profile.
1351
 */
1352
function ckeditor_admin_profile_form_validate($form, &$form_state) {
1353
  $edit = & $form_state['values'];
1354
  /*
1355
    if ($edit['default'] == 't' && $edit['popup'] == 't') {
1356
    form_set_error('popup', t('If CKEditor is enabled by default, the popup window must be disabled.'));
1357
    }
1358

    
1359
    if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') {
1360
    form_set_error('popup', t('If toggle is enabled, the popup window must be disabled.'));
1361
    }
1362
   */
1363
  if (!$edit['name']) {
1364
    form_set_error('name', t('You must give a profile name.'));
1365
  }
1366
  elseif (!preg_match('/^[A-Za-z0-9_]+$/', $edit['name'])) {
1367
    form_set_error('name', t('Enter a valid profile name. Only alphanumeric and underscore characters are allowed.'));
1368
  }
1369
  elseif ($edit['name'] == 'CKEditor Global Profile') {
1370
    form_set_error('name', t('This profile name is reserved. Please choose a different name.'));
1371
  }
1372
  elseif (!isset($edit['_profile']) || ($edit['_profile']->name != $edit['name'])) {
1373
    $result = ckeditor_profile_load($edit['name']);
1374
    if (!empty($result)) {
1375
      form_set_error('name', t('The profile name must be unique. A profile with this name already exists.'));
1376
    }
1377
  }
1378

    
1379
  if (!preg_match('/^\d+%?$/', $edit['width'])) {
1380
    form_set_error('width', t('Enter a valid width value. Examples: 400, 100%.'));
1381
  }
1382

    
1383
  if (!empty($edit['css_path'])) {
1384
    if ($edit['css_mode'] != 'self') {
1385
      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.'));
1386
    }
1387
    elseif (FALSE !== strpos($edit['css_path'], '"')) {
1388
      form_set_error('css_path', t('Double quotes are not allowed in the CSS path.'));
1389
    }
1390
    elseif (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") {
1391
      form_set_error('css_path', t('Enter a valid CSS path, do not surround it with quotes.'));
1392
    }
1393
  }
1394

    
1395
  if (!empty($edit['styles_path'])) {
1396
    if ($edit['css_style'] != 'self') {
1397
      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.'));
1398
    }
1399
    elseif (FALSE !== strpos($edit['styles_path'], '"')) {
1400
      form_set_error('styles_path', t('Double quotes are not allowed in the styles path.'));
1401
    }
1402
    elseif (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") {
1403
      form_set_error('styles_path', t('Enter a valid styles path, do not surround it with quotes.'));
1404
    }
1405
  }
1406

    
1407
  if (!empty($edit['font_format'])) {
1408
    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'])) {
1409
      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).'));
1410
    }
1411
  }
1412
  // @todo DOWNLOAD API
1413
  if (!empty($edit['UserFilesAbsolutePath']) && empty($edit['UserFilesPath'])) {
1414
    form_set_error('UserFilesPath', t('The path to uploaded files is required.'));
1415
  }
1416
  if (!empty($edit['UserFilesPath']) && empty($edit['UserFilesAbsolutePath'])) {
1417
    form_set_error('UserFilesPath', t('An absolute path to uploaded files is required.'));
1418
  }
1419

    
1420
  if (ckeditor_get_version(TRUE) == 3) {
1421
    $load_methods = _ckeditor_load_methods();
1422
    if (!isset($load_methods[$edit['ckeditor_load_method']])) {
1423
      form_set_error('ckeditor_load_method', t('Set a valid loading method.'));
1424
    }
1425
    if (!preg_match('#\d+#', $edit['ckeditor_load_time_out'])) {
1426
      form_set_error('ckeditor_load_time_out', t('Enter a valid loading timeout in seconds.'));
1427
    }
1428
  }
1429
  $toolbar = $edit['toolbar'];
1430
  $toolbar = str_replace("'", '"', $toolbar);
1431
  $toolbar = preg_replace('/(\w*)\s*\:/', '"${1}":', $toolbar);
1432
  if (!json_decode($toolbar)) {
1433
    form_set_error('toolbar', t('Enter a valid toolbar configuration.'));
1434
  }
1435
}
1436

    
1437
/**
1438
 * Form submit for a profile
1439
 */
1440
function ckeditor_admin_profile_form_submit($form, &$form_state) {
1441
  $edit = & $form_state['values'];
1442

    
1443
  if (isset($edit['_profile'])) {
1444
    ckeditor_profile_delete($edit['_profile']->name);
1445
    drupal_set_message(t('Your CKEditor profile was updated.'));
1446
  }
1447
  else {
1448
    drupal_set_message(t('Your CKEditor profile was created.'));
1449
  }
1450

    
1451
  $settings = ckeditor_admin_values_to_settings($edit);
1452
  db_insert('ckeditor_settings')
1453
      ->fields(array(
1454
        "name" => $edit['name'],
1455
        "settings" => $settings
1456
      ))
1457
      ->execute();
1458

    
1459
  if (!empty($edit['input_formats'])) {
1460
    foreach (array_keys($edit['input_formats']) as $format) {
1461
      if ($edit['input_formats'][$format] != '0') {
1462
        db_insert('ckeditor_input_format')->fields(array("name" => $edit['name'], "format" => $format))->execute();
1463
      }
1464
    }
1465
  }
1466

    
1467
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1468
}
1469

    
1470
/**
1471
 * Form builder for a clone profile
1472
 */
1473
function ckeditor_admin_profile_clone_form($form, $form_state, $oldprofile) {
1474
  return ckeditor_admin_profile_form($form, $form_state, $oldprofile);
1475
}
1476

    
1477
/**
1478
 * Form validation for a clone profile
1479
 */
1480
function ckeditor_admin_profile_clone_form_validate($form_state, $oldprofile) {
1481
  ckeditor_admin_profile_form_validate($form_state, $oldprofile);
1482
}
1483

    
1484
/**
1485
 * Form submit for a clone profile
1486
 */
1487
function ckeditor_admin_profile_clone_form_submit($form, &$form_state) {
1488
  $edit = & $form_state['values'];
1489
  drupal_set_message(t('Your CKEditor profile was created.'));
1490
  $settings = ckeditor_admin_values_to_settings($edit);
1491
  db_insert('ckeditor_settings')
1492
      ->fields(array(
1493
        "name" => $edit['name'],
1494
        "settings" => $settings
1495
      ))
1496
      ->execute();
1497

    
1498
  if (!empty($edit['input_formats'])) {
1499
    foreach (array_keys($edit['input_formats']) as $format) {
1500
      if ($edit['input_formats'][$format] != 0) {
1501
        db_insert('ckeditor_input_format')->fields(array("name" => $edit['name'], "format" => $format))->execute();
1502
      }
1503
    }
1504
  }
1505

    
1506
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1507
}
1508

    
1509
/**
1510
 * Form builder for a profile delete
1511
 */
1512
function ckeditor_admin_profile_delete_form($form, $form_state, $profile) {
1513
  $form = array();
1514

    
1515
  $form['_profile'] = array(
1516
    '#type' => 'value',
1517
    '#value' => $profile,
1518
  );
1519

    
1520
  $form['question'] = array(
1521
    '#type' => 'item',
1522
    '#markup' => t(
1523
        'Are you sure that you want to delete the CKEditor profile <strong>%profile</strong>?', array(
1524
      '%profile' => $profile->name
1525
        )
1526
    ),
1527
  );
1528

    
1529
  $form['delete'] = array(
1530
    '#type' => 'submit',
1531
    '#id' => 'delete',
1532
    '#value' => t('Delete'),
1533
  );
1534

    
1535
  $form['back'] = array(
1536
    '#type' => 'submit',
1537
    '#id' => 'back',
1538
    '#value' => t('Cancel'),
1539
  );
1540

    
1541
  return $form;
1542
}
1543

    
1544
/**
1545
 * Submit form for a profile delete
1546
 */
1547
function ckeditor_admin_profile_delete_form_submit($form, &$form_state) {
1548
  $v = & $form_state['values'];
1549

    
1550
  if ($form_state['clicked_button']['#id'] == 'delete') {
1551
    ckeditor_profile_delete($v['_profile']->name);
1552
    drupal_set_message(t('The CKEditor profile was deleted.'));
1553
  }
1554

    
1555
  $form_state['redirect'] = 'admin/config/content/ckeditor';
1556
}
1557

    
1558
/**
1559
 * Converts an array of form values to a serialized array that does not
1560
 * contain Drupal Form API values
1561
 */
1562
function ckeditor_admin_values_to_settings($values) {
1563
  $plugins = array();
1564
  if (isset($values['loadPlugins'])) {
1565
    $plugins = $values['loadPlugins'];
1566
  }
1567
  unset($values['name'], $values['input_formats'], $values['_profile'], $values['op'], $values['submit'], $values['form_build_id'], $values['form_token'], $values['form_id'], $values['loadPlugins']);
1568

    
1569
  module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
1570
  $plugin_list = ckeditor_load_plugins();
1571
  $values['loadPlugins'] = array();
1572
  if (!empty($plugins)) {
1573
    foreach (array_keys($plugins) as $plugin) {
1574
      if ($plugins[$plugin] != '0') {
1575
        $values['loadPlugins'][$plugin] = $plugin_list[$plugin];
1576
      }
1577
    }
1578
  }
1579

    
1580
  return serialize($values);
1581
}
1582

    
1583
/**
1584
 * Remove a profile from the database.
1585
 */
1586
function ckeditor_profile_delete($name) {
1587
  db_delete('ckeditor_settings')
1588
      ->condition('name', $name)
1589
      ->execute();
1590
  db_delete('ckeditor_input_format')
1591
      ->condition('name', $name)
1592
      ->execute();
1593
}
1594

    
1595
/*
1596
 * List of CKEditor librares to load
1597
 */
1598

    
1599
function _ckeditor_load_methods() {
1600
  $result = array('ckeditor.js' => 'ckeditor.js');
1601
  if (file_exists(ckeditor_path('local') . '/ckeditor_basic.js')) {
1602
    $result['ckeditor_basic.js'] = 'ckeditor_basic.js';
1603
  }
1604
  if (file_exists(ckeditor_path('local') . '/ckeditor_source.js')) {
1605
    $result['ckeditor_source.js'] = 'ckeditor_source.js (' . t('for developers only') . ')';
1606
  }
1607
  return $result;
1608
}
1609

    
1610
/*
1611
 * Disable WYSIWYG module
1612
 */
1613

    
1614
function ckeditor_disable_wysiwyg($token) {
1615
  if (!drupal_valid_token($token, 'ckeditorDisableWysiwyg')) {
1616
    exit();
1617
  }
1618
  module_disable(array('wysiwyg'));
1619
  drupal_set_message(t('The WYSIWYG module is disabled.'));
1620

    
1621
  drupal_goto('admin/config/content/ckeditor');
1622
}
1623

    
1624
/*
1625
 * Get all available toolbar buttons
1626
 */
1627

    
1628
function ckeditor_toolbar_buttons_all() {
1629
  $path = base_path() . drupal_get_path('module', 'ckeditor');
1630

    
1631
  //CKEditor default buttons
1632
  $buttons = array(
1633
    'Source' => array('name' => 'Source', 'icon' => $path . '/images/buttons/source.png', 'title' => 'Source', 'row' => 1),
1634
    'Save' => array('name' => 'Save', 'icon' => $path . '/images/buttons/save.png', 'title' => 'Save', 'row' => 1),
1635
    'NewPage' => array('name' => 'NewPage', 'icon' => $path . '/images/buttons/newPage.png', 'title' => 'New Page', 'row' => 1),
1636
    'Preview' => array('name' => 'Preview', 'icon' => $path . '/images/buttons/preview.png', 'title' => 'Preview', 'row' => 1),
1637
    'Templates' => array('name' => 'Templates', 'icon' => $path . '/images/buttons/templates.png', 'title' => 'Templates', 'row' => 1),
1638
    'Cut' => array('name' => 'Cut', 'icon' => $path . '/images/buttons/cut.png', 'title' => 'Cut', 'row' => 1),
1639
    'Copy' => array('name' => 'Copy', 'icon' => $path . '/images/buttons/copy.png', 'title' => 'Copy', 'row' => 1),
1640
    'Paste' => array('name' => 'Paste', 'icon' => $path . '/images/buttons/paste.png', 'title' => 'Paste', 'row' => 1),
1641
    'PasteText' => array('name' => 'PasteText', 'icon' => $path . '/images/buttons/pastePlainText.png', 'title' => 'Paste as plain text', 'row' => 1),
1642
    'PasteFromWord' => array('name' => 'PasteFromWord', 'icon' => $path . '/images/buttons/pasteWord.png', 'title' => 'Paste from Word', 'row' => 1),
1643
    'Print' => array('name' => 'Print', 'icon' => $path . '/images/buttons/print.png', 'title' => 'Print', 'row' => 1),
1644
    'SpellChecker' => array('name' => 'SpellChecker', 'icon' => $path . '/images/buttons/checkSpelling.png', 'title' => 'Check Spelling', 'row' => 1),
1645
    'Scayt' => array('name' => 'Scayt', 'icon' => $path . '/images/buttons/checkSpelling.png', 'title' => 'Spell Check As you Type', 'row' => 1), //TODO sprawdzic ta opcje
1646
    'Undo' => array('name' => 'Undo', 'icon' => $path . '/images/buttons/undo.png', 'title' => 'Undo', 'row' => 1),
1647
    'Redo' => array('name' => 'Redo', 'icon' => $path . '/images/buttons/redo.png', 'title' => 'Redo', 'row' => 1),
1648
    'Find' => array('name' => 'Find', 'icon' => $path . '/images/buttons/find.png', 'title' => 'Find', 'row' => 1),
1649
    'Replace' => array('name' => 'Replace', 'icon' => $path . '/images/buttons/replace.png', 'title' => 'Replace', 'row' => 1),
1650
    'SelectAll' => array('name' => 'SelectAll', 'icon' => $path . '/images/buttons/selectAll.png', 'title' => 'Select All', 'row' => 1),
1651
    'RemoveFormat' => array('name' => 'RemoveFormat', 'icon' => $path . '/images/buttons/removeFormat.png', 'title' => 'Remove Format', 'row' => 1),
1652
    'Form' => array('name' => 'Form', 'icon' => $path . '/images/buttons/form.png', 'title' => 'Form', 'row' => 1),
1653
    'Checkbox' => array('name' => 'Checkbox', 'icon' => $path . '/images/buttons/checkbox.png', 'title' => 'Checkbox', 'row' => 1),
1654
    'Radio' => array('name' => 'Radio', 'icon' => $path . '/images/buttons/radioButton.png', 'title' => 'Radio Button', 'row' => 1),
1655
    'TextField' => array('name' => 'TextField', 'icon' => $path . '/images/buttons/textField.png', 'title' => 'Text Field', 'row' => 1),
1656
    'Textarea' => array('name' => 'Textarea', 'icon' => $path . '/images/buttons/textarea.png', 'title' => 'Textarea', 'row' => 1),
1657
    'Select' => array('name' => 'Select', 'icon' => $path . '/images/buttons/selectionField.png', 'title' => 'Selection Field', 'row' => 1),
1658
    'Button' => array('name' => 'Button', 'icon' => $path . '/images/buttons/button.png', 'title' => 'Button', 'row' => 1),
1659
    'ImageButton' => array('name' => 'ImageButton', 'icon' => $path . '/images/buttons/imageButton.png', 'title' => 'Image Button', 'row' => 1),
1660
    'HiddenField' => array('name' => 'HiddenField', 'icon' => $path . '/images/buttons/hiddenField.png', 'title' => 'Hidden Field', 'row' => 1),
1661
    'Bold' => array('name' => 'Bold', 'icon' => $path . '/images/buttons/bold.png', 'title' => 'Bold', 'row' => 2),
1662
    'Italic' => array('name' => 'Italic', 'icon' => $path . '/images/buttons/italic.png', 'type' => 'command', 'title' => 'Italic', 'row' => 2),
1663
    'Underline' => array('name' => 'Underline', 'icon' => $path . '/images/buttons/underline.png', 'title' => 'Underline', 'row' => 2),
1664
    'Strike' => array('name' => 'Strike', 'icon' => $path . '/images/buttons/strike.png', 'title' => 'Strike Through', 'row' => 2),
1665
    'Subscript' => array('name' => 'Subscript', 'icon' => $path . '/images/buttons/subscript.png', 'title' => 'Subscript', 'row' => 2),
1666
    'Superscript' => array('name' => 'Superscript', 'icon' => $path . '/images/buttons/superscript.png', 'title' => 'Superscript', 'row' => 2),
1667
    'NumberedList' => array('name' => 'NumberedList', 'icon' => $path . '/images/buttons/numberedList.png', 'title' => 'Insert/Remove Numbered List', 'row' => 2),
1668
    'BulletedList' => array('name' => 'BulletedList', 'icon' => $path . '/images/buttons/bulletedList.png', 'title' => 'Insert/Remove Bulleted List', 'row' => 2),
1669
    'Outdent' => array('name' => 'Outdent', 'icon' => $path . '/images/buttons/decreaseIndent.png', 'title' => 'Decrease Indent', 'row' => 2),
1670
    'Indent' => array('name' => 'Indent', 'icon' => $path . '/images/buttons/increaseIndent.png', 'title' => 'Increase Indent', 'row' => 2),
1671
    'Blockquote' => array('name' => 'Blockquote', 'icon' => $path . '/images/buttons/blockQuote.png', 'title' => 'Block Quote', 'row' => 2),
1672
    'CreateDiv' => array('name' => 'CreateDiv', 'icon' => $path . '/images/buttons/createDivContainer.png', 'title' => 'Create Div Container', 'row' => 2),
1673
    'JustifyLeft' => array('name' => 'JustifyLeft', 'icon' => $path . '/images/buttons/leftJustify.png', 'title' => 'Left Justify', 'row' => 2),
1674
    'JustifyCenter' => array('name' => 'JustifyCenter', 'icon' => $path . '/images/buttons/centerJustify.png', 'title' => 'Center Justify', 'row' => 2),
1675
    'JustifyRight' => array('name' => 'JustifyRight', 'icon' => $path . '/images/buttons/rightJustify.png', 'title' => 'Right Justify', 'row' => 2),
1676
    'JustifyBlock' => array('name' => 'JustifyBlock', 'icon' => $path . '/images/buttons/blockJustify.png', 'title' => 'Block Justify', 'row' => 2),
1677
    'BidiLtr' => array('name' => 'BidiLtr', 'icon' => $path . '/images/buttons/bidiLeft.png', 'title' => 'Text direction from left to right', 'row' => 2),
1678
    'BidiRtl' => array('name' => 'BidiRtl', 'icon' => $path . '/images/buttons/bidiRight.png', 'title' => 'Text direction from right to left', 'row' => 2),
1679
    'Link' => array('name' => 'Link', 'icon' => $path . '/images/buttons/link.png', 'title' => 'Link', 'row' => 2),
1680
    'Unlink' => array('name' => 'Unlink', 'icon' => $path . '/images/buttons/unlink.png', 'title' => 'Unlink', 'row' => 2),
1681
    'Anchor' => array('name' => 'Anchor', 'icon' => $path . '/images/buttons/anchor.png', 'title' => 'Anchor', 'row' => 2),
1682
    'Image' => array('name' => 'Image', 'icon' => $path . '/images/buttons/image.png', 'title' => 'Image', 'row' => 2),
1683
    'Flash' => array('name' => 'Flash', 'icon' => $path . '/images/buttons/flash.png', 'title' => 'Flash', 'row' => 2),
1684
    'Table' => array('name' => 'Table', 'icon' => $path . '/images/buttons/table.png', 'title' => 'Table', 'row' => 2),
1685
    'HorizontalRule' => array('name' => 'HorizontalRule', 'icon' => $path . '/images/buttons/horizontalLine.png', 'title' => 'Insert Horizontal Line', 'row' => 2),
1686
    'Smiley' => array('name' => 'Smiley', 'icon' => $path . '/images/buttons/smiley.png', 'title' => 'Smiley', 'row' => 2),
1687
    'SpecialChar' => array('name' => 'SpecialChar', 'icon' => $path . '/images/buttons/specialCharacter.png', 'title' => 'Inseert Special Character', 'row' => 2),
1688
    'PageBreak' => array('name' => 'PageBreak', 'icon' => $path . '/images/buttons/pageBreakPrinting.png', 'title' => 'Insert Page Break for Printing', 'row' => 2),
1689
    'Styles' => array('name' => 'Styles', 'icon' => $path . '/images/buttons/styles.png', 'title' => 'Formatting Styles', 'row' => 3),
1690
    'Format' => array('name' => 'Format', 'icon' => $path . '/images/buttons/format.png', 'title' => 'Paragraph Format', 'row' => 3),
1691
    'Font' => array('name' => 'Font', 'icon' => $path . '/images/buttons/font.png', 'title' => 'Font Name', 'row' => 3),
1692
    'FontSize' => array('name' => 'FontSize', 'icon' => $path . '/images/buttons/fontSize.png', 'title' => 'Font Size', 'row' => 3),
1693
    'TextColor' => array('name' => 'TextColor', 'icon' => $path . '/images/buttons/textColor.png', 'title' => 'Text Color', 'row' => 3),
1694
    'BGColor' => array('name' => 'BGColor', 'icon' => $path . '/images/buttons/backgroundColor.png', 'title' => 'Background Color', 'row' => 3),
1695
    'Maximize' => array('name' => 'Maximize', 'icon' => $path . '/images/buttons/maximize.png', 'title' => 'Maximize', 'row' => 3),
1696
    'ShowBlocks' => array('name' => 'ShowBlocks', 'icon' => $path . '/images/buttons/showBlocks.png', 'title' => 'Show Blocks', 'row' => 3),
1697
    'Iframe' => array('name' => 'Iframe', 'icon' => $path . '/images/buttons/iframe.png', 'title' => 'IFrame', 'row' => 3),
1698
    'About' => array('name' => 'About', 'icon' => $path . '/images/buttons/about.png', 'title' => 'About', 'row' => 3),
1699
    '__spacer' => array('name' => FALSE, 'icon' => $path . '/images/buttons/spacer.png', 'title' => 'Spacer', 'row' => 4),
1700
    '__group' => array('name' => FALSE, 'icon' => $path . '/images/buttons/group.png', 'title' => 'Group', 'row' => 4)
1701
  );
1702

    
1703
  $plugins = ckeditor_load_plugins(TRUE);
1704
  foreach ($plugins as $plugin_name => $plugin) {
1705
    if (!isset($plugin['buttons']) || $plugin['buttons'] == FALSE)
1706
      continue;
1707
    foreach ((array) $plugin['buttons'] as $button_name => $button) {
1708
      $buttons[$button_name] = array('name' => $button_name, 'icon' => $plugin['path'] . $button['icon'], 'title' => t($button['label']), 'row' => 4);
1709
    }
1710
  }
1711

    
1712
  return $buttons;
1713
}
1714

    
1715
/**
1716
 * Add security filters to the configuration panel available in the CKEditor profile administration section
1717
 */
1718
function _ckeditor_admin_profile_form_security_filters(&$form, $profile, $security_filters) {
1719
  foreach ((array) $security_filters['modules'] as $module_name => $module_conf) {
1720
    if (isset($module_conf['project_page']) && strlen($module_conf['project_page']) > 0) {
1721
      $form['security']['filters'][$module_name] = array(
1722
        '#type' => 'fieldset',
1723
        '#title' => t(
1724
            "!title <a href=\"!link\" target=\"_blank\">project page</a>", array(
1725
          "!title" => $module_conf['title'],
1726
          "!link" => $module_conf['project_page']
1727
            )
1728
        ),
1729
        '#weight' => $module_conf['weight']
1730
      );
1731
    }
1732
    else {
1733
      $form['security']['filters'][$module_name] = array(
1734
        '#type' => 'fieldset',
1735
        '#title' => t("!title", array("!title" => $module_conf['title'])),
1736
        '#weight' => $module_conf['weight']
1737
      );
1738
    }
1739

    
1740
    if ($module_conf['installed'] == TRUE) {
1741
      foreach ((array) $module_conf['filters'] as $filter_name => $filter_conf) {
1742
        $filter_text_formats = '<div class="filter-text-formats" filter="' . $filter_name . '"></div><div class="filter-info">';
1743
        $form['security']['filters'][$module_name][$filter_name] = array(
1744
          '#type' => 'item',
1745
          '#title' => t("@data", array('@data' => $filter_conf['title'])),
1746
          '#description' => t("!data", array('!data' => $filter_conf['description'])),
1747
          '#prefix' => "<div class=\"filter-wrapper\"></div>" . $filter_text_formats,
1748
          '#suffix' => "</div>"
1749
        );
1750
      }
1751
    }
1752
    else {
1753
      $form['security']['filters'][$module_name]['not_installed'] = array(
1754
        '#markup' => t("<i>Not installed</i>")
1755
      );
1756
    }
1757
  }
1758
}
1759

    
1760
function ckeditor_skinframe() {
1761
  header('Content-Type: text/html; charset=utf-8');
1762

    
1763
  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'ckeditorSkinframeCall')) {
1764
    exit;
1765
  }
1766

    
1767
  $editor_path = ckeditor_path('relative');
1768
  $module_drupal_path = ckeditor_module_path('relative');
1769

    
1770
  $html = "<!DOCTYPE html>";
1771
  $html .= "<html>";
1772
  $html .= "<head>";
1773
  $html .= '<title>CKEditor UI Color Picker</title>';
1774
  $html .= "<script type=\"text/javascript\" src=\"{$editor_path}/ckeditor.js\"></script>";
1775
  $html .= "</head>";
1776
  $html .= "<body>";
1777
  $html .= "<input type=\"hidden\" name=\"uicolor_user\"/>";
1778
  $html .= "<div id=\"editor\" style=\"height: 200px;\">Click the <strong>UI Color Picker</strong> button to set your color preferences.</div>";
1779
  $html .= "<script type=\"text/javascript\">
1780
var skin = window.location.search.match(/skin=([^&]*)/)[1];
1781
var uicolor = window.location.search.match(/uicolor=([^&]*)/)[1];
1782
var ckeditorUiColorOnChange = function() {
1783
  var color = CKEDITOR.instances['editor'].getUiColor();
1784
  if (typeof(color) != 'undefined') {
1785
    document.getElementsByName('uicolor_user').value = parent.document.getElementsByName('uicolor_user')[0].value = color;
1786
    var edit_uicolor = parent.document.getElementById('edit-uicolor');
1787
    for (i=0; i<edit_uicolor.options.length; i++) {
1788
      if (edit_uicolor[i].value == 'custom') {
1789
        edit_uicolor.selectedIndex = i;
1790
        edit_uicolor[i].selected = 'selected';
1791
        break;
1792
      }
1793
    }
1794
  }
1795
};
1796
CKEDITOR.on('dialogDefinition', function( ev ) {
1797
  var dialogName = ev.data.name;
1798
  var dialogDefinition = ev.data.definition;
1799

    
1800
  if (dialogName == 'uicolor') {
1801
    dialogDefinition.getContents('tab1').get('configBox').style = 'display:none';
1802
  }
1803
});
1804
CKEDITOR.replace('editor', {
1805
  extraPlugins : 'uicolor',
1806
  height: 400,
1807
  uiColor: '#' + uicolor,
1808
  toolbar : [[ 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList'],[ 'UIColor' ]],
1809
  skin: skin,
1810
  on: {
1811
    configLoaded: function(ev) {
1812
      var ckeditor_ver = CKEDITOR.version.split('.')[0];
1813
      if (ckeditor_ver == 3) {
1814
        if (skin != 'kama') {
1815
          ev.editor.config.toolbar = [[ 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList']];
1816
        }
1817
      }
1818
      else {
1819
        CKEDITOR.plugins.addExternal('uicolor', '{$module_drupal_path}/includes/uicolor/', 'plugin.js');
1820
        if (uicolor.length == 0 || uicolor == 'default') {
1821
          delete ev.editor.config.uiColor;
1822
        }
1823
      }
1824
    },
1825
    blur: ckeditorUiColorOnChange,
1826
    focus: ckeditorUiColorOnChange
1827
  }
1828
});
1829
</script>";
1830
  $html .= "</body>";
1831
  $html .= "</html>";
1832
  echo $html;
1833
}