Projet

Général

Profil

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

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

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' => '', '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
          'body' => '',
139
          'format' => filter_default_format(),
140
          'substitute' => TRUE,
141
          'custom_type' => 'fixed',
142
          'content' => $content,
143
        );
144
      }
145
    }
146
    // This means that it is created as custom and has not been set to
147
    // reusable.
148
    else {
149
      $settings = $conf;
150
      $settings['custom_type'] = 'local';
151
    }
152
  }
153

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

    
160
  return $settings;
161
}
162

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

    
168
  return TRUE;
169
}
170

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

    
178
  static $delta = 0;
179

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

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

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

    
202
  return $block;
203
}
204

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

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

    
222
  return $output;
223
}
224

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

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

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

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

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

    
280
  $form['title'] = array(
281
    '#type' => 'textfield',
282
    '#default_value' => $settings['title'],
283
    '#title' => t('Title'),
284
  );
285

    
286
  $form['body'] = array(
287
    '#type' => 'text_format',
288
    '#title' => t('Body'),
289
    '#default_value' => $settings['body'],
290
    '#format' => $settings['format'],
291
  );
292

    
293
  if (!empty($form_state['contexts'])) {
294
    // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords
295
    if (module_exists('content') && module_exists('token')) {
296
      $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>.');
297
    }
298
    elseif (!module_exists('token')) {
299
      $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.');
300
    }
301
    else {
302
      $description = t('If checked, context keywords will be substituted in this content.');
303
    }
304

    
305
    $form['substitute'] = array(
306
      '#type' => 'checkbox',
307
      '#title' => t('Use context keywords'),
308
      '#description' => $description,
309
      '#default_value' => !empty($settings['substitute']),
310
    );
311
    $form['contexts'] = array(
312
      '#title' => t('Substitutions'),
313
      '#type' => 'fieldset',
314
      '#collapsible' => TRUE,
315
      '#collapsed' => TRUE,
316
    );
317

    
318
    $rows = array();
319
    foreach ($form_state['contexts'] as $context) {
320
      foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) {
321
        $rows[] = array(
322
          check_plain($keyword),
323
          t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)),
324
        );
325
      }
326
    }
327
    $header = array(t('Keyword'), t('Value'));
328
    $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows)));
329
  }
330

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

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

    
339
  $form['reusable'] = array(
340
    '#type' => 'checkbox',
341
    '#title' => t('Make this content reusable'),
342
    '#default_value' => FALSE,
343
  );
344

    
345
  $form['name'] = array(
346
    '#type' => 'textfield',
347
    '#title' => t('Machine name'),
348
    '#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!'),
349
    '#dependency' => array('edit-reusable' => array(1)),
350
  );
351

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

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

    
368
function _ctools_custom_content_type_edit_save(&$content, $form_state) {
369
  // Apply updates to the content object.
370
  $content->category = $form_state['values']['category'];
371
  $content->admin_title = $form_state['values']['admin_title'];
372
  $content->admin_description = $form_state['values']['admin_description'];
373
  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
374
    if (isset($form_state['values'][$key])) {
375
      $content->settings[$key] = $form_state['values'][$key];
376
    }
377
  }
378

    
379
  ctools_export_crud_save('ctools_custom_content', $content);
380
}
381

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

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

    
397
    if (!module_exists('ctools_custom_content')) {
398
      return;
399
    }
400

    
401
    // Check for name collision
402
    if ($form_state['values']['name'] == 'custom' || (ctools_export_crud_load('ctools_custom_content', $form_state['values']['name']))) {
403
      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.'));
404
    }
405
  }
406
}
407

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

    
416
  if ($form_state['settings']['custom_type'] == 'fixed') {
417
    _ctools_custom_content_type_edit_save($form_state['settings']['content'], $form_state);
418
  }
419
  // If the 'reusable' checkbox was checked, we will create a new
420
  // custom content and give it the proper values.
421
  else if (!empty($form_state['values']['reusable'])) {
422
    $content = ctools_export_crud_new('ctools_custom_content');
423
    $content->name = $form_state['values']['name'];
424
    _ctools_custom_content_type_edit_save($content, $form_state);
425
    $form_state['conf']['name'] = $content->name;
426
  }
427
  else {
428
    // Otherwise, just save values into $conf normally.
429

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