wysiwyg.dialog.inc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. /**
  3. * @file
  4. * Wysiwyg dialog page handling functions.
  5. */
  6. /**
  7. * Page callback; Outputs a dialog page for a wysiwyg plugin.
  8. *
  9. * A Wysiwyg dialog is a bare minimum, simple HTML page; presented in a
  10. * modal/popup window, triggered via JavaScript.
  11. *
  12. * However, Drupal core does not support such a concept, at all.
  13. * Insanity happens on two separate layers:
  14. * - All HTML pages go through the default delivery callback of
  15. * drupal_deliver_html_page(), which calls into drupal_render_page(), which
  16. * in turn *unconditionally* invokes hook_page_build() implementations. Thus,
  17. * block_page_build() and similar implementations add the entirety of their
  18. * page regions and blocks to our simple dialog page.
  19. * Obviously, we don't want that.
  20. * - There is a nice default 'page' theme template implementation, which
  21. * performs all the heavy-lifting that is required for outputting a sane HTML
  22. * page through preprocess and process functions. The theme system does not
  23. * support to "inherit" preprocess and process hooks to alternative
  24. * implementations. Even a very basic HTML page requires almost all of that.
  25. * However, the default page template (normally overridden by a theme)
  26. * contains too many regions and usually also huge a header and footer.
  27. * Obviously, we don't want that.
  28. *
  29. * The poor workaround would be to follow the Overlay module's implementation in
  30. * core: override the theme, build everything, and after doing all of that,
  31. * strip away what isn't needed. Obviously, we don't want that.
  32. *
  33. * Instead, we bend Drupal to sane rules:
  34. * - This page callback returns the actual main content.
  35. * - wysiwyg_menu() defines a custom delivery callback that replaces
  36. * drupal_deliver_html_page(), just because we need to replace
  37. * drupal_render_page().
  38. * - Our replacement for drupal_render_page() builds a $page that does not use
  39. * #type 'page' but #type 'wysiwyg_dialog_page' instead.
  40. * - #type 'wysiwyg_dialog_page' is defined like #type 'page' in
  41. * system_element_info(), but is required, because there's no way to inherit
  42. * a theme definition but override the page template file to be used.
  43. * - As a consequence, #type 'wysiwyg_dialog_page' uses
  44. * #theme 'wysiwyg_dialog_page', for which we have to implement stub
  45. * preprocess and process callbacks in order to call into the ones for
  46. * #theme 'page'.
  47. *
  48. * As a result we get:
  49. * - A HTML response.
  50. * - A HTML page wrapped into html.tpl.php.
  51. * - A page title, title prefix/suffix, messages, help, etc.pp.
  52. * - A simple page without regions and blocks (neither built nor rendered).
  53. *
  54. * @see wysiwyg_menu()
  55. * @see wysiwyg_deliver_dialog_page
  56. * @see wysiwyg_render_dialog_page()
  57. * @see wysiwyg_element_info()
  58. * @see wysiwyg_theme()
  59. * @see template_preprocess_wysiwyg_dialog_page()
  60. * @see template_process_wysiwyg_dialog_page()
  61. *
  62. * @see drupal_deliver_page()
  63. * @see drupal_deliver_html_page()
  64. * @see drupal_render_page()
  65. * @see system_element_info()
  66. * @see drupal_common_theme()
  67. * @see template_preprocess_page()
  68. * @see template_process_page()
  69. */
  70. function wysiwyg_dialog($plugin, $instance) {
  71. $plugins = wysiwyg_get_all_plugins();
  72. if (!isset($plugins[$plugin])) {
  73. return drupal_access_denied();
  74. }
  75. $callback = $plugin . '_wysiwyg_dialog';
  76. if (!function_exists($callback)) {
  77. return drupal_not_found();
  78. }
  79. // Suppress admin menu.
  80. module_invoke('admin_menu', 'suppress');
  81. // Add editor instance id to Drupal.settings.
  82. $settings = array(
  83. 'plugin' => $plugin,
  84. 'instance' => $instance,
  85. );
  86. drupal_add_js(array('wysiwyg' => $settings), 'setting');
  87. $build = $callback($instance);
  88. if (!is_array($build)) {
  89. $build = array('#markup' => $build);
  90. }
  91. $build += array(
  92. '#instance' => $instance,
  93. '#plugin' => $plugin,
  94. );
  95. return $build;
  96. }
  97. /**
  98. * @see drupal_deliver_html_page()
  99. */
  100. function wysiwyg_deliver_dialog_page($page_callback_result) {
  101. // Menu status constants are integers; page content is a string or array.
  102. if (is_int($page_callback_result)) {
  103. return drupal_deliver_html_page($page_callback_result);
  104. }
  105. // Emit the correct charset HTTP header, but not if the page callback
  106. // result is NULL, since that likely indicates that it printed something
  107. // in which case, no further headers may be sent, and not if code running
  108. // for this page request has already set the content type header.
  109. if (isset($page_callback_result) && is_null(drupal_get_http_header('Content-Type'))) {
  110. drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
  111. }
  112. // Send appropriate HTTP-Header for browsers and search engines.
  113. global $language;
  114. drupal_add_http_header('Content-Language', $language->language);
  115. if (isset($page_callback_result)) {
  116. // Print anything besides a menu constant, assuming it's not NULL or
  117. // undefined.
  118. print wysiwyg_render_dialog_page($page_callback_result);
  119. }
  120. // Perform end-of-request tasks.
  121. drupal_page_footer();
  122. }
  123. /**
  124. * @see drupal_render_page()
  125. */
  126. function wysiwyg_render_dialog_page($page) {
  127. $main_content_display = &drupal_static('system_main_content_added', FALSE);
  128. // Allow menu callbacks to return strings or arbitrary arrays to render.
  129. // If the array returned is not of #type page directly, we need to fill
  130. // in the page with defaults.
  131. if (is_string($page) || (is_array($page) && (!isset($page['#type']) || ($page['#type'] != 'page')))) {
  132. drupal_set_page_content($page);
  133. $page = element_info('wysiwyg_dialog_page');
  134. }
  135. // Modules alter the $page as needed. Blocks are populated into regions like
  136. // 'sidebar_first', 'footer', etc.
  137. drupal_alter(array('wysiwyg_dialog_page', 'page'), $page);
  138. // If no module has taken care of the main content, add it to the page now.
  139. // This allows the site to still be usable even if no modules that
  140. // control page regions (for example, the Block module) are enabled.
  141. if (!$main_content_display) {
  142. $page['content']['system_main'] = drupal_set_page_content();
  143. }
  144. return drupal_render($page);
  145. }
  146. /**
  147. * Template preprocess function for theme_wysiwyg_dialog_page().
  148. *
  149. * @see wysiwyg_dialog()
  150. * @see wysiwyg-dialog-page.tpl.php
  151. * @see template_preprocess_page()
  152. */
  153. function template_preprocess_wysiwyg_dialog_page(&$variables) {
  154. template_preprocess_page($variables);
  155. }
  156. /**
  157. * Template process function for theme_wysiwyg_dialog_page().
  158. *
  159. * @see wysiwyg_dialog()
  160. * @see wysiwyg-dialog-page.tpl.php
  161. * @see template_process_page()
  162. */
  163. function template_process_wysiwyg_dialog_page(&$variables) {
  164. template_process_page($variables);
  165. }