Projet

Général

Profil

Paste
Télécharger (15,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / plugins / content_types / custom / custom.inc @ c304a780

1
<?php
2

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

    
12
/**
13
 * Plugins are described by creating a $plugin array which will be used
14
 * by the system that includes this file.
15
 */
16
$plugin = array(
17
  'title' => t('Custom content'),
18
  'no title override' => TRUE,
19
  'defaults' => array('admin_title' => '', 'title' => '', 'title_heading' => 'h2', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
20
  'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
21
  // Make sure the edit form is only used for some subtypes.
22
  'edit form' => '',
23
  'add form' => '',
24
  'edit text' => t('Edit'),
25
  'all contexts' => TRUE,
26
);
27

    
28
/**
29
 * Return the custom content types with the specified $subtype_id.
30
 */
31
function ctools_custom_content_type_content_type($subtype_id) {
32
  if ($subtype_id == 'custom') {
33
    return _ctools_default_content_type_content_type();
34
  }
35
  elseif (module_exists('ctools_custom_content')) {
36
    ctools_include('export');
37
    $content = ctools_export_crud_load('ctools_custom_content', $subtype_id);
38
    if ($content) {
39
      return _ctools_custom_content_type_content_type($content);
40
    }
41
  }
42
}
43

    
44
/**
45
 * Return all custom content types available.
46
 */
47
function ctools_custom_content_type_content_types() {
48
  $types = &drupal_static(__FUNCTION__);
49
  if (isset($types)) {
50
    return $types;
51
  }
52

    
53
  ctools_include('export');
54
  $types = array();
55
  $types['custom'] = _ctools_default_content_type_content_type();
56

    
57
  if (module_exists('ctools_custom_content')) {
58
    foreach (ctools_export_crud_load_all('ctools_custom_content') as $name => $content) {
59
      $types[$name] = _ctools_custom_content_type_content_type($content);
60
    }
61
  }
62

    
63
  return $types;
64
}
65

    
66
/**
67
 * Settings for the default custom content type.
68
 *
69
 * The default is the one that allows the user to actually create a type.
70
 */
71
function _ctools_default_content_type_content_type() {
72
  $info = array(
73
    'name' => 'custom',
74
    'title' => t('New custom content'),
75
    'top level' => TRUE,
76
    'category' => t('Custom'),
77
    'description' => t('Create a completely custom piece of HTML content.'),
78
    'edit form' => 'ctools_custom_content_type_edit_form',
79
    'all contexts' => TRUE,
80
    'check editable' => 'ctools_custom_content_type_editable',
81
  );
82

    
83
  return $info;
84
}
85

    
86
/**
87
 * Return an info array for a specific custom content type.
88
 */
89
function _ctools_custom_content_type_content_type($content) {
90
  $info = array(
91
    'name' => $content->name,
92
    'title' => check_plain($content->admin_title),
93
    'description' => check_plain($content->admin_description),
94
    'category' => $content->category ? check_plain($content->category) : t('Miscellaneous'),
95
    'all contexts' => TRUE,
96
    'icon' => 'icon_block_custom.png',
97
    // Store this here to make it easy to access.
98
    'content' => $content,
99
  );
100

    
101
  return $info;
102
}
103

    
104
/**
105
 * Given a subtype and a $conf, return the actual settings to use.
106
 *
107
 * The actual settings may be stored directly in the pane or this may
108
 * be a pointer to re-usable content that may be in the database or in
109
 * an export. We have to determine from the subtype whether or not it
110
 * is local or shared custom content.
111
 */
112
function ctools_custom_content_type_get_conf($subtype, $conf) {
113
  if ($subtype['name'] != 'custom') {
114
    $settings = $subtype['content']->settings;
115
    $settings['custom_type'] = 'fixed';
116
    $settings['content'] = $subtype['content'];
117
  }
118
  else {
119
    // This means they created it as custom content and then set it as
120
    // reusable. Since we're not allowed to change the subtype, we're
121
    // still stored as though we are local, but are pointing off to
122
    // non-local.
123
    if (!empty($conf['name']) && module_exists('ctools_custom_content')) {
124
      ctools_include('export');
125
      $content = ctools_export_crud_load('ctools_custom_content', $conf['name']);
126
      if ($content) {
127
        $settings = $content->settings;
128
        $settings['custom_type'] = 'fixed';
129
        $settings['content'] = $content;
130
        $settings['admin_title'] = $content->admin_title;
131
      }
132
      else {
133
        $content = ctools_export_crud_new('ctools_custom_content');
134
        $content->name = $conf['name'];
135
        $settings = array(
136
          'admin_title' => t('Missing/deleted content'),
137
          'title' => '',
138
          'title_heading' => '',
139
          'body' => '',
140
          'format' => filter_default_format(),
141
          'substitute' => TRUE,
142
          'custom_type' => 'fixed',
143
          'content' => $content,
144
        );
145
      }
146
    }
147
    // This means that it is created as custom and has not been set to
148
    // reusable.
149
    else {
150
      $settings = $conf;
151
      $settings['custom_type'] = 'local';
152
    }
153
  }
154

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

    
161
  return $settings;
162
}
163

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

    
169
  return TRUE;
170
}
171

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

    
179
  static $delta = 0;
180

    
181
  $block                = new stdClass();
182
  $block->subtype       = ++$delta;
183
  $block->title         = filter_xss_admin($settings['title']);
184
  $block->title_heading = isset($settings['title_heading']) ? $settings['title_heading'] : 'h2';
185

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

    
192
  $block->content = check_markup($content, $settings['format']);
193
  if ($settings['custom_type'] == 'fixed' && user_access('administer custom content')) {
194
    $block->admin_links = array(
195
      array(
196
        'title' => t('Configure content pane'),
197
        'alt' => t("Configure this pane in administer >> structure >> custom content panes"),
198
        'href' => 'admin/structure/ctools-content/list/' . $settings['content']->name . '/edit',
199
        'query' => drupal_get_destination(),
200
      ),
201
    );
202
  }
203

    
204
  return $block;
205
}
206

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

    
213
  $output = t('Custom');
214
  $title = !empty($settings['admin_title']) ? $settings['admin_title'] : $settings['title'];
215
  if ($title) {
216
    if ($settings['custom_type'] != 'fixed') {
217
      $output = t('Custom: @title', array('@title' => $title));
218
    }
219
    else {
220
      $output = $title;
221
    }
222
  }
223

    
224
  return $output;
225
}
226

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

    
234
  $block = new stdClass();
235
  $block->title = filter_xss_admin($settings['title']);
236
  // We don't want to render php output on preview here, because if something is
237
  // wrong the whole display will be borked. So we check to see if the php
238
  // evaluator filter is being used, and make a temporary change to the filter
239
  // so that we get the printed php, not the eval'ed php.
240
  $php_filter = FALSE;
241
  foreach (filter_list_format($settings['format']) as $filter) {
242
    if ($filter->module == 'php') {
243
      $php_filter = TRUE;
244
      break;
245
    }
246
  }
247
  // If a php filter is active, just print the source, but only if the current
248
  // user has access to the actual filter.
249
  if ($php_filter) {
250
    $filter = filter_format_load($settings['format']);
251
    if (!filter_access($filter)) {
252
      return NULL;
253
    }
254
    $block->content = '<pre>' . check_plain($settings['body']) . '</pre>';
255
  }
256
  else {
257
    // We also need to filter through XSS admin because <script> tags can
258
    // cause javascript which will interfere with our ajax.
259
    $block->content = filter_xss_admin(check_markup($settings['body'], $settings['format']));
260
  }
261
  return $block;
262
}
263

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

    
271
  if ($settings['custom_type'] == 'fixed') {
272
    // No form for this case.
273
    return $form;
274
  }
275

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

    
283
  // Copy over the title override settings for a title heading.
284
  $form['aligner_start'] = array(
285
    '#markup' => '<div class="option-text-aligner clearfix">',
286
  );
287

    
288
  $form['title'] = array(
289
    '#type' => 'textfield',
290
    '#default_value' => $settings['title'],
291
    '#title' => t('Title'),
292
    '#id' => 'override-title-textfield',
293
  );
294

    
295
  $form['title_heading'] = array(
296
    '#type' => 'select',
297
    '#default_value' => isset($settings['title_heading']) ? $settings['title_heading'] : 'h2',
298
    '#options' => array(
299
      'h1' => t('h1'),
300
      'h2' => t('h2'),
301
      'h3' => t('h3'),
302
      'h4' => t('h4'),
303
      'h5' => t('h5'),
304
      'h6' => t('h6'),
305
      'div' => t('div'),
306
      'span' => t('span'),
307
    ),
308
    '#id' => 'override-title-heading',
309
  );
310

    
311
  $form['aligner_stop'] = array(
312
    '#markup' => '</div>',
313
  );
314

    
315
  $form['body'] = array(
316
    '#type' => 'text_format',
317
    '#title' => t('Body'),
318
    '#default_value' => $settings['body'],
319
    '#format' => $settings['format'],
320
  );
321

    
322
  if (!empty($form_state['contexts'])) {
323
    // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords.
324
    if (module_exists('content') && module_exists('token')) {
325
      $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>.');
326
    }
327
    elseif (!module_exists('token')) {
328
      $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.');
329
    }
330
    else {
331
      $description = t('If checked, context keywords will be substituted in this content.');
332
    }
333

    
334
    $form['substitute'] = array(
335
      '#type' => 'checkbox',
336
      '#title' => t('Use context keywords'),
337
      '#description' => $description,
338
      '#default_value' => !empty($settings['substitute']),
339
    );
340
    $form['contexts'] = array(
341
      '#title' => t('Substitutions'),
342
      '#type' => 'fieldset',
343
      '#collapsible' => TRUE,
344
      '#collapsed' => TRUE,
345
    );
346

    
347
    $rows = array();
348
    foreach ($form_state['contexts'] as $context) {
349
      foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) {
350
        $rows[] = array(
351
          check_plain($keyword),
352
          t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)),
353
        );
354
      }
355
    }
356
    $header = array(t('Keyword'), t('Value'));
357
    $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows)));
358
  }
359

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

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

    
368
  $form['reusable'] = array(
369
    '#type' => 'checkbox',
370
    '#title' => t('Make this content reusable'),
371
    '#default_value' => FALSE,
372
  );
373

    
374
  $form['name'] = array(
375
    '#type' => 'textfield',
376
    '#title' => t('Machine name'),
377
    '#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!'),
378
    '#dependency' => array('edit-reusable' => array(1)),
379
  );
380

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

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

    
397
function _ctools_custom_content_type_edit_save(&$content, $form_state) {
398
  // Apply updates to the content object.
399
  $content->category = $form_state['values']['category'];
400
  $content->admin_title = $form_state['values']['admin_title'];
401
  $content->admin_description = $form_state['values']['admin_description'];
402
  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
403
    if (isset($form_state['values'][$key])) {
404
      $content->settings[$key] = $form_state['values'][$key];
405
    }
406
  }
407

    
408
  ctools_export_crud_save('ctools_custom_content', $content);
409
}
410

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

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

    
426
    if (!module_exists('ctools_custom_content')) {
427
      return;
428
    }
429

    
430
    // Check for name collision.
431
    if ($form_state['values']['name'] == 'custom' || (ctools_export_crud_load('ctools_custom_content', $form_state['values']['name']))) {
432
      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.'));
433
    }
434
  }
435
}
436

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

    
445
  if ($form_state['settings']['custom_type'] == 'fixed') {
446
    _ctools_custom_content_type_edit_save($form_state['settings']['content'], $form_state);
447
  }
448
  // If the 'reusable' checkbox was checked, we will create a new
449
  // custom content and give it the proper values.
450
  elseif (!empty($form_state['values']['reusable'])) {
451
    $content = ctools_export_crud_new('ctools_custom_content');
452
    $content->name = $form_state['values']['name'];
453
    _ctools_custom_content_type_edit_save($content, $form_state);
454
    $form_state['conf']['name'] = $content->name;
455
  }
456
  else {
457
    // Otherwise, just save values into $conf normally.
458
    foreach (array_keys($form_state['plugin']['defaults']) as $key) {
459
      $form_state['conf'][$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : $form_state['plugin']['defaults'][$key];
460
    }
461
  }
462
}