summaryrefslogtreecommitdiff
path: root/kolab.org/www/drupal-7.26/sites/all/modules/ctools/plugins/content_types/custom/custom.inc
blob: ac2f2a3ff253d9a3da3174c31ff77d926c5f6049 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
<?php

/**
 * @file
 * Custom content type.
 *
 * This content type is nothing more than a title and a body that is entered
 * by the user and run through standard filters. The information is stored
 * right in the config, so each custom content is unique.
 */

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = array(
  'title' => t('Custom content'),
  'no title override' => TRUE,
  'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
  'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
  // Make sure the edit form is only used for some subtypes.
  'edit form' => '',
  'add form' => '',
  'edit text' => t('Edit'),
  'all contexts' => TRUE,
);

/**
 * Return the custom content types with the specified $subtype_id.
 */
function ctools_custom_content_type_content_type($subtype_id) {
  if ($subtype_id == 'custom') {
    return _ctools_default_content_type_content_type();
  }
  elseif (module_exists('ctools_custom_content')) {
    ctools_include('export');
    $content = ctools_export_crud_load('ctools_custom_content', $subtype_id);
    if ($content) {
      return _ctools_custom_content_type_content_type($content);
    }
  }
}

/**
 * Return all custom content types available.
 */
function ctools_custom_content_type_content_types() {
  $types = &drupal_static(__FUNCTION__);
  if (isset($types)) {
    return $types;
  }

  ctools_include('export');
  $types = array();
  $types['custom'] = _ctools_default_content_type_content_type();

  if (module_exists('ctools_custom_content')) {
    foreach (ctools_export_crud_load_all('ctools_custom_content') as $name => $content) {
      $types[$name] = _ctools_custom_content_type_content_type($content);
    }
  }

  return $types;
}

/**
 * Settings for the default custom content type.
 *
 * The default is the one that allows the user to actually create a type.
 */
function _ctools_default_content_type_content_type() {
  $info = array(
    'name' => 'custom',
    'title' => t('New custom content'),
    'top level' => TRUE,
    'category' => t('Custom'),
    'description' => t('Create a completely custom piece of HTML content.'),
    'edit form' => 'ctools_custom_content_type_edit_form',
    'all contexts' => TRUE,
    'check editable' => 'ctools_custom_content_type_editable',
  );

  return $info;
}

/**
 * Return an info array for a specific custom content type.
 */
function _ctools_custom_content_type_content_type($content) {
  $info = array(
    'name' => $content->name,
    'title' => check_plain($content->admin_title),
    'description' => check_plain($content->admin_description),
    'category' => $content->category ? check_plain($content->category) : t('Miscellaneous'),
    'all contexts' => TRUE,
    'icon' => 'icon_block_custom.png',
    // Store this here to make it easy to access.
    'content' => $content,
  );

  return $info;
}

/**
 * Given a subtype and a $conf, return the actual settings to use.
 *
 * The actual settings may be stored directly in the pane or this may
 * be a pointer to re-usable content that may be in the database or in
 * an export. We have to determine from the subtype whether or not it
 * is local or shared custom content.
 */
function ctools_custom_content_type_get_conf($subtype, $conf) {
  if ($subtype['name'] != 'custom') {
    $settings = $subtype['content']->settings;
    $settings['custom_type'] = 'fixed';
    $settings['content'] = $subtype['content'];
  }
  else {
    // This means they created it as custom content and then set it as
    // reusable. Since we're not allowed to change the subtype, we're
    // still stored as though we are local, but are pointing off to
    // non-local.
    if (!empty($conf['name']) && module_exists('ctools_custom_content')) {
      ctools_include('export');
      $content = ctools_export_crud_load('ctools_custom_content', $conf['name']);
      if ($content) {
        $settings = $content->settings;
        $settings['custom_type'] = 'fixed';
        $settings['content'] = $content;
        $settings['admin_title'] = $content->admin_title;
      }
      else {
        $content = ctools_export_crud_new('ctools_custom_content');
        $content->name = $conf['name'];
        $settings = array(
          'admin_title' => t('Missing/deleted content'),
          'title' => '',
          'body' => '',
          'format' => filter_default_format(),
          'substitute' => TRUE,
          'custom_type' => 'fixed',
          'content' => $content,
        );
      }
    }
    // This means that it is created as custom and has not been set to
    // reusable.
    else {
      $settings = $conf;
      $settings['custom_type'] = 'local';
    }
  }

  // Correct for an error that came in because filter format changed.
  if (is_array($settings['body'])) {
    $settings['format'] = $settings['body']['format'];
    $settings['body'] = $settings['body']['value'];
  }

  return $settings;
}

function ctools_custom_content_type_editable($content_type, $subtype, $conf) {
  if ($subtype['name'] == 'custom' && !empty($conf['name'])) {
    return FALSE;
  }

  return TRUE;
}

/**
 * Output function for the 'custom' content type. Outputs a custom
 * based on the module and delta supplied in the configuration.
 */
function ctools_custom_content_type_render($subtype, $conf, $args, $contexts) {
  $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf);

  static $delta = 0;

  $block          = new stdClass();
  $block->subtype = ++$delta;
  $block->title   = filter_xss_admin($settings['title']);

  // Add keyword substitutions if we were configured to do so.
  $content = $settings['body'];
  if (!empty($contexts) && !empty($settings['substitute'])) {
    $content = ctools_context_keyword_substitute($content, array(), $contexts);
  }

  $block->content = check_markup($content, $settings['format']);
  if ($settings['custom_type'] == 'fixed' && user_access('administer custom content')) {
    $block->admin_links = array(
      array(
        'title' => t('Configure content pane'),
        'alt' => t("Configure this pane in administer >> structure >> custom content panes"),
        'href' => 'admin/structure/ctools-content/list/' . $settings['content']->name . '/edit',
        'query' => drupal_get_destination(),
      ),
    );
  }

  return $block;
}

/**
 * Callback to provide the administrative title of the custom content.
 */
function ctools_custom_content_type_admin_title($subtype, $conf) {
  $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf);

  $output = t('Custom');
  $title = !empty($settings['admin_title']) ? $settings['admin_title'] : $settings['title'];
  if ($title) {
    if ($settings['custom_type'] != 'fixed') {
      $output = t('Custom: @title', array('@title' => $title));
    }
    else {
      $output = $title;
    }
  }

  return $output;
}

/**
 * Callback to provide administrative info. In this case we'll render the
 * content as long as it's not PHP, which is too risky to render here.
 */
function ctools_custom_content_type_admin_info($subtype, $conf) {
  $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf);

  $block = new stdClass();
  $block->title = filter_xss_admin($settings['title']);
  // We don't want to render php output on preview here, because if something is
  // wrong the whole display will be borked. So we check to see if the php
  // evaluator filter is being used, and make a temporary change to the filter
  // so that we get the printed php, not the eval'ed php.
  $php_filter = FALSE;
  foreach (filter_list_format($settings['format']) as $filter) {
    if ($filter->module == 'php') {
      $php_filter = TRUE;
      break;
    }
  }
  // If a php filter is active, just print the source, but only if the current
  // user has access to the actual filter.
  if ($php_filter) {
    $filter = filter_format_load($settings['format']);
    if (!filter_access($filter)) {
      return NULL;
    }
    $block->content = '<pre>' . check_plain($settings['body']) . '</pre>';
  }
  else {
    // We also need to filter through XSS admin because <script> tags can
    // cause javascript which will interfere with our ajax.
    $block->content = filter_xss_admin(check_markup($settings['body'], $settings['format']));
  }
  return $block;
}

/**
 * Returns an edit form for the custom type.
 */
function ctools_custom_content_type_edit_form($form, &$form_state) {
  $settings = ctools_custom_content_type_get_conf($form_state['subtype'], $form_state['conf']);
  $form_state['settings'] = $settings;

  if ($settings['custom_type'] == 'fixed') {
    return $form; // no form for this case.
  }

  $form['admin_title'] = array(
    '#type' => 'textfield',
    '#default_value' => isset($settings['admin_title']) ? $settings['admin_title'] : '',
    '#title' => t('Administrative title'),
    '#description' => t('This title will be used administratively to identify this pane. If blank, the regular title will be used.'),
  );

  $form['title'] = array(
    '#type' => 'textfield',
    '#default_value' => $settings['title'],
    '#title' => t('Title'),
  );

  $form['body'] = array(
    '#type' => 'text_format',
    '#title' => t('Body'),
    '#default_value' => $settings['body'],
    '#format' => $settings['format'],
  );

  if (!empty($form_state['contexts'])) {
    // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords
    if (module_exists('content') && module_exists('token')) {
      $description = t('If checked, context keywords will be substituted in this content. Note that CCK fields may be used as keywords using patterns like <em>%node:field_name-formatted</em>.');
    }
    elseif (!module_exists('token')) {
      $description = t('If checked, context keywords will be substituted in this content. More keywords will be available if you install the Token module, see http://drupal.org/project/token.');
    }
    else {
      $description = t('If checked, context keywords will be substituted in this content.');
    }

    $form['substitute'] = array(
      '#type' => 'checkbox',
      '#title' => t('Use context keywords'),
      '#description' => $description,
      '#default_value' => !empty($settings['substitute']),
    );
    $form['contexts'] = array(
      '#title' => t('Substitutions'),
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );

    $rows = array();
    foreach ($form_state['contexts'] as $context) {
      foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) {
        $rows[] = array(
          check_plain($keyword),
          t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)),
        );
      }
    }
    $header = array(t('Keyword'), t('Value'));
    $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows)));
  }

  if (!user_access('administer custom content') || !module_exists('ctools_custom_content')) {
    return $form;
  }

  // Make the other form items dependent upon it.
  ctools_include('dependent');
  ctools_add_js('dependent');

  $form['reusable'] = array(
    '#type' => 'checkbox',
    '#title' => t('Make this content reusable'),
    '#default_value' => FALSE,
  );

  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Machine name'),
    '#description' => t('The machine readable name of this content. It must be unique, and it must contain only alphanumeric characters and underscores. Once created, you will not be able to change this value!'),
    '#dependency' => array('edit-reusable' => array(1)),
  );

  $form['category'] = array(
    '#type' => 'textfield',
    '#title' => t('Category'),
    '#description' => t('What category this content should appear in. If left blank the category will be "Miscellaneous".'),
    '#dependency' => array('edit-reusable' => array(1)),
  );

  $form['admin_description'] = array(
    '#type' => 'textarea',
    '#title' => t('Administrative description'),
    '#description' => t('A description of what this content is, does or is for, for administrative use.'),
    '#dependency' => array('edit-reusable' => array(1)),
  );
  return $form;
}

function _ctools_custom_content_type_edit_save(&$content, $form_state) {
  // Apply updates to the content object.
  $content->category = $form_state['values']['category'];
  $content->admin_title = $form_state['values']['admin_title'];
  $content->admin_description = $form_state['values']['admin_description'];
  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
    if (isset($form_state['values'][$key])) {
      $content->settings[$key] = $form_state['values'][$key];
    }
  }

  ctools_export_crud_save('ctools_custom_content', $content);
}

/**
 * The validate form to ensure the custom content data is okay.
 */
function ctools_custom_content_type_edit_form_validate(&$form, &$form_state) {
  if ($form_state['settings']['custom_type'] != 'fixed' && !empty($form_state['values']['reusable'])) {
    if (empty($form_state['values']['name'])) {
      form_error($form['name'], t('Name is required.'));
    }

    // Check for string identifier sanity
    if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['name'])) {
      form_error($form['name'], t('The name can only consist of lowercase letters, underscores, and numbers.'));
      return;
    }

    if (!module_exists('ctools_custom_content')) {
      return;
    }

    // Check for name collision
    if ($form_state['values']['name'] == 'custom' || (ctools_export_crud_load('ctools_custom_content', $form_state['values']['name']))) {
      form_error($form['name'], t('Content with this name already exists. Please choose another name or delete the existing item before creating a new one.'));
    }
  }
}

/**
 * The submit form stores the data in $conf.
 */
function ctools_custom_content_type_edit_form_submit($form, &$form_state) {
  // Because of changes in filter form, these two keys are out of position:
  $form_state['values']['format'] = $form_state['values']['body']['format'];
  $form_state['values']['body'] = $form_state['values']['body']['value'];

  if ($form_state['settings']['custom_type'] == 'fixed') {
    _ctools_custom_content_type_edit_save($form_state['settings']['content'], $form_state);
  }
  // If the 'reusable' checkbox was checked, we will create a new
  // custom content and give it the proper values.
  else if (!empty($form_state['values']['reusable'])) {
    $content = ctools_export_crud_new('ctools_custom_content');
    $content->name = $form_state['values']['name'];
    _ctools_custom_content_type_edit_save($content, $form_state);
    $form_state['conf']['name'] = $content->name;
  }
  else {
    // Otherwise, just save values into $conf normally.

    foreach (array_keys($form_state['plugin']['defaults']) as $key) {
      $form_state['conf'][$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : $form_state['plugin']['defaults'][$key];
    }
  }
}