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
<?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
}