Projet

Général

Profil

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

root / htmltest / sites / all / modules / panels / panels_ipe / plugins / display_renderers / panels_renderer_ipe.class.php @ c12e7e6a

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * Renderer class for all In-Place Editor (IPE) behavior.
5
 */
6
class panels_renderer_ipe extends panels_renderer_editor {
7
  // The IPE operates in normal render mode, not admin mode.
8
  var $admin = FALSE;
9
10
  function render() {
11
    $output = parent::render();
12
    return "<div id='panels-ipe-display-{$this->clean_key}' class='panels-ipe-display-container'>$output</div>";
13
  }
14
15
  function add_meta() {
16
    ctools_include('display-edit', 'panels');
17
    ctools_include('content');
18
19
    if (empty($this->display->cache_key)) {
20
      $this->cache = panels_edit_cache_get_default($this->display);
21
    }
22
    // @todo we may need an else to load the cache, but I am not sure we
23
    // actually need to load it if we already have our cache key, and doing
24
    // so is a waste of resources.
25
26
    ctools_include('cleanstring');
27
    $this->clean_key = ctools_cleanstring($this->display->cache_key);
28
    $button = array(
29
      '#type' => 'link',
30
      '#title' => t('Customize this page'),
31
      '#href' => $this->get_url('save_form'),
32
      '#id' => 'panels-ipe-customize-page',
33
      '#attributes' => array(
34
        'class' => array('panels-ipe-startedit', 'panels-ipe-pseudobutton'),
35
      ),
36
      '#ajax' => array(
37
        'progress' => 'throbber',
38
        'ipe_cache_key' => $this->clean_key,
39
      ),
40
      '#prefix' => '<div class="panels-ipe-pseudobutton-container">',
41
      '#suffix' => '</div>',
42
    );
43
44
    panels_ipe_toolbar_add_button($this->clean_key, 'panels-ipe-startedit', $button);
45
46
    // @todo this actually should be an IPE setting instead.
47
    if (user_access('change layouts in place editing')) {
48
      $button = array(
49
        '#type' => 'link',
50
        '#title' => t('Change layout'),
51
        '#href' => $this->get_url('change_layout'),
52
        '#attributes' => array(
53
          'class' => array('panels-ipe-change-layout', 'panels-ipe-pseudobutton', 'ctools-modal-layout'),
54
        ),
55
        '#ajax' => array(
56
          'progress' => 'throbber',
57
          'ipe_cache_key' => $this->clean_key,
58
        ),
59
60
      '#prefix' => '<div class="panels-ipe-pseudobutton-container">',
61
      '#suffix' => '</div>',
62
      );
63
64
      panels_ipe_toolbar_add_button($this->clean_key, 'panels-ipe-change-layout', $button);
65
    }
66
67
    ctools_include('ajax');
68
    ctools_include('modal');
69
    ctools_modal_add_js();
70
71
    ctools_add_css('panels_dnd', 'panels');
72
    ctools_add_css('panels_admin', 'panels');
73
    ctools_add_js('panels_ipe', 'panels_ipe');
74
    ctools_add_css('panels_ipe', 'panels_ipe');
75
76
    drupal_add_js(array('PanelsIPECacheKeys' => array($this->clean_key)), 'setting');
77
78
    drupal_add_library('system', 'ui.draggable');
79
    drupal_add_library('system', 'ui.droppable');
80
    drupal_add_library('system', 'ui.sortable');
81
82
    parent::add_meta();
83
  }
84
85
  /**
86
   * Override & call the parent, then pass output through to the dnd wrapper
87
   * theme function.
88
   *
89
   * @param $pane
90
   */
91
  function render_pane(&$pane) {
92
    $output = parent::render_pane($pane);
93
    if (empty($output)) {
94
      return;
95
    }
96
97
    // If there are region locks, add them.
98
    if (!empty($pane->locks['type']) && $pane->locks['type'] == 'regions') {
99
      static $key = NULL;
100
      $javascript = &drupal_static('drupal_add_js', array());
101
102
      // drupal_add_js breaks as we add these, but we can't just lump them
103
      // together because panes can be rendered independently. So game the system:
104
      if (empty($key)) {
105
        $settings['Panels']['RegionLock'][$pane->pid] = $pane->locks['regions'];
106
        drupal_add_js($settings, 'setting');
107
108
        // These are just added via [] so we have to grab the last one
109
        // and reference it.
110
        $keys = array_keys($javascript['settings']['data']);
111
        $key = end($keys);
112
      }
113
      else {
114
        $javascript['settings']['data'][$key]['Panels']['RegionLock'][$pane->pid] = $pane->locks['regions'];
115
      }
116
117
    }
118
119
    if (empty($pane->IPE_empty)) {
120
      // Add an inner layer wrapper to the pane content before placing it into
121
      // draggable portlet
122
      $output = "<div class=\"panels-ipe-portlet-content\">$output</div>";
123
    }
124
    else {
125
      $output = "<div class=\"panels-ipe-portlet-content panels-ipe-empty-pane\">$output</div>";
126
    }
127
    // Hand it off to the plugin/theme for placing draggers/buttons
128
    $output = theme('panels_ipe_pane_wrapper', array('output' => $output, 'pane' => $pane, 'display' => $this->display, 'renderer' => $this));
129
130
    if (!empty($pane->locks['type']) && $pane->locks['type'] == 'immovable') {
131
      return "<div id=\"panels-ipe-paneid-{$pane->pid}\" class=\"panels-ipe-nodrag panels-ipe-portlet-wrapper panels-ipe-portlet-marker\">" . $output . "</div>";
132
    }
133
134
    return "<div id=\"panels-ipe-paneid-{$pane->pid}\" class=\"panels-ipe-portlet-wrapper panels-ipe-portlet-marker\">" . $output . "</div>";
135
  }
136
137
  function render_pane_content(&$pane) {
138
    $content = parent::render_pane_content($pane);
139
    // Ensure that empty panes have some content.
140
    if (empty($content) || empty($content->content)) {
141
      // Get the administrative title.
142
      $content_type = ctools_get_content_type($pane->type);
143
      $title = ctools_content_admin_title($content_type, $pane->subtype, $pane->configuration, $this->display->context);
144
145
      $content->content = t('Placeholder for empty "@title"', array('@title' => $title));
146
      // Add these to prevent notices.
147
      $content->type = 'panels_ipe';
148
      $content->subtype = 'panels_ipe';
149
      $pane->IPE_empty = TRUE;
150
    }
151
152
    return $content;
153
  }
154
155
  /**
156
   * Add an 'empty' pane placeholder above all the normal panes.
157
   *
158
   * @param $region_id
159
   * @param $panes
160
   */
161
  function render_region($region_id, $panes) {
162
    // Generate this region's 'empty' placeholder pane from the IPE plugin.
163
    $empty_ph = theme('panels_ipe_placeholder_pane', array('region_id' => $region_id, 'region_title' => $this->plugins['layout']['regions'][$region_id]));
164
165
    // Wrap the placeholder in some guaranteed markup.
166
    $control = '<div class="panels-ipe-placeholder panels-ipe-on panels-ipe-portlet-marker panels-ipe-portlet-static">' . $empty_ph . theme('panels_ipe_add_pane_button', array('region_id' => $region_id, 'display' => $this->display, 'renderer' => $this)) . "</div>";
167
168
    $output = parent::render_region($region_id, $panes);
169
    $output = theme('panels_ipe_region_wrapper', array('output' => $output, 'region_id' => $region_id, 'display' => $this->display, 'controls' => $control, 'renderer' => $this));
170
    $classes = 'panels-ipe-region';
171
172
    return "<div id='panels-ipe-regionid-$region_id' class='panels-ipe-region'>$output</div>";
173
  }
174
175
  /**
176
   * This is a generic lock test.
177
   */
178
  function ipe_test_lock($url, $break) {
179
    if (!empty($this->cache->locked)) {
180
      if ($break != 'break') {
181
        $account  = user_load($this->cache->locked->uid);
182
        $name     = format_username($account);
183
        $lock_age = format_interval(time() - $this->cache->locked->updated);
184
185
        $message = t("This panel is being edited by user !user, and is therefore locked from editing by others. This lock is !age old.\n\nClick OK to break this lock and discard any changes made by !user.", array('!user' => $name, '!age' => $lock_age));
186
187
        $this->commands[] = array(
188
          'command' => 'unlockIPE',
189
          'message' => $message,
190
          'break_path' => url($this->get_url($url, 'break')),
191
          'key' => $this->clean_key,
192
        );
193
        return TRUE;
194
      }
195
196
      // Break the lock.
197
      panels_edit_cache_break_lock($this->cache);
198
    }
199
  }
200
201
  /**
202
   * AJAX callback to unlock the IPE.
203
   *
204
   * This is called whenever something server side determines that editing
205
   * has stopped and cleans up no longer needed locks.
206
   *
207
   * It has no visible return value as this is considered a background task
208
   * and the client side has already given all indications that things are
209
   * now in a 'normal' state.
210
   */
211
  function ajax_unlock_ipe() {
212
    panels_edit_cache_clear($this->cache);
213
    $this->commands[] = array();
214
  }
215
216
  /**
217
   * AJAX entry point to create the controller form for an IPE.
218
   */
219
  function ajax_save_form($break = NULL) {
220
    if ($this->ipe_test_lock('save-form', $break)) {
221
      return;
222
    }
223
224
    // Reset the $_POST['ajax_html_ids'] values to preserve
225
    // proper IDs on form elements when they are rebuilt
226
    // by the Panels IPE without refreshing the page
227
    $_POST['ajax_html_ids'] = array();
228
229
    $form_state = array(
230
      'display' => &$this->display,
231
      'content_types' => $this->cache->content_types,
232
      'rerender' => FALSE,
233
      'no_redirect' => TRUE,
234
      // Panels needs this to make sure that the layout gets callbacks
235
      'layout' => $this->plugins['layout'],
236
    );
237
238
    $output = drupal_build_form('panels_ipe_edit_control_form', $form_state);
239
    if (empty($form_state['executed'])) {
240
      // At this point, we want to save the cache to ensure that we have a lock.
241
      $this->cache->ipe_locked = TRUE;
242
      panels_edit_cache_set($this->cache);
243
      $this->commands[] = array(
244
        'command' => 'initIPE',
245
        'key' => $this->clean_key,
246
        'data' => drupal_render($output),
247
        'lockPath' => $this->get_url('unlock_ipe'),
248
      );
249
      return;
250
    }
251
252
    // Check to see if we have a lock that was broken. If so we need to
253
    // inform the user and abort.
254
    if (empty($this->cache->ipe_locked)) {
255
      $this->commands[] = ajax_command_alert(t('A lock you had has been externally broken, and all your changes have been reverted.'));
256
      $this->commands[] = array(
257
        'command' => 'cancelIPE',
258
        'key' => $this->clean_key,
259
      );
260
      return;
261
    }
262
263
    // Otherwise it was submitted.
264
    if (!empty($form_state['clicked_button']['#save-display'])) {
265
      // Saved. Save the cache.
266
      panels_edit_cache_save($this->cache);
267
      // A rerender should fix IDs on added panes as well as ensure style changes are
268
      // rendered.
269
      $this->meta_location = 'inline';
270
      $this->commands[] = ajax_command_replace("#panels-ipe-display-{$this->clean_key}", panels_render_display($this->display, $this));
271
    }
272
    else {
273
      // Cancelled. Clear the cache.
274
      panels_edit_cache_clear($this->cache);
275
    }
276
277
    $this->commands[] = array(
278
      'command' => 'endIPE',
279
      'key' => $this->clean_key,
280
    );
281
  }
282
283
  /**
284
   * AJAX entry point to create the controller form for an IPE.
285
   */
286
  function ajax_change_layout($break = NULL) {
287
    if ($this->ipe_test_lock('change_layout', $break)) {
288
      return;
289
    }
290
291
    // At this point, we want to save the cache to ensure that we have a lock.
292
    $this->cache->ipe_locked = TRUE;
293
    panels_edit_cache_set($this->cache);
294
295
    ctools_include('plugins', 'panels');
296
    ctools_include('common', 'panels');
297
298
    // @todo figure out a solution for this, it's critical
299
    if (isset($this->display->allowed_layouts)) {
300
      $layouts = $this->display->allowed_layouts;
301
    }
302
    else {
303
      $layouts = panels_common_get_allowed_layouts('panels_page');
304
    }
305
306
    // Filter out builders
307
    $layouts = array_filter($layouts, '_panels_builder_filter');
308
309
    // Define the current layout
310
    $current_layout = $this->plugins['layout']['name'];
311
312
    $output = panels_common_print_layout_links($layouts, $this->get_url('set_layout'), array('attributes' => array('class' => array('use-ajax'))), $current_layout);
313
314
    $this->commands[] = ctools_modal_command_display(t('Change layout'), $output);
315
    $this->commands[] = array(
316
      'command' => 'IPEsetLockState',
317
      'key' => $this->clean_key,
318
      'lockPath' => $this->get_url('unlock_ipe'),
319
    );
320
  }
321
322
  function ajax_set_layout($layout) {
323
    ctools_include('context');
324
    ctools_include('display-layout', 'panels');
325
    $form_state = array(
326
      'layout' => $layout,
327
      'display' => $this->display,
328
      'finish' => t('Save'),
329
      'no_redirect' => TRUE,
330
    );
331
332
    // Reset the $_POST['ajax_html_ids'] values to preserve
333
    // proper IDs on form elements when they are rebuilt
334
    // by the Panels IPE without refreshing the page
335
    $_POST['ajax_html_ids'] = array();
336
337
    $output = drupal_build_form('panels_change_layout', $form_state);
338
    $output = drupal_render($output);
339
    if (!empty($form_state['executed'])) {
340
      if (isset($form_state['back'])) {
341
        return $this->ajax_change_layout();
342
      }
343
344
      if (!empty($form_state['clicked_button']['#save-display'])) {
345
        // Saved. Save the cache.
346
        panels_edit_cache_save($this->cache);
347
        $this->display->skip_cache;
348
349
        // Since the layout changed, we have to update these things in the
350
        // renderer in order to get the right settings.
351
        $layout = panels_get_layout($this->display->layout);
352
        $this->plugins['layout'] = $layout;
353
        if (!isset($layout['regions'])) {
354
          $this->plugins['layout']['regions'] = panels_get_regions($layout, $this->display);
355
        }
356
357
        $this->meta_location = 'inline';
358
359
        $this->commands[] = ajax_command_replace("#panels-ipe-display-{$this->clean_key}", panels_render_display($this->display, $this));
360
        $this->commands[] = ctools_modal_command_dismiss();
361
        return;
362
      }
363
    }
364
365
    $this->commands[] = ctools_modal_command_display(t('Change layout'), $output);
366
  }
367
368
  /**
369
   * Create a command array to redraw a pane.
370
   */
371
  function command_update_pane($pid) {
372
    if (is_object($pid)) {
373
      $pane = $pid;
374
    }
375
    else {
376
      $pane = $this->display->content[$pid];
377
    }
378
379
    $this->commands[] = ajax_command_replace("#panels-ipe-paneid-$pane->pid", $this->render_pane($pane));
380
    $this->commands[] = ajax_command_changed("#panels-ipe-display-{$this->clean_key}");
381
  }
382
383
  /**
384
   * Create a command array to add a new pane.
385
   */
386
  function command_add_pane($pid) {
387
    if (is_object($pid)) {
388
      $pane = $pid;
389
    }
390
    else {
391
      $pane = $this->display->content[$pid];
392
    }
393
394
    $this->commands[] = ajax_command_prepend("#panels-ipe-regionid-{$pane->panel} div.panels-ipe-sort-container", $this->render_pane($pane));
395
    $this->commands[] = ajax_command_changed("#panels-ipe-display-{$this->clean_key}");
396
  }
397
}
398
399
/**
400
 * FAPI callback to create the Save/Cancel form for the IPE.
401
 */
402
function panels_ipe_edit_control_form($form, &$form_state) {
403
  $display = &$form_state['display'];
404
  // @todo -- this should be unnecessary as we ensure cache_key is set in add_meta()
405
//  $display->cache_key = isset($display->cache_key) ? $display->cache_key : $display->did;
406
407
  // Annoyingly, theme doesn't have access to form_state so we have to do this.
408
  $form['#display'] = $display;
409
410
  $layout = panels_get_layout($display->layout);
411
  $layout_panels = panels_get_regions($layout, $display);
412
413
  $form['panel'] = array('#tree' => TRUE);
414
  $form['panel']['pane'] = array('#tree' => TRUE);
415
416
  foreach ($layout_panels as $panel_id => $title) {
417
    // Make sure we at least have an empty array for all possible locations.
418
    if (!isset($display->panels[$panel_id])) {
419
      $display->panels[$panel_id] = array();
420
    }
421
422
    $form['panel']['pane'][$panel_id] = array(
423
      // Use 'hidden' instead of 'value' so the js can access it.
424
      '#type' => 'hidden',
425
      '#default_value' => implode(',', (array) $display->panels[$panel_id]),
426
    );
427
  }
428
429
  $form['buttons']['submit'] = array(
430
    '#type' => 'submit',
431
    '#value' => t('Save'),
432
    '#id' => 'panels-ipe-save',
433
    '#submit' => array('panels_edit_display_form_submit'),
434
    '#save-display' => TRUE,
435
  );
436
  $form['buttons']['cancel'] = array(
437
    '#type' => 'submit',
438
    '#id' => 'panels-ipe-cancel',
439
    '#value' => t('Cancel'),
440
  );
441
  return $form;
442
}